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 * aint32 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 #include "common/events.h"
28
29 #include "saga2/saga2.h"
30 #include "saga2/panel.h"
31 #include "saga2/fontlib.h"
32 #include "saga2/floating.h"
33 #include "saga2/display.h"
34 #include "saga2/gbevel.h"
35
36 namespace Saga2 {
37
38 //extern vDisplayPage *drawPage;
39 extern char iniFile[];
40
41 // Function to enable/disable user interface keys
42 extern bool enableUIKeys(bool enabled);
43
44 /* ======================================================================= *
45 global dispatcher base
46 * ======================================================================= */
47
48 gDisplayPort *globalPort;
49 gFont *mainFont;
50
51 // UI locking feature, currently kludged it could get better later.
52 int lockUINest = 0;
53
54 /* ======================================================================= *
55 gPanel member functions
56 * ======================================================================= */
57
gPanel(gWindow & win,const Rect16 & box,AppFunc * cmd)58 gPanel::gPanel(gWindow &win, const Rect16 &box, AppFunc *cmd)
59 : window(win), _extent(box), command(cmd) {
60 enabled = 1;
61 ghosted = 0;
62 selected = 0;
63 imageLabel = 0;
64 title = nullptr;
65 id = 0;
66 wantMousePoll = 0;
67 userData = nullptr;
68 }
69
gPanel(gPanelList & list,const Rect16 & box,const char * newTitle,uint16 ident,AppFunc * cmd)70 gPanel::gPanel(gPanelList &list, const Rect16 &box,
71 const char *newTitle, uint16 ident, AppFunc *cmd)
72 : window(list.window) {
73 title = newTitle;
74 _extent = box;
75 enabled = 1;
76 ghosted = 0;
77 selected = 0;
78 imageLabel = 0;
79 command = cmd;
80 id = ident;
81 wantMousePoll = 0;
82 userData = nullptr;
83 }
84
gPanel(gPanelList & list,const Rect16 & box,gPixelMap & pic,uint16 ident,AppFunc * cmd)85 gPanel::gPanel(gPanelList &list, const Rect16 &box,
86 gPixelMap &pic, uint16 ident, AppFunc *cmd)
87 : window(list.window) {
88 title = (char *)&pic;
89 _extent = box;
90 enabled = 1;
91 ghosted = 0;
92 selected = 0;
93 imageLabel = 1;
94 command = cmd;
95 id = ident;
96 wantMousePoll = 0;
97 userData = nullptr;
98 }
99
gPanel(gPanelList & list,const StaticRect & box,const char * newTitle,uint16 ident,AppFunc * cmd)100 gPanel::gPanel(gPanelList &list, const StaticRect &box,
101 const char *newTitle, uint16 ident, AppFunc *cmd)
102 : window(list.window) {
103 title = newTitle;
104 _extent = Rect16(box);
105 enabled = 1;
106 ghosted = 0;
107 selected = 0;
108 imageLabel = 0;
109 command = cmd;
110 id = ident;
111 wantMousePoll = 0;
112 userData = nullptr;
113 }
114
115 // Dummy virtual functions
116
~gPanel()117 gPanel::~gPanel() {
118 if (this == g_vm->_toolBase->mousePanel)
119 g_vm->_toolBase->mousePanel = NULL;
120 if (this == g_vm->_toolBase->activePanel)
121 g_vm->_toolBase->activePanel = NULL;
122 }
draw(void)123 void gPanel::draw(void) {}
drawClipped(gPort &,const Point16 &,const Rect16 &)124 void gPanel::drawClipped(gPort &, const Point16 &, const Rect16 &) {}
pointerMove(gPanelMessage &)125 void gPanel::pointerMove(gPanelMessage &) {}
pointerHit(gPanelMessage &)126 bool gPanel::pointerHit(gPanelMessage &) {
127 return false;
128 }
pointerRHit(gPanelMessage &)129 bool gPanel::pointerRHit(gPanelMessage &) {
130 return false;
131 }
pointerDrag(gPanelMessage &)132 void gPanel::pointerDrag(gPanelMessage &) {}
pointerRelease(gPanelMessage &)133 void gPanel::pointerRelease(gPanelMessage &) {}
keyStroke(gPanelMessage &)134 bool gPanel::keyStroke(gPanelMessage &) {
135 return false;
136 }
timerTick(gPanelMessage &)137 void gPanel::timerTick(gPanelMessage &) {}
onMouseHintDelay(void)138 void gPanel::onMouseHintDelay(void) {}
139
enable(bool abled)140 void gPanel::enable(bool abled) {
141 enabled = abled ? 1 : 0;
142 }
143
select(uint16 sel)144 void gPanel::select(uint16 sel) {
145 selected = sel ? 1 : 0;
146 }
147
ghost(bool b)148 void gPanel::ghost(bool b) {
149 ghosted = b ? 1 : 0;
150 }
151
isActive(void)152 bool gPanel::isActive(void) {
153 return (this == g_vm->_toolBase->activePanel);
154 }
155
notify(enum gEventType type,int32 value)156 void gPanel::notify(enum gEventType type, int32 value) {
157 gEvent ev;
158
159 ev.panel = this;
160 ev.eventType = type;
161 ev.value = value;
162 ev.mouse.x = g_vm->_toolBase->pickPos.x - _extent.x;
163 ev.mouse.y = g_vm->_toolBase->pickPos.y - _extent.y;
164 ev.window = &window;
165
166 if (command) command(ev);
167 else if (this != &window) window.notify(ev);
168 }
169
activate(gEventType)170 bool gPanel::activate(gEventType) {
171 return false;
172 }
173
deactivate(void)174 void gPanel::deactivate(void) {
175 if (isActive()) g_vm->_toolBase->activePanel = NULL;
176 }
177
makeActive(void)178 void gPanel::makeActive(void) {
179 g_vm->_toolBase->setActive(this);
180 }
181
invalidate(Rect16 *)182 void gPanel::invalidate(Rect16 *) {
183 assert(displayEnabled());
184 window.update(_extent);
185 }
186
187
drawTitle(enum text_positions placement)188 void gPanel::drawTitle(enum text_positions placement) {
189 gPort &port = window.windowPort;
190 Rect16 r = _extent;
191 const gPixelMap *img = nullptr;
192
193 if (title == NULL)
194 return;
195
196 if (imageLabel) {
197 img = (const gPixelMap *)title;
198 r.width = img->size.x;
199 r.height = img->size.y;
200 } else {
201 r.width = TextWidth(mainFont, title, -1, textStyleUnderBar);
202 r.height = mainFont->height;
203 }
204
205 switch (placement) {
206 case textPosLeft:
207 r.x -= r.width + 2;
208 r.y += (_extent.height - r.height) / 2 + 1;
209 break;
210
211 case textPosRight:
212 r.x += _extent.width + 3;
213 r.y += (_extent.height - r.height) / 2 + 1;
214 break;
215
216 case textPosHigh:
217 r.x += (_extent.width - r.width) / 2;
218 r.y -= r.height + 1;
219 break;
220
221 case textPosLow:
222 r.x += (_extent.width - r.width) / 2;
223 r.y += _extent.height + 2;
224 break;
225
226 default:
227 r.x += (_extent.width - r.width) / 2;
228 r.y += (_extent.height - r.height) / 2;
229 break;
230 }
231
232 SAVE_GPORT_STATE(port); // save pen color, etc.
233
234 if (imageLabel) {
235 port.setIndirectColor(blackPen); // pen color black
236 port.setMode(drawModeColor); // draw as glyph
237 port.bltPixels(*img, 0, 0, r.x, r.y, r.width, r.height);
238 } else {
239 port.setMode(drawModeMatte); // draw as glyph
240 port.setIndirectColor(blackPen); // pen color black
241 port.setStyle(textStyleUnderBar); // set style to do underbars
242 port.moveTo(r.x, r.y); // move to new text pos
243
244 g_vm->_pointer->hide(*globalPort, r); // hide the pointer
245 port.drawText(title, -1); // draw the text
246 g_vm->_pointer->show(*globalPort, r); // hide the pointer
247 }
248 }
249
hitTest(const Point16 & p)250 gPanel *gPanel::hitTest(const Point16 &p) {
251 return enabled && !ghosted && _extent.ptInside(p) ? this : NULL;
252 }
253
keyTest(int16)254 gPanel *gPanel::keyTest(int16) {
255 return NULL;
256 }
257
258 /* ===================================================================== *
259 gPanelList class: A context for holding panels.
260 * ===================================================================== */
261
262 // Constructor which is called from window subclass
263
gPanelList(gWindow & win,const Rect16 & box,char * newTitle,uint16 ident,AppFunc * cmd)264 gPanelList::gPanelList(gWindow &win, const Rect16 &box, char *newTitle,
265 uint16 ident, AppFunc *cmd)
266 : gPanel(win, box, cmd) {
267 title = newTitle;
268 id = ident;
269 }
270
271 // Constructor for standalone panels..
272
gPanelList(gPanelList & list)273 gPanelList::gPanelList(gPanelList &list)
274 : gPanel(list, list.window.getExtent(), NULL, 0, NULL) {
275 window.contents.push_back(this);
276 }
277
~gPanelList()278 gPanelList::~gPanelList() {
279 removeControls();
280 window.contents.remove(this);
281 }
282
removeControls(void)283 void gPanelList::removeControls(void) {
284 gPanel *ctl;
285
286 // Delete all sub-panels.
287 while (contents.size()) {
288 ctl = contents.front();
289 contents.remove(ctl);
290 delete ctl;
291 }
292 }
293
294 // enable/disable gPanelList and all it's children
enable(bool abled)295 void gPanelList::enable(bool abled) {
296 gPanel::enable(abled);
297 }
298
invalidate(Rect16 *)299 void gPanelList::invalidate(Rect16 *) {
300 gPanel *ctl;
301 Rect16 invArea;
302
303 assert(displayEnabled());
304
305 if (displayEnabled())
306 if (contents.size()) {
307 ctl = contents.back();
308 invArea = ctl->getExtent();
309
310 for (Common::List<gPanel *>::iterator it = contents.reverse_begin(); it != contents.end(); --it) {
311 ctl = *it;
312 invArea = bound(invArea, ctl->getExtent());
313 }
314 window.update(invArea);
315 }
316 }
317
draw(void)318 void gPanelList::draw(void) {
319 gPanel *ctl;
320
321 if (displayEnabled())
322 if (enabled) {
323 for (Common::List<gPanel *>::iterator it = contents.reverse_begin(); it != contents.end(); --it) {
324 ctl = *it;
325 if (ctl->getEnabled())
326 ctl->draw();
327 }
328 }
329 }
330
drawClipped(gPort & port,const Point16 & offset,const Rect16 & r)331 void gPanelList::drawClipped(
332 gPort &port,
333 const Point16 &offset,
334 const Rect16 &r) {
335 gPanel *ctl;
336 Point16 tmpOffset = offset - Point16(_extent.x, _extent.y);
337 Rect16 tmpR = r - Point16(_extent.x, _extent.y);
338
339 if (displayEnabled())
340 if (enabled) {
341 for (Common::List<gPanel *>::iterator it = contents.reverse_begin(); it != contents.end(); --it) {
342 ctl = *it;
343 if (ctl->getEnabled())
344 ctl->drawClipped(port, tmpOffset, tmpR);
345 }
346 }
347 }
348
hitTest(const Point16 & p)349 gPanel *gPanelList::hitTest(const Point16 &p) {
350 gPanel *ctl;
351 gPanel *result;
352
353 if (enabled && !ghosted) {
354 for (Common::List<gPanel *>::iterator it = contents.begin(); it != contents.end(); ++it) {
355 ctl = *it;
356 if ((result = ctl->hitTest(p)) != NULL)
357 return result;
358 }
359 }
360 return NULL;
361 }
362
keyTest(int16 key)363 gPanel *gPanelList::keyTest(int16 key) {
364 gPanel *ctl;
365 gPanel *result;
366
367 if (enabled && !ghosted) {
368 for (Common::List<gPanel *>::iterator it = contents.reverse_begin(); it != contents.end(); --it) {
369 ctl = *it;
370 if ((result = ctl->keyTest(key)) != NULL)
371 return result;
372 }
373 }
374
375 return NULL;
376 }
377
378 /* ===================================================================== *
379 gWindow class: A panel list plus a drawing port.
380 * ===================================================================== */
381
382 // gWindow static variables
383
384 int gWindow::dragMode = 0; // current dragging mode
385 StaticRect gWindow::dragExtent = {0, 0, 0, 0}; // dragging extent
386 StaticPoint16 gWindow::dragOffset = {0, 0}; // offset to window origin
387
gWindow(const Rect16 & box,uint16 ident,const char saveName[],AppFunc * cmd)388 gWindow::gWindow(const Rect16 &box, uint16 ident, const char saveName[], AppFunc *cmd)
389 : gPanelList(*this, box, NULL, ident, cmd)
390 //, saver(WIIFF_POS|WIIFS_NORMAL|WIIFE_ONEXIT,iniFile,saveName,box,this)
391 {
392 openFlag = false;
393 // pointerImage = &arrowPtr;
394 // pointerOffset = Point16( 0, 0 );
395
396 // Set up the window feature bits
397
398 // windowFeatures = features;
399
400 // Set up the window's gPort
401
402 windowPort.setFont(mainFont);
403 windowPort.setPenMap(globalPort->penMap);
404
405 /* if (windowFeatures & windowBackSaved) // backsave data under window
406 {
407 backSave = NEW_UI gBackSave( box );
408 // rem: if backsave fails, then what?
409 }
410 else backSave = NULL;
411 */
412 // Set the window position.
413
414 setPos(Point16(box.x, box.y));
415 }
416
~gWindow()417 gWindow::~gWindow() {
418 // gControl *ctl;
419
420 if (isOpen()) close();
421
422 // Delete all sub-panels.
423
424 // while ( (ctl = (gControl *)contents.remHead()) != NULL )
425 // delete ctl;
426
427 // delete backSave;
428 }
429
open(void)430 bool gWindow::open(void) {
431 if (isOpen()) return true;
432
433 // Send a "pointer-leave" message to mouse panel.
434
435 g_vm->_toolBase->leavePanel();
436 g_vm->_toolBase->windowList.push_front(this);
437 g_vm->_toolBase->activeWindow = this;
438 g_vm->_toolBase->setActive(NULL);
439
440 // g_vm->_pointer->hide();
441 // if (backSave) backSave->save( *globalPort );
442 // g_vm->_pointer->setImage( *pointerImage, pointerOffset.x, pointerOffset.y );
443 // g_vm->_pointer->show();
444
445 openFlag = true;
446
447 draw();
448 return true;
449 }
450
close(void)451 void gWindow::close(void) {
452 //saver.onExit(this);
453 if (!isOpen()) return;
454
455 // If any panels on this window are active, then deactivate them.
456 if (g_vm->_toolBase->activePanel && g_vm->_toolBase->activePanel->getWindow() == this)
457 g_vm->_toolBase->activePanel->deactivate();
458
459 // Don't close a window that is being dragged (should never happen,
460 // but just in case).
461 if (DragBar::dragWindow == (FloatingWindow *)this)
462 return;
463
464 openFlag = false;
465
466 // remove this window from the window list.
467
468 g_vm->_toolBase->windowList.remove(this);
469
470 g_vm->_toolBase->mouseWindow = g_vm->_toolBase->activeWindow = g_vm->_toolBase->windowList.front();
471 g_vm->_toolBase->mousePanel = g_vm->_toolBase->activePanel = NULL;
472 }
473
474 // Move the window to the front...
475
toFront(void)476 void gWindow::toFront(void) { // re-order the windows
477 if (!isOpen()) return;
478
479 g_vm->_toolBase->windowList.remove(this);
480 g_vm->_toolBase->windowList.push_front(this);
481
482 g_vm->_toolBase->activePanel = NULL;
483 g_vm->_toolBase->activeWindow = this;
484
485 // redraw the window
486 update(_extent);
487 }
488
isModal(void)489 bool gWindow::isModal(void) {
490 return false;
491 }
492
setPos(Point16 pos)493 void gWindow::setPos(Point16 pos) {
494 Rect16 newClip;
495
496 _extent.x = pos.x;
497 _extent.y = pos.y;
498
499 // int16 titleHeight = mainFont->height + 5;
500
501 // We also need to set up the window's port in a similar fashion.
502
503 windowPort.origin.x = _extent.x;
504 windowPort.origin.y = _extent.y;
505
506 // set port's clip
507 newClip = intersect(_extent, g_vm->_mainPort.clip);
508 newClip.x -= _extent.x;
509 newClip.y -= _extent.y;
510 windowPort.setClip(newClip);
511 //saver.onMove(this);
512
513 // if (backSave) backSave->setPos( pos );
514 }
515
setExtent(const Rect16 & r)516 void gWindow::setExtent(const Rect16 &r) {
517 _extent.width = r.width;
518 _extent.height = r.height;
519
520 //saver.onSize(this);
521 setPos(Point16(r.x, r.y));
522 }
523
524 // insert window into window list
insert(void)525 void gWindow::insert(void) {
526 g_vm->_toolBase->windowList.push_front(this);
527 }
528
529
530 // REM: Need to either adjuct coords when we draw OR
531 // redefine the address of the pixel map.
532
deactivate(void)533 void gWindow::deactivate(void) {
534 selected = 0;
535 gPanel::deactivate();
536 }
537
activate(gEventType why)538 bool gWindow::activate(gEventType why) {
539 if (why == gEventMouseDown) { // momentarily depress
540 selected = 1;
541 notify(why, 0); // notify App of successful hit
542 return true;
543 }
544 return false;
545 }
546
pointerMove(gPanelMessage &)547 void gWindow::pointerMove(gPanelMessage &) {
548 notify(gEventMouseMove, 0);
549 }
550
pointerHit(gPanelMessage &)551 bool gWindow::pointerHit(gPanelMessage &) {
552 activate(gEventMouseDown);
553 return true;
554 }
555
pointerDrag(gPanelMessage &)556 void gWindow::pointerDrag(gPanelMessage &) {
557 if (selected) {
558 notify(gEventMouseDrag, 0);
559 }
560 }
561
pointerRelease(gPanelMessage &)562 void gWindow::pointerRelease(gPanelMessage &) {
563 if (selected) notify(gEventMouseUp, 0); // notify App of successful hit
564 deactivate();
565 }
566
draw(void)567 void gWindow::draw(void) {
568 if (displayEnabled())
569 gPanelList::draw();
570 }
571
drawClipped(gPort & port,const Point16 & offset,const Rect16 & r)572 void gWindow::drawClipped(
573 gPort &port,
574 const Point16 &offset,
575 const Rect16 &r) {
576 if (displayEnabled())
577 gPanelList::drawClipped(port, offset, r);
578 }
579
enable(bool abled)580 void gWindow::enable(bool abled) {
581 gPanel::enable(abled);
582 draw();
583 }
584
select(uint16 sel)585 void gWindow::select(uint16 sel) {
586 gPanel::select(sel);
587 draw();
588 }
589
590 /*
591 void gWindow::setPointer( gPixelMap &map, int x, int y )
592 {
593 pointerImage = ↦
594 pointerOffset.x = x;
595 pointerOffset.y = y;
596
597 if (this == g_vm->_toolBase->activeWindow)
598 {
599 g_vm->_pointer->hide();
600 g_vm->_pointer->setImage( *pointerImage, pointerOffset.x, pointerOffset.y );
601 g_vm->_pointer->show();
602 }
603 }
604 */
605
606 /* ===================================================================== *
607 gControl class: The basis for buttons and other controls.
608 * ===================================================================== */
609
gControl(gPanelList & list,const Rect16 & box,const char * title_,uint16 ident,AppFunc * cmd)610 gControl::gControl(gPanelList &list, const Rect16 &box, const char *title_, uint16 ident,
611 AppFunc *cmd) : gPanel(list, box, title_, ident, cmd) {
612 accelKey = 0;
613
614 // Add control to the window's control list.
615
616 _list = &list;
617 list.contents.push_back(this);
618 }
619
gControl(gPanelList & list,const Rect16 & box,gPixelMap & img,uint16 ident,AppFunc * cmd)620 gControl::gControl(gPanelList &list, const Rect16 &box, gPixelMap &img, uint16 ident,
621 AppFunc *cmd) : gPanel(list, box, img, ident, cmd) {
622 accelKey = 0;
623
624 // Add control to the window's control list.
625
626 _list = &list;
627 list.contents.push_back(this);
628 }
629
~gControl()630 gControl::~gControl() {
631 _list->contents.remove(this);
632 }
633
gControl(gPanelList & list,const StaticRect & box,const char * title_,uint16 ident,AppFunc * cmd)634 gControl::gControl(gPanelList &list, const StaticRect &box, const char *title_, uint16 ident,
635 AppFunc *cmd) : gPanel(list, box, title_, ident, cmd) {
636 accelKey = 0;
637
638 // Add control to the window's control list.
639
640 _list = &list;
641 list.contents.push_back(this);
642 }
643
enable(bool abled)644 void gControl::enable(bool abled) {
645 if (!abled != !getEnabled()) { // Use '!' to insure boolean-ness
646 gPanel::enable(abled);
647 invalidate();
648 }
649 }
650
select(uint16 sel)651 void gControl::select(uint16 sel) {
652 if (!sel != !isSelected()) { // Use '!' to insure boolean-ness
653 gPanel::select(sel);
654 invalidate();
655 }
656 }
657
ghost(bool sel)658 void gControl::ghost(bool sel) {
659 if (!sel != !isGhosted()) { // Use '!' to insure boolean-ness
660 gPanel::ghost(sel);
661 invalidate();
662 }
663 }
664
keyTest(int16 key)665 gPanel *gControl::keyTest(int16 key) {
666 return accelKey == key ? this : NULL;
667 }
668
669 // For many controls, the only drawing routine we need is the
670 // "clipped" one, and the normal draw routine just calls
671 // drawClipped with the main port.
672
draw(void)673 void gControl::draw(void) {
674 g_vm->_pointer->hide(window.windowPort, _extent);
675 if (displayEnabled())
676 drawClipped(*globalPort,
677 Point16(-window._extent.x, -window._extent.y),
678 window._extent);
679 g_vm->_pointer->show(window.windowPort, _extent);
680 }
681
682 /* ===================================================================== *
683 gGenericControl class: A generic button that notifies everything
684 * ===================================================================== */
685
gGenericControl(gPanelList & list,const Rect16 & box,uint16 ident,AppFunc * cmd)686 gGenericControl::gGenericControl(gPanelList &list, const Rect16 &box,
687 uint16 ident, AppFunc *cmd)
688 : gControl(list, box, NULL, ident, cmd) {
689 dblClickFlag = false;
690 }
691
activate(gEventType)692 bool gGenericControl::activate(gEventType) {
693 selected = 1;
694 return true;
695 }
696
deactivate(void)697 void gGenericControl::deactivate(void) {
698 selected = 0;
699 gPanel::deactivate();
700 }
701
pointerMove(gPanelMessage & msg)702 void gGenericControl::pointerMove(gPanelMessage &msg) {
703 notify(gEventMouseMove, (msg.pointerEnter ? enter : 0) | (msg.pointerLeave ? leave : 0));
704 }
705
pointerHit(gPanelMessage & msg)706 bool gGenericControl::pointerHit(gPanelMessage &msg) {
707 if (msg.rightButton)
708 notify(gEventRMouseDown, 0);
709 else if (msg.doubleClick && !dblClickFlag) {
710 dblClickFlag = true;
711 notify(gEventDoubleClick, 0);
712 } else {
713 dblClickFlag = false;
714 notify(gEventMouseDown, 0);
715 }
716
717 return true;
718 }
719
pointerDrag(gPanelMessage &)720 void gGenericControl::pointerDrag(gPanelMessage &) {
721 notify(gEventMouseDrag, 0);
722 }
723
pointerRelease(gPanelMessage &)724 void gGenericControl::pointerRelease(gPanelMessage &) {
725 notify(gEventMouseUp, 0);
726 deactivate();
727 }
728
729 // Generic control has no rendering code.
draw(void)730 void gGenericControl::draw(void) {
731 }
732
733 /* ===================================================================== *
734 class gToolBase: Global dispatcher for events
735 * ===================================================================== */
736
setActive(gPanel * ctl)737 void gToolBase::setActive(gPanel *ctl) {
738 if (activePanel && activePanel == ctl) return;
739 if (activePanel) activePanel->deactivate();
740 if (ctl == NULL || ctl->activate(gEventNone)) activePanel = ctl;
741 }
742
handleMouse(Common::Event & event,uint32 time)743 void gToolBase::handleMouse(Common::Event &event, uint32 time) {
744 gWindow *w = activeWindow;
745 gPanel *ctl,
746 *pickPanel = NULL;
747 static gMouseState prevState;
748 static int32 lastClickTime = 0x8000;
749 static Point16 lastClickPos;
750
751
752 // Emulate mouse state for now
753 switch (event.type) {
754 case Common::EVENT_LBUTTONDOWN:
755 _curMouseState.left = true;
756 break;
757 case Common::EVENT_RBUTTONDOWN:
758 _curMouseState.right = true;
759 break;
760 case Common::EVENT_LBUTTONUP:
761 _curMouseState.left = false;
762 break;
763 case Common::EVENT_RBUTTONUP:
764 _curMouseState.right = false;
765 break;
766 case Common::EVENT_MOUSEMOVE:
767 _curMouseState.pos.x = event.mouse.x;
768 _curMouseState.pos.y = event.mouse.y;
769 g_vm->_pointer->move(Point16(_curMouseState.pos.x, _curMouseState.pos.y));
770 break;
771 default:
772 break;
773 }
774
775 // Do nothing if UI locked.
776 if (lockUINest > 0)
777 return;
778
779 #if CURSOR_CYCLING
780 if (_curMouseState.right) {
781 cycleCursor();
782 return;
783 }
784 #endif
785
786 // Code for "Tool tip delay"
787 if (prevState.pos != _curMouseState.pos
788 && prevState.left != _curMouseState.left
789 && prevState.right != _curMouseState.right) {
790 lastMouseMoveTime = msg.timeStamp;
791 if (mouseHintSet)
792 setMouseTextF(NULL);
793 }
794
795 // If there is no active window, then do nothing.
796
797 if (w == NULL) {
798 prevState = _curMouseState;
799 return;
800 }
801
802 // Set up the pick position relative to the window
803
804 if (activePanel) {
805 pickPos.x = _curMouseState.pos.x - activePanel->window._extent.x;
806 pickPos.y = _curMouseState.pos.y - activePanel->window._extent.y;
807 } else {
808 pickPos.x = _curMouseState.pos.x - w->_extent.x;
809 pickPos.y = _curMouseState.pos.y - w->_extent.y;
810 }
811
812 // Fill in the message to be sent to the various panels
813
814 msg.pickAbsPos = pickPos;
815 msg.leftButton = _curMouseState.left ? 1 : 0;
816 msg.rightButton = _curMouseState.right ? 1 : 0;
817 msg.pointerEnter = 0;
818 msg.pointerLeave = 0;
819 msg.doubleClick = 0;
820 msg.timeStamp = time;
821
822 if (((_curMouseState.left && !leftDrag) // if left button hit
823 || (_curMouseState.right && !rightDrag)) // or right button hit
824 && activePanel != NULL) { // and a panel is active
825 // Then we have a button hit event. If the button hit
826 // is occuring outside the panel, then it should be
827 // deselected.
828
829 if (activePanel->_extent.ptInside(pickPos) == false)
830 activePanel->deactivate();
831 }
832
833 if (prevState.pos == _curMouseState.pos) ; // don't do anything if same pos
834 else if (activePanel) { // if control active
835 mousePanel = activePanel; // assume mouse over active panel
836
837 if (leftDrag || rightDrag) {
838 setMsg(msg, activePanel); // set up gPanelMessage
839 activePanel->pointerDrag(msg); // send panel a mouse movement
840 } else {
841 setMsg(msg, activePanel); // set up gPanelMessage
842 activePanel->pointerMove(msg); // send panel a mouse movement
843 }
844 }
845
846 if (!activePanel /* && !ms.right */) {
847 // If the point is within the window
848 Common::List<gWindow *>::iterator it;
849 for (it = windowList.begin(); it != windowList.end(); ++it) {
850 w = *it;
851 if (w->_extent.ptInside(_curMouseState.pos) || w->isModal()) {
852 // Set up the pick position relative to the window
853
854 pickPos.x = _curMouseState.pos.x - w->_extent.x;
855 pickPos.y = _curMouseState.pos.y - w->_extent.y;
856
857 if ((ctl = w->hitTest(pickPos)) != NULL)
858 pickPanel = ctl;
859 else
860 pickPanel = w;
861
862 break;
863 }
864 }
865
866 if (it == windowList.end()) {
867 prevState = _curMouseState;
868 return;
869 }
870
871 mouseWindow = w;
872
873 // If the mouse is not over the control any more, tell it so.
874
875 if (mousePanel && mousePanel != pickPanel) {
876 if (&mousePanel->window != w) {
877 // Temporarily adjust pickPos to be relative to the old panel's window
878 // instead of the new panel's window.
879 pickPos.x = _curMouseState.pos.x - mousePanel->window._extent.x;
880 pickPos.y = _curMouseState.pos.y - mousePanel->window._extent.y;
881
882 setMsgQ(msg, mousePanel); // set up gPanelMessage
883
884 pickPos.x = _curMouseState.pos.x - w->_extent.x;
885 pickPos.y = _curMouseState.pos.y - w->_extent.y;
886 } else {
887 setMsgQ(msg, mousePanel); // set up gPanelMessage
888 }
889 // msg.pickPos.x = pickPos.x - mousePanel->extent.x;
890 // msg.pickPos.y = pickPos.y - mousePanel->extent.y;
891 msg.inPanel = 0;
892 msg.pointerEnter = 0;
893 msg.pointerLeave = 1;
894
895 mousePanel->pointerMove(msg);
896
897 }
898
899 // If the mouse is over a new control, make that the current
900 // mouse control.
901
902 if (pickPanel) {
903 setMsg(msg, pickPanel); // set up gPanelMessage
904 // msg.pickPos.x = pickPos.x - pickPanel->extent.x;
905 // msg.pickPos.y = pickPos.y - pickPanel->extent.y;
906 msg.leftButton = _curMouseState.left ? 1 : 0;
907 // msg.inPanel = pickPanel->extent.ptInside(pickPos);
908 msg.pointerEnter = (mousePanel == pickPanel) ? 0 : 1;
909 msg.pointerLeave = 0;
910
911 mousePanel = pickPanel;
912 mousePanel->pointerMove(msg);
913 } else
914 mousePanel = NULL;
915 }
916
917 // Fix up flags because earlier code may have changed them
918
919 msg.pointerEnter = 0;
920 msg.pointerLeave = 0;
921
922 // Send appropriate button-press messages to the panels
923
924 if (prevState.left != _curMouseState.left // if buttons changed state
925 || prevState.right != _curMouseState.right) {
926
927 // If both buttons were previously up, then a mouse
928 // hit must have occured.
929
930 if (prevState.left == 0 && prevState.right == 0) {
931
932 // Check for mouse double-click. Check to see that
933 // the elapsed time from the last click is less than
934 // 1/3 of a second, and that the mouse ptr hasn't moved
935 // very much.
936
937 if (((uint32)(msg.timeStamp - lastClickTime) < 333)
938 || _curMouseState.left > 1
939 || _curMouseState.right > 1) {
940 Point16 diff = lastClickPos - _curMouseState.pos;
941
942 if (ABS(diff.x) + ABS(diff.y) < 6)
943 msg.doubleClick = 1;
944 }
945
946 // Record the last mouse time and position for
947 // future double-click checks.
948
949 lastClickTime = msg.timeStamp;
950 lastClickPos = _curMouseState.pos;
951
952 if (mousePanel) { // if over a control
953 setMsgQ(msg, mousePanel); // set up gPanelMessage
954 // msg.pickPos.x = pickPos.x - mousePanel->extent.x;
955 // msg.pickPos.y = pickPos.y - mousePanel->extent.y;
956 msg.inPanel = 1;
957
958 if (activeWindow && activeWindow->isModal()) {
959 mouseWindow = activeWindow;
960 } else if (mouseWindow == NULL) {
961 mouseWindow = &mousePanel->window;
962 }
963
964 if (mouseWindow && mouseWindow != activeWindow) {
965 msg.pickAbsPos = pickPos;
966 // Re-order the windows.
967 mouseWindow->toFront();
968 }
969 // send it a hit message
970 if (mousePanel->pointerHit(msg)) {
971 activePanel = mousePanel;
972 if (_curMouseState.left)
973 leftDrag = true;
974 else
975 rightDrag = true;
976 }
977 }
978 } else if ((leftDrag && _curMouseState.left == false) // check for release
979 || (rightDrag && _curMouseState.right == false)) {
980 if (activePanel && mousePanel) { // if a control is active
981 setMsg(msg, mousePanel); // send it a release message
982 mousePanel->pointerRelease(msg);
983 }
984 leftDrag = rightDrag = false;
985 }
986 }
987
988 prevState = _curMouseState;
989 }
990
leavePanel(void)991 void gToolBase::leavePanel(void) {
992 msg.timeStamp = g_system->getMillis();
993
994 if (mousePanel) {
995 msg.inPanel = 0;
996 msg.pointerEnter = 0;
997 msg.pointerLeave = 1;
998
999 mousePanel->pointerMove(msg);
1000 mousePanel = NULL;
1001 }
1002
1003 if (activePanel) activePanel->deactivate();
1004 }
1005
handleKeyStroke(Common::Event & event)1006 void gToolBase::handleKeyStroke(Common::Event &event) {
1007 gWindow *w = activeWindow;
1008 gPanel *ctl;
1009
1010 uint16 key = event.kbd.ascii; // FIXME
1011 uint16 qualifier = 0;
1012
1013 if (event.kbd.flags & Common::KBD_SHIFT)
1014 qualifier |= qualifierShift;
1015
1016 if (event.kbd.flags & Common::KBD_CTRL)
1017 qualifier |= qualifierControl;
1018
1019 if (event.kbd.flags & Common::KBD_ALT)
1020 qualifier |= qualifierAlt;
1021
1022 msg.pickAbsPos = pickPos;
1023 msg.pointerEnter = 0;
1024 msg.pointerLeave = 0;
1025 msg.key = key;
1026 msg.qualifier = qualifier;
1027 msg.timeStamp = g_system->getMillis();
1028
1029 if (activePanel) { // send keystroke to active panel
1030 setMsg(msg, activePanel); // set up gPanelMessage
1031 if (activePanel->keyStroke(msg))
1032 return;
1033 }
1034
1035 // Now, search the contents of the window for a control with
1036 // the correct accelerator key
1037
1038 if (w) {
1039 uint16 k = key;
1040 //uint8 k = key & 0xff;
1041
1042 if (k != 0) {
1043 k = toupper(k);
1044
1045 if ((ctl = w->keyTest(k)) != NULL) {
1046 if (activePanel == ctl) return;
1047 if (activePanel) activePanel->deactivate();
1048 if (ctl->activate(gEventKeyDown)) {
1049 activePanel = ctl;
1050 return;
1051 }
1052 }
1053 }
1054
1055 // Try sending the message to the window
1056
1057 if (w->keyStroke(msg))
1058 return;
1059
1060 // else send the message to the app.
1061
1062 w->notify(gEventKeyDown, (qualifier << 16) | key);
1063 }
1064 }
1065
handleTimerTick(int32 tick)1066 void gToolBase::handleTimerTick(int32 tick) {
1067 msg.pickAbsPos = pickPos;
1068 msg.pointerEnter = 0;
1069 msg.pointerLeave = 0;
1070 msg.timeStamp = tick;
1071
1072 if (activePanel) { // send keystroke to active panel
1073 setMsg(msg, activePanel); // set up gPanelMessage
1074 activePanel->timerTick(msg);
1075 } else if (mousePanel) {
1076 if (mousePanel->wantMousePoll) {
1077 setMsg(msg, mousePanel); // set up gPanelMessage
1078 mousePanel->pointerMove(msg);
1079 } else if (!mouseHintSet
1080 && ((uint32)(tick - lastMouseMoveTime) > 500)) {
1081 mousePanel->onMouseHintDelay();
1082 }
1083 }
1084 }
1085
HandleTimerTick(long tick)1086 void HandleTimerTick(long tick) {
1087 static int32 lastTick;
1088
1089 if (tick - lastTick > 1) {
1090 lastTick = tick;
1091 g_vm->_toolBase->handleTimerTick(tick);
1092 }
1093 }
1094
1095 /* ===================================================================== *
1096 Code to initialize the panel system
1097 * ===================================================================== */
1098
initPanels(gDisplayPort & port)1099 void initPanels(gDisplayPort &port) {
1100 globalPort = &port;
1101 mainFont = &Helv11Font;
1102 }
1103
cleanupPanels(void)1104 void cleanupPanels(void) {
1105 }
1106
leftButtonState(void)1107 int16 leftButtonState(void) {
1108 return g_vm->_toolBase->msg.leftButton;
1109 }
1110
rightButtonState(void)1111 int16 rightButtonState(void) {
1112 return g_vm->_toolBase->msg.rightButton;
1113 }
1114
LockUI(bool state)1115 void LockUI(bool state) {
1116 if (state == true) {
1117 if (lockUINest <= 0) {
1118 g_vm->_pointer->hide();
1119 enableUIKeys(false);
1120 g_vm->_toolBase->setActive(NULL);
1121 }
1122 lockUINest++;
1123 } else {
1124 lockUINest--;
1125 assert(lockUINest >= 0);
1126 if (lockUINest <= 0) {
1127 enableUIKeys(true);
1128 g_vm->_pointer->show();
1129 }
1130 }
1131 }
1132
dumpGBASE(char * msg)1133 void dumpGBASE(char *msg) {
1134 }
1135
1136 } // end of namespace Saga2
1137