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