/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "common/translation.h" #include "gui/dialog.h" #include "gui/widget.h" #include "tsage/tsage.h" #include "tsage/core.h" #include "tsage/dialogs.h" #include "tsage/staticres.h" #include "tsage/globals.h" #include "tsage/ringworld/ringworld_logic.h" namespace TsAGE { /*--------------------------------------------------------------------------*/ /** * This dialog class provides a simple message display with support for either one or two buttons. */ MessageDialog::MessageDialog(const Common::String &message, const Common::String &btn1Message, const Common::String &btn2Message) : GfxDialog() { // Set up the message addElements(&_msg, &_btn1, NULL); _msg.set(message, 200, ALIGN_LEFT); _msg._bounds.moveTo(0, 0); _defaultButton = &_btn1; // Set up the first button _btn1.setText(btn1Message); _btn1._bounds.moveTo(_msg._bounds.right - _btn1._bounds.width(), _msg._bounds.bottom + 2); if (!btn2Message.empty()) { // Set up the second button add(&_btn2); _btn2.setText(btn2Message); _btn2._bounds.moveTo(_msg._bounds.right - _btn2._bounds.width(), _msg._bounds.bottom + 2); _btn1._bounds.translate(-(_btn2._bounds.width() + 4), 0); } // Do post setup for the dialog setDefaults(); // Set the dialog's center setCenter(g_globals->_dialogCenter.x, g_globals->_dialogCenter.y); } int MessageDialog::show(const Common::String &message, const Common::String &btn1Message, const Common::String &btn2Message) { // Ensure that the cursor is the arrow g_globals->_events.setCursor(CURSOR_ARROW); int result = show2(message, btn1Message, btn2Message); g_globals->_events.setCursorFromFlag(); return result; } int MessageDialog::show2(const Common::String &message, const Common::String &btn1Message, const Common::String &btn2Message) { MessageDialog *dlg = new MessageDialog(message, btn1Message, btn2Message); dlg->draw(); GfxButton *defaultButton = !btn2Message.empty() ? &dlg->_btn2 : &dlg->_btn1; GfxButton *selectedButton = dlg->execute(defaultButton); int result = (selectedButton == defaultButton) ? 1 : 0; delete dlg; return result; } /*--------------------------------------------------------------------------*/ ConfigDialog::ConfigDialog() : GUI::OptionsDialog("", "GlobalConfig") { // // Sound controllers // addVolumeControls(this, "GlobalConfig."); setVolumeSettingsState(true); // could disable controls by GUI options // // Add the buttons // new GUI::ButtonWidget(this, "GlobalConfig.Ok", _("~O~K"), 0, GUI::kOKCmd); new GUI::ButtonWidget(this, "GlobalConfig.Cancel", _("~C~ancel"), 0, GUI::kCloseCmd); } /*--------------------------------------------------------------------------*/ void ModalDialog::draw() { // Set the palette for use in the dialog setPalette(); // Make a backup copy of the area the dialog will occupy Rect tempRect = _bounds; tempRect.collapse(-10, -10); _savedArea = Surface_getArea(g_globals->_gfxManagerInstance.getSurface(), tempRect); _gfxManager.activate(); // Fill in the contents of the entire dialog _gfxManager._bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); drawFrame(); // Draw each element in the dialog in order GfxElementList::iterator i; for (i = _elements.begin(); i != _elements.end(); ++i) { (*i)->draw(); } _gfxManager.deactivate(); } void ModalDialog::drawFrame() { Rect origRect = _bounds; _bounds.collapse(-10, -10); // Fill the dialog area g_globals->gfxManager().fillRect(origRect, 54); // Draw top line GfxSurface surface = surfaceFromRes(8, 1, 7); for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) surface.draw(Common::Point(xp, _bounds.top)); surface.draw(Common::Point(_bounds.right - 20, _bounds.top)); surface = surfaceFromRes(8, 1, 1); surface.draw(Common::Point(_bounds.left, _bounds.top)); surface = surfaceFromRes(8, 1, 4); surface.draw(Common::Point(_bounds.right - 10, _bounds.top)); // Draw vertical edges surface = surfaceFromRes(8, 1, 2); for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) surface.draw(Common::Point(_bounds.left, yp)); surface.draw(Common::Point(_bounds.left, _bounds.bottom - 20)); surface = surfaceFromRes(8, 1, 5); for (int yp = _bounds.top + 10; yp < (_bounds.bottom - 20); yp += 10) surface.draw(Common::Point(_bounds.right - 10, yp)); surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 20)); // Draw bottom line surface = surfaceFromRes(8, 1, 8); for (int xp = _bounds.left + 10; xp < (_bounds.right - 20); xp += 10) surface.draw(Common::Point(xp, _bounds.bottom - 10)); surface.draw(Common::Point(_bounds.right - 20, _bounds.bottom - 10)); surface = surfaceFromRes(8, 1, 3); surface.draw(Common::Point(_bounds.left, _bounds.bottom - 10)); surface = surfaceFromRes(8, 1, 6); surface.draw(Common::Point(_bounds.right - 10, _bounds.bottom - 10)); // Set the dialog's manager bounds _gfxManager._bounds = origRect; } /*--------------------------------------------------------------------------*/ bool GfxInvImage::process(Event &event) { if (!event.handled && (event.eventType == EVENT_BUTTON_DOWN)) { event.handled = _bounds.contains(event.mousePos); return event.handled; } return false; } /*--------------------------------------------------------------------------*/ void InventoryDialog::show() { // Determine how many items are in the player's inventory int itemCount = 0; SynchronizedList::iterator i; for (i = RING_INVENTORY._itemList.begin(); i != RING_INVENTORY._itemList.end(); ++i) { if ((*i)->inInventory()) ++itemCount; } if (itemCount == 0) { MessageDialog::show(INV_EMPTY_MSG, OK_BTN_STRING); return; } InventoryDialog *dlg = new InventoryDialog(); dlg->draw(); dlg->execute(); delete dlg; } InventoryDialog::InventoryDialog() { // Determine the maximum size of the image of any item in the player's inventory int imgWidth = 0, imgHeight = 0; SynchronizedList::iterator i; for (i = RING_INVENTORY._itemList.begin(); i != RING_INVENTORY._itemList.end(); ++i) { InvObject *invObject = *i; if (invObject->inInventory()) { // Get the image for the item GfxSurface itemSurface = surfaceFromRes(invObject->_displayResNum, invObject->_rlbNum, invObject->_cursorNum); // Maintain the dimensions of the largest item image imgWidth = MAX(imgWidth, (int)itemSurface.getBounds().width()); imgHeight = MAX(imgHeight, (int)itemSurface.getBounds().height()); // Add the item to the display list GfxInvImage *img = new GfxInvImage(); _images.push_back(img); img->setDetails(invObject->_displayResNum, invObject->_rlbNum, invObject->_cursorNum); img->_invObject = invObject; add(img); } } assert(_images.size() > 0); // Figure out the number of columns/rows to show all the items int cellsSize = 3; while ((cellsSize * cellsSize) < (int)_images.size()) ++cellsSize; // Set the position of each inventory item to be displayed int cellX = 0; Common::Point pt(0, 0); for (uint idx = 0; idx < _images.size(); ++idx) { if (cellX == cellsSize) { // Move to the start of the next line pt.x = 0; pt.y += imgHeight + 2; cellX = 0; } _images[idx]->_bounds.moveTo(pt.x, pt.y); pt.x += imgWidth + 2; ++cellX; } // Set up the buttons pt.y += imgHeight + 2; _btnOk.setText(OK_BTN_STRING); _btnOk._bounds.moveTo((imgWidth + 2) * cellsSize - _btnOk._bounds.width(), pt.y); _btnLook.setText(LOOK_BTN_STRING); _btnLook._bounds.moveTo(_btnOk._bounds.left - _btnLook._bounds.width() - 2, _btnOk._bounds.top); addElements(&_btnLook, &_btnOk, NULL); frame(); setCenter(SCREEN_CENTER_X, SCREEN_CENTER_Y); } InventoryDialog::~InventoryDialog() { for (uint idx = 0; idx < _images.size(); ++idx) delete _images[idx]; } void InventoryDialog::execute() { if ((RING_INVENTORY._selectedItem) && RING_INVENTORY._selectedItem->inInventory()) RING_INVENTORY._selectedItem->setCursor(); GfxElement *hiliteObj; bool lookFlag = false; _gfxManager.activate(); while (!g_vm->shouldQuit()) { // Get events Event event; while (!g_globals->_events.getEvent(event) && !g_vm->shouldQuit()) { g_system->delayMillis(10); g_system->updateScreen(); } if (g_vm->shouldQuit()) break; hiliteObj = NULL; if ((event.eventType == EVENT_BUTTON_DOWN) && !_bounds.contains(event.mousePos)) break; // Pass event to elements event.mousePos.x -= _gfxManager._bounds.left; event.mousePos.y -= _gfxManager._bounds.top; for (GfxElementList::iterator i = _elements.begin(); i != _elements.end(); ++i) { if ((*i)->process(event)) hiliteObj = *i; } if (!event.handled && event.eventType == EVENT_KEYPRESS) { if ((event.kbd.keycode == Common::KEYCODE_RETURN) || (event.kbd.keycode == Common::KEYCODE_ESCAPE)) { // Exit the dialog //hiliteObj = &_btnOk; break; } } if (hiliteObj == &_btnOk) { // Ok button clicked if (lookFlag) g_globals->_events.setCursor(CURSOR_WALK); break; } else if (hiliteObj == &_btnLook) { // Look button clicked if (_btnLook._message == LOOK_BTN_STRING) { _btnLook._message = PICK_BTN_STRING; lookFlag = 1; g_globals->_events.setCursor(CURSOR_LOOK); } else { _btnLook._message = LOOK_BTN_STRING; lookFlag = 0; g_globals->_events.setCursor(CURSOR_WALK); } hiliteObj->draw(); } else if (hiliteObj) { // Inventory item selected InvObject *invObject = static_cast(hiliteObj)->_invObject; if (lookFlag) { g_globals->_screenSurface.displayText(invObject->_description); } else { RING_INVENTORY._selectedItem = invObject; invObject->setCursor(); } } } _gfxManager.deactivate(); } /*--------------------------------------------------------------------------*/ void OptionsDialog::show() { OptionsDialog *dlg = new OptionsDialog(); dlg->draw(); GfxButton *btn = dlg->execute(); if (btn == &dlg->_btnQuit) { // Quit game if (MessageDialog::show(QUIT_CONFIRM_MSG, CANCEL_BTN_STRING, QUIT_BTN_STRING) == 1) { g_vm->quitGame(); } } else if (btn == &dlg->_btnRestart) { // Restart game g_globals->_game->restartGame(); } else if (btn == &dlg->_btnSound) { // Sound dialog SoundDialog::execute(); } else if (btn == &dlg->_btnSave) { // Save button g_globals->_game->saveGame(); } else if (btn == &dlg->_btnRestore) { // Restore button g_globals->_game->restoreGame(); } dlg->remove(); delete dlg; } OptionsDialog::OptionsDialog() { // Set the element text _gfxMessage.set(OPTIONS_MSG, 140, ALIGN_LEFT); _btnRestore.setText(RESTORE_BTN_STRING); _btnSave.setText(SAVE_BTN_STRING); _btnRestart.setText(RESTART_BTN_STRING); _btnQuit.setText(QUIT_BTN_STRING); _btnSound.setText(SOUND_BTN_STRING); _btnResume.setText(RESUME_BTN_STRING); // Set position of the elements _gfxMessage._bounds.moveTo(0, 1); _btnRestore._bounds.moveTo(0, _gfxMessage._bounds.bottom + 1); _btnSave._bounds.moveTo(0, _btnRestore._bounds.bottom + 1); _btnRestart._bounds.moveTo(0, _btnSave._bounds.bottom + 1); _btnQuit._bounds.moveTo(0, _btnRestart._bounds.bottom + 1); _btnSound._bounds.moveTo(0, _btnQuit._bounds.bottom + 1); _btnResume._bounds.moveTo(0, _btnSound._bounds.bottom + 1); // Set all the buttons to the widest button GfxButton *btnList[6] = {&_btnRestore, &_btnSave, &_btnRestart, &_btnQuit, &_btnSound, &_btnResume}; int16 btnWidth = 0; for (int idx = 0; idx < 6; ++idx) btnWidth = MAX(btnWidth, btnList[idx]->_bounds.width()); for (int idx = 0; idx < 6; ++idx) btnList[idx]->_bounds.setWidth(btnWidth); // Add the items to the dialog addElements(&_gfxMessage, &_btnRestore, &_btnSave, &_btnRestart, &_btnQuit, &_btnSound, &_btnResume, NULL); // Set the dialog size and position frame(); setCenter(160, 100); } /*--------------------------------------------------------------------------*/ void SoundDialog::execute() { ConfigDialog *dlg = new ConfigDialog(); dlg->runModal(); delete dlg; g_globals->_soundManager.syncSounds(); g_globals->_events.setCursorFromFlag(); } } // End of namespace TsAGE