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 #include "illusions/menusystem.h"
24 #include "illusions/illusions.h"
25 #include "illusions/dictionary.h"
26 #include "illusions/input.h"
27 #include "illusions/screen.h"
28 #include "illusions/screentext.h"
29 #include "illusions/thread.h"
30 #include "illusions/time.h"
31 #include "common/config-manager.h"
32 #include "common/translation.h"
33 #include "gui/saveload.h"
34 
35 namespace Illusions {
36 
37 // MenuItem
38 
MenuItem(const Common::String text,BaseMenuAction * action)39 MenuItem::MenuItem(const Common::String text, BaseMenuAction *action)
40 	: _text(text), _action(action) {
41 }
42 
~MenuItem()43 MenuItem::~MenuItem() {
44 	delete _action;
45 }
46 
executeAction(const Common::Point & point)47 void MenuItem::executeAction(const Common::Point &point) {
48 	_mouseClickPoint = point;
49 	_action->execute();
50 }
51 
52 // BaseMenu
53 
BaseMenu(BaseMenuSystem * menuSystem,uint32 fontId,byte backgroundColor,byte borderColor,byte textColor,byte fieldE,uint defaultMenuItemIndex)54 BaseMenu::BaseMenu(BaseMenuSystem *menuSystem, uint32 fontId, byte backgroundColor, byte borderColor, byte textColor, byte fieldE,
55 	uint defaultMenuItemIndex)
56 	: _menuSystem(menuSystem), _fontId(fontId), _backgroundColor(backgroundColor), _borderColor(borderColor), _textColor(textColor), _fieldE(fieldE),
57 	_defaultMenuItemIndex(defaultMenuItemIndex)
58 {
59 }
60 
~BaseMenu()61 BaseMenu::~BaseMenu() {
62 	for (MenuItems::iterator it = _menuItems.begin(); it != _menuItems.end(); ++it) {
63 		delete *it;
64 	}
65 }
66 
addText(const Common::String text)67 void BaseMenu::addText(const Common::String text) {
68 	_text.push_back(text);
69 }
70 
addMenuItem(MenuItem * menuItem)71 void BaseMenu::addMenuItem(MenuItem *menuItem) {
72 	_menuItems.push_back(menuItem);
73 }
74 
getHeaderLinesCount()75 uint BaseMenu::getHeaderLinesCount() {
76 	return _text.size();
77 }
78 
getHeaderLine(uint index)79 const Common::String& BaseMenu::getHeaderLine(uint index) {
80 	return _text[index];
81 }
82 
getMenuItemsCount()83 uint BaseMenu::getMenuItemsCount() {
84 	return _menuItems.size();
85 }
86 
getMenuItem(uint index)87 MenuItem *BaseMenu::getMenuItem(uint index) {
88 	return _menuItems[index];
89 }
90 
enterMenu()91 void BaseMenu::enterMenu() {
92 	// Empty, implemented if neccessary by the inherited class when the menu is entered
93 }
94 
95 // BaseMenuSystem
96 
BaseMenuSystem(IllusionsEngine * vm)97 BaseMenuSystem::BaseMenuSystem(IllusionsEngine *vm)
98 	: _vm(vm), _isTimeOutEnabled(false), _menuChoiceOffset(0) {
99 }
100 
~BaseMenuSystem()101 BaseMenuSystem::~BaseMenuSystem() {
102 }
103 
playSoundEffect13()104 void BaseMenuSystem::playSoundEffect13() {
105 	playSoundEffect(13);
106 }
107 
playSoundEffect14()108 void BaseMenuSystem::playSoundEffect14() {
109 	playSoundEffect(14);
110 }
111 
selectMenuChoiceIndex(uint choiceIndex)112 void BaseMenuSystem::selectMenuChoiceIndex(uint choiceIndex) {
113 	debug(0, "choiceIndex: %d", choiceIndex);
114 	debug(0, "_menuChoiceOffset: %p", (void*)_menuChoiceOffset);
115 	if (choiceIndex > 0 && _menuChoiceOffset) {
116 		*_menuChoiceOffset = _menuChoiceOffsets[choiceIndex - 1];
117 		debug(0, "*_menuChoiceOffset: %04X", *_menuChoiceOffset);
118 	}
119 	_vm->_threads->notifyId(_menuCallerThreadId);
120 	_menuCallerThreadId = 0;
121 	closeMenu();
122 }
123 
leaveMenu()124 void BaseMenuSystem::leaveMenu() {
125 	playSoundEffect13();
126 	if (!_menuStack.empty())
127 		leaveSubMenu();
128 	else
129 		closeMenu();
130 }
131 
enterSubMenu(BaseMenu * menu)132 void BaseMenuSystem::enterSubMenu(BaseMenu *menu) {
133 	_menuStack.push(_activeMenu);
134 	activateMenu(menu);
135 	_hoveredMenuItemIndex = _hoveredMenuItemIndex3;
136 	_hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
137 	setMouseCursorToMenuItem(_hoveredMenuItemIndex);
138 	placeActorHoverBackground();
139 	placeActorTextColorRect();
140 }
141 
leaveSubMenu()142 void BaseMenuSystem::leaveSubMenu() {
143 	_activeMenu = _menuStack.pop();
144 	_field54 = _activeMenu->_field2C18;
145 	_menuLinesCount = _activeMenu->getHeaderLinesCount();
146 	_hoveredMenuItemIndex = 1;
147 	_vm->_screenText->removeText();
148 	_vm->_screenText->removeText();
149 	activateMenu(_activeMenu);
150 	_hoveredMenuItemIndex = _hoveredMenuItemIndex3;
151 	_hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
152 	setMouseCursorToMenuItem(_hoveredMenuItemIndex);
153 	initActorHoverBackground();
154 	placeActorTextColorRect();
155 }
156 
enterSubMenuById(int menuId)157 void BaseMenuSystem::enterSubMenuById(int menuId) {
158 	BaseMenu *menu = getMenuById(menuId);
159 	enterSubMenu(menu);
160 }
161 
getQueryConfirmationChoiceIndex() const162 uint BaseMenuSystem::getQueryConfirmationChoiceIndex() const {
163 	return _queryConfirmationChoiceIndex;
164 }
165 
setQueryConfirmationChoiceIndex(uint queryConfirmationChoiceIndex)166 void BaseMenuSystem::setQueryConfirmationChoiceIndex(uint queryConfirmationChoiceIndex) {
167 	_queryConfirmationChoiceIndex = queryConfirmationChoiceIndex;
168 }
169 
setMouseCursorToMenuItem(int menuItemIndex)170 void BaseMenuSystem::setMouseCursorToMenuItem(int menuItemIndex) {
171 	Common::Point mousePos;
172 	if (calcMenuItemMousePos(menuItemIndex, mousePos))
173 		setMousePos(mousePos);
174 }
175 
calcMenuItemRect(uint menuItemIndex,WRect & rect)176 void BaseMenuSystem::calcMenuItemRect(uint menuItemIndex, WRect &rect) {
177 	FontResource *font = _vm->_dict->findFont(_activeMenu->_fontId);
178 	int charHeight = font->getCharHeight() + font->getLineIncr();
179 
180 	_vm->_screenText->getTextInfoPosition(rect._topLeft);
181 	if (_activeMenu->_backgroundColor) {
182 		rect._topLeft.y += 4;
183 		rect._topLeft.x += 4;
184 	}
185 	rect._topLeft.y += charHeight * (menuItemIndex + _menuLinesCount - 1);
186 
187 	WidthHeight textInfoDimensions;
188 	_vm->_screenText->getTextInfoDimensions(textInfoDimensions);
189 	rect._bottomRight.x = rect._topLeft.x + textInfoDimensions._width;
190 	rect._bottomRight.y = rect._topLeft.y + charHeight;
191 }
192 
calcMenuItemMousePos(uint menuItemIndex,Common::Point & pt)193 bool BaseMenuSystem::calcMenuItemMousePos(uint menuItemIndex, Common::Point &pt) {
194 	if (menuItemIndex < _hoveredMenuItemIndex3 || menuItemIndex >= _hoveredMenuItemIndex3 + _menuItemCount)
195 		return false;
196 
197 	WRect rect;
198 	calcMenuItemRect(menuItemIndex - _hoveredMenuItemIndex3 + 1, rect);
199 	pt.x = rect._topLeft.x;
200 	pt.y = rect._topLeft.y + (rect._bottomRight.y - rect._topLeft.y) / 2;
201 	return true;
202 }
203 
calcMenuItemIndexAtPoint(Common::Point pt,uint & menuItemIndex)204 bool BaseMenuSystem::calcMenuItemIndexAtPoint(Common::Point pt, uint &menuItemIndex) {
205 	WRect rect;
206 	calcMenuItemRect(1, rect);
207 
208 	uint index = _hoveredMenuItemIndex3 + (pt.y - rect._topLeft.y) / (rect._bottomRight.y - rect._topLeft.y);
209 
210 	if (pt.y < rect._topLeft.y || pt.x < rect._topLeft.x || pt.x > rect._bottomRight.x ||
211 		index > _field54 || index > _hoveredMenuItemIndex3 + _menuItemCount - 1)
212 		return false;
213 
214 	menuItemIndex = index;
215 	return true;
216 }
217 
setMousePos(Common::Point & mousePos)218 void BaseMenuSystem::setMousePos(Common::Point &mousePos) {
219 	_vm->_input->setCursorPosition(mousePos);
220 	Control *mouseCursor = _vm->getObjectControl(Illusions::CURSOR_OBJECT_ID);
221 	mouseCursor->_actor->_position = mousePos;
222 }
223 
activateMenu(BaseMenu * menu)224 void BaseMenuSystem::activateMenu(BaseMenu *menu) {
225 	_activeMenu = menu;
226 	// TODO Run menu enter callback if neccessary
227 	_menuLinesCount = menu->getHeaderLinesCount();
228 	menu->_field2C18 = menu->getMenuItemsCount();
229 	_hoveredMenuItemIndex3 = 1;
230 	_field54 = menu->_field2C18;
231 
232 	uint v2 = drawMenuText(menu);
233 	if (menu->_field2C18 <= v2)
234 		_menuItemCount = menu->_field2C18;
235 	else
236 		_menuItemCount = v2;
237 
238 }
239 
initActorHoverBackground()240 void BaseMenuSystem::initActorHoverBackground() {
241 	Control *v0 = _vm->getObjectControl(0x4013E);
242 	if (!v0) {
243 		WidthHeight dimensions;
244 		dimensions._width = 300;
245 		dimensions._height = 15;
246 		if (_vm->getGameId() == kGameIdBBDOU) {
247 			_vm->_controls->placeSequenceLessActor(0x4013E, Common::Point(0, 0), dimensions, 91);
248 		} else {
249 			_vm->_controls->placeSequenceLessActor(0x4013E, Common::Point(0, 0), dimensions, 18);
250 		}
251 		v0 = _vm->getObjectControl(0x4013E);
252 		v0->_flags |= 8;
253 	}
254 	placeActorHoverBackground();
255 	v0->appearActor();
256 }
257 
placeActorHoverBackground()258 void BaseMenuSystem::placeActorHoverBackground() {
259 	Control *v0 = _vm->getObjectControl(0x4013E);
260 	v0->fillActor(0);
261 
262 	WidthHeight textInfoDimensions;
263 	_vm->_screenText->getTextInfoDimensions(textInfoDimensions);
264 
265 	if (_activeMenu->_backgroundColor && _activeMenu->_borderColor != _activeMenu->_backgroundColor)
266 		textInfoDimensions._width -= 6;
267 
268 	WidthHeight frameDimensions;
269 	v0->getActorFrameDimensions(frameDimensions);
270 
271 	FontResource *font = _vm->_dict->findFont(_activeMenu->_fontId);
272 	int charHeight = font->getCharHeight() + font->getLineIncr();
273 	if (frameDimensions._height < charHeight)
274 		charHeight = frameDimensions._height;
275 
276 	v0->drawActorRect(Common::Rect(textInfoDimensions._width - 1, charHeight), _activeMenu->_fieldE);
277 
278 	updateActorHoverBackground();
279 }
280 
updateActorHoverBackground()281 void BaseMenuSystem::updateActorHoverBackground() {
282 	Control *v0 = _vm->getObjectControl(0x4013E);
283 	WRect rect;
284 	calcMenuItemRect(_hoveredMenuItemIndex2 - _hoveredMenuItemIndex3 + 1, rect);
285   	v0->setActorPosition(rect._topLeft);
286 }
287 
hideActorHoverBackground()288 void BaseMenuSystem::hideActorHoverBackground() {
289 	Control *v0 = _vm->getObjectControl(0x4013E);
290 	if (v0)
291 		v0->disappearActor();
292 }
293 
initActorTextColorRect()294 void BaseMenuSystem::initActorTextColorRect() {
295 	Control *v0 = _vm->getObjectControl(0x40143);
296 	if (!v0) {
297 		WidthHeight dimensions;
298 		if (_vm->getGameId() == kGameIdBBDOU) {
299 			dimensions._width = 420;
300 			dimensions._height = 180;
301 			_vm->_controls->placeSequenceLessActor(0x40143, Common::Point(0, 0), dimensions, 90);
302 		} else {
303 			dimensions._width = 300;
304 			dimensions._height = 180;
305 			_vm->_controls->placeSequenceLessActor(0x40143, Common::Point(0, 0), dimensions, 17);
306 		}
307 		v0 = _vm->getObjectControl(0x40143);
308 		v0->_flags |= 8;
309 	}
310 	placeActorTextColorRect();
311 	v0->appearActor();
312 }
313 
placeActorTextColorRect()314 void BaseMenuSystem::placeActorTextColorRect() {
315 	Control *v0 = _vm->getObjectControl(0x40143);
316 	v0->fillActor(0);
317 
318 	Common::Point textInfoPosition;
319 	WidthHeight textInfoDimensions;
320 	_vm->_screenText->getTextInfoPosition(textInfoPosition);
321 	_vm->_screenText->getTextInfoDimensions(textInfoDimensions);
322 
323 	if (_activeMenu->_backgroundColor && _activeMenu->_borderColor != _activeMenu->_backgroundColor) {
324 		textInfoDimensions._width -= 2;
325 		textInfoDimensions._height -= 6;
326 	}
327 
328 	v0->setActorPosition(textInfoPosition);
329 	v0->drawActorRect(Common::Rect(textInfoDimensions._width - 1, textInfoDimensions._height - 1), _activeMenu->_textColor);
330 }
331 
hideActorTextColorRect()332 void BaseMenuSystem::hideActorTextColorRect() {
333 	Control *v0 = _vm->getObjectControl(0x40143);
334 	if (v0)
335 		v0->disappearActor();
336 }
337 
openMenu(BaseMenu * menu)338 void BaseMenuSystem::openMenu(BaseMenu *menu) {
339 
340 	_isActive = true;
341 	_menuStack.clear();
342 
343 	_cursorInitialVisibleFlag = initMenuCursor();
344 	_savedCursorPos = _vm->_input->getCursorPosition();
345 	_savedGameState = getGameState();
346 	Control *cursorControl = _vm->getObjectControl(Illusions::CURSOR_OBJECT_ID);
347 	_savedCursorActorIndex = cursorControl->_actor->_actorIndex;
348 	_savedCursorSequenceId = cursorControl->_actor->_sequenceId;
349 
350 	setMenuCursorNum(1);
351 
352 	if (_vm->getGameId() == kGameIdDuckman) {
353 		setGameState(4);
354 	} else if (_vm->getGameId() == kGameIdBBDOU) {
355 		setGameState(3);
356 	}
357 
358 	activateMenu(menu);
359 
360 	_hoveredMenuItemIndex = _hoveredMenuItemIndex3;
361 	_hoveredMenuItemIndex2 = _hoveredMenuItemIndex3;
362 	setMouseCursorToMenuItem(_hoveredMenuItemIndex);
363 	initActorHoverBackground();
364 	initActorTextColorRect();
365 	_vm->_input->discardAllEvents();
366 }
367 
closeMenu()368 void BaseMenuSystem::closeMenu() {
369 	while (!_menuStack.empty()) {
370 		_vm->_screenText->removeText();
371 		_menuStack.pop();
372 	}
373 	_vm->_screenText->removeText();
374 	hideActorHoverBackground();
375 	hideActorTextColorRect();
376 	Control *mouseCursor = _vm->getObjectControl(Illusions::CURSOR_OBJECT_ID);
377 	setGameState(_savedGameState);
378 	mouseCursor->_actor->_actorIndex = _savedCursorActorIndex;
379 	mouseCursor->_actor->_position = _savedCursorPos;
380 	setMousePos(_savedCursorPos);
381 	mouseCursor->startSequenceActor(_savedCursorSequenceId, 2, 0);
382 	if (_cursorInitialVisibleFlag)
383 		mouseCursor->disappearActor();
384 	_vm->_input->discardAllEvents();
385 	_isActive = false;
386 }
387 
handleClick(uint menuItemIndex,const Common::Point & mousePos)388 void BaseMenuSystem::handleClick(uint menuItemIndex, const Common::Point &mousePos) {
389 	debug(0, "BaseMenuSystem::handleClick() menuItemIndex: %d click point: (%d, %d)", menuItemIndex, mousePos.x, mousePos.y);
390 
391 	if (menuItemIndex == 0) {
392 		playSoundEffect14();
393 		return;
394 	}
395 
396 	MenuItem *menuItem = _activeMenu->getMenuItem(menuItemIndex - 1);
397 	menuItem->executeAction(mousePos);
398 
399 }
400 
drawMenuText(BaseMenu * menu)401 uint BaseMenuSystem::drawMenuText(BaseMenu *menu) {
402 	MenuTextBuilder *menuTextBuilder = new MenuTextBuilder();
403 	uint lineCount = 0;
404 
405 	for (uint i = 0; i < menu->getHeaderLinesCount(); ++i) {
406 		menuTextBuilder->appendString(menu->getHeaderLine(i));
407 		menuTextBuilder->appendNewLine();
408 	}
409 
410 	for (uint i = _hoveredMenuItemIndex3; i <= _field54; ++i) {
411 		menuTextBuilder->appendString(menu->getMenuItem(i - 1)->getText());
412 		if (i + 1 <= menu->getMenuItemsCount())
413 			menuTextBuilder->appendNewLine();
414 		++lineCount;
415 	}
416 
417 	menuTextBuilder->finalize();
418 
419 	uint16 *text = menuTextBuilder->getText();
420 
421 	Common::Point textPt;
422 	int16 v9 = 0;
423 	if (menu->_backgroundColor)
424 		v9 = 4;
425 	textPt.x = v9;
426 	textPt.y = v9;
427 
428 	uint flags = TEXT_FLAG_LEFT_ALIGN;
429 	if (menu->_backgroundColor != menu->_borderColor)
430 		flags |= TEXT_FLAG_BORDER_DECORATION;
431 
432 	WidthHeight dimensions;
433 
434 	if (_vm->getGameId() == kGameIdDuckman) {
435 		dimensions._width = 300;
436 		dimensions._height = 180;
437 	} else if (_vm->getGameId() == kGameIdBBDOU) {
438 		dimensions._width = 580;
439 		dimensions._height = 420;
440 	}
441 
442 	uint16 *outTextPtr;
443 	if (!_vm->_screenText->insertText(text, menu->_fontId, dimensions, textPt, flags, menu->_backgroundColor, menu->_borderColor, 0xFF, 0xFF, 0xFF, outTextPtr)) {
444 		--lineCount;
445 		for ( ; *outTextPtr; ++outTextPtr) {
446 			if (*outTextPtr == 13)
447 				--lineCount;
448 		}
449 	}
450 
451 	delete menuTextBuilder;
452 
453 	return lineCount;
454 }
455 
update(Control * cursorControl)456 void BaseMenuSystem::update(Control *cursorControl) {
457 	Common::Point mousePos = _vm->_input->getCursorPosition();
458 	setMousePos(mousePos);
459 
460 	uint newHoveredMenuItemIndex;
461 	bool resetTimeOut = false;
462 
463 	if (calcMenuItemIndexAtPoint(mousePos, newHoveredMenuItemIndex)) {
464 		if (newHoveredMenuItemIndex != _hoveredMenuItemIndex) {
465 			if (_hoveredMenuItemIndex == 0)
466 				initActorHoverBackground();
467 			_hoveredMenuItemIndex = newHoveredMenuItemIndex;
468 			_hoveredMenuItemIndex2 = newHoveredMenuItemIndex;
469 			setMenuCursorNum(2);
470 			updateActorHoverBackground();
471 			resetTimeOut = true;
472 		}
473 	} else if (_hoveredMenuItemIndex != 0) {
474 		setMenuCursorNum(1);
475 		hideActorHoverBackground();
476 		_hoveredMenuItemIndex = 0;
477 		resetTimeOut = true;
478 	}
479 
480 	if (_vm->_input->hasNewEvents())
481 		resetTimeOut = true;
482 
483 	if (_vm->_input->pollEvent(kEventLeftClick)) {
484 		handleClick(_hoveredMenuItemIndex, mousePos);
485 	} else if (_vm->_input->pollEvent(kEventAbort) && _activeMenu->_defaultMenuItemIndex) {
486 		handleClick(_activeMenu->_defaultMenuItemIndex, mousePos);
487 	} else if (_vm->_input->pollEvent(kEventUp)) {
488 		// TODO handleUpKey();
489 		if (_hoveredMenuItemIndex == 1) {
490 			_hoveredMenuItemIndex = _activeMenu->getMenuItemsCount();
491 		} else {
492 			_hoveredMenuItemIndex--;
493 		}
494 		setMouseCursorToMenuItem(_hoveredMenuItemIndex);
495 		_hoveredMenuItemIndex2 = _hoveredMenuItemIndex;
496 		updateActorHoverBackground();
497 		playSoundEffect(0xC);
498 	} else if (_vm->_input->pollEvent(kEventDown)) {
499 		// TODO handleDownKey();
500 		if (_hoveredMenuItemIndex == _activeMenu->getMenuItemsCount()) {
501 			_hoveredMenuItemIndex = 1;
502 		} else {
503 			_hoveredMenuItemIndex++;
504 		}
505 		setMouseCursorToMenuItem(_hoveredMenuItemIndex);
506 		_hoveredMenuItemIndex2 = _hoveredMenuItemIndex;
507 		updateActorHoverBackground();
508 		playSoundEffect(0xC);
509 	}
510 
511 	updateTimeOut(resetTimeOut);
512 }
513 
setTimeOutDuration(uint32 duration,uint timeOutMenuChoiceIndex)514 void BaseMenuSystem::setTimeOutDuration(uint32 duration, uint timeOutMenuChoiceIndex) {
515 	if (duration > 0) {
516 		_isTimeOutEnabled = true;
517 		_isTimeOutReached = false;
518 		_timeOutDuration = duration;
519 		_timeOutMenuChoiceIndex = timeOutMenuChoiceIndex;
520 		_timeOutStartTime = getCurrentTime();
521 		_timeOutEndTime = duration + _timeOutStartTime;
522 	} else {
523 		_isTimeOutEnabled = false;
524 	}
525 }
526 
setMenuCallerThreadId(uint32 menuCallerThreadId)527 void BaseMenuSystem::setMenuCallerThreadId(uint32 menuCallerThreadId) {
528 	_menuCallerThreadId = menuCallerThreadId;
529 }
530 
setMenuChoiceOffsets(MenuChoiceOffsets menuChoiceOffsets,int16 * menuChoiceOffset)531 void BaseMenuSystem::setMenuChoiceOffsets(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset) {
532 	_menuChoiceOffsets = menuChoiceOffsets;
533 	_menuChoiceOffset = menuChoiceOffset;
534 }
535 
setSavegameSlotNum(int slotNum)536 void BaseMenuSystem::setSavegameSlotNum(int slotNum) {
537 	_vm->_savegameSlotNum = slotNum;
538 }
539 
setSavegameDescription(Common::String desc)540 void BaseMenuSystem::setSavegameDescription(Common::String desc) {
541 	_vm->_savegameDescription = desc;
542 }
543 
updateTimeOut(bool resetTimeOut)544 void BaseMenuSystem::updateTimeOut(bool resetTimeOut) {
545 
546 	if (!_isTimeOutEnabled)
547 		return;
548 
549 	if (_menuStack.empty()) {
550 		if (_isTimeOutReached) {
551 			resetTimeOut = true;
552 			_isTimeOutReached = false;
553 		}
554 	} else if (!_isTimeOutReached) {
555 		_isTimeOutReached = true;
556 	}
557 
558 	if (!_isTimeOutReached) {
559 		if (resetTimeOut) {
560 			_timeOutStartTime = getCurrentTime();
561 			_timeOutEndTime = _timeOutDuration + _timeOutStartTime;
562 		} else if (isTimerExpired(_timeOutStartTime, _timeOutEndTime)) {
563 			_isTimeOutEnabled = false;
564 			selectMenuChoiceIndex(_timeOutMenuChoiceIndex);
565 		}
566 	}
567 
568 }
569 
redrawMenuText(BaseMenu * menu)570 void BaseMenuSystem::redrawMenuText(BaseMenu *menu) {
571 	_vm->_screenText->removeText();
572 	drawMenuText(menu);
573 }
574 
calcMenuItemTextPositionAtPoint(Common::Point pt,int & offset)575 bool BaseMenuSystem::calcMenuItemTextPositionAtPoint(Common::Point pt, int &offset) {
576 	uint menuItemIndex;
577 	if (!calcMenuItemIndexAtPoint(pt, menuItemIndex)) {
578 		return false;
579 	}
580 
581 	WRect rect;
582 
583 	MenuItem *menuItem = _activeMenu->getMenuItem(menuItemIndex - 1);
584 	calcMenuItemRect(menuItemIndex, rect);
585 	int x = pt.x - rect._topLeft.x;
586 	Common::String text = menuItem->getText();
587 	FontResource *font = _vm->_dict->findFont(_activeMenu->_fontId);
588 
589 	int curX = 0;
590 	for (uint i = 0; i < text.size(); i++) {
591 		int16 w = font->getCharInfo(text[i])->_width;
592 		if (x >= curX && x <= curX + w) {
593 			offset = i;
594 			return true;
595 		}
596 		curX = curX + w;
597 	}
598 
599 	return false;
600 }
601 
602 // MenuTextBuilder
603 
MenuTextBuilder()604 MenuTextBuilder::MenuTextBuilder() : _pos(0) {
605 }
606 
appendString(const Common::String & value)607 void MenuTextBuilder::appendString(const Common::String &value) {
608 	for (uint i = 0; i < value.size(); ++i) {
609 		_text[_pos++] = value[i];
610 	}
611 }
612 
appendNewLine()613 void MenuTextBuilder::appendNewLine() {
614 	_text[_pos++] = '\r';
615 }
616 
finalize()617 void MenuTextBuilder::finalize() {
618 	_text[_pos] = '\0';
619 }
620 
621 // BaseMenuAction
622 
BaseMenuAction(BaseMenuSystem * menuSystem)623 BaseMenuAction::BaseMenuAction(BaseMenuSystem *menuSystem)
624 	: _menuSystem(menuSystem) {
625 }
626 
627 // MenuActionEnterMenu
628 
MenuActionEnterMenu(BaseMenuSystem * menuSystem,int menuId)629 MenuActionEnterMenu::MenuActionEnterMenu(BaseMenuSystem *menuSystem, int menuId)
630 	: BaseMenuAction(menuSystem), _menuId(menuId) {
631 }
632 
execute()633 void MenuActionEnterMenu::execute() {
634 	_menuSystem->enterSubMenuById(_menuId);
635 }
636 
637 // MenuActionLeaveMenu
638 
MenuActionLeaveMenu(BaseMenuSystem * menuSystem)639 MenuActionLeaveMenu::MenuActionLeaveMenu(BaseMenuSystem *menuSystem)
640 	: BaseMenuAction(menuSystem) {
641 }
642 
execute()643 void MenuActionLeaveMenu::execute() {
644 	_menuSystem->leaveMenu();
645 }
646 
647 // MenuActionReturnChoice
648 
MenuActionReturnChoice(BaseMenuSystem * menuSystem,uint choiceIndex)649 MenuActionReturnChoice::MenuActionReturnChoice(BaseMenuSystem *menuSystem, uint choiceIndex)
650 	: BaseMenuAction(menuSystem), _choiceIndex(choiceIndex) {
651 }
652 
execute()653 void MenuActionReturnChoice::execute() {
654 	_menuSystem->playSoundEffect13();
655 	_menuSystem->selectMenuChoiceIndex(_choiceIndex);
656 }
657 
658 // MenuActionEnterQueryMenu
659 
MenuActionEnterQueryMenu(BaseMenuSystem * menuSystem,int menuId,uint confirmationChoiceIndex)660 MenuActionEnterQueryMenu::MenuActionEnterQueryMenu(BaseMenuSystem *menuSystem, int menuId, uint confirmationChoiceIndex)
661 	: BaseMenuAction(menuSystem), _menuId(menuId), _confirmationChoiceIndex(confirmationChoiceIndex) {
662 }
663 
execute()664 void MenuActionEnterQueryMenu::execute() {
665 	_menuSystem->setQueryConfirmationChoiceIndex(_confirmationChoiceIndex);
666 	_menuSystem->enterSubMenuById(_menuId);
667 }
668 
669 // MenuActionLoadGame
670 
MenuActionLoadGame(BaseMenuSystem * menuSystem,uint choiceIndex)671 MenuActionLoadGame::MenuActionLoadGame(BaseMenuSystem *menuSystem, uint choiceIndex)
672 	: BaseMenuAction(menuSystem), _choiceIndex(choiceIndex) {
673 }
674 
execute()675 void MenuActionLoadGame::execute() {
676 	const Plugin *plugin = NULL;
677 	EngineMan.findGame(ConfMan.get("gameid"), &plugin);
678 	GUI::SaveLoadChooser *dialog;
679 	Common::String desc;
680 	int slot;
681 
682 	dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
683 	slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
684 
685 	delete dialog;
686 
687 	if (slot >= 0) {
688 		_menuSystem->setSavegameSlotNum(slot);
689 		_menuSystem->selectMenuChoiceIndex(_choiceIndex);
690 	}
691 
692 }
693 
694 // MenuActionSaveGame
695 
MenuActionSaveGame(BaseMenuSystem * menuSystem,uint choiceIndex)696 MenuActionSaveGame::MenuActionSaveGame(BaseMenuSystem *menuSystem, uint choiceIndex)
697 		: BaseMenuAction(menuSystem), _choiceIndex(choiceIndex) {
698 }
699 
execute()700 void MenuActionSaveGame::execute() {
701 	const Plugin *plugin = NULL;
702 	EngineMan.findGame(ConfMan.get("gameid"), &plugin);
703 	GUI::SaveLoadChooser *dialog;
704 	Common::String desc;
705 	int slot;
706 
707 	dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
708 	slot = dialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName());
709 	desc = dialog->getResultString().c_str();
710 
711 	delete dialog;
712 
713 	if (slot >= 0) {
714 		_menuSystem->setSavegameSlotNum(slot);
715 		_menuSystem->setSavegameDescription(desc);
716 		_menuSystem->selectMenuChoiceIndex(_choiceIndex);
717 	}
718 }
719 
720 } // End of namespace Illusions
721