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