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 "common/config-manager.h"
24 #include "common/savefile.h"
25 #include "common/system.h"
26 #include "common/events.h"
27 #include "common/localization.h"
28 #include "common/translation.h"
29 #include "common/ustr.h"
30 
31 #include "graphics/scaler.h"
32 
33 #include "gui/gui-manager.h"
34 #include "gui/widget.h"
35 #include "gui/ThemeEval.h"
36 
37 #include "scumm/dialogs.h"
38 #include "scumm/sound.h"
39 #include "scumm/scumm.h"
40 #include "scumm/imuse/imuse.h"
41 #include "scumm/imuse_digi/dimuse.h"
42 #include "scumm/verbs.h"
43 
44 #ifndef DISABLE_HELP
45 #include "scumm/help.h"
46 #endif
47 
48 using Graphics::kTextAlignCenter;
49 using Graphics::kTextAlignLeft;
50 using GUI::WIDGET_ENABLED;
51 
52 namespace Scumm {
53 
54 struct ResString {
55 	int num;
56 	char string[80];
57 };
58 
59 static const ResString string_map_table_v8[] = {
60 	{0, "/BT_100/Please insert disk %d. Press ENTER"},
61 	{0, "/BT__003/Unable to Find %s, (%s %d) Press Button."},
62 	{0, "/BT__004/Error reading disk %c, (%c%d) Press Button."},
63 	{0, "/BT__002/Game Paused.  Press SPACE to Continue."},
64 	{0, "/BT__005/Are you sure you want to restart?  (Y/N)"}, //BOOT.004
65 	{0, "/BT__006/Are you sure you want to quit?  (Y/N)"}, //BOOT.005
66 	{0, "/BT__008/Save"},
67 	{0, "/BT__009/Load"},
68 	{0, "/BT__010/Play"},
69 	{0, "/BT__011/Cancel"},
70 	{0, "/BT__012/Quit"},
71 	{0, "/BT__013/OK"},
72 	{0, ""},
73 	{0, "/BT__014/You must enter a name"},
74 	{0, "/BT__015/The game was NOT saved (disk full?)"},
75 	{0, "/BT__016/The game was NOT loaded"},
76 	{0, "/BT__017/Saving '%s'"},
77 	{0, "/BT__018/Loading '%s'"},
78 	{0, "/BT__019/Name your SAVE game"},
79 	{0, "/BT__020/Select a game to LOAD"}
80 };
81 
82 static const ResString string_map_table_v7[] = {
83 	{96, "game name and version"}, //that's how it's supposed to be
84 	{83, "Unable to Find %s, (%c%d) Press Button."},
85 	{84, "Error reading disk %c, (%c%d) Press Button."},
86 	{85, "/BOOT.003/Game Paused.  Press SPACE to Continue."},
87 	{86, "/BOOT.004/Are you sure you want to restart?  (Y/N)"},
88 	{87, "/BOOT.005/Are you sure you want to quit?  (Y/N)"},
89 	{70, "/BOOT.008/Save"},
90 	{71, "/BOOT.009/Load"},
91 	{72, "/BOOT.010/Play"},
92 	{73, "/BOOT.011/Cancel"},
93 	{74, "/BOOT.012/Quit"},
94 	{75, "/BOOT.013/OK"},
95 	{0, ""},
96 	{78, "/BOOT.014/You must enter a name"},
97 	{81, "/BOOT.015/The game was NOT saved (disk full?)"},
98 	{82, "/BOOT.016/The game was NOT loaded"},
99 	{79, "/BOOT.017/Saving '%s'"},
100 	{80, "/BOOT.018/Loading '%s'"},
101 	{76, "/BOOT.019/Name your SAVE game"},
102 	{77, "/BOOT.020/Select a game to LOAD"}
103 
104 	/* This is the complete string map for v7
105 	{68, "/BOOT.007/c:\\dig"},
106 	{69, "/BOOT.021/The Dig"},
107 	{70, "/BOOT.008/Save"},
108 	{71, "/BOOT.009/Load"},
109 	{72, "/BOOT.010/Play"},
110 	{73, "/BOOT.011/Cancel"},
111 	{74, "/BOOT.012/Quit"},
112 	{75, "/BOOT.013/OK"},
113 	{76, "/BOOT.019/Name your SAVE game"},
114 	{77, "/BOOT.020/Select a game to LOAD"},
115 	{78, "/BOOT.014/You must enter a name"},
116 	{79, "/BOOT.017/Saving '%s'"},
117 	{80, "/BOOT.018/Loading '%s'"},
118 	{81, "/BOOT.015/The game was NOT saved (disk full?)"},
119 	{82, "/BOOT.016/The game was NOT loaded"},
120 	{83, "Unable to Find %s, (%c%d) Press Button."},
121 	{84, "Error reading disk %c, (%c%d) Press Button."},
122 	{85, "/BOOT.003/Game Paused.  Press SPACE to Continue."},
123 	{86, "/BOOT.004/Are you sure you want to restart?  (Y/N)"},
124 	{87, "/BOOT.005/Are you sure you want to quit?  (Y/N)"},
125 	{90, "/BOOT.022/Music"},
126 	{91, "/BOOT.023/Voice"},
127 	{92, "/BOOT.024/Sfx"},
128 	{93, "/BOOT.025/disabled"},
129 	{94, "/BOOT.026/Text speed"},
130 	{95, "/BOOT.027/Display Text"},
131 	{96, "The Dig v1.0"},
132 	{138, "/BOOT.028/Spooled Music"),
133 	{139, "/BOOT.029/Do you want to replace this saved game?  (Y/N)"},
134 	{141, "Voice Only"},
135 	{142, "Voice and Text"},
136 	{143, "Text Display Only"}, */
137 
138 };
139 
140 static const ResString string_map_table_v6[] = {
141 	{90, "Insert Disk %c and Press Button to Continue."},
142 	{91, "Unable to Find %s, (%c%d) Press Button."},
143 	{92, "Error reading disk %c, (%c%d) Press Button."},
144 	{93, "Game Paused.  Press SPACE to Continue."},
145 	{94, "Are you sure you want to restart?  (Y/N)Y"},
146 	{95, "Are you sure you want to quit?  (Y/N)Y"},
147 	{96, "Save"},
148 	{97, "Load"},
149 	{98, "Play"},
150 	{99, "Cancel"},
151 	{100, "Quit"},
152 	{101, "OK"},
153 	{102, "Insert save/load game disk"},
154 	{103, "You must enter a name"},
155 	{104, "The game was NOT saved (disk full?)"},
156 	{105, "The game was NOT loaded"},
157 	{106, "Saving '%s'"},
158 	{107, "Loading '%s'"},
159 	{108, "Name your SAVE game"},
160 	{109, "Select a game to LOAD"},
161 	{117, "How may I serve you?"}
162 };
163 
164 static const ResString string_map_table_v345[] = {
165 	{1, _s("Insert Disk %c and Press Button to Continue.")},
166 	{2, _s("Unable to Find %s, (%c%d) Press Button.")},
167 	{3, _s("Error reading disk %c, (%c%d) Press Button.")},
168 	{4, _s("Game Paused.  Press SPACE to Continue.")},
169 	// I18N: You may specify 'Yes' symbol at the end of the line, like this:
170 	// "Moechten Sie wirklich neu starten?  (J/N)J"
171 	// Will react to J as 'Yes'
172 	{5, _s("Are you sure you want to restart?  (Y/N)Y")},
173 	// I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
174 	{6, _s("Are you sure you want to quit?  (Y/N)Y")},
175 
176 	// Added in SCUMM4
177 	{7, _s("Save")},
178 	{8, _s("Load")},
179 	{9, _s("Play")},
180 	{10, _s("Cancel")},
181 	{11, _s("Quit")},
182 	{12, _s("OK")},
183 	{13, _s("Insert save/load game disk")},
184 	{14, _s("You must enter a name")},
185 	{15, _s("The game was NOT saved (disk full?)")},
186 	{16, _s("The game was NOT loaded")},
187 	{17, _s("Saving '%s'")},
188 	{18, _s("Loading '%s'")},
189 	{19, _s("Name your SAVE game")},
190 	{20, _s("Select a game to LOAD")},
191 	{28, _s("Game title)")}
192 };
193 
194 #pragma mark -
195 
196 #ifndef DISABLE_HELP
197 
198 class HelpDialog : public ScummDialog {
199 public:
200 	HelpDialog(const GameSettings &game);
201 	void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
202 
203 	void reflowLayout() override;
204 
205 protected:
206 	typedef Common::String String;
207 
208 	GUI::ButtonWidget *_nextButton;
209 	GUI::ButtonWidget *_prevButton;
210 
211 	GUI::StaticTextWidget *_title;
212 	GUI::StaticTextWidget *_key[HELP_NUM_LINES];
213 	GUI::StaticTextWidget *_dsc[HELP_NUM_LINES];
214 
215 	int _page;
216 	int _numPages;
217 	int _numLines;
218 
219 	const GameSettings _game;
220 
221 	void displayKeyBindings();
222 };
223 
224 #endif
225 
226 #pragma mark -
227 
ScummDialog(int x,int y,int w,int h)228 ScummDialog::ScummDialog(int x, int y, int w, int h) : GUI::Dialog(x, y, w, h) {
229 	_backgroundType = GUI::ThemeEngine::kDialogBackgroundSpecial;
230 }
231 
ScummDialog(String name)232 ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
233 	_backgroundType = GUI::ThemeEngine::kDialogBackgroundSpecial;
234 }
235 
236 #pragma mark -
237 
238 #ifndef DISABLE_HELP
239 
ScummMenuDialog(ScummEngine * scumm)240 ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
241 	: MainMenuDialog(scumm) {
242 	_helpDialog = new HelpDialog(scumm->_game);
243 	_helpButton->setEnabled(true);
244 }
245 
~ScummMenuDialog()246 ScummMenuDialog::~ScummMenuDialog() {
247 	delete _helpDialog;
248 }
249 
handleCommand(GUI::CommandSender * sender,uint32 cmd,uint32 data)250 void ScummMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
251 	switch (cmd) {
252 	case kHelpCmd:
253 		_helpDialog->runModal();
254 		break;
255 	default:
256 		MainMenuDialog::handleCommand(sender, cmd, data);
257 	}
258 }
259 
260 #pragma mark -
261 
262 enum {
263 	kNextCmd = 'NEXT',
264 	kPrevCmd = 'PREV'
265 };
266 
HelpDialog(const GameSettings & game)267 HelpDialog::HelpDialog(const GameSettings &game)
268 	: ScummDialog("ScummHelp"), _game(game) {
269 	_title = new GUI::StaticTextWidget(this, "ScummHelp.Title", Common::U32String());
270 
271 	_page = 1;
272 	_backgroundType = GUI::ThemeEngine::kDialogBackgroundDefault;
273 
274 	_numPages = ScummHelp::numPages(_game.id);
275 
276 	// I18N: Previous page button
277 	_prevButton = new GUI::ButtonWidget(this, "ScummHelp.Prev", _("~P~revious"), Common::U32String(), kPrevCmd);
278 	// I18N: Next page button
279 	_nextButton = new GUI::ButtonWidget(this, "ScummHelp.Next", _("~N~ext"), Common::U32String(), kNextCmd);
280 	new GUI::ButtonWidget(this, "ScummHelp.Close", _("~C~lose"), Common::U32String(), GUI::kCloseCmd);
281 	_prevButton->clearFlags(WIDGET_ENABLED);
282 
283 	GUI::ContainerWidget *placeHolder = new GUI::ContainerWidget(this, "ScummHelp.HelpText");
284 	placeHolder->setBackgroundType(GUI::ThemeEngine::kWidgetBackgroundNo);
285 
286 	_numLines = HELP_NUM_LINES;
287 
288 	// Dummy entries
289 	for (int i = 0; i < HELP_NUM_LINES; i++) {
290 		_key[i] = new GUI::StaticTextWidget(this, 0, 0, 10, 10, Common::U32String(), Graphics::kTextAlignRight);
291 		_dsc[i] = new GUI::StaticTextWidget(this, 0, 0, 10, 10, Common::U32String(), Graphics::kTextAlignLeft);
292 	}
293 
294 }
295 
reflowLayout()296 void HelpDialog::reflowLayout() {
297 	ScummDialog::reflowLayout();
298 
299 	int lineHeight = g_gui.getFontHeight();
300 	int16 x, y;
301 	int16 w, h;
302 
303 	assert(lineHeight);
304 
305 	g_gui.xmlEval()->getWidgetData("ScummHelp.HelpText", x, y, w, h);
306 
307 	// Make sure than we don't have more lines than what we can fit
308 	// on the space that the layout reserves for text
309 	_numLines = MIN(HELP_NUM_LINES, (int)(h / lineHeight));
310 
311 	int keyW = w * 20 / 100;
312 	int dscX = x + keyW + 32;
313 	int dscW = w * 80 / 100;
314 
315 	int xoff = (_w >> 1) - (w >> 1);
316 
317 	for (int i = 0; i < _numLines; i++) {
318 		_key[i]->resize(xoff + x, y + lineHeight * i, keyW, lineHeight, false);
319 		_dsc[i]->resize(xoff + dscX, y + lineHeight * i, dscW, lineHeight, false);
320 	}
321 
322 	displayKeyBindings();
323 }
324 
displayKeyBindings()325 void HelpDialog::displayKeyBindings() {
326 	U32String titleStr, *keyStr, *dscStr;
327 
328 	ScummHelp::updateStrings(_game.id, _game.version, _game.platform, _page, titleStr, keyStr, dscStr);
329 
330 	_title->setLabel(titleStr);
331 	for (int i = 0; i < _numLines; i++) {
332 		_key[i]->setLabel(keyStr[i]);
333 		_dsc[i]->setLabel(dscStr[i]);
334 	}
335 
336 	delete[] keyStr;
337 	delete[] dscStr;
338 }
339 
handleCommand(GUI::CommandSender * sender,uint32 cmd,uint32 data)340 void HelpDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
341 
342 	switch (cmd) {
343 	case kNextCmd:
344 		_page++;
345 		if (_page >= _numPages) {
346 			_nextButton->clearFlags(WIDGET_ENABLED);
347 		}
348 		if (_page >= 2) {
349 			_prevButton->setFlags(WIDGET_ENABLED);
350 		}
351 		displayKeyBindings();
352 		g_gui.scheduleTopDialogRedraw();
353 		break;
354 	case kPrevCmd:
355 		_page--;
356 		if (_page <= _numPages) {
357 			_nextButton->setFlags(WIDGET_ENABLED);
358 		}
359 		if (_page <= 1) {
360 			_prevButton->clearFlags(WIDGET_ENABLED);
361 		}
362 		displayKeyBindings();
363 		g_gui.scheduleTopDialogRedraw();
364 		break;
365 	default:
366 		ScummDialog::handleCommand(sender, cmd, data);
367 	}
368 }
369 
370 #endif
371 
372 #pragma mark -
373 
isCJKLanguage(Common::Language lang)374 static bool isCJKLanguage(Common::Language lang) {
375 	switch (lang) {
376 	case Common::KO_KOR:
377 	case Common::JA_JPN:
378 	case Common::ZH_TWN:
379 	case Common::ZH_CNA:
380 		return true;
381 	default:
382 		return false;
383 	}
384 }
385 
InfoDialog(ScummEngine * scumm,int res)386 InfoDialog::InfoDialog(ScummEngine *scumm, int res)
387 : ScummDialog(0, 0, 0, 0), _vm(scumm), _style(GUI::ThemeEngine::kFontStyleBold) { // dummy x and w
388 
389 	_message = queryResString(res);
390 
391 	Common::Language lang = isCJKLanguage(_vm->_language) ? _vm->_language : Common::UNK_LANG;
392 
393 	// Width and height are dummy
394 	_text = new GUI::StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter, Common::U32String(), GUI::ThemeEngine::kFontStyleBold, lang);
395 
396 	// Store this for the calls to getStringWidth() and getStringHeight() in reflowLayout().
397 	if (lang != Common::UNK_LANG)
398 		_style = GUI::ThemeEngine::kFontStyleLangExtra;
399 }
400 
InfoDialog(ScummEngine * scumm,const U32String & message)401 InfoDialog::InfoDialog(ScummEngine *scumm, const U32String &message)
402 : ScummDialog(0, 0, 0, 0), _vm(scumm), _style(GUI::ThemeEngine::kFontStyleBold) { // dummy x and w
403 
404 	_message = message;
405 
406 	// Width and height are dummy
407 	_text = new GUI::StaticTextWidget(this, 0, 0, 10, 10, _message, kTextAlignCenter);
408 }
409 
setInfoText(const U32String & message)410 void InfoDialog::setInfoText(const U32String &message) {
411 	_message = message;
412 	_text->setLabel(_message);
413 	//reflowLayout(); // FIXME: Should we call this here? Depends on the usage patterns, I guess...
414 }
415 
reflowLayout()416 void InfoDialog::reflowLayout() {
417 	const int screenW = g_system->getOverlayWidth();
418 	const int screenH = g_system->getOverlayHeight();
419 
420 	int width = g_gui.getStringWidth(_message, _style) + 16;
421 	int height = g_gui.getFontHeight(_style) + 8;
422 
423 	_w = width;
424 	_h = height;
425 	_x = (screenW - width) / 2;
426 	_y = (screenH - height) / 2;
427 
428 	_text->setSize(_w, _h);
429 }
430 
queryResString(int stringno)431 const Common::U32String InfoDialog::queryResString(int stringno) {
432 	byte buf[256];
433 	byte reverseBuf[256];
434 	const byte *result;
435 
436 	if (stringno == 0)
437 		return String();
438 
439 	if (_vm->_game.heversion >= 80)
440 		return _(string_map_table_v6[stringno - 1].string);
441 	else if (_vm->_game.version == 8)
442 		result = (const byte *)string_map_table_v8[stringno - 1].string;
443 	else if (_vm->_game.version == 7)
444 		result = _vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
445 	else if (_vm->_game.version == 6)
446 		result = _vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
447 	else if (_vm->_game.version >= 3)
448 		result = _vm->getStringAddress(string_map_table_v345[stringno - 1].num);
449 	else
450 		return _(string_map_table_v345[stringno - 1].string);
451 
452 	if (result && *result == '/') {
453 		_vm->translateText(result, buf);
454 		result = buf;
455 	}
456 
457 	if (!result || *result == '\0') {	// Gracelessly degrade to english :)
458 		return _(string_map_table_v345[stringno - 1].string);
459 	}
460 
461 	if (_vm->reverseIfNeeded(result, reverseBuf))
462 		result = reverseBuf;
463 	// Convert to a proper string (take care of FF codes)
464 	byte chr;
465 	String tmp;
466 	while ((chr = *result++)) {
467 		if (chr == 0xFF) {
468 			result += 3;
469 		} else if (chr != '@') {
470 			tmp += chr;
471 		}
472 	}
473 
474 	const Common::CodePage convertFromCodePage = _vm->getDialogCodePage();
475 	return convertFromCodePage == Common::kCodePageInvalid ? _(tmp) : U32String(tmp, convertFromCodePage);
476 }
477 
478 #pragma mark -
479 
PauseDialog(ScummEngine * scumm,int res)480 PauseDialog::PauseDialog(ScummEngine *scumm, int res)
481 	: InfoDialog(scumm, res) {
482 }
483 
handleKeyDown(Common::KeyState state)484 void PauseDialog::handleKeyDown(Common::KeyState state) {
485 	if (state.ascii == ' ')  // Close pause dialog if space key is pressed
486 		close();
487 	else
488 		ScummDialog::handleKeyDown(state);
489 }
490 
ConfirmDialog(ScummEngine * scumm,int res)491 ConfirmDialog::ConfirmDialog(ScummEngine *scumm, int res)
492 	: InfoDialog(scumm, res), _yesKey('y'), _noKey('n') {
493 
494 	if (_message.empty())
495 		return;
496 
497 	if (_message[_message.size() - 1] != ')') {
498 		_yesKey = _message[_message.size() - 1];
499 		_message.deleteLastChar();
500 
501 		if (_yesKey >= 'A' && _yesKey <= 'Z')
502 			_yesKey += 'a' - 'A';
503 
504 		_text->setLabel(_message);
505 		reflowLayout();
506 	}
507 }
508 
handleKeyDown(Common::KeyState state)509 void ConfirmDialog::handleKeyDown(Common::KeyState state) {
510 	Common::KeyCode keyYes, keyNo;
511 
512 	Common::getLanguageYesNo(keyYes, keyNo);
513 
514 	if (state.keycode == Common::KEYCODE_n || state.ascii == _noKey || state.ascii == keyNo) {
515 		setResult(0);
516 		close();
517 	} else if (state.keycode == Common::KEYCODE_y || state.ascii == _yesKey || state.ascii == keyYes) {
518 		setResult(1);
519 		close();
520 	} else
521 		ScummDialog::handleKeyDown(state);
522 }
523 
524 #pragma mark -
525 
ValueDisplayDialog(const Common::U32String & label,int minVal,int maxVal,int val,uint16 incKey,uint16 decKey)526 ValueDisplayDialog::ValueDisplayDialog(const Common::U32String &label, int minVal, int maxVal,
527 		int val, uint16 incKey, uint16 decKey)
528 	: GUI::Dialog(0, 0, 0, 0),
529 	_label(label), _min(minVal), _max(maxVal),
530 	_value(val), _incKey(incKey), _decKey(decKey), _timer(0) {
531 	assert(_min <= _value && _value <= _max);
532 }
533 
drawDialog(GUI::DrawLayer layerToDraw)534 void ValueDisplayDialog::drawDialog(GUI::DrawLayer layerToDraw) {
535 	Dialog::drawDialog(layerToDraw);
536 
537 	const int labelWidth = _w - 8 - _percentBarWidth;
538 	g_gui.theme()->drawText(Common::Rect(_x+4, _y+4, _x+labelWidth+4,
539 				_y+g_gui.theme()->getFontHeight()+4), _label);
540 	g_gui.theme()->drawSlider(Common::Rect(_x+4+labelWidth, _y+4, _x+_w-4, _y+_h-4),
541 				_percentBarWidth * (_value - _min) / (_max - _min));
542 }
543 
handleTickle()544 void ValueDisplayDialog::handleTickle() {
545 	if (g_system->getMillis() > _timer) {
546 		close();
547 	}
548 }
549 
reflowLayout()550 void ValueDisplayDialog::reflowLayout() {
551 	const int screenW = g_system->getOverlayWidth();
552 	const int screenH = g_system->getOverlayHeight();
553 
554 	_percentBarWidth = screenW * 100 / 640;
555 
556 	int width = g_gui.getStringWidth(_label) + 16 + _percentBarWidth;
557 	int height = g_gui.getFontHeight() + 4 * 2;
558 
559 	_x = (screenW - width) / 2;
560 	_y = (screenH - height) / 2;
561 	_w = width;
562 	_h = height;
563 }
564 
handleKeyDown(Common::KeyState state)565 void ValueDisplayDialog::handleKeyDown(Common::KeyState state) {
566 	if (state.ascii == _incKey || state.ascii == _decKey) {
567 		if (state.ascii == _incKey && _value < _max)
568 			_value++;
569 		else if (state.ascii == _decKey && _value > _min)
570 			_value--;
571 
572 		setResult(_value);
573 		_timer = g_system->getMillis() + kDisplayDelay;
574 		g_gui.scheduleTopDialogRedraw();
575 	} else {
576 		close();
577 	}
578 }
579 
open()580 void ValueDisplayDialog::open() {
581 	GUI::Dialog::open();
582 	setResult(_value);
583 	_timer = g_system->getMillis() + kDisplayDelay;
584 }
585 
SubtitleSettingsDialog(ScummEngine * scumm,int value)586 SubtitleSettingsDialog::SubtitleSettingsDialog(ScummEngine *scumm, int value)
587 	: InfoDialog(scumm, U32String()), _value(value), _timer(0) {
588 
589 }
590 
handleTickle()591 void SubtitleSettingsDialog::handleTickle() {
592 	InfoDialog::handleTickle();
593 	if (g_system->getMillis() > _timer)
594 		close();
595 }
596 
handleKeyDown(Common::KeyState state)597 void SubtitleSettingsDialog::handleKeyDown(Common::KeyState state) {
598 	if (state.keycode == Common::KEYCODE_t && state.hasFlags(Common::KBD_CTRL)) {
599 		cycleValue();
600 
601 		reflowLayout();
602 		g_gui.scheduleTopDialogRedraw();
603 	} else {
604 		close();
605 	}
606 }
607 
open()608 void SubtitleSettingsDialog::open() {
609 	cycleValue();
610 	InfoDialog::open();
611 	setResult(_value);
612 }
613 
cycleValue()614 void SubtitleSettingsDialog::cycleValue() {
615 	static const char *const subtitleDesc[] = {
616 		_s("Speech Only"),
617 		_s("Speech and Subtitles"),
618 		_s("Subtitles Only")
619 	};
620 
621 	_value += 1;
622 	if (_value > 2)
623 		_value = 0;
624 
625 	if (_value == 1 && g_system->getOverlayWidth() <= 320)
626 		setInfoText(_c("Speech & Subs", "lowres"));
627 	else
628 		setInfoText(_(subtitleDesc[_value]));
629 
630 	_timer = g_system->getMillis() + 1500;
631 }
632 
Indy3IQPointsDialog(ScummEngine * scumm,char * text)633 Indy3IQPointsDialog::Indy3IQPointsDialog(ScummEngine *scumm, char* text)
634 	: InfoDialog(scumm, Common::U32String(text)) {
635 }
636 
handleKeyDown(Common::KeyState state)637 void Indy3IQPointsDialog::handleKeyDown(Common::KeyState state) {
638 	if (state.ascii == 'i')
639 		close();
640 	else
641 		ScummDialog::handleKeyDown(state);
642 }
643 
DebugInputDialog(ScummEngine * scumm,char * text)644 DebugInputDialog::DebugInputDialog(ScummEngine *scumm, char* text)
645 	: InfoDialog(scumm, U32String(text)) {
646 	mainText = text;
647 	done = 0;
648 }
649 
handleKeyDown(Common::KeyState state)650 void DebugInputDialog::handleKeyDown(Common::KeyState state) {
651 	if (state.keycode == Common::KEYCODE_BACKSPACE && buffer.size() > 0) {
652 		buffer.deleteLastChar();
653 		Common::String total = mainText + ' ' + buffer;
654 		setInfoText(total);
655 		g_gui.scheduleTopDialogRedraw();
656 		reflowLayout();
657 	} else if (state.keycode == Common::KEYCODE_RETURN) {
658 		done = 1;
659 		close();
660 		return;
661 	} else if ((state.ascii >= '0' && state.ascii <= '9') || (state.ascii >= 'A' && state.ascii <= 'Z') || (state.ascii >= 'a' && state.ascii <= 'z') || state.ascii == '.' || state.ascii == ' ') {
662 		buffer += state.ascii;
663 		Common::String total = mainText + ' ' + buffer;
664 		g_gui.scheduleTopDialogRedraw();
665 		reflowLayout();
666 		setInfoText(total);
667 	}
668 }
669 
LoomTownsDifficultyDialog()670 LoomTownsDifficultyDialog::LoomTownsDifficultyDialog()
671 	: Dialog("LoomTownsDifficultyDialog"), _difficulty(-1) {
672 	GUI::StaticTextWidget *text1 = new GUI::StaticTextWidget(this, "LoomTownsDifficultyDialog.Description1", _("Select a Proficiency Level."));
673 	text1->setAlign(Graphics::kTextAlignCenter);
674 	GUI::StaticTextWidget *text2 = new GUI::StaticTextWidget(this, "LoomTownsDifficultyDialog.Description2", _("Refer to your Loom(TM) manual for help."));
675 	text2->setAlign(Graphics::kTextAlignCenter);
676 
677 	new GUI::ButtonWidget(this, "LoomTownsDifficultyDialog.Standard", _("Standard"), Common::U32String(), kStandardCmd);
678 	new GUI::ButtonWidget(this, "LoomTownsDifficultyDialog.Practice", _("Practice"), Common::U32String(), kPracticeCmd);
679 	new GUI::ButtonWidget(this, "LoomTownsDifficultyDialog.Expert", _("Expert"), Common::U32String(), kExpertCmd);
680 }
681 
handleCommand(GUI::CommandSender * sender,uint32 cmd,uint32 data)682 void LoomTownsDifficultyDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
683 	switch (cmd) {
684 	case kStandardCmd:
685 		_difficulty = 1;
686 		close();
687 		break;
688 
689 	case kPracticeCmd:
690 		_difficulty = 0;
691 		close();
692 		break;
693 
694 	case kExpertCmd:
695 		_difficulty = 2;
696 		close();
697 		break;
698 
699 	default:
700 		GUI::Dialog::handleCommand(sender, cmd, data);
701 	}
702 }
703 
704 } // End of namespace Scumm
705