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
23 /*
24 * Based on
25 * WebVenture (c) 2010, Sean Kasun
26 * https://github.com/mrkite/webventure, http://seancode.com/webventure/
27 *
28 * Used with explicit permission from the author
29 */
30
31 #include "common/file.h"
32 #include "common/system.h"
33 #include "common/debug-channels.h"
34 #include "common/debug.h"
35 #include "image/bmp.h"
36 #include "graphics/macgui/macfontmanager.h"
37
38 #include "macventure/gui.h"
39 #include "macventure/dialog.h"
40
41 namespace MacVenture {
42
43 enum {
44 kCursorWidth = 2,
45 kCursorHeight = 2
46 };
47
48 enum {
49 kExitButtonWidth = 10,
50 kExitButtonHeight = 10
51 };
52
53 enum {
54 kMenuHighLevel = -1,
55 kMenuAbout = 0,
56 kMenuFile = 1,
57 kMenuEdit = 2,
58 kMenuSpecial = 3
59 };
60
61 enum {
62 kCommandNum = 8
63 };
64
65 enum {
66 kDragThreshold = 5
67 };
68
69 const bool kLoadStaticMenus = true;
70
71 static const Graphics::MacMenuData menuSubItems[] = {
72 { kMenuHighLevel, "File", 0, 0, false },
73 { kMenuHighLevel, "Edit", 0, 0, false },
74 { kMenuHighLevel, "Special", 0, 0, false },
75 { kMenuHighLevel, "Font", 0, 0, false },
76 { kMenuHighLevel, "FontSize", 0, 0, false },
77
78 //{ kMenuAbout, "About", kMenuActionAbout, 0, true},
79
80 { kMenuFile, "New", kMenuActionNew, 0, true },
81 { kMenuFile, NULL, 0, 0, false },
82 { kMenuFile, "Open...", kMenuActionOpen, 0, true },
83 { kMenuFile, "Save", kMenuActionSave, 0, true },
84 { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true },
85 { kMenuFile, NULL, 0, 0, false },
86 { kMenuFile, "Quit", kMenuActionQuit, 0, true },
87
88 { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false },
89 { kMenuEdit, NULL, 0, 0, false },
90 { kMenuEdit, "Cut", kMenuActionCut, 'K', false },
91 { kMenuEdit, "Copy", kMenuActionCopy, 'C', false },
92 { kMenuEdit, "Paste", kMenuActionPaste, 'V', false },
93 { kMenuEdit, "Clear", kMenuActionClear, 'B', false },
94
95 { kMenuSpecial, "Clean Up", kMenuActionCleanUp, 0, false },
96 { kMenuSpecial, "Mess Up", kMenuActionMessUp, 0, false },
97
98 { 0, NULL, 0, 0, false }
99 };
100
101
102 bool commandsWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
103 bool mainGameWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
104 bool outConsoleWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
105 bool selfWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
106 bool exitsWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
107 bool diplomaWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
108 bool inventoryWindowCallback(Graphics::WindowClick, Common::Event &event, void *gui);
109
110 void menuCommandsCallback(int action, Common::String &text, void *data);
111
Gui(MacVentureEngine * engine,Common::MacResManager * resman)112 Gui::Gui(MacVentureEngine *engine, Common::MacResManager *resman) {
113 _engine = engine;
114 _resourceManager = resman;
115 _windowData = NULL;
116 _controlData = NULL;
117 _draggedObj.id = 0;
118 _draggedObj.pos = Common::Point(0, 0);
119 _dialog = NULL;
120
121 _cursor = new Cursor(this);
122
123 _consoleText = new ConsoleText(this);
124 _graphics = NULL;
125
126 initGUI();
127 }
128
~Gui()129 Gui::~Gui() {
130
131 if (_windowData)
132 delete _windowData;
133
134 if (_controlData)
135 delete _controlData;
136
137 if (_exitsData)
138 delete _exitsData;
139
140 if (_cursor)
141 delete _cursor;
142
143 if (_consoleText)
144 delete _consoleText;
145
146 if (_dialog)
147 delete _dialog;
148
149 clearAssets();
150
151 if (_graphics)
152 delete _graphics;
153 }
154
initGUI()155 void Gui::initGUI() {
156 _screen.create(kScreenWidth, kScreenHeight, Graphics::PixelFormat::createFormatCLUT8());
157 _wm.setScreen(&_screen);
158
159 // Menu
160 _menu = _wm.addMenu();
161 if (!loadMenus())
162 error("GUI: Could not load menus");
163 _menu->setCommandsCallback(menuCommandsCallback, this);
164 _menu->calcDimensions();
165
166 loadGraphics();
167
168 if (!loadWindows())
169 error("GUI: Could not load windows");
170
171 initWindows();
172
173 assignObjReferences();
174
175 if (!loadControls())
176 error("GUI: Could not load controls");
177
178 draw();
179
180 }
181
reloadInternals()182 void Gui::reloadInternals() {
183 clearAssets();
184 loadGraphics();
185 }
186
draw()187 void Gui::draw() {
188 // Will be performance-improved after the milestone
189 _wm.setFullRefresh(true);
190
191 drawWindows();
192
193 _wm.draw();
194
195 drawDraggedObject();
196 drawDialog();
197 // TODO: When window titles with custom borders are in MacGui, this should be used.
198 //drawWindowTitle(kMainGameWindow, _mainGameWindow->getSurface());
199 }
200
drawMenu()201 void Gui::drawMenu() {
202 _menu->draw(&_screen);
203 }
204
drawTitle()205 void Gui::drawTitle() {
206 warning("drawTitle hasn't been tested yet");
207 }
208
clearControls()209 void Gui::clearControls() {
210 if (!_controlData)
211 return;
212
213 Common::Array<CommandButton>::iterator it = _controlData->begin();
214 for (; it != _controlData->end(); ++it) {
215 it->unselect();
216 }
217 }
218
initWindows()219 void Gui::initWindows() {
220 // Game Controls Window
221 _controlsWindow = _wm.addWindow(false, false, false);
222 _controlsWindow->setDimensions(getWindowData(kCommandsWindow).bounds);
223 _controlsWindow->setActive(false);
224 _controlsWindow->setCallback(commandsWindowCallback, this);
225 loadBorders(_controlsWindow, findWindowData(kCommandsWindow).type);
226
227 // Main Game Window
228 _mainGameWindow = _wm.addWindow(false, false, false);
229 _mainGameWindow->setDimensions(getWindowData(kMainGameWindow).bounds);
230 _mainGameWindow->setActive(false);
231 _mainGameWindow->setCallback(mainGameWindowCallback, this);
232 loadBorders(_mainGameWindow, findWindowData(kMainGameWindow).type);
233
234 // In-game Output Console
235 _outConsoleWindow = _wm.addWindow(true, true, false);
236 // HACK We have to hand-create the dimensions, otherwise they don't fit
237 const WindowData &wd = getWindowData(kOutConsoleWindow);
238 Common::Rect dimensions = wd.bounds;
239 dimensions.setWidth(dimensions.width() - borderBounds(wd.type).rightOffset);
240 _outConsoleWindow->setDimensions(dimensions);
241 _outConsoleWindow->setActive(false);
242 _outConsoleWindow->setCallback(outConsoleWindowCallback, this);
243 loadBorders(_outConsoleWindow, findWindowData(kOutConsoleWindow).type);
244
245 // Self Window
246 _selfWindow = _wm.addWindow(false, true, false);
247 _selfWindow->setDimensions(getWindowData(kSelfWindow).bounds);
248 _selfWindow->setActive(false);
249 _selfWindow->setCallback(selfWindowCallback, this);
250 loadBorders(_selfWindow, findWindowData(kSelfWindow).type);
251
252 // Exits Window
253 _exitsWindow = _wm.addWindow(false, false, false);
254 _exitsWindow->setDimensions(getWindowData(kExitsWindow).bounds);
255 _exitsWindow->setActive(false);
256 _exitsWindow->setCallback(exitsWindowCallback, this);
257
258 // TODO: In the original, the background is actually a clickable
259 // object that can be used to refer to the room itself. In that case,
260 // the background should be kPatternDarkGray.
261 _exitsWindow->setBackgroundPattern(kPatternLightGray);
262 loadBorders(_exitsWindow, findWindowData(kExitsWindow).type);
263 }
264
getWindowData(WindowReference reference)265 const WindowData &Gui::getWindowData(WindowReference reference) {
266 return findWindowData(reference);
267 }
268
getCurrentFont()269 const Graphics::Font &Gui::getCurrentFont() {
270 return *_wm._fontMan->getFont(Graphics::MacFont(Graphics::kMacFontChicago, 12));
271 }
272
bringToFront(WindowReference winID)273 void Gui::bringToFront(WindowReference winID) {
274 findWindow(winID)->setActive(true);
275 }
276
setWindowTitle(WindowReference winID,Common::String string)277 void Gui::setWindowTitle(WindowReference winID, Common::String string) {
278 findWindowData(winID).title = string;
279 findWindowData(winID).titleLength = string.size();
280 }
281
updateWindowInfo(WindowReference ref,ObjID objID,const Common::Array<ObjID> & children)282 void Gui::updateWindowInfo(WindowReference ref, ObjID objID, const Common::Array<ObjID> &children) {
283 if (ref == kNoWindow) {
284 return;
285 }
286 WindowData &data = findWindowData(ref);
287 data.children.clear();
288 data.objRef = objID;
289 uint32 originx = 0x7fff;
290 uint32 originy = 0x7fff;
291 for (uint i = 0; i < children.size(); i++) {
292 if (children[i] != 1) {
293 ObjID child = children[i];
294 if (ref != kMainGameWindow) {
295 Common::Point childPos = _engine->getObjPosition(child);
296 originx = originx > (uint)childPos.x ? (uint)childPos.x : originx;
297 originy = originy > (uint)childPos.y ? (uint)childPos.y : originy;
298 }
299 data.children.push_back(DrawableObject(child, kBlitBIC));
300 }
301 }
302 if (originx != 0x7fff) {
303 data.bounds.left = originx;
304 }
305 if (originy != 0x7fff) {
306 data.bounds.top = originy;
307 }
308 if (ref != kMainGameWindow) {
309 data.updateScroll = true;
310 }
311 }
312
addChild(WindowReference target,ObjID child)313 void Gui::addChild(WindowReference target, ObjID child) {
314 findWindowData(target).children.push_back(DrawableObject(child, kBlitBIC));
315 }
316
removeChild(WindowReference target,ObjID child)317 void Gui::removeChild(WindowReference target, ObjID child) {
318 WindowData &data = findWindowData(target);
319 uint index = 0;
320 for (;index < data.children.size(); index++) {
321 if (data.children[index].obj == child) {
322 break;
323 }
324 }
325
326 if (index < data.children.size())
327 data.children.remove_at(index);
328 }
329
assignObjReferences()330 void Gui::assignObjReferences() {
331 findWindowData(kSelfWindow).objRef = 0;
332 }
333
createInventoryWindow(ObjID objRef)334 WindowReference Gui::createInventoryWindow(ObjID objRef) {
335 Graphics::MacWindow *newWindow = _wm.addWindow(true, true, true);
336 WindowData newData;
337 GlobalSettings settings = _engine->getGlobalSettings();
338 newData.refcon = (WindowReference)(_inventoryWindows.size() + kInventoryStart); // This is a HACK
339
340 if (_windowData->back().refcon < 0x80) { // There is already another inventory window
341 newData.bounds = _windowData->back().bounds; // Inventory windows are always last
342 newData.bounds.translate(newData.bounds.left + settings._invOffsetX, newData.bounds.top + settings._invOffsetY);
343 } else {
344 BorderBounds bbs = borderBounds(kInvWindow);
345 newData.bounds = Common::Rect(
346 settings._invLeft - bbs.leftOffset,
347 settings._invTop - bbs.topOffset,
348 settings._invLeft + settings._invWidth,
349 settings._invTop + settings._invHeight);
350 }
351 newData.type = kInvWindow;
352 newData.hasCloseBox = true;
353 newData.visible = true;
354 newData.objRef = objRef;
355 _windowData->push_back(newData);
356
357 newWindow->setDimensions(newData.bounds);
358 newWindow->setCallback(inventoryWindowCallback, this);
359 newWindow->setCloseable(true);
360 loadBorders(newWindow, newData.type);
361 _inventoryWindows.push_back(newWindow);
362
363 debugC(1, kMVDebugGUI, "Create new inventory window. Reference: %d", newData.refcon);
364 return newData.refcon;
365 }
366
loadBorders(Graphics::MacWindow * target,MVWindowType type)367 void Gui::loadBorders(Graphics::MacWindow *target, MVWindowType type) {
368 loadBorder(target, type, false);
369 loadBorder(target, type, true);
370 }
371
loadBorder(Graphics::MacWindow * target,MVWindowType type,bool active)372 void Gui::loadBorder(Graphics::MacWindow *target, MVWindowType type, bool active) {
373
374 Common::SeekableReadStream *stream = _engine->getBorderFile(type, active);
375
376 if (stream) {
377 BorderBounds bbs = borderBounds(type);
378 target->loadBorder(*stream, active, bbs.leftOffset, bbs.rightOffset, bbs.topOffset, bbs.bottomOffset);
379
380 delete stream;
381 }
382 }
383
loadGraphics()384 void Gui::loadGraphics() {
385 if (_graphics)
386 delete _graphics;
387 _graphics = new Container(_engine->getFilePath(kGraphicPathID));
388 }
389
clearAssets()390 void Gui::clearAssets() {
391 Common::HashMap<ObjID, ImageAsset*>::const_iterator it = _assets.begin();
392 for (; it != _assets.end(); it++) {
393 delete it->_value;
394 }
395 _assets.clear();
396 }
397
loadMenus()398 bool Gui::loadMenus() {
399
400 if (kLoadStaticMenus) {
401 // We assume that, if there are static menus, we don't need dynamic ones
402 _menu->addStaticMenus(menuSubItems);
403 return true;
404 }
405
406 Common::MacResIDArray resArray;
407 Common::SeekableReadStream *res;
408 Common::MacResIDArray::const_iterator iter;
409
410 if ((resArray = _resourceManager->getResIDArray(MKTAG('M', 'E', 'N', 'U'))).size() == 0)
411 return false;
412
413 _menu->addMenuSubItem(0, "Abb", kMenuActionAbout, 0, 'A', true);
414
415 int i = 1;
416 for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
417 res = _resourceManager->getResource(MKTAG('M', 'E', 'N', 'U'), *iter);
418 uint16 key;
419 uint16 style;
420 uint8 titleLength;
421 char *title;
422
423 /* Skip menuID, width, height, resourceID, placeholder */
424 for (int skip = 0; skip < 5; skip++) {
425 res->readUint16BE();
426 }
427 titleLength = res->readByte();
428 title = new char[titleLength + 1];
429 res->read(title, titleLength);
430 title[titleLength] = '\0';
431
432 if (titleLength > 1) {
433 _menu->addMenuItem(title);
434
435 // Read submenu items
436 while ((titleLength = res->readByte())) {
437 title = new char[titleLength + 1];
438 res->read(title, titleLength);
439 title[titleLength] = '\0';
440 // Skip icon
441 res->readUint16BE();
442 // Read key
443 key = res->readUint16BE();
444 // Skip mark
445 res->readUint16BE();
446 // Read style
447 style = res->readUint16BE();
448 _menu->addMenuSubItem(i, title, 0, style, key, false);
449 }
450 }
451
452 i++;
453 delete res;
454 }
455
456 return true;
457 }
458
loadWindows()459 bool Gui::loadWindows() {
460 Common::MacResIDArray resArray;
461 Common::SeekableReadStream *res;
462 Common::MacResIDArray::const_iterator iter;
463
464 _windowData = new Common::List<WindowData>();
465
466 if ((resArray = _resourceManager->getResIDArray(MKTAG('W', 'I', 'N', 'D'))).size() == 0)
467 return false;
468
469 uint32 id = kCommandsWindow;
470 for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
471 res = _resourceManager->getResource(MKTAG('W', 'I', 'N', 'D'), *iter);
472 WindowData data;
473 uint16 top, left, bottom, right;
474 top = res->readUint16BE();
475 left = res->readUint16BE();
476 bottom = res->readUint16BE();
477 right = res->readUint16BE();
478 data.type = (MVWindowType)res->readUint16BE();
479 BorderBounds bbs = borderBounds(data.type);
480 data.bounds = Common::Rect(
481 left - bbs.leftOffset,
482 top - bbs.topOffset,
483 right + bbs.rightOffset,
484 bottom + bbs.bottomOffset);
485
486 data.visible = res->readUint16BE();
487 data.hasCloseBox = res->readUint16BE();
488 data.refcon = (WindowReference)id; id++;
489 res->readUint32BE(); // Skip the true id. For some reason it's reading 0
490 data.titleLength = res->readByte();
491 if (data.titleLength) {
492 char *newTitle = new char[data.titleLength + 1];
493 res->read(newTitle, data.titleLength);
494 newTitle[data.titleLength] = '\0';
495 data.title = Common::String(newTitle);
496 delete[] newTitle;
497 }
498 data.scrollPos = Common::Point(0, 0);
499
500 debugC(1, kMVDebugGUI, "Window loaded: %s", data.title.c_str());
501
502 _windowData->push_back(data);
503
504 delete res;
505 }
506
507 return true;
508 }
509
loadControls()510 bool Gui::loadControls() {
511 Common::MacResIDArray resArray;
512 Common::SeekableReadStream *res;
513 Common::MacResIDArray::const_iterator iter;
514
515 _controlData = new Common::Array<CommandButton>();
516 _exitsData = new Common::Array<CommandButton>();
517
518 if ((resArray = _resourceManager->getResIDArray(MKTAG('C', 'N', 'T', 'L'))).size() == 0)
519 return false;
520
521 uint32 id = kControlExitBox;
522 for (iter = resArray.begin(); iter != resArray.end(); ++iter) {
523 res = _resourceManager->getResource(MKTAG('C', 'N', 'T', 'L'), *iter);
524 ControlData data;
525 uint16 top, left, bottom, right;
526 top = res->readUint16BE();
527 left = res->readUint16BE();
528 bottom = res->readUint16BE();
529 right = res->readUint16BE();
530 data.scrollValue = res->readUint16BE();
531 data.visible = res->readByte();
532 res->readByte(); // Unused
533 data.scrollMax = res->readUint16BE();
534 data.scrollMin = res->readUint16BE();
535 data.cdef = res->readUint16BE();
536 data.refcon = (ControlAction)res->readUint32BE();
537 data.type = (ControlType)id; id++;
538 data.titleLength = res->readByte();
539 if (data.titleLength) {
540 char *title = new char[data.titleLength + 1];
541 res->read(title, data.titleLength);
542 title[data.titleLength] = '\0';
543 data.title = Common::String(title);
544 delete[] title;
545 }
546 if (data.type != kControlExitBox) {
547 BorderBounds bbs = borderBounds(getWindowData(kCommandsWindow).type);
548 // We just want to move the button, not change it's size
549 data.bounds = Common::Rect(left + bbs.leftOffset, top + bbs.topOffset, right + bbs.leftOffset, bottom + bbs.topOffset);
550 } else {
551 data.bounds = Common::Rect(left, top, right, bottom);
552 }
553
554
555 _controlData->push_back(CommandButton(data, this));
556
557 delete res;
558 }
559
560 return true;
561 }
562
drawWindows()563 void Gui::drawWindows() {
564
565 drawCommandsWindow();
566 drawMainGameWindow();
567 drawSelfWindow();
568 drawInventories();
569 drawExitsWindow();
570 drawConsoleWindow();
571
572 }
573
drawCommandsWindow()574 void Gui::drawCommandsWindow() {
575 if (_engine->needsClickToContinue()) {
576 Graphics::ManagedSurface *srf = _controlsWindow->getSurface();
577 WindowData data = getWindowData(kCommandsWindow);
578 srf->fillRect(Common::Rect(0, 0, srf->w, srf->h), kColorWhite);
579 getCurrentFont().drawString(
580 srf,
581 _engine->getCommandsPausedString(),
582 0,
583 (srf->h / 2) - getCurrentFont().getFontHeight(),
584 data.bounds.right - data.bounds.left,
585 kColorBlack,
586 Graphics::kTextAlignCenter);
587 } else {
588 Common::Array<CommandButton>::const_iterator it = _controlData->begin();
589 for (; it != _controlData->end(); ++it) {
590 CommandButton button = *it;
591 if (button.getData().type != kControlExitBox)
592 button.draw(*_controlsWindow->getSurface());
593 }
594 }
595 }
596
drawMainGameWindow()597 void Gui::drawMainGameWindow() {
598 const WindowData &data = getWindowData(kMainGameWindow);
599 BorderBounds border = borderBounds(data.type);
600 ObjID objRef = data.objRef;
601
602 _mainGameWindow->setDirty(true);
603
604 if (data.objRef > 0 && data.objRef < 2000) {
605 ensureAssetLoaded(objRef);
606
607 _assets[objRef]->blitInto(
608 _mainGameWindow->getSurface(),
609 border.leftOffset,
610 border.topOffset,
611 kBlitDirect);
612 }
613
614 drawObjectsInWindow(data, _mainGameWindow->getSurface());
615
616 if (DebugMan.isDebugChannelEnabled(kMVDebugGUI)) {
617 Graphics::MacWindow *win = findWindow(data.refcon);
618 Common::Rect innerDims = win->getInnerDimensions();
619 int x = win->getDimensions().left;
620 int y = win->getDimensions().top;
621 innerDims.translate(-x, -y);
622 win->getSurface()->frameRect(innerDims, kColorGreen);
623 }
624
625 findWindow(kMainGameWindow)->setDirty(true);
626 }
627
drawSelfWindow()628 void Gui::drawSelfWindow() {
629 drawObjectsInWindow(getWindowData(kSelfWindow), _selfWindow->getSurface());
630 if (_engine->isObjSelected(1)) {
631 invertWindowColors(kSelfWindow);
632 }
633 findWindow(kSelfWindow)->setDirty(true);
634 }
635
drawInventories()636 void Gui::drawInventories() {
637
638 Graphics::ManagedSurface *srf;
639 for (uint i = 0; i < _inventoryWindows.size(); i++) {
640 const WindowData &data = getWindowData((WindowReference)(kInventoryStart + i));
641 Graphics::MacWindow *win = findWindow(data.refcon);
642 srf = win->getSurface();
643 srf->clear(kColorGreen);
644 srf->fillRect(srf->getBounds(), kColorWhite);
645 drawObjectsInWindow(data, srf);
646
647 if (DebugMan.isDebugChannelEnabled(kMVDebugGUI)) {
648 Common::Rect innerDims = win->getInnerDimensions();
649 int x = win->getDimensions().left;
650 int y = win->getDimensions().top;
651 innerDims.translate(-x, -y);
652 srf->frameRect(innerDims, kColorGreen);
653 }
654
655 findWindow(data.refcon)->setDirty(true);
656 }
657
658 }
659
drawExitsWindow()660 void Gui::drawExitsWindow() {
661 _exitsWindow->setBackgroundPattern(kPatternLightGray);
662
663 Graphics::ManagedSurface *srf = _exitsWindow->getSurface();
664
665 Common::Array<CommandButton>::const_iterator it = _exitsData->begin();
666 for (; it != _exitsData->end(); ++it) {
667 CommandButton button = *it;
668 button.draw(*srf);
669 }
670
671 findWindow(kExitsWindow)->setDirty(true);
672 }
673
drawConsoleWindow()674 void Gui::drawConsoleWindow() {
675
676 Graphics::ManagedSurface *srf = _outConsoleWindow->getSurface();
677 BorderBounds bounds = borderBounds(getWindowData(kOutConsoleWindow).type);
678 _consoleText->renderInto(srf, bounds, kConsoleLeftOffset);
679 }
680
drawObjectsInWindow(const WindowData & targetData,Graphics::ManagedSurface * surface)681 void Gui::drawObjectsInWindow(const WindowData &targetData, Graphics::ManagedSurface *surface) {
682 BorderBounds border = borderBounds(targetData.type);
683 Common::Point pos;
684 ObjID child;
685 BlitMode mode;
686
687 if (targetData.children.size() == 0) {
688 return;
689 }
690
691 Graphics::ManagedSurface composeSurface;
692 createInnerSurface(&composeSurface, surface, border);
693 assert(composeSurface.w <= surface->w &&
694 composeSurface.h <= surface->h);
695 composeSurface.clear(kColorGreen);
696
697 for (uint i = 0; i < targetData.children.size(); i++) {
698 child = targetData.children[i].obj;
699 mode = (BlitMode)targetData.children[i].mode;
700 pos = _engine->getObjPosition(child);
701 pos -= targetData.scrollPos;
702 ensureAssetLoaded(child);
703
704 _assets[child]->blitInto(
705 &composeSurface,
706 pos.x,
707 pos.y,
708 mode);
709
710 if (_engine->isObjVisible(child)) {
711 if (_engine->isObjSelected(child) ||
712 child == _draggedObj.id) {
713
714 _assets[child]->blitInto(
715 &composeSurface, pos.x, pos.y, kBlitOR);
716 }
717 }
718
719 if (DebugMan.isDebugChannelEnabled(kMVDebugGUI)) {
720 Common::Rect testBounds = _engine->getObjBounds(child);
721 testBounds.translate(-targetData.scrollPos.x, -targetData.scrollPos.y);
722 surface->frameRect(testBounds, kColorGreen);
723 }
724 }
725 Common::Point composePosition = Common::Point(border.leftOffset, border.topOffset);
726 surface->transBlitFrom(composeSurface, composePosition, kColorGreen);
727 }
728
drawWindowTitle(WindowReference target,Graphics::ManagedSurface * surface)729 void Gui::drawWindowTitle(WindowReference target, Graphics::ManagedSurface *surface) {
730 // TODO: Implement when MacGui supports titles in windows with custom borders.
731 }
732
drawDraggedObject()733 void Gui::drawDraggedObject() {
734 if (_draggedObj.id != 0 &&
735 _engine->isObjVisible(_draggedObj.id)) {
736 ensureAssetLoaded(_draggedObj.id);
737 ImageAsset *asset = _assets[_draggedObj.id];
738
739 // In case of overflow from the right/top
740 uint w = asset->getWidth() + MIN((int16)0, _draggedObj.pos.x);
741 uint h = asset->getHeight() + MIN((int16)0, _draggedObj.pos.y);
742
743 // In case of overflow from the bottom/left
744 if (_draggedObj.pos.x > 0 && _draggedObj.pos.x + w > kScreenWidth) {
745 w = kScreenWidth - _draggedObj.pos.x;
746 }
747 if (_draggedObj.pos.y > 0 && _draggedObj.pos.y + h > kScreenHeight) {
748 h = kScreenHeight - _draggedObj.pos.y;
749 }
750
751 Common::Point target = _draggedObj.pos;
752 if (target.x < 0) {
753 target.x = 0;
754 }
755 if (target.y < 0) {
756 target.y = 0;
757 }
758
759 _draggedSurface.create(w, h, _screen.format);
760 _draggedSurface.blitFrom(
761 _screen,
762 Common::Rect(
763 target.x,
764 target.y,
765 target.x + _draggedSurface.w,
766 target.y + _draggedSurface.h),
767 Common::Point(0, 0));
768 asset->blitInto(&_draggedSurface, MIN((int16)0, _draggedObj.pos.x), MIN((int16)0, _draggedObj.pos.y), kBlitBIC);
769
770 g_system->copyRectToScreen(
771 _draggedSurface.getBasePtr(0, 0),
772 _draggedSurface.pitch,
773 target.x,
774 target.y,
775 _draggedSurface.w,
776 _draggedSurface.h
777 );
778 }
779 }
780
drawDialog()781 void Gui::drawDialog() {
782 if (_dialog) {
783 _dialog->draw();
784 }
785 }
786
updateWindow(WindowReference winID,bool containerOpen)787 void Gui::updateWindow(WindowReference winID, bool containerOpen) {
788 if (winID == kNoWindow) {
789 return;
790 }
791 if (winID == kSelfWindow || containerOpen) {
792 WindowData &data = findWindowData(winID);
793 if (winID == kCommandsWindow) {
794 Common::Array<CommandButton>::iterator it = _controlData->begin();
795 for (; it != _controlData->end(); ++it) {
796 it->unselect();
797 }
798 }
799 Common::Array<DrawableObject> &children = data.children;
800 for (uint i = 0; i < children.size(); i++) {
801 uint flag = 0;
802 ObjID child = children[i].obj;
803 BlitMode mode = kBlitDirect;
804 bool off = !_engine->isObjVisible(child);
805 // CHECKME: Since flag = 0, this always evaluates to false
806 if (flag || !off || !_engine->isObjClickable(child)) {
807 mode = kBlitBIC;
808 if (off || flag) {
809 mode = kBlitXOR;
810 } else if (!off && _engine->isObjSelected(child)) {
811 mode = kBlitOR;
812 }
813 children[i] = DrawableObject(child, mode);
814 } else {
815 children[i] = DrawableObject(child, kBlitXOR);
816 }
817 }
818 if (winID == kMainGameWindow) {
819 drawMainGameWindow();
820 } else {
821 Graphics::MacWindow *winRef = findWindow(winID);
822 winRef->getSurface()->fillRect(data.bounds, kColorGray);
823 }
824 if (data.type == kZoomDoc && data.updateScroll) {
825 warning("Unimplemented: update scroll");
826 }
827 }
828 }
829
clearExits()830 void Gui::clearExits() {
831 _exitsData->clear();
832 }
833
unselectExits()834 void Gui::unselectExits() {
835 Common::Array<CommandButton>::const_iterator it = _exitsData->begin();
836 for (; it != _exitsData->end(); ++it) {
837 CommandButton button = *it;
838 button.unselect();
839 }
840 }
841
updateExit(ObjID obj)842 void Gui::updateExit(ObjID obj) {
843 if (!_engine->isObjExit(obj)) {
844 return;
845 }
846 BorderBounds border = borderBounds(getWindowData(kExitsWindow).type);
847
848 int ctl = -1;
849 int i = 0;
850 Common::Array<CommandButton>::const_iterator it = _exitsData->begin();
851 for (;it != _exitsData->end(); it++) {
852 if (it->getData().refcon == obj)
853 ctl = i;
854 else
855 i++;
856 }
857
858 if (ctl != -1)
859 _exitsData->remove_at(ctl);
860
861 if (!_engine->isHiddenExit(obj) &&
862 _engine->getParent(obj) == _engine->getParent(1)) {
863 ControlData data;
864 data.titleLength = 0;
865 data.refcon = (ControlAction)obj; // Objects can be exits (actions)
866 Common::Point pos = _engine->getObjExitPosition(obj);
867 pos.x += border.leftOffset;
868 pos.y += border.topOffset;
869 data.bounds = Common::Rect(pos.x, pos.y, pos.x + kExitButtonWidth, pos.y + kExitButtonHeight);
870 data.visible = true;
871
872 _exitsData->push_back(CommandButton(data, this));
873 }
874 }
875
printText(const Common::String & text)876 void Gui::printText(const Common::String &text) {
877 debugC(1, kMVDebugGUI, "Print Text: %s", text.c_str());
878 _consoleText->printLine(text, _outConsoleWindow->getDimensions().width());
879 }
880
showPrebuiltDialog(PrebuiltDialogs type)881 void Gui::showPrebuiltDialog(PrebuiltDialogs type) {
882 closeDialog();
883 _dialog = new Dialog(this, type);
884 }
885
isDialogOpen()886 bool Gui::isDialogOpen() {
887 return _dialog != NULL;
888 }
889
setTextInput(Common::String str)890 void Gui::setTextInput(Common::String str) {
891 _engine->setTextInput(str);
892 }
893
894
closeDialog()895 void Gui::closeDialog() {
896 delete _dialog;
897 _dialog = NULL;
898 }
899
getTextFromUser()900 void Gui::getTextFromUser() {
901 if (_dialog) {
902 delete _dialog;
903 }
904 showPrebuiltDialog(kSpeakDialog);
905 }
906
loadGame()907 void Gui::loadGame() {
908 _engine->scummVMSaveLoadDialog(false);
909 }
910
saveGame()911 void Gui::saveGame() {
912 _engine->scummVMSaveLoadDialog(true);
913 }
914
newGame()915 void Gui::newGame() {
916 _engine->newGame();
917 }
918
quitGame()919 void Gui::quitGame() {
920 _engine->requestQuit();
921 }
922
createInnerSurface(Graphics::ManagedSurface * innerSurface,Graphics::ManagedSurface * outerSurface,const BorderBounds & borders)923 void Gui::createInnerSurface(Graphics::ManagedSurface *innerSurface, Graphics::ManagedSurface *outerSurface, const BorderBounds &borders) {
924 innerSurface->create(
925 outerSurface->w - borders.leftOffset - borders.rightOffset,
926 outerSurface->h - borders.topOffset - borders.bottomOffset,
927 outerSurface->format);
928 }
929
moveDraggedObject(Common::Point target)930 void Gui::moveDraggedObject(Common::Point target) {
931 ensureAssetLoaded(_draggedObj.id);
932 _draggedObj.pos = target + _draggedObj.mouseOffset;
933
934 // TODO FInd more elegant way of making pow2
935 _draggedObj.hasMoved = (_draggedObj.startPos.sqrDist(_draggedObj.pos) >= (kDragThreshold * kDragThreshold));
936
937 debugC(4, kMVDebugGUI, "Dragged obj position: (%d, %d), mouse offset: (%d, %d), hasMoved: %d, dist: %d, threshold: %d",
938 _draggedObj.pos.x, _draggedObj.pos.y,
939 _draggedObj.mouseOffset.x, _draggedObj.mouseOffset.y,
940 _draggedObj.hasMoved,
941 _draggedObj.startPos.sqrDist(_draggedObj.pos),
942 kDragThreshold * kDragThreshold
943 );
944
945 }
946
findWindowAtPoint(Common::Point point)947 WindowReference Gui::findWindowAtPoint(Common::Point point) {
948 Common::List<WindowData>::iterator it;
949 Graphics::MacWindow *win;
950 for (it = _windowData->begin(); it != _windowData->end(); it++) {
951 win = findWindow(it->refcon);
952 if (win && it->refcon != kDiplomaWindow) { //HACK, diploma should be cosnidered
953 if (win->getDimensions().contains(point)) {
954 return it->refcon;
955 }
956 }
957 }
958 return kNoWindow;
959 }
960
getGlobalScrolledSurfacePosition(WindowReference reference)961 Common::Point Gui::getGlobalScrolledSurfacePosition(WindowReference reference) {
962 const WindowData &data = getWindowData(reference);
963 BorderBounds border = borderBounds(data.type);
964 Graphics::MacWindow *win = findWindow(reference);
965 if (!win) {
966 return Common::Point(0, 0);
967 }
968 return Common::Point(
969 win->getDimensions().left + border.leftOffset - data.scrollPos.x,
970 win->getDimensions().top + border.topOffset - data.scrollPos.y);
971 }
972
findWindowData(WindowReference reference)973 WindowData &Gui::findWindowData(WindowReference reference) {
974 assert(_windowData);
975
976 Common::List<WindowData>::iterator iter = _windowData->begin();
977 while (iter->refcon != reference && iter != _windowData->end()) {
978 iter++;
979 }
980
981 if (iter->refcon == reference)
982 return *iter;
983
984 error("GUI: Could not locate the desired window data");
985 }
986
findWindow(WindowReference reference)987 Graphics::MacWindow *Gui::findWindow(WindowReference reference) {
988 if (reference < 0x80 && reference >= kInventoryStart) { // It's an inventory window
989 return _inventoryWindows[reference - kInventoryStart];
990 }
991 switch (reference) {
992 case MacVenture::kNoWindow:
993 return NULL;
994 case MacVenture::kCommandsWindow:
995 return _controlsWindow;
996 case MacVenture::kMainGameWindow:
997 return _mainGameWindow;
998 case MacVenture::kOutConsoleWindow:
999 return _outConsoleWindow;
1000 case MacVenture::kSelfWindow:
1001 return _selfWindow;
1002 case MacVenture::kExitsWindow:
1003 return _exitsWindow;
1004 case MacVenture::kDiplomaWindow:
1005 return _diplomaWindow;
1006 default:
1007 return NULL;
1008 }
1009 return NULL;
1010 }
1011
ensureInventoryOpen(WindowReference reference,ObjID id)1012 void Gui::ensureInventoryOpen(WindowReference reference, ObjID id) {
1013 assert(reference < 0x80 && reference >= kInventoryStart);
1014 if (reference - kInventoryStart == (int)_inventoryWindows.size()) {
1015 createInventoryWindow(id);
1016 }
1017 }
1018
getObjWindow(ObjID objID)1019 WindowReference Gui::getObjWindow(ObjID objID) {
1020 switch (objID) {
1021 case 0xfffc: return kExitsWindow;
1022 case 0xfffd: return kSelfWindow;
1023 case 0xfffe: return kOutConsoleWindow;
1024 case 0xffff: return kCommandsWindow;
1025 default: return findObjWindow(objID);
1026 }
1027 }
1028
findObjWindow(ObjID objID)1029 WindowReference Gui::findObjWindow(ObjID objID) {
1030 // This is a bit of a HACK, we take advantage of the consecutive nature of references
1031 for (uint i = kCommandsWindow; i <= kDiplomaWindow; i++) {
1032 const WindowData &data = getWindowData((WindowReference)i);
1033 if (data.objRef == objID) {
1034 return data.refcon;
1035 }
1036 }
1037
1038 for (uint i = kInventoryStart; i < _inventoryWindows.size() + kInventoryStart; i++) {
1039 const WindowData &data = getWindowData((WindowReference)i);
1040 if (data.objRef == objID) {
1041 return data.refcon;
1042 }
1043 }
1044
1045 return kNoWindow;
1046 }
1047
checkSelect(const WindowData & data,Common::Point pos,const Common::Rect & clickRect,WindowReference ref)1048 void Gui::checkSelect(const WindowData &data, Common::Point pos, const Common::Rect &clickRect, WindowReference ref) {
1049 ObjID child = 0;
1050 for (Common::Array<DrawableObject>::const_iterator it = data.children.begin(); it != data.children.end(); it++) {
1051 if (canBeSelected((*it).obj, clickRect, ref)) {
1052 child = (*it).obj;
1053 }
1054 }
1055 if (child != 0) {
1056 selectDraggable(child, ref, pos);
1057 bringToFront(ref);
1058 }
1059 }
1060
canBeSelected(ObjID obj,const Common::Rect & clickRect,WindowReference ref)1061 bool Gui::canBeSelected(ObjID obj, const Common::Rect &clickRect, WindowReference ref) {
1062 return (_engine->isObjClickable(obj) &&
1063 isRectInsideObject(clickRect, obj));
1064 }
1065
isRectInsideObject(Common::Rect target,ObjID obj)1066 bool Gui::isRectInsideObject(Common::Rect target, ObjID obj) {
1067 ensureAssetLoaded(obj);
1068 Common::Rect bounds = _engine->getObjBounds(obj);
1069 Common::Rect intersection = bounds.findIntersectingRect(target);
1070 // We translate it to the image's coord system
1071 intersection = Common::Rect(
1072 intersection.left - bounds.left,
1073 intersection.top - bounds.top,
1074 intersection.left - bounds.left + intersection.width(),
1075 intersection.top - bounds.top + intersection.height());
1076
1077 return _assets[obj]->isRectInside(intersection);
1078 }
1079
selectDraggable(ObjID child,WindowReference origin,Common::Point click)1080 void Gui::selectDraggable(ObjID child, WindowReference origin, Common::Point click) {
1081 if (_engine->isObjClickable(child) && _draggedObj.id == 0) {
1082 _draggedObj.hasMoved = false;
1083 _draggedObj.id = child;
1084 _draggedObj.startWin = origin;
1085 Common::Point localizedClick = click - getGlobalScrolledSurfacePosition(origin);
1086 _draggedObj.mouseOffset = _engine->getObjPosition(child) - localizedClick;
1087 _draggedObj.pos = click + _draggedObj.mouseOffset;
1088 _draggedObj.startPos = _draggedObj.pos;
1089 }
1090 }
1091
handleDragRelease(bool shiftPressed,bool isDoubleClick)1092 void Gui::handleDragRelease(bool shiftPressed, bool isDoubleClick) {
1093 if (_draggedObj.id != 0) {
1094 WindowReference destinationWindow = findWindowAtPoint(_draggedObj.pos);
1095 if (destinationWindow == kNoWindow) {
1096 return;
1097 }
1098 if (_draggedObj.hasMoved) {
1099 const WindowData &destinationWindowData = getWindowData(destinationWindow);
1100 ObjID destObject = destinationWindowData.objRef;
1101 Common::Point dropPosition = _draggedObj.pos - _draggedObj.startPos;
1102 dropPosition = localizeTravelledDistance(dropPosition, _draggedObj.startWin, destinationWindow);
1103 debugC(3, kMVDebugGUI, "Drop the object %d at obj %d, pos (%d, %d)", _draggedObj.id, destObject, dropPosition.x, dropPosition.y);
1104
1105 _engine->handleObjectDrop(_draggedObj.id, dropPosition, destObject);
1106 }
1107 _engine->handleObjectSelect(_draggedObj.id, destinationWindow, shiftPressed, isDoubleClick);
1108 _draggedObj.id = 0;
1109 _draggedObj.hasMoved = false;
1110 }
1111 }
1112
calculateClickRect(Common::Point clickPos,Common::Rect windowBounds)1113 Common::Rect Gui::calculateClickRect(Common::Point clickPos, Common::Rect windowBounds) {
1114 int left = clickPos.x - windowBounds.left;
1115 int top = clickPos.y - windowBounds.top;
1116 return Common::Rect(left - kCursorWidth, top - kCursorHeight, left + kCursorWidth, top + kCursorHeight);
1117 }
1118
localizeTravelledDistance(Common::Point point,WindowReference origin,WindowReference target)1119 Common::Point Gui::localizeTravelledDistance(Common::Point point, WindowReference origin, WindowReference target) {
1120 if (origin != target) {
1121 // ori.local to global
1122 point += getGlobalScrolledSurfacePosition(origin);
1123 if (findWindow(target)) {
1124 // dest.globalToLocal
1125 point -= getGlobalScrolledSurfacePosition(target);
1126 }
1127 }
1128 return point;
1129 }
1130
removeInventoryWindow(WindowReference ref)1131 void Gui::removeInventoryWindow(WindowReference ref) {
1132 _inventoryWindows.remove_at(ref - kInventoryStart);
1133 Common::List<WindowData>::iterator it;
1134 for (it = _windowData->begin(); it != _windowData->end(); it++) {
1135 if (it->refcon == ref) {
1136 _windowData->erase(it);
1137 break;
1138 }
1139 }
1140 }
1141
1142
1143 /* HANDLERS */
handleMenuAction(MenuAction action)1144 void Gui::handleMenuAction(MenuAction action) {
1145 switch (action) {
1146 case MacVenture::kMenuActionAbout:
1147 warning("Unimplemented MacVenture Menu Action: About");
1148 break;
1149 case MacVenture::kMenuActionNew:
1150 _engine->newGame();
1151 break;
1152 case MacVenture::kMenuActionOpen:
1153 loadGame();
1154 break;
1155 case MacVenture::kMenuActionSave:
1156 saveGame();
1157 break;
1158 case MacVenture::kMenuActionSaveAs:
1159 saveGame();
1160 break;
1161 case MacVenture::kMenuActionQuit:
1162 _engine->requestQuit();
1163 break;
1164 case MacVenture::kMenuActionUndo:
1165 warning("Unimplemented MacVenture Menu Action: Undo");
1166 break;
1167 case MacVenture::kMenuActionCut:
1168 warning("Unimplemented MacVenture Menu Action: Cut");
1169 break;
1170 case MacVenture::kMenuActionCopy:
1171 warning("Unimplemented MacVenture Menu Action: Copy");
1172 break;
1173 case MacVenture::kMenuActionPaste:
1174 warning("Unimplemented MacVenture Menu Action: Paste");
1175 break;
1176 case MacVenture::kMenuActionClear:
1177 warning("Unimplemented MacVenture Menu Action: Clear");
1178 break;
1179 case MacVenture::kMenuActionCleanUp:
1180 warning("Unimplemented MacVenture Menu Action: Clean Up");
1181 break;
1182 case MacVenture::kMenuActionMessUp:
1183 warning("Unimplemented MacVenture Menu Action: Mess Up");
1184 break;
1185 case MacVenture::kMenuActionCommand:
1186 warning("Unimplemented MacVenture Menu Action: GENERIC");
1187 break;
1188 default:
1189 break;
1190 }
1191 }
1192
1193 /* CALLBACKS */
1194
commandsWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1195 bool commandsWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1196 Gui *g = (Gui*)gui;
1197 return g->processCommandEvents(click, event);
1198 }
1199
mainGameWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1200 bool mainGameWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1201 Gui *g = (Gui*)gui;
1202 return g->processMainGameEvents(click, event);
1203 }
1204
outConsoleWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1205 bool outConsoleWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1206 Gui *g = (Gui*)gui;
1207 return g->processOutConsoleEvents(click, event);
1208 }
1209
selfWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1210 bool selfWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1211 Gui *g = (Gui*)gui;
1212
1213 return g->processSelfEvents(click, event);
1214 }
1215
exitsWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1216 bool exitsWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1217 Gui *g = (Gui*)gui;
1218
1219 return g->processExitsEvents(click, event);
1220 }
1221
diplomaWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1222 bool diplomaWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1223 Gui *g = (Gui*)gui;
1224
1225 return g->processDiplomaEvents(click, event);
1226 }
1227
inventoryWindowCallback(Graphics::WindowClick click,Common::Event & event,void * gui)1228 bool inventoryWindowCallback(Graphics::WindowClick click, Common::Event &event, void *gui) {
1229 Gui *g = (Gui*)gui;
1230
1231 return g->processInventoryEvents(click, event);
1232 }
1233
menuCommandsCallback(int action,Common::String & text,void * data)1234 void menuCommandsCallback(int action, Common::String &text, void *data) {
1235 Gui *g = (Gui *)data;
1236
1237 g->handleMenuAction((MenuAction)action);
1238 }
1239
1240
invertWindowColors(WindowReference winID)1241 void Gui::invertWindowColors(WindowReference winID) {
1242 Graphics::ManagedSurface *srf = findWindow(winID)->getSurface();
1243 for (uint y = 0; y < srf->h; y++) {
1244 for (uint x = 0; x < srf->w; x++) {
1245 byte p = *(byte *)srf->getBasePtr(x, y);
1246 *(byte *)srf->getBasePtr(x, y) =
1247 (p == kColorWhite) ? kColorBlack : kColorGray;
1248 }
1249 }
1250 }
1251
tryCloseWindow(WindowReference winID)1252 bool Gui::tryCloseWindow(WindowReference winID) {
1253 //WindowData data = findWindowData(winID);
1254 Graphics::MacWindow *win = findWindow(winID);
1255 _wm.removeWindow(win);
1256 if (winID < 0x80) {
1257 removeInventoryWindow(winID);
1258 }
1259 return true;
1260 }
1261
getObjMeasures(ObjID obj)1262 Common::Point Gui::getObjMeasures(ObjID obj) {
1263 ensureAssetLoaded(obj);
1264 int w = _assets[obj]->getWidth();
1265 int h = _assets[obj]->getHeight();
1266 return Common::Point(w, h);
1267 }
1268
processEvent(Common::Event & event)1269 bool Gui::processEvent(Common::Event &event) {
1270 bool processed = false;
1271
1272 processed |= _cursor->processEvent(event);
1273
1274 if (_dialog && _dialog->processEvent(event)) {
1275 return true;
1276 }
1277
1278 if (event.type == Common::EVENT_MOUSEMOVE) {
1279 if (_draggedObj.id != 0) {
1280 moveDraggedObject(event.mouse);
1281 }
1282 processed = true;
1283 }
1284
1285 processed |= _wm.processEvent(event);
1286 return (processed);
1287 }
1288
processCommandEvents(WindowClick click,Common::Event & event)1289 bool Gui::processCommandEvents(WindowClick click, Common::Event &event) {
1290 if (event.type == Common::EVENT_LBUTTONUP) {
1291 if (_engine->needsClickToContinue()) {
1292 _engine->selectControl(kClickToContinue);
1293 return true;
1294 }
1295
1296 Common::Point position(
1297 event.mouse.x - _controlsWindow->getDimensions().left,
1298 event.mouse.y - _controlsWindow->getDimensions().top);
1299
1300 CommandButton data;
1301 if (!_controlData)
1302 return false;
1303
1304 Common::Array<CommandButton>::iterator it = _controlData->begin();
1305 for (; it != _controlData->end(); ++it) {
1306 if (it->isInsideBounds(position)) {
1307 it->select();
1308 data = *it;
1309 } else {
1310 it->unselect();
1311 }
1312 }
1313
1314 _engine->selectControl(data.getData().refcon);
1315 _engine->refreshReady();
1316 _engine->preparedToRun();
1317 }
1318 return false;
1319 }
1320
processMainGameEvents(WindowClick click,Common::Event & event)1321 bool MacVenture::Gui::processMainGameEvents(WindowClick click, Common::Event &event) {
1322 if (_engine->needsClickToContinue())
1323 return true;
1324
1325 return false;
1326 }
1327
processOutConsoleEvents(WindowClick click,Common::Event & event)1328 bool MacVenture::Gui::processOutConsoleEvents(WindowClick click, Common::Event &event) {
1329 if (_engine->needsClickToContinue())
1330 return true;
1331
1332 if (click == kBorderScrollUp && event.type == Common::EVENT_LBUTTONDOWN) {
1333 _consoleText->scrollUp();
1334 return true;
1335 }
1336 if (click == kBorderScrollDown && event.type == Common::EVENT_LBUTTONDOWN) {
1337 _consoleText->scrollDown();
1338 return true;
1339 }
1340
1341 return getWindowData(kOutConsoleWindow).visible;
1342 }
1343
processSelfEvents(WindowClick click,Common::Event & event)1344 bool MacVenture::Gui::processSelfEvents(WindowClick click, Common::Event &event) {
1345 if (_engine->needsClickToContinue())
1346 return true;
1347
1348 if (event.type == Common::EVENT_LBUTTONUP) {
1349 _engine->handleObjectSelect(1, kSelfWindow, false, false);
1350 }
1351 return true;
1352 }
1353
processExitsEvents(WindowClick click,Common::Event & event)1354 bool MacVenture::Gui::processExitsEvents(WindowClick click, Common::Event &event) {
1355 if (event.type == Common::EVENT_LBUTTONUP) {
1356 if (_engine->needsClickToContinue()) {
1357 return true;
1358 }
1359
1360 Common::Point position(
1361 event.mouse.x - _exitsWindow->getDimensions().left,
1362 event.mouse.y - _exitsWindow->getDimensions().top);
1363
1364 CommandButton button;
1365 if (!_exitsData)
1366 return false;
1367
1368 Common::Array<CommandButton>::iterator it = _exitsData->begin();
1369 for (; it != _exitsData->end(); ++it) {
1370 if (it->isInsideBounds(position)) {
1371 it->select();
1372 button = *it;
1373 _engine->handleObjectSelect(button.getData().refcon, kExitsWindow, false, false);
1374 return true;
1375 } else {
1376 it->unselect();
1377 }
1378 }
1379
1380 }
1381 return getWindowData(kExitsWindow).visible;
1382 }
1383
processDiplomaEvents(WindowClick click,Common::Event & event)1384 bool MacVenture::Gui::processDiplomaEvents(WindowClick click, Common::Event &event) {
1385 if (_engine->needsClickToContinue())
1386 return true;
1387
1388 return getWindowData(kDiplomaWindow).visible;
1389 }
1390
processInventoryEvents(WindowClick click,Common::Event & event)1391 bool Gui::processInventoryEvents(WindowClick click, Common::Event &event) {
1392 if (event.type == Common::EVENT_LBUTTONDOWN && click == kBorderCloseButton) {
1393 WindowReference ref = findWindowAtPoint(event.mouse);
1394 if (ref == kNoWindow) {
1395 return false;
1396 }
1397
1398 if (click == kBorderCloseButton) {
1399 removeInventoryWindow(ref);
1400 return true;
1401 }
1402 }
1403
1404 if (_engine->needsClickToContinue())
1405 return true;
1406
1407 if (event.type == Common::EVENT_LBUTTONDOWN) {
1408 // Find the appropriate window
1409 WindowReference ref = findWindowAtPoint(event.mouse);
1410 if (ref == kNoWindow) {
1411 return false;
1412 }
1413
1414 WindowData &data = findWindowData((WindowReference) ref);
1415
1416 if (click == kBorderScrollUp) {
1417 data.scrollPos.y = MAX(0, data.scrollPos.y - kScrollAmount);
1418 }
1419 if (click == kBorderScrollDown) {
1420 data.scrollPos.y += kScrollAmount;
1421 }
1422 if (click == kBorderScrollLeft) {
1423 data.scrollPos.x = MAX(0, data.scrollPos.x - kScrollAmount);
1424 }
1425 if (click == kBorderScrollRight) {
1426 data.scrollPos.x += kScrollAmount;
1427 }
1428 }
1429 return true;
1430 }
1431
selectForDrag(Common::Point cursorPosition)1432 void Gui::selectForDrag(Common::Point cursorPosition) {
1433 WindowReference ref = findWindowAtPoint(cursorPosition);
1434 if (ref == kNoWindow) {
1435 return;
1436 }
1437
1438 Graphics::MacWindow *win = findWindow(ref);
1439 WindowData &data = findWindowData((WindowReference) ref);
1440
1441 Common::Rect clickRect = calculateClickRect(cursorPosition + data.scrollPos, win->getDimensions());
1442 checkSelect(data, cursorPosition, clickRect, (WindowReference)ref);
1443 }
1444
handleSingleClick()1445 void Gui::handleSingleClick() {
1446 debugC(2, kMVDebugGUI, "Registered Single Click");
1447 // HACK THERE HAS TO BE A MORE ELEGANT WAY
1448 if (_dialog) {
1449 return;
1450 }
1451 handleDragRelease(false, false);
1452 }
1453
handleDoubleClick()1454 void Gui::handleDoubleClick() {
1455 debugC(2, kMVDebugGUI, "Registered Double Click");
1456 if (_dialog) {
1457 return;
1458 }
1459 handleDragRelease(false, true);
1460 }
1461
ensureAssetLoaded(ObjID obj)1462 void Gui::ensureAssetLoaded(ObjID obj) {
1463 if (!_assets.contains(obj)) {
1464 _assets[obj] = new ImageAsset(obj, _graphics);
1465 }
1466 }
1467
1468
1469 } // End of namespace MacVenture
1470