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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 *
22 * Based on the original sources
23 * Faery Tale II -- The Halls of the Dead
24 * (c) 1993-1996 The Wyrmkeep Entertainment Co.
25 */
26
27 #ifndef SAGA2_PANEL_H
28 #define SAGA2_PANEL_H
29
30 #include "saga2/input.h"
31 #include "saga2/vdraw.h"
32
33 namespace Common {
34 struct Event;
35 }
36
37 namespace Saga2 {
38 // Fix problem with DOS's encroachment on name space that should
39 // rightfully belong to the application programmer.
40
41 #ifdef enable
42 #undef enable
43 #undef disable
44 #endif
45
46 /* ===================================================================== *
47 Cursor Cycling Stuff
48 * ===================================================================== */
49
50 #if DINO
51 #define CURSOR_CYCLING 1
52 #endif
53 #if CURSOR_CYCLING
54 void cycleCursor();
55 #endif
56
57 /* ===================================================================== *
58 Forward declarations
59 * ===================================================================== */
60
61 class gPanel;
62 class gPanelList;
63 class gPanelMessage;
64 class gWindow;
65
66 /* ===================================================================== *
67 Input dispatching functions
68 * ===================================================================== */
69
70 void HandleTimerTick(long newTick);
71 void EventLoop(bool &running, bool modal = false);
72
73 /* ===================================================================== *
74 Constants
75 * ===================================================================== */
76
77 enum gEventType {
78 gEventNone = 0, // no event occured
79 gEventMouseDown, // left button pressed
80 gEventMouseUp, // left button released
81 gEventRMouseDown, // right button pressed
82 gEventRMouseUp, // right button released
83 gEventMouseMove, // mouse moved
84 gEventMouseDrag, // mouse dragged
85 gEventMouseOutside, // mouse click outside of window
86 gEventKeyDown, // keystroke
87
88 gEventNewValue, // object had new value
89 gEventDoubleClick, // double-clicked on object
90 gEventAltValue, // for multi-function objects
91
92 gEventLast
93 };
94
95 /* ===================================================================== *
96 gEvent: returns input events to the user
97 * ===================================================================== */
98
99 struct gEvent {
100 gPanel *panel; // where event came from
101 enum gEventType eventType; // type of event that occured
102 Point16 mouse; // mouse position
103 int32 value; // new value of control
104 gWindow *window; // active window
105 };
106
107 typedef void AppFunc(gEvent &);
108
109 #ifndef __WATCOMC__
110 #define APPFUNCDECL __cdecl
111 #else
112 #define APPFUNCDECL
113 #endif
114
115 #define APPFUNC(a) void a ( gEvent &ev )
116 #define APPFUNCV(a) void a ( gEvent & )
117
118 // Note: panels in this system are not, in general, resizeable
119
120 /* ===================================================================== *
121 gPanel class: The basic user interface element
122 * ===================================================================== */
123
124 class gPanel {
125 friend class gToolBase;
126 friend class gWindow;
127
128 AppFunc *command; // application function
129 protected:
130 gWindow &window; // window this belongs to
131 Rect16 _extent; // rectangular bounds of the control
132 const char *title; // title of the panel
133 byte enabled, // allows disabling the panel
134 selected, // some panels have a selected state
135 imageLabel, // button label is image, not text
136 ghosted, // button is dimmed
137 wantMousePoll; // send mousemoves even if mouse not moving!
138
139 // window constructor
140 gPanel(gWindow &, const Rect16 &, AppFunc *cmd);
141
142 public:
143 uint32 id; // panel id number
144 void *userData; // data for this panel
145
146 // constructor
147 gPanel(gPanelList &, const Rect16 &, const char *, uint16, AppFunc *cmd = NULL);
148 gPanel(gPanelList &, const Rect16 &, gPixelMap &, uint16, AppFunc *cmd = NULL);
149
150 gPanel(gPanelList &, const StaticRect &, const char *, uint16, AppFunc *cmd = NULL);
151 virtual ~gPanel(); // destructor
152
153 virtual gPanel *hitTest(const Point16 &p);
154 virtual gPanel *keyTest(int16 key);
155
156 protected:
157 virtual void pointerMove(gPanelMessage &msg);
158 virtual bool pointerHit(gPanelMessage &msg);
159 virtual bool pointerRHit(gPanelMessage &msg);
160 virtual void pointerDrag(gPanelMessage &msg);
161 virtual void pointerRelease(gPanelMessage &msg);
162 virtual bool keyStroke(gPanelMessage &msg);
163 virtual void timerTick(gPanelMessage &msg);
164 virtual void onMouseHintDelay(void);
165
166 void notify(enum gEventType, int32 value);
notify(gEvent & ev)167 void notify(gEvent &ev) {
168 if (command) command(ev);
169 }
170 void drawTitle(enum text_positions placement);
171
172
173 public:
174 bool isActive(void); // true if we are active panel
175 virtual bool activate(gEventType why); // activate the control
176 virtual void deactivate(void); // deactivate the control
177 virtual void draw(void); // redraw the panel.
178 virtual void enable(bool abled);
179 virtual void select(uint16 selected);
180 virtual void ghost(bool ghosted);
181 virtual void invalidate(Rect16 *area = nullptr);
setMousePoll(bool abled)182 virtual void setMousePoll(bool abled) {
183 wantMousePoll = abled ? 1 : 0;
184 }
185
186 // Redraw the panel, but only a small clipped section,
187 // and perhaps drawn onto an off-screen map.
188 virtual void drawClipped(
189 gPort &port,
190 const Point16 &offset,
191 const Rect16 &r);
192
193 // void setCommand( AppFunc *func ) { command = func; }
getWindow(void)194 gWindow *getWindow(void) {
195 return &window;
196 }
197 void makeActive(void);
getExtent(void)198 Rect16 getExtent(void) {
199 return _extent;
200 }
isSelected(void)201 bool isSelected(void) {
202 return selected != 0;
203 }
isGhosted(void)204 bool isGhosted(void) {
205 return ghosted != 0;
206 }
getEnabled(void)207 bool getEnabled(void) const {
208 return (bool) enabled;
209 }
210 void show(bool shown = true, bool inval = true) {
211 enable(shown);
212 if (inval)
213 invalidate();
214 }
215
216 void moveToFront(gPanelList &l);
217 void moveToBack(gPanelList &l);
218 };
219
220 /* ===================================================================== *
221 gPanelMessage class: How user input is distributes to panels
222 * ===================================================================== */
223
224 class gPanelMessage {
225 public:
226 Point16 pickPos, // mouse position relative to panel
227 pickAbsPos; // mouse position relative to display
228 byte leftButton, // left button state
229 rightButton, // right button state
230 inPanel, // whether mouse is currently in panel
231 pointerEnter, // set when pointer enters panel
232 pointerLeave, // set when pointer leaves panel
233 doubleClick; // set when double click detected
234
235 // For keyboard input
236
237 uint16 key, // keystroke from keyboard
238 qualifier; // qualifier from keyboard
239
240 uint32 timeStamp; // time of message
241
gPanelMessage()242 gPanelMessage() {
243 leftButton = 0;
244 rightButton = 0;
245 inPanel = 0;
246 pointerEnter = 0;
247 pointerLeave = 0;
248 doubleClick = 0;
249 key = 0;
250 qualifier = 0;
251 timeStamp = 0;
252 }
253 };
254
255 /* ===================================================================== *
256 gPanelList class: A list of panels
257 * ===================================================================== */
258
259 class gControl;
260
261 class gPanelList : public gPanel {
262
263 friend class gControl;
264 friend class gToolBase;
265
266 friend void gPanel::moveToFront(gPanelList &l);
267 friend void gPanel::moveToBack(gPanelList &l);
268
269 protected:
270
271 Common::List<gPanel *> contents; // list of panels
272
273 gPanelList(gWindow &, const Rect16 &, char *, uint16, AppFunc *cmd = NULL);
274
275 public:
276
277 gPanelList(gPanelList &);
278 ~gPanelList();
279
280 gPanel *hitTest(const Point16 &p);
281 gPanel *keyTest(int16 key);
282 void removeControls(void);
283
284 public:
285 void invalidate(Rect16 *area = nullptr);
286 void draw(void); // redraw the controls
287 void drawClipped(
288 gPort &port,
289 const Point16 &offset,
290 const Rect16 &r);
291
292 void enable(bool abled); // enable list and all children
293 // void setPointer( gPixelMap &map, int x, int y );
294 };
295
moveToFront(gPanelList & l)296 inline void gPanel::moveToFront(gPanelList &l) {
297 l.contents.remove(this);
298 l.contents.push_front(this);
299 }
300
moveToBack(gPanelList & l)301 inline void gPanel::moveToBack(gPanelList &l) {
302 l.contents.remove(this);
303 l.contents.push_back(this);
304 }
305
306 /* ===================================================================== *
307 gWindow class: A context for holding panels.
308 * ===================================================================== */
309
310 /*
311 enum windowFeatures {
312 windowTitleBar = (1<<0), // window has a title bar
313 windowCanDrag = (1<<1), // window is draggable
314 // windowVisible = (1<<2), // window is visible
315 // windowBackSaved = (1<<3), // backsave data under window
316 // windowCloseBox = (1<<4), // create a close box
317 // windowNoBorder = (1<<5), // window with no border
318 };
319 */
320
321 class gWindow : public gPanelList {
322
323 friend class gControl;
324 friend class gPanel;
325 friend class gToolBase;
326
327 public:
328 gDisplayPort windowPort;
329
330 gWindow(const Rect16 &, uint16, const char saveName[], AppFunc *cmd = NULL);
331 ~gWindow();
332
gPort()333 operator gPort() {
334 return windowPort;
335 }
postEvent(gEvent & ev)336 void postEvent(gEvent &ev) {
337 gPanel::notify(ev);
338 }
339
340 protected:
341 bool openFlag; // true if window open.
342
343 //gWindowWinInfoInINIFile saver;
344
345 private:
346 bool activate(gEventType why); // activate the control
347 void deactivate(void);
348
349 void pointerMove(gPanelMessage &msg);
350 bool pointerHit(gPanelMessage &msg);
351 void pointerDrag(gPanelMessage &msg);
352 void pointerRelease(gPanelMessage &msg);
353
354 // Dragging modes for window -- private and static!
355
356 enum drag_modes {
357 dragNone = 0,
358 dragPosition
359 };
360
361 static int dragMode; // current dragging mode
362 static StaticRect dragExtent; // dragging extent
363 static StaticPoint16 dragOffset; // offset to window origin
364
365 void shadow(void);
366
367 public:
368 void setExtent(const Rect16 &); // set window position and size
getExtent(void)369 Rect16 getExtent(void) {
370 return _extent; // set window position and size
371 }
372 protected:
373 void setPos(Point16 pos); // set window position
374 void insert(void); // insert window into window list
375 virtual void toFront(void); // re-order the windows
376
377 public:
isOpen(void)378 bool isOpen(void) {
379 return openFlag; // true if window is visible
380 }
381 void draw(void); // redraw the panel.
382 void drawClipped(
383 gPort &port,
384 const Point16 &offset,
385 const Rect16 &r);
386
387 // Redraw the window, but only a small clipped section,
388 // and perhaps drawn onto an off-screen map.
389 // void drawClipped(
390 // gPort &port,
391 // const Point16 &offset,
392 // const Rect16 &r );
393
394 void enable(bool abled);
395 void select(uint16 sel); // activate the window
396
397 virtual bool open(void);
398 virtual void close(void);
399 virtual bool isModal(void);
400
401 // Update a region of a window, and all floaters which
402 // might be above that window.
403 virtual void update(const Rect16 &updateRect) = 0;
404
405 // void setPointer( gPixelMap &map, int x, int y );
406 };
407
408 /* ===================================================================== *
409 gControl class: The basis for buttons and other controls.
410 * ===================================================================== */
411
412 class gControl : public gPanel {
413 public:
414 uint8 accelKey;
415 gPanelList *_list;
416
417 gControl(gPanelList &, const Rect16 &, const char *, uint16, AppFunc *cmd = NULL);
418 gControl(gPanelList &, const Rect16 &, gPixelMap &, uint16, AppFunc *cmd = NULL);
419
420 gControl(gPanelList &, const StaticRect &, const char *, uint16, AppFunc *cmd = NULL);
421 ~gControl(); // destructor
422
423 gPanel *keyTest(int16 key);
424
425 void enable(bool abled); // enable the control
426 void select(uint16 sel); // selecte the control
427 void ghost(bool ghosted);
428 // virtual void newValue( void );
429
430 void draw(void); // redraw the control.
431 };
432
433 /* ===================================================================== *
434 gGenericControl class: A generic button that notifies everything
435 * ===================================================================== */
436
437 class gGenericControl : public gControl {
438 bool dblClickFlag;
439
440 public:
441 gGenericControl(gPanelList &, const Rect16 &, uint16, AppFunc *cmd = NULL);
442
443 // Disable double click for next mouse click
disableDblClick(void)444 void disableDblClick(void) {
445 dblClickFlag = true;
446 }
447
448 enum controlValue {
449 enter = (1 << 0),
450 leave = (1 << 1)
451 };
452
453 protected:
454 bool activate(gEventType why); // activate the control
455 void deactivate(void);
456
457 void pointerMove(gPanelMessage &msg);
458 bool pointerHit(gPanelMessage &msg);
459 void pointerDrag(gPanelMessage &msg);
460 void pointerRelease(gPanelMessage &msg);
461
462 void draw(void); // redraw the control.
463 };
464
465
466 /* ===================================================================== *
467 gToolBase class: The primary dispatcher for user interface events
468 * ===================================================================== */
469
470 void setMouseTextF(char *format, ...);
471 void LockUI(bool state);
472
473 class gToolBase {
474 friend class gWindow;
475 friend class gPanel;
476 friend void EventLoop(bool &running);
477 friend int16 leftButtonState(void);
478 friend int16 rightButtonState(void);
479 friend void StageModeCleanup(void);
480 friend void TileModeCleanup(void);
481 friend void dumpGBASE(char *msg);
482
483 // windows
484
485 Common::List<gWindow *> windowList; // list of windows
486 gWindow *mouseWindow, // window mouse is in
487 *activeWindow; // current active window
488 gPanel *mousePanel, // panel that mouse is in
489 *activePanel; // panel that has input focus
490 Rect16 dragRect; // dragging rectangle for windows
491 Point16 pickPos; // mouse pos relative to panel
492 uint8 leftDrag, // left-button dragging
493 rightDrag; // right button dragging
494 gPanelMessage msg; // message that we send out
495
496 int32 lastMouseMoveTime; // time of last mouse move
497
498 gMouseState _curMouseState;
499
500 public:
501 bool mouseHintSet; // true if mouse hint is up.
502
gToolBase()503 gToolBase() {
504 mouseWindow = nullptr;
505 activeWindow = nullptr;
506 mousePanel = nullptr;
507 activePanel = nullptr;
508 leftDrag = 0;
509 rightDrag = 0;
510 lastMouseMoveTime = 0;
511 }
512
513 private:
setMsgQ(gPanelMessage & msg_,gPanel * panel)514 void setMsgQ(gPanelMessage &msg_, gPanel *panel) {
515 if (panel == &panel->window)
516 msg_.pickPos = pickPos;
517 else {
518 msg.pickPos.x = (int16)(pickPos.x - panel->_extent.x);
519 msg.pickPos.y = (int16)(pickPos.y - panel->_extent.y);
520 }
521 }
522
setMsg(gPanelMessage & msg_,gPanel * panel)523 void setMsg(gPanelMessage &msg_, gPanel *panel) {
524 setMsgQ(msg_, panel);
525 msg.inPanel = (msg_.pickPos.x >= 0
526 && msg_.pickPos.y >= 0
527 && msg_.pickPos.x < panel->_extent.width
528 && msg_.pickPos.y < panel->_extent.height);
529 // panel->extent.ptInside( pickPos );
530 }
531
532 public:
533 void setActive(gPanel *newActive);
534 void leavePanel(void); // we're changing windows
535 public:
536 void handleMouse(Common::Event &event, uint32 time);
537 void handleKeyStroke(Common::Event &event);
538 void handleTimerTick(int32 tick);
topWindowIterator(void)539 Common::List<gWindow *>::iterator topWindowIterator(void) {
540 return windowList.end();
541 }
bottomWindowIterator(void)542 Common::List<gWindow *>::iterator bottomWindowIterator(void) {
543 return windowList.reverse_begin();
544 }
topWindow(void)545 gWindow *topWindow(void) {
546 return windowList.front();
547 }
bottomWindow(void)548 gWindow *bottomWindow(void) {
549 return windowList.back();
550 }
isMousePanel(gPanel * p)551 bool isMousePanel(gPanel *p) {
552 return (mousePanel != NULL) ? (p == mousePanel) : (p == topWindow());
553 }
554 };
555
556 /* ===================================================================== *
557 Application functions to call for event handling
558 * ===================================================================== */
559
560 void EventLoop(bool &running);
561 void initPanels(gDisplayPort &port);
562 void cleanupPanels(void);
563
564 //void writeHelpLine( char *msg, ... );
565
566 int16 leftButtonState(void);
567 int16 rightButtonState(void);
568
569 // Kludge structure to contain both a mouse event and a time stamp
570 struct MouseExtState {
571 gMouseState st;
572 int32 time;
573 };
574
575 } // end of namespace Saga2
576
577 #endif
578