ScummVM API documentation
macgui_impl.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef SCUMM_MACGUI_MACGUI_IMPL_H
23 #define SCUMM_MACGUI_MACGUI_IMPL_H
24 
25 #define TEXT_END_MARKER { 0, 0, kStyleRegular, Graphics::kTextAlignLeft, nullptr }
26 
27 #include "common/events.h"
28 #include "common/hashmap.h"
29 #include "common/rect.h"
30 #include "common/str.h"
31 #include "common/str-array.h"
32 
33 #include "graphics/font.h"
34 
35 class OSystem;
36 
37 namespace Graphics {
38 struct Surface;
39 class MacWindowManager;
40 }
41 
42 namespace Scumm {
43 
44 class ScummEngine;
45 class Actor;
46 
47 class MacGuiImpl {
48 public:
49  class MacDialogWindow;
50 
51 protected:
52  ScummEngine *_vm = nullptr;
53  OSystem *_system = nullptr;
54 
55  Graphics::Surface *_surface = nullptr;
56  MacGuiImpl::MacDialogWindow *_bannerWindow = nullptr;
57 
58  Common::Path _resourceFile;
59 
60  bool _menuIsActive = false;
61  bool _cursorWasVisible = false;
62 
64  int _gameFontId = -1;
65 
66  byte _unicodeToMacRoman[96];
67 
68  enum DelayStatus {
69  kDelayDone = 0,
70  kDelayInterrupted = 1,
71  kDelayAborted
72  };
73 
74  enum Color {
75  kBlack = 0,
76  kBlue = 1,
77  kGreen = 2,
78  kCyan = 3,
79  kRed = 4,
80  kMagenta = 5,
81  kBrown = 6,
82  kLightGray = 7,
83  kDarkGray = 8,
84  kBrightBlue = 9,
85  kBrightGreen = 10,
86  kBrightCyan = 11,
87  kBrightRed = 12,
88  kBrightMagenta = 13,
89  kBrightYellow = 14,
90  kWhite = 15,
91 
92  // Reserved for custom colors, loaded from PICT resources.
93  kCustomColor = 100,
94 
95  kBackground = 254, // Gray or checkerboard
96  kTransparency = 255
97  };
98 
99  enum FontId {
100  kSystemFont,
101 
102  kAboutFontRegular,
103  kAboutFontBold,
104  kAboutFontExtraBold,
105  kAboutFontHeaderInside,
106  kAboutFontHeaderOutside,
107 
108  kIndy3FontSmall,
109  kIndy3FontMedium,
110  kIndy3VerbFontRegular,
111  kIndy3VerbFontBold,
112  kIndy3VerbFontOutline,
113 
114  kLoomFontSmall,
115  kLoomFontMedium,
116  kLoomFontLarge
117  };
118 
119  enum TextStyle {
120  kStyleHeader,
121  kStyleBold,
122  kStyleExtraBold,
123  kStyleRegular
124  };
125 
126  struct TextLine {
127  int x;
128  int y;
129  TextStyle style;
130  Graphics::TextAlign align;
131  const char *str;
132  };
133 
134  enum MacDialogWindowStyle {
135  kStyleNormal,
136  kStyleRounded
137  };
138 
139  MacGuiImpl::DelayStatus delay(uint32 ms = 0);
140 
141  virtual bool getFontParams(FontId fontId, int &id, int &size, int &slant) const;
142 
143  Common::String getDialogString(Common::SeekableReadStream *res, int len);
144 
145  virtual bool handleMenu(int id, Common::String &name);
146 
147  virtual void runAboutDialog() = 0;
148  virtual bool runOpenDialog(int &saveSlotToHandle) = 0;
149  virtual bool runSaveDialog(int &saveSlotToHandle, Common::String &name) = 0;
150  virtual bool runOptionsDialog() = 0;
151  void prepareSaveLoad(Common::StringArray &savegameNames, bool *availSlots, int *slotIds, int size);
152 
153  bool runOkCancelDialog(Common::String text);
154 
155 public:
156  class MacGuiObject {
157  protected:
158  Common::Rect _bounds;
159  bool _redraw = false;
160  bool _enabled = false;
161  bool _visible = true;
162 
163  public:
164  MacGuiObject(Common::Rect bounds, bool enabled) : _bounds(bounds), _enabled(enabled) {}
165  virtual ~MacGuiObject() {}
166 
167  Common::Rect getBounds() const { return _bounds; }
168  bool getRedraw() const { return _redraw; }
169  bool isEnabled() const { return _enabled; }
170  bool isVisible() const { return _visible; }
171  };
172 
173  class MacWidget : public MacGuiObject {
174  protected:
176  int _id = -1;
177 
178  bool _fullRedraw = false;
179 
180  Common::String _text;
181  int _value = 0;
182 
183  int drawText(Common::String text, int x, int y, int w, Color fg = kBlack, Color bg = kWhite, Graphics::TextAlign align = Graphics::kTextAlignLeft, bool wordWrap = false, int deltax = 0) const;
184  void drawBitmap(Common::Rect r, const uint16 *bitmap, Color color) const;
185 
186  public:
187  MacWidget(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled);
188  virtual ~MacWidget() {};
189 
190  void setId(int id) { _id = id; }
191  int getId() const { return _id; }
192 
193  // Visibility never changes after initialization, so it does
194  // not trigger a redraw.
195  void setVisible(bool visible) { _visible = visible; }
196 
197  virtual void getFocus() { setRedraw(); }
198  virtual void loseFocus() { setRedraw(); }
199 
200  virtual void setRedraw(bool fullRedraw = false);
201 
202  void setEnabled(bool enabled);
203 
204  virtual void setValue(int value);
205  int getValue() const { return _value; }
206 
207  Common::String getText() const;
208 
209  virtual bool useBeamCursor() { return false; }
210  virtual bool findWidget(int x, int y) const;
211  virtual bool shouldDeferAction() { return false; }
212 
213  virtual void draw(bool drawFocused = false) = 0;
214 
215  virtual void handleMouseDown(Common::Event &event) {}
216  virtual bool handleDoubleClick(Common::Event &event) { return false; }
217  virtual bool handleMouseUp(Common::Event &event) { return false; }
218  virtual void handleMouseMove(Common::Event &event) {}
219  virtual void handleMouseHeld() {}
220  virtual void handleWheelUp() {}
221  virtual void handleWheelDown() {}
222  virtual bool handleKeyDown(Common::Event &event) { return false; }
223  };
224 
225  class MacButton : public MacWidget {
226  private:
227  struct CornerLine {
228  int start;
229  int length;
230  };
231 
232  void hLine(int x0, int y0, int x1, bool enabled);
233  void vLine(int x0, int y0, int y1, bool enabled);
234  void drawCorners(Common::Rect r, CornerLine *corner, bool enabled);
235 
236  public:
237  MacButton(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled) : MacWidget(window, bounds, text, enabled) {}
238 
239  void draw(bool drawFocused = false);
240 
241  bool handleMouseUp(Common::Event &event) { return true; }
242  };
243 
244  class MacCheckbox : public MacWidget {
245  private:
246  Common::Rect _hitBounds;
247 
248  public:
249  MacCheckbox(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled);
250 
251  bool findWidget(int x, int y) const;
252  void draw(bool drawFocused = false);
253  bool handleMouseUp(Common::Event &event);
254  };
255 
256  // The dialogs add texts as disabled, but we don't want it to be drawn
257  // as disabled so we enable it and make it "disabled" by giving it a
258  // custom findWidget().
259 
260  class MacStaticText : public MacWidget {
261  private:
262  Color _fg = kBlack;
263  Color _bg = kWhite;
264  bool _wordWrap = false;
265 
266  public:
267  MacStaticText(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled) : MacWidget(window, bounds, text, true) {}
268 
269  void getFocus() {}
270  void loseFocus() {}
271 
272  void setWordWrap(bool wordWrap) { _wordWrap = wordWrap; }
273 
274  void setText(Common::String text) {
275  if (text != _text) {
276  _text = text;
277  setRedraw();
278  }
279  }
280 
281  void setColor(Color fg, Color bg) {
282  if (fg != _fg || bg != _bg) {
283  _fg = fg;
284  _bg = bg;
285  setRedraw();
286  }
287  }
288 
289  void draw(bool drawFocused = false);
290  };
291 
292  class MacEditText : public MacWidget {
293  private:
294  // Max length of a SCUMM saved game name. We could make this
295  // configurable later, if needed.
296  uint _maxLength = 31;
297 
298  int _textPos = 1;
299  int _selectLen = 0;
300  int _caretPos = 0;
301  int _caretX = -1;
302 
303  uint32 _nextCaretBlink = 0;
304  bool _caretVisible = true;
305 
306  const Graphics::Font *_font;
307  Graphics::Surface _textSurface;
308 
309  int getTextPosFromMouse(int x, int y);
310 
311  void updateSelection(int x, int y);
312  void deleteSelection();
313 
314  public:
315  MacEditText(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::String text, bool enabled);
316 
317  void getFocus() override {}
318  void loseFocus() override {}
319 
320  void selectAll();
321 
322  bool useBeamCursor() override { return true; }
323  bool findWidget(int x, int y) const override;
324  bool shouldDeferAction() override { return true; }
325 
326  void draw(bool drawFocused = false) override;
327 
328  void handleMouseDown(Common::Event &event) override;
329  bool handleDoubleClick(Common::Event &event) override;
330  bool handleKeyDown(Common::Event &event) override;
331  void handleMouseHeld() override;
332  void handleMouseMove(Common::Event &event) override;
333  };
334 
335  class MacPicture : public MacWidget {
336  private:
337  Graphics::Surface *_picture = nullptr;
338 
339  public:
340  MacPicture(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, int id, bool enabled);
341  ~MacPicture();
342 
343  Graphics::Surface *getPicture() const { return _picture; }
344 
345  void draw(bool drawFocused = false);
346  };
347 
348  class MacSliderBase : public MacWidget {
349  protected:
350  int _minValue;
351  int _maxValue;
352  int _minPos;
353  int _maxPos;
354  int _handlePos = -1;
355  int _grabOffset = -1;
356 
357  int calculateValueFromPos() const;
358  int calculatePosFromValue() const;
359 
360  public:
361  MacSliderBase(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, int minValue, int maxValue, int minPos, int maxPos, bool enabled)
362  : MacWidget(window, bounds, "SliderBase", enabled),
363  _minValue(minValue), _maxValue(maxValue),
364  _minPos(minPos), _maxPos(maxPos) {}
365 
366  void getFocus() {}
367  void loseFocus() {}
368 
369  void setValue(int value);
370  };
371 
372  class MacSlider : public MacSliderBase {
373  private:
374  Common::Point _clickPos;
375  uint32 _nextRepeat;
376 
377  int _pageSize;
378  int _paging;
379 
380  bool _upArrowPressed = false;
381  bool _downArrowPressed = false;
382 
383  Common::Rect _boundsButtonUp;
384  Common::Rect _boundsButtonDown;
385  Common::Rect _boundsBody;
386 
387  Common::Rect getHandleRect(int value);
388 
389  void fill(Common::Rect r, bool inverted = false);
390 
391  void drawUpArrow(bool markAsDirty);
392  void drawDownArrow(bool markAsDirty);
393  void drawArrow(Common::Rect r, const uint16 *bitmap, bool markAsDirty);
394 
395  void eraseDragHandle();
396  void drawHandle(Common::Rect r);
397 
398  public:
399  MacSlider(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, int minValue, int maxValue, int pageSize, bool enabled);
400 
401  bool isScrollable() const { return (_maxValue - _minValue) > 0; }
402  int getPageSize() const { return _pageSize; }
403 
404  bool findWidget(int x, int y) const;
405  void draw(bool drawFocued = false);
406  void redrawHandle(int oldValue, int newValue);
407 
408  void handleMouseDown(Common::Event &event);
409  bool handleMouseUp(Common::Event &event);
410  void handleMouseMove(Common::Event &event);
411  void handleMouseHeld();
412  void handleWheelUp();
413  void handleWheelDown();
414  };
415 
417  private:
418  MacPicture *_background;
419  MacPicture *_handle;
420  int _minX;
421  int _maxX;
422 
423  void eraseHandle();
424  void drawHandle();
425 
426  public:
427  MacPictureSlider(MacGuiImpl::MacDialogWindow *window, MacPicture *background, MacPicture *handle, bool enabled, int minX, int maxX, int minValue, int maxValue, int leftMargin, int rightMargin)
428  : MacSliderBase(window, background->getBounds(), minValue, maxValue, minX + leftMargin, maxX - rightMargin, enabled),
429  _background(background), _handle(handle), _minX(minX),
430  _maxX(maxX) {}
431 
432  bool findWidget(int x, int y) const;
433  void draw(bool drawFocused = false);
434 
435  void handleMouseDown(Common::Event &event);
436  bool handleMouseUp(Common::Event &event);
437  void handleMouseMove(Common::Event &event);
438  void handleWheelUp();
439  void handleWheelDown();
440  };
441 
442  class MacListBox : public MacWidget {
443  private:
444  Common::StringArray _texts;
445  Common::Array<MacStaticText *> _textWidgets;
446  MacSlider *_slider;
447  bool _sliderFocused = false;
448 
449  void updateTexts();
450  void handleWheel(int distance);
451 
452  public:
453  MacListBox(MacGuiImpl::MacDialogWindow *window, Common::Rect bounds, Common::StringArray texts, bool enabled, bool contentUntouchable = true);
454  ~MacListBox();
455 
456  void getFocus() {}
457  void loseFocus() {}
458 
459  void setValue(int value) {
460  if (value != _value) {
461  _value = value;
462  updateTexts();
463  }
464  }
465 
466  int getValue() {
467  return _value;
468  }
469 
470  bool findWidget(int x, int y) const;
471  void setRedraw(bool fullRedraw = false);
472  void draw(bool drawFocused = false);
473 
474  void handleMouseDown(Common::Event &event);
475  bool handleDoubleClick(Common::Event &event);
476  bool handleMouseUp(Common::Event &event);
477  void handleMouseMove(Common::Event &event);
478  void handleMouseHeld();
479  void handleWheelUp();
480  void handleWheelDown();
481  bool handleKeyDown(Common::Event &event);
482  };
483 
485  private:
486  bool _shakeWasEnabled;
487 
488  Common::Rect _bounds;
489  int _margin;
490 
491  bool _visible = false;
492 
493  uint32 _lastClickTime = 0;
494  Common::Point _lastClickPos;
495 
496  Graphics::Surface *_beamCursor = nullptr;
497  Common::Point _beamCursorPos;
498  bool _cursorWasVisible = false;
499  bool _beamCursorVisible = false;
500  const int _beamCursorHotspotX = 3;
501  const int _beamCursorHotspotY = 4;
502 
503  void drawBeamCursor();
504  void undrawBeamCursor();
505 
506  PauseToken _pauseToken;
507 
508  Graphics::Surface *_from = nullptr;
509  Graphics::Surface *_backup = nullptr;
510  Graphics::Surface _surface;
511  Graphics::Surface _innerSurface;
512 
514 
515  MacWidget *_defaultWidget = nullptr;
516 
517  MacWidget *_focusedWidget = nullptr;
518  Common::Point _focusClick;
519  Common::Point _oldMousePos;
520  Common::Point _mousePos;
521  Common::Point _realMousePos;
522 
523  Common::StringArray _substitutions;
524  Common::Array<Common::Rect> _dirtyRects;
525 
526  void copyToScreen(Graphics::Surface *s = nullptr) const;
527 
528  public:
529  OSystem *_system;
530  MacGuiImpl *_gui;
531 
532  MacDialogWindow(MacGuiImpl *gui, OSystem *system, Graphics::Surface *from, Common::Rect bounds, MacDialogWindowStyle style = kStyleNormal);
533  ~MacDialogWindow();
534 
535  Graphics::Surface *surface() { return &_surface; }
536  Graphics::Surface *innerSurface() { return &_innerSurface; }
537 
538  bool isVisible() const { return _visible; }
539 
540  void show();
541  int runDialog(Common::Array<int> &deferredActionIds);
542  void updateCursor();
543 
544  MacWidget *getWidget(int nr) const { return _widgets[nr]; }
545  void setDefaultWidget(int nr) { _defaultWidget = _widgets[nr]; }
546  MacWidget *getDefaultWidget() const { return _defaultWidget; }
547 
548  void setFocusedWidget(int x, int y);
549  void clearFocusedWidget();
550  MacWidget *getFocusedWidget() const { return _focusedWidget; }
551  Common::Point getFocusClick() const { return _focusClick; }
552  Common::Point getMousePos() const { return _mousePos; }
553 
554  void setWidgetEnabled(int nr, bool enabled) { _widgets[nr]->setEnabled(enabled); }
555  bool isWidgetEnabled(int nr) const { return _widgets[nr]->isEnabled(); }
556  void setWidgetVisible(int nr, bool visible) { _widgets[nr]->setVisible(visible); }
557  int getWidgetValue(int nr) const { return _widgets[nr]->getValue(); }
558  void setWidgetValue(int nr, int value) { _widgets[nr]->setValue(value); }
559  int findWidget(int x, int y) const;
560  void redrawWidget(int nr) { _widgets[nr]->setRedraw(true); }
561 
562  MacGuiImpl::MacButton *addButton(Common::Rect bounds, Common::String text, bool enabled);
563  MacGuiImpl::MacCheckbox *addCheckbox(Common::Rect bounds, Common::String text, bool enabled);
564  MacGuiImpl::MacStaticText *addStaticText(Common::Rect bounds, Common::String text, bool enabled);
565  MacGuiImpl::MacEditText *addEditText(Common::Rect bounds, Common::String text, bool enabled);
566  MacGuiImpl::MacPicture *addPicture(Common::Rect bounds, int id, bool enabled);
567  MacGuiImpl::MacSlider *addSlider(int x, int y, int h, int minValue, int maxValue, int pageSize, bool enabled);
568  MacGuiImpl::MacPictureSlider *addPictureSlider(int backgroundId, int handleId, bool enabled, int minX, int maxX, int minValue, int maxValue, int leftMargin = 0, int rightMargin = 0);
569  MacGuiImpl::MacListBox *addListBox(Common::Rect bounds, Common::StringArray texts, bool enabled, bool contentUntouchable = false);
570 
571  void addSubstitution(Common::String text) { _substitutions.push_back(text); }
572  void replaceSubstitution(int nr, Common::String text) { _substitutions[nr] = text; }
573 
574  bool hasSubstitution(uint n) const { return n < _substitutions.size(); }
575  Common::String &getSubstitution(uint n) { return _substitutions[n]; }
576 
577  void markRectAsDirty(Common::Rect r);
578  void update(bool fullRedraw = false);
579 
580  static void plotPixel(int x, int y, int color, void *data);
581  static void plotPattern(int x, int y, int pattern, void *data);
582  static void plotPatternDarkenOnly(int x, int y, int pattern, void *data);
583 
584  void drawDottedHLine(int x0, int y, int x1);
585  void fillPattern(Common::Rect r, uint16 pattern);
586  void drawSprite(const Graphics::Surface *sprite, int x, int y);
587  void drawSprite(const Graphics::Surface *sprite, int x, int y, Common::Rect clipRect);
588  void drawTexts(Common::Rect r, const TextLine *lines);
589  void drawTextBox(Common::Rect r, const TextLine *lines, int arc = 9);
590  };
591 
592  MacGuiImpl(ScummEngine *vm, const Common::Path &resourceFile);
593  virtual ~MacGuiImpl();
594 
595  Graphics::MacWindowManager *_windowManager = nullptr;
596  bool _forceMenuClosed = false;
597 
598  Graphics::Surface *surface() { return _surface; }
599 
600  virtual const Common::String name() const = 0;
601 
602  int toMacRoman(int unicode) const;
603 
604  void setPalette(const byte *palette, uint size);
605  virtual bool handleEvent(Common::Event event);
606 
607  static void menuCallback(int id, Common::String &name, void *data);
608  virtual void initialize();
609  void updateWindowManager();
610 
611  const Graphics::Font *getFont(FontId fontId);
612  virtual const Graphics::Font *getFontByScummId(int32 id) = 0;
613 
614  Graphics::Surface *loadPict(int id);
615 
616  virtual bool isVerbGuiActive() const { return false; }
617  virtual void reset() {}
618  virtual void resetAfterLoad() = 0;
619  virtual void update(int delta) = 0;
620 
621  bool runQuitDialog();
622  bool runRestartDialog();
623 
624  virtual void setupCursor(int &width, int &height, int &hotspotX, int &hotspotY, int &animate) = 0;
625 
626  virtual Graphics::Surface *textArea() { return nullptr; }
627  virtual void clearTextArea() {}
628  virtual void initTextAreaForActor(Actor *a, byte color) {}
629  virtual void printCharToTextArea(int chr, int x, int y, int color) {}
630 
631  MacDialogWindow *createWindow(Common::Rect bounds, MacDialogWindowStyle style = kStyleNormal);
632  MacDialogWindow *createDialog(int dialogId);
633  void drawBanner(char *message);
634  void undrawBanner();
635 
636  void drawBitmap(Graphics::Surface *s, Common::Rect r, const uint16 *bitmap, Color color) const;
637 };
638 
639 } // End of namespace Scumm
640 #endif
Definition: engine.h:102
Definition: macgui_impl.h:47
Definition: macgui_impl.h:372
Definition: str.h:59
Definition: font.h:82
TextAlign
Definition: font.h:48
Definition: surface.h:66
Definition: macgui_impl.h:260
Definition: macgui_impl.h:244
Align the text to the left.
Definition: font.h:51
Definition: rect.h:144
Definition: path.h:52
Definition: macgui_impl.h:292
Definition: stream.h:745
Definition: macwindowmanager.h:148
Definition: scumm.h:518
Definition: macgui_impl.h:416
Definition: macgui_impl.h:225
Definition: macgui_impl.h:442
void push_back(const T &element)
Definition: array.h:142
Definition: hashmap.h:85
Definition: events.h:198
Definition: macgui_impl.h:484
Definition: formatinfo.h:28
Definition: rect.h:45
size_type size() const
Definition: array.h:275
Definition: macgui_impl.h:156
Definition: actor.h:91
Definition: macgui_impl.h:335
signed char * fill(signed char *first, signed char *last, Value val)
Definition: algorithm.h:111
Definition: system.h:175
Definition: macgui_impl.h:348
Definition: actor.h:30
Definition: macgui_impl.h:126
Definition: macgui_impl.h:173