1 | //============================================================================ |
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | // |
17 | // Based on code from ScummVM - Scumm Interpreter |
18 | // Copyright (C) 2002-2004 The ScummVM project |
19 | //============================================================================ |
20 | |
21 | #ifndef WIDGET_HXX |
22 | #define WIDGET_HXX |
23 | |
24 | class Dialog; |
25 | |
26 | namespace GUI { |
27 | class Font; |
28 | } |
29 | |
30 | #include <cassert> |
31 | |
32 | #include "bspf.hxx" |
33 | #include "Event.hxx" |
34 | #include "GuiObject.hxx" |
35 | #include "Font.hxx" |
36 | |
37 | /** |
38 | This is the base class for all widgets. |
39 | |
40 | @author Stephen Anthony |
41 | */ |
42 | class Widget : public GuiObject |
43 | { |
44 | friend class Dialog; |
45 | |
46 | public: |
47 | enum : uInt32 { |
48 | FLAG_ENABLED = 1 << 0, |
49 | FLAG_INVISIBLE = 1 << 1, |
50 | FLAG_HILITED = 1 << 2, |
51 | FLAG_BORDER = 1 << 3, |
52 | FLAG_CLEARBG = 1 << 4, |
53 | FLAG_TRACK_MOUSE = 1 << 5, |
54 | FLAG_RETAIN_FOCUS = 1 << 6, |
55 | FLAG_WANTS_TAB = 1 << 7, |
56 | FLAG_WANTS_RAWDATA = 1 << 8 |
57 | }; |
58 | |
59 | public: |
60 | Widget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); |
61 | virtual ~Widget(); |
62 | |
63 | virtual int getAbsX() const override { return _x + _boss->getChildX(); } |
64 | virtual int getAbsY() const override { return _y + _boss->getChildY(); } |
65 | virtual int getLeft() const { return _x; } |
66 | virtual int getTop() const { return _y; } |
67 | virtual int getRight() const { return _x + getWidth(); } |
68 | virtual int getBottom() const { return _y + getHeight(); } |
69 | |
70 | virtual bool handleText(char text) { return false; } |
71 | virtual bool handleKeyDown(StellaKey key, StellaMod mod) { return false; } |
72 | virtual bool handleKeyUp(StellaKey key, StellaMod mod) { return false; } |
73 | virtual void handleMouseDown(int x, int y, MouseButton b, int clickCount) { } |
74 | virtual void handleMouseUp(int x, int y, MouseButton b, int clickCount) { } |
75 | virtual void handleMouseEntered() { } |
76 | virtual void handleMouseLeft() { } |
77 | virtual void handleMouseMoved(int x, int y) { } |
78 | virtual void handleMouseWheel(int x, int y, int direction) { } |
79 | virtual bool handleMouseClicks(int x, int y, MouseButton b) { return false; } |
80 | virtual void handleJoyDown(int stick, int button, bool longPress = false) { } |
81 | virtual void handleJoyUp(int stick, int button) { } |
82 | virtual void handleJoyAxis(int stick, JoyAxis axis, JoyDir adir, int button = JOY_CTRL_NONE) { } |
83 | virtual bool handleJoyHat(int stick, int hat, JoyHatDir hdir, int button = JOY_CTRL_NONE) { return false; } |
84 | virtual bool handleEvent(Event::Type event) { return false; } |
85 | |
86 | void setDirty() override; |
87 | void draw() override; |
88 | void receivedFocus(); |
89 | void lostFocus(); |
90 | void addFocusWidget(Widget* w) override { _focusList.push_back(w); } |
91 | void addToFocusList(WidgetArray& list) override { |
92 | Vec::append(_focusList, list); |
93 | } |
94 | |
95 | /** Set/clear FLAG_ENABLED */ |
96 | void setEnabled(bool e); |
97 | |
98 | void setFlags(uInt32 flags) { _flags |= flags; setDirty(); } |
99 | void clearFlags(uInt32 flags) { _flags &= ~flags; setDirty(); } |
100 | uInt32 getFlags() const { return _flags; } |
101 | |
102 | bool isEnabled() const { return _flags & FLAG_ENABLED; } |
103 | bool isVisible() const override { return !(_flags & FLAG_INVISIBLE); } |
104 | virtual bool wantsFocus() const { return _flags & FLAG_RETAIN_FOCUS; } |
105 | bool wantsTab() const { return _flags & FLAG_WANTS_TAB; } |
106 | bool wantsRaw() const { return _flags & FLAG_WANTS_RAWDATA; } |
107 | |
108 | void setID(uInt32 id) { _id = id; } |
109 | uInt32 getID() const { return _id; } |
110 | |
111 | virtual const GUI::Font& font() const { return _font; } |
112 | |
113 | void setTextColor(ColorId color) { _textcolor = color; setDirty(); } |
114 | void setTextColorHi(ColorId color) { _textcolorhi = color; setDirty(); } |
115 | void setBGColor(ColorId color) { _bgcolor = color; setDirty(); } |
116 | void setBGColorHi(ColorId color) { _bgcolorhi = color; setDirty(); } |
117 | void setShadowColor(ColorId color) { _shadowcolor = color; setDirty(); } |
118 | |
119 | virtual void loadConfig() { } |
120 | |
121 | protected: |
122 | virtual void drawWidget(bool hilite) { } |
123 | |
124 | virtual void receivedFocusWidget() { } |
125 | virtual void lostFocusWidget() { } |
126 | |
127 | virtual Widget* findWidget(int x, int y) { return this; } |
128 | |
129 | void releaseFocus() override { assert(_boss); _boss->releaseFocus(); } |
130 | |
131 | // By default, delegate unhandled commands to the boss |
132 | void handleCommand(CommandSender* sender, int cmd, int data, int id) override |
133 | { assert(_boss); _boss->handleCommand(sender, cmd, data, id); } |
134 | |
135 | protected: |
136 | GuiObject* _boss; |
137 | const GUI::Font& _font; |
138 | Widget* _next; |
139 | uInt32 _id; |
140 | uInt32 _flags; |
141 | bool _hasFocus; |
142 | int _fontWidth; |
143 | int _fontHeight; |
144 | ColorId _bgcolor; |
145 | ColorId _bgcolorhi; |
146 | ColorId _bgcolorlo; |
147 | ColorId _textcolor; |
148 | ColorId _textcolorhi; |
149 | ColorId _textcolorlo; |
150 | ColorId _shadowcolor; |
151 | |
152 | public: |
153 | static Widget* findWidgetInChain(Widget* start, int x, int y); |
154 | |
155 | /** Determine if 'find' is in the chain pointed to by 'start' */ |
156 | static bool isWidgetInChain(Widget* start, Widget* find); |
157 | |
158 | /** Determine if 'find' is in the widget array */ |
159 | static bool isWidgetInChain(WidgetArray& list, Widget* find); |
160 | |
161 | /** Select either previous, current, or next widget in chain to have |
162 | focus, and deselects all others */ |
163 | static Widget* setFocusForChain(GuiObject* boss, WidgetArray& arr, |
164 | Widget* w, int direction, |
165 | bool emitFocusEvents = true); |
166 | |
167 | /** Sets all widgets in this chain to be dirty (must be redrawn) */ |
168 | static void setDirtyInChain(Widget* start); |
169 | |
170 | private: |
171 | // Following constructors and assignment operators not supported |
172 | Widget() = delete; |
173 | Widget(const Widget&) = delete; |
174 | Widget(Widget&&) = delete; |
175 | Widget& operator=(const Widget&) = delete; |
176 | Widget& operator=(Widget&&) = delete; |
177 | }; |
178 | |
179 | /* StaticTextWidget */ |
180 | class StaticTextWidget : public Widget |
181 | { |
182 | public: |
183 | StaticTextWidget(GuiObject* boss, const GUI::Font& font, |
184 | int x, int y, int w, int h, |
185 | const string& text = "" , TextAlign align = TextAlign::Left, |
186 | ColorId shadowColor = kNone); |
187 | StaticTextWidget(GuiObject* boss, const GUI::Font& font, |
188 | int x, int y, |
189 | const string& text = "" , TextAlign align = TextAlign::Left, |
190 | ColorId shadowColor = kNone); |
191 | void setValue(int value); |
192 | void setLabel(const string& label); |
193 | void setAlign(TextAlign align) { _align = align; setDirty(); } |
194 | const string& getLabel() const { return _label; } |
195 | bool isEditable() const { return _editable; } |
196 | |
197 | protected: |
198 | void drawWidget(bool hilite) override; |
199 | |
200 | protected: |
201 | string _label; |
202 | bool _editable; |
203 | TextAlign _align; |
204 | |
205 | private: |
206 | // Following constructors and assignment operators not supported |
207 | StaticTextWidget() = delete; |
208 | StaticTextWidget(const StaticTextWidget&) = delete; |
209 | StaticTextWidget(StaticTextWidget&&) = delete; |
210 | StaticTextWidget& operator=(const StaticTextWidget&) = delete; |
211 | StaticTextWidget& operator=(StaticTextWidget&&) = delete; |
212 | }; |
213 | |
214 | /* ButtonWidget */ |
215 | class ButtonWidget : public StaticTextWidget, public CommandSender |
216 | { |
217 | public: |
218 | ButtonWidget(GuiObject* boss, const GUI::Font& font, |
219 | int x, int y, int w, int h, |
220 | const string& label, int cmd = 0, bool repeat = false); |
221 | ButtonWidget(GuiObject* boss, const GUI::Font& font, |
222 | int x, int y, int dw, |
223 | const string& label, int cmd = 0, bool repeat = false); |
224 | ButtonWidget(GuiObject* boss, const GUI::Font& font, |
225 | int x, int y, |
226 | const string& label, int cmd = 0, bool repeat = false); |
227 | ButtonWidget(GuiObject* boss, const GUI::Font& font, |
228 | int x, int y, int dw, int dh, |
229 | uInt32* bitmap, int bmw, int bmh, |
230 | int cmd = 0, bool repeat = false); |
231 | |
232 | void setCmd(int cmd) { _cmd = cmd; } |
233 | int getCmd() const { return _cmd; } |
234 | /* Sets/changes the button's bitmap **/ |
235 | void setBitmap(uInt32* bitmap, int bmw, int bmh); |
236 | |
237 | protected: |
238 | bool handleMouseClicks(int x, int y, MouseButton b) override; |
239 | void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; |
240 | void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; |
241 | void handleMouseEntered() override; |
242 | void handleMouseLeft() override; |
243 | bool handleEvent(Event::Type event) override; |
244 | |
245 | void drawWidget(bool hilite) override; |
246 | |
247 | protected: |
248 | int _cmd; |
249 | bool _repeat; // button repeats |
250 | bool _useBitmap; |
251 | uInt32* _bitmap; |
252 | int _bmw, _bmh; |
253 | |
254 | private: |
255 | // Following constructors and assignment operators not supported |
256 | ButtonWidget() = delete; |
257 | ButtonWidget(const ButtonWidget&) = delete; |
258 | ButtonWidget(ButtonWidget&&) = delete; |
259 | ButtonWidget& operator=(const ButtonWidget&) = delete; |
260 | ButtonWidget& operator=(ButtonWidget&&) = delete; |
261 | }; |
262 | |
263 | /* CheckboxWidget */ |
264 | class CheckboxWidget : public ButtonWidget |
265 | { |
266 | public: |
267 | enum { kCheckActionCmd = 'CBAC' }; |
268 | enum class FillType { Normal, Inactive, Circle }; |
269 | |
270 | public: |
271 | CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, |
272 | const string& label, int cmd = 0); |
273 | |
274 | void setEditable(bool editable); |
275 | void setFill(FillType type); |
276 | |
277 | void setState(bool state, bool changed = false); |
278 | void toggleState() { setState(!_state); } |
279 | bool getState() const { return _state; } |
280 | |
281 | void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; |
282 | void handleMouseEntered() override; |
283 | void handleMouseLeft() override; |
284 | |
285 | static int boxSize() { return 14; } // box is square |
286 | |
287 | protected: |
288 | void drawWidget(bool hilite) override; |
289 | |
290 | protected: |
291 | bool _state; |
292 | bool _holdFocus; |
293 | bool _drawBox; |
294 | bool _changed; |
295 | |
296 | uInt32* _img; |
297 | ColorId _fillColor; |
298 | int _boxY; |
299 | int _textY; |
300 | |
301 | private: |
302 | // Following constructors and assignment operators not supported |
303 | CheckboxWidget() = delete; |
304 | CheckboxWidget(const CheckboxWidget&) = delete; |
305 | CheckboxWidget(CheckboxWidget&&) = delete; |
306 | CheckboxWidget& operator=(const CheckboxWidget&) = delete; |
307 | CheckboxWidget& operator=(CheckboxWidget&&) = delete; |
308 | }; |
309 | |
310 | /* SliderWidget */ |
311 | class SliderWidget : public ButtonWidget |
312 | { |
313 | public: |
314 | SliderWidget(GuiObject* boss, const GUI::Font& font, |
315 | int x, int y, int w, int h, |
316 | const string& label = "" , int labelWidth = 0, int cmd = 0, |
317 | int valueLabelWidth = 0, const string& valueUnit = "" , int valueLabelGap = 4); |
318 | SliderWidget(GuiObject* boss, const GUI::Font& font, |
319 | int x, int y, |
320 | const string& label = "" , int labelWidth = 0, int cmd = 0, |
321 | int valueLabelWidth = 0, const string& valueUnit = "" , int valueLabelGap = 4); |
322 | |
323 | void setValue(int value); |
324 | int getValue() const { return _value; } |
325 | |
326 | void setMinValue(int value); |
327 | int getMinValue() const { return _valueMin; } |
328 | void setMaxValue(int value); |
329 | int getMaxValue() const { return _valueMax; } |
330 | void setStepValue(int value); |
331 | int getStepValue() const { return _stepValue; } |
332 | void setValueLabel(const string& valueLabel); |
333 | void setValueLabel(int value); |
334 | const string& getValueLabel() const { return _valueLabel; } |
335 | void setValueUnit(const string& valueUnit); |
336 | |
337 | void setTickmarkIntervals(int numIntervals); |
338 | |
339 | protected: |
340 | void handleMouseMoved(int x, int y) override; |
341 | void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; |
342 | void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; |
343 | void handleMouseWheel(int x, int y, int direction) override; |
344 | bool handleEvent(Event::Type event) override; |
345 | |
346 | void drawWidget(bool hilite) override; |
347 | |
348 | int valueToPos(int value) const; |
349 | int posToValue(int pos) const; |
350 | |
351 | protected: |
352 | int _value, _stepValue; |
353 | int _valueMin, _valueMax; |
354 | bool _isDragging; |
355 | int _labelWidth; |
356 | string _valueLabel; |
357 | string _valueUnit; |
358 | int _valueLabelGap; |
359 | int _valueLabelWidth; |
360 | int _numIntervals; |
361 | |
362 | private: |
363 | // Following constructors and assignment operators not supported |
364 | SliderWidget() = delete; |
365 | SliderWidget(const SliderWidget&) = delete; |
366 | SliderWidget(SliderWidget&&) = delete; |
367 | SliderWidget& operator=(const SliderWidget&) = delete; |
368 | SliderWidget& operator=(SliderWidget&&) = delete; |
369 | }; |
370 | |
371 | #endif |
372 | |