diff options
Diffstat (limited to 'engines/sci/gui/gui_menu.cpp')
-rw-r--r-- | engines/sci/gui/gui_menu.cpp | 648 |
1 files changed, 0 insertions, 648 deletions
diff --git a/engines/sci/gui/gui_menu.cpp b/engines/sci/gui/gui_menu.cpp deleted file mode 100644 index e9795edc5c..0000000000 --- a/engines/sci/gui/gui_menu.cpp +++ /dev/null @@ -1,648 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/event.h" -#include "sci/engine/state.h" -#include "sci/gui/gui_helpers.h" -#include "sci/gui/gui_gfx.h" -#include "sci/gui/gui_cursor.h" -#include "sci/gui/gui_font.h" -#include "sci/gui/gui_text.h" -#include "sci/gui/gui_screen.h" -#include "sci/gui/gui_menu.h" - -namespace Sci { - -SciGuiMenu::SciGuiMenu(SciEvent *event, SegManager *segMan, SciGuiGfx *gfx, SciGuiText *text, SciGuiScreen *screen, SciGuiCursor *cursor) - : _event(event), _segMan(segMan), _gfx(gfx), _text(text), _screen(screen), _cursor(cursor) { - - _listCount = 0; - // We actually set active item in here and remember last selection of the user - // sierra sci always defaulted to first item every time menu was called via ESC, we dont follow that logic - _curMenuId = 1; - _curItemId = 1; - - _menuSaveHandle = NULL_REG; - _barSaveHandle = NULL_REG; - _oldPort = NULL; -} - -SciGuiMenu::~SciGuiMenu() { - // TODO: deallocate _list and _itemList -} - -void SciGuiMenu::add(Common::String title, Common::String content, reg_t contentVmPtr) { - GuiMenuEntry *menuEntry; - uint16 itemCount = 0; - GuiMenuItemEntry *itemEntry; - int contentSize = content.size(); - int separatorCount; - int curPos, beginPos, endPos, tempPos; - int tagPos, rightAlignedPos, functionPos, altPos, controlPos; - - // Sierra SCI starts with id 1, so we do so as well - _listCount++; - menuEntry = new GuiMenuEntry(_listCount); - menuEntry->text = title; - _list.push_back(menuEntry); - - curPos = 0; - do { - itemCount++; - itemEntry = new GuiMenuItemEntry(_listCount, itemCount); - - beginPos = curPos; - - // Now go through the content till we find end-marker and collect data about it - // ':' is an end-marker for each item - tagPos = 0; rightAlignedPos = 0; - controlPos = 0; altPos = 0; functionPos = 0; - while ((curPos < contentSize) && (content[curPos] != ':')) { - switch (content[curPos]) { - case '=': // Set tag - if (tagPos) - error("multiple tag markers within one menu-item"); - tagPos = curPos; - break; - case '`': // Right-aligned - if (rightAlignedPos) - error("multiple right-aligned markers within one menu-item"); - rightAlignedPos = curPos; - break; - case '^': // Ctrl-prefix - if (controlPos) - error("multiple control markers within one menu-item"); - controlPos = curPos; - break; - case '@': // Alt-prefix - if (altPos) - error("multiple alt markers within one menu-item"); - altPos = curPos; - break; - case '#': // Function-prefix - if (functionPos) - error("multiple function markers within one menu-item"); - functionPos = curPos; - break; - } - curPos++; - } - endPos = curPos; - - // Control/Alt/Function key mapping... - if (controlPos) { - content.setChar(SCI_MENU_REPLACE_ONCONTROL, controlPos); - itemEntry->keyModifier = SCI_KEYMOD_CTRL; - tempPos = controlPos + 1; - if (tempPos >= contentSize) - error("control marker at end of item"); - itemEntry->keyPress = tolower(content[tempPos]); - content.setChar(toupper(content[tempPos]), tempPos); - } - if (altPos) { - content.setChar(SCI_MENU_REPLACE_ONALT, altPos); - itemEntry->keyModifier = SCI_KEYMOD_ALT; - tempPos = altPos + 1; - if (tempPos >= contentSize) - error("alt marker at end of item"); - itemEntry->keyPress = tolower(content[tempPos]); - content.setChar(toupper(content[tempPos]), tempPos); - } - if (functionPos) { - content.setChar(SCI_MENU_REPLACE_ONFUNCTION, functionPos); - tempPos = functionPos + 1; - if (tempPos >= contentSize) - error("function marker at end of item"); - itemEntry->keyPress = content[tempPos]; - switch (content[functionPos + 1]) { - case '1': itemEntry->keyPress = SCI_KEY_F1; break; - case '2': itemEntry->keyPress = SCI_KEY_F2; break; - case '3': itemEntry->keyPress = SCI_KEY_F3; break; - case '4': itemEntry->keyPress = SCI_KEY_F4; break; - case '5': itemEntry->keyPress = SCI_KEY_F5; break; - case '6': itemEntry->keyPress = SCI_KEY_F6; break; - case '7': itemEntry->keyPress = SCI_KEY_F7; break; - case '8': itemEntry->keyPress = SCI_KEY_F8; break; - case '9': itemEntry->keyPress = SCI_KEY_F9; break; - case '0': itemEntry->keyPress = SCI_KEY_F10; break; - default: - error("illegal function key specified"); - } - } - - // Now get all strings - tempPos = endPos; - if (rightAlignedPos) { - tempPos = rightAlignedPos; - } else if (tagPos) { - tempPos = tagPos; - } - curPos = beginPos; - separatorCount = 0; - while (curPos < tempPos) { - switch (content[curPos]) { - case '!': - case '-': - case ' ': - separatorCount++; - } - curPos++; - } - if (separatorCount == tempPos - beginPos) { - itemEntry->separatorLine = true; - } else { - EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() - itemEntry->text = s->strSplit(Common::String(content.c_str() + beginPos, tempPos - beginPos).c_str()); - } - itemEntry->textVmPtr = contentVmPtr; - itemEntry->textVmPtr.offset += beginPos; - - if (rightAlignedPos) { - rightAlignedPos++; - tempPos = endPos; - // Shouldnt be needed at all, cause right aligned occurs after tag (hopefully) - // If no game is found that causes problems, remove this line (29.11.2009) - //if (tagPos && tagPos >= rightAlignedPos) - // tempPos = tagPos; - itemEntry->textRightAligned = Common::String(content.c_str() + rightAlignedPos, tempPos - rightAlignedPos); - } - - if (tagPos) { - tempPos = functionPos + 1; - if (tempPos >= contentSize) - error("tag marker at end of item"); - itemEntry->tag = atoi(content.c_str() + tempPos); - } - - curPos = endPos + 1; - - _itemList.push_back(itemEntry); - } while (curPos < contentSize); -} - -GuiMenuItemEntry *SciGuiMenu::findItem(uint16 menuId, uint16 itemId) { - GuiMenuItemList::iterator listIterator; - GuiMenuItemList::iterator listEnd = _itemList.end(); - GuiMenuItemEntry *listEntry; - - listIterator = _itemList.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - if ((listEntry->menuId == menuId) && (listEntry->id == itemId)) - return listEntry; - - listIterator++; - } - return NULL; -} - -void SciGuiMenu::setAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value) { - EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() - GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); - if (!itemEntry) - error("Tried to setAttribute() on non-existant menu-item %d:%d", menuId, itemId); - switch (attributeId) { - case SCI_MENU_ATTRIBUTE_ENABLED: - itemEntry->enabled = value.isNull() ? false : true; - break; - case SCI_MENU_ATTRIBUTE_SAID: - itemEntry->saidVmPtr = value; - break; - case SCI_MENU_ATTRIBUTE_TEXT: - itemEntry->text = s->strSplit(_segMan->getString(value).c_str()); - itemEntry->textVmPtr = value; - // We assume here that no script ever creates a separatorLine dynamically - break; - case SCI_MENU_ATTRIBUTE_KEYPRESS: - itemEntry->keyPress = tolower(value.offset); - itemEntry->keyModifier = 0; - // TODO: Find out how modifier is handled - printf("setAttr keypress %X %X\n", value.segment, value.offset); - break; - case SCI_MENU_ATTRIBUTE_TAG: - itemEntry->tag = value.offset; - break; - default: - // Happens when loading a game in LSL3 - attribute 1A - warning("setAttribute() called with unsupported attributeId %X", attributeId); - } -} - -reg_t SciGuiMenu::getAttribute(uint16 menuId, uint16 itemId, uint16 attributeId) { - GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); - if (!itemEntry) - error("Tried to getAttribute() on non-existant menu-item %d:%d", menuId, itemId); - switch (attributeId) { - case SCI_MENU_ATTRIBUTE_ENABLED: - if (itemEntry->enabled) - return make_reg(0, 1); - break; - case SCI_MENU_ATTRIBUTE_SAID: - return itemEntry->saidVmPtr; - case SCI_MENU_ATTRIBUTE_TEXT: - return itemEntry->textVmPtr; - case SCI_MENU_ATTRIBUTE_KEYPRESS: - // TODO: Find out how modifier is handled - return make_reg(0, itemEntry->keyPress); - case SCI_MENU_ATTRIBUTE_TAG: - return make_reg(0, itemEntry->tag); - default: - error("getAttribute() called with unsupported attributeId %X", attributeId); - } - return NULL_REG; -} - -void SciGuiMenu::drawBar() { - GuiMenuEntry *listEntry; - GuiMenuList::iterator listIterator; - GuiMenuList::iterator listEnd = _list.end(); - - // Hardcoded black on white - _gfx->FillRect(_gfx->_menuBarRect, 1, _screen->_colorWhite); - _gfx->PenColor(0); - _gfx->MoveTo(8, 1); - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - _text->Draw_String(listEntry->text.c_str()); - - listIterator++; - } -} - -// This helper calculates all text widths for all menus/items -void SciGuiMenu::calculateTextWidth() { - GuiMenuList::iterator menuIterator; - GuiMenuList::iterator menuEnd = _list.end(); - GuiMenuEntry *menuEntry; - GuiMenuItemList::iterator itemIterator; - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry; - int16 dummyHeight; - - menuIterator = _list.begin(); - while (menuIterator != menuEnd) { - menuEntry = *menuIterator; - _text->StringWidth(menuEntry->text.c_str(), 0, menuEntry->textWidth, dummyHeight); - - menuIterator++; - } - - itemIterator = _itemList.begin(); - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - _text->StringWidth(itemEntry->text.c_str(), 0, itemEntry->textWidth, dummyHeight); - _text->StringWidth(itemEntry->textRightAligned.c_str(), 0, itemEntry->textRightAlignedWidth, dummyHeight); - - itemIterator++; - } -} - -reg_t SciGuiMenu::select(reg_t eventObject) { - int16 eventType = GET_SEL32V(_segMan, eventObject, type); - int16 keyPress, keyModifier; - Common::Point mousePosition; - GuiMenuItemList::iterator itemIterator = _itemList.begin(); - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry = NULL; - bool forceClaimed = false; - EngineState *s; - byte saidSpec[64]; - - switch (eventType) { - case SCI_EVENT_KEYBOARD: - keyPress = GET_SEL32V(_segMan, eventObject, message); - keyModifier = GET_SEL32V(_segMan, eventObject, modifiers); - switch (keyPress) { - case 0: - break; - case SCI_KEY_ESC: - itemEntry = interactiveWithKeyboard(); - forceClaimed = true; - break; - default: - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - if ((itemEntry->keyPress == keyPress) && (itemEntry->keyModifier == keyModifier)) - break; - itemIterator++; - } - if (itemIterator == itemEnd) - itemEntry = NULL; - } - break; - - case SCI_EVENT_SAID: - // HACK: should be removed as soon as said() is cleaned up - s = ((SciEngine *)g_engine)->getEngineState(); - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - - if (!itemEntry->saidVmPtr.isNull()) { - // TODO: get a pointer to saidVmPtr or make said() work on VmPtrs - _segMan->memcpy(saidSpec, itemEntry->saidVmPtr, 64); - if (said(s, saidSpec, 0) != SAID_NO_MATCH) - break; - } - itemIterator++; - } - if (itemIterator == itemEnd) - itemEntry = NULL; - break; - - case SCI_EVENT_MOUSE_PRESS: - mousePosition = _cursor->getPosition(); - if (mousePosition.y < 10) { - itemEntry = interactiveWithMouse(); - forceClaimed = true; - } - break; - } - - if (!_menuSaveHandle.isNull()) { - _gfx->BitsRestore(_menuSaveHandle); - _gfx->BitsShow(_menuRect); - _menuSaveHandle = NULL_REG; - // TODO: Change to ReAnimate() - } - if (!_barSaveHandle.isNull()) { - _gfx->BitsRestore(_barSaveHandle); - _gfx->BitsShow(_gfx->_menuBarRect); - _barSaveHandle = NULL_REG; - } - if (_oldPort) - _gfx->SetPort(_oldPort); - - if ((itemEntry) || (forceClaimed)) - PUT_SEL32(_segMan, eventObject, claimed, make_reg(0, 1)); - if (itemEntry) - return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id)); - return NULL_REG; -} - -GuiMenuItemEntry *SciGuiMenu::interactiveGetItem(uint16 menuId, uint16 itemId, bool menuChanged) { - GuiMenuItemList::iterator itemIterator = _itemList.begin(); - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry; - GuiMenuItemEntry *firstItemEntry = NULL; - GuiMenuItemEntry *lastItemEntry = NULL; - - // Fixup menuId if needed - if (menuId > _listCount) - menuId = 1; - if (menuId == 0) - menuId = _listCount; - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - if (itemEntry->menuId == menuId) { - if (itemEntry->id == itemId) - return itemEntry; - if (!firstItemEntry) - firstItemEntry = itemEntry; - if ((!lastItemEntry) || (itemEntry->id > lastItemEntry->id)) - lastItemEntry = itemEntry; - } - itemIterator++; - } - if ((itemId == 0) || (menuChanged)) - return lastItemEntry; - return firstItemEntry; -} - -void SciGuiMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) { - GuiMenuEntry *listEntry; - GuiMenuList::iterator listIterator; - GuiMenuList::iterator listEnd = _list.end(); - GuiMenuItemEntry *listItemEntry; - GuiMenuItemList::iterator listItemIterator; - GuiMenuItemList::iterator listItemEnd = _itemList.end(); - Common::Rect menuTextRect; - uint16 listNr = 0; - int16 maxTextWidth = 0, maxTextRightAlignedWidth = 0; - int16 topPos; - Common::Point pixelPos; - - // Remove menu, if one is displayed - if (!_menuSaveHandle.isNull()) { - _gfx->BitsRestore(_menuSaveHandle); - _gfx->BitsShow(_menuRect); - // TODO: Change to ReAnimate() - } - - // First calculate rect of menu and also invert old and new menu text - _menuRect.top = _gfx->_menuBarRect.bottom; - menuTextRect.top = _gfx->_menuBarRect.top; - menuTextRect.bottom = _gfx->_menuBarRect.bottom; - menuTextRect.left = menuTextRect.right = 7; - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - listNr++; - menuTextRect.left = menuTextRect.right; - menuTextRect.right += listEntry->textWidth; - if (listNr == newMenuId) - _menuRect.left = menuTextRect.left; - if ((listNr == newMenuId) || (listNr == oldMenuId)) { - menuTextRect.translate(1, 0); - _gfx->InvertRect(menuTextRect); - menuTextRect.translate(-1, 0); - } - - listIterator++; - } - if (oldMenuId != 0) - _gfx->BitsShow(_gfx->_menuBarRect); - - _menuRect.bottom = _menuRect.top + 2; - listItemIterator = _itemList.begin(); - while (listItemIterator != listItemEnd) { - listItemEntry = *listItemIterator; - if (listItemEntry->menuId == newMenuId) { - _menuRect.bottom += _gfx->_curPort->fontHeight; - maxTextWidth = MAX<int16>(maxTextWidth, listItemEntry->textWidth); - maxTextRightAlignedWidth = MAX<int16>(maxTextRightAlignedWidth, listItemEntry->textRightAlignedWidth); - } - listItemIterator++; - } - _menuRect.right = _menuRect.left + 16 + 4 + 2; - _menuRect.right += maxTextWidth + maxTextRightAlignedWidth; - if (!maxTextRightAlignedWidth) - _menuRect.right -= 5; - - // Save background - _menuSaveHandle = _gfx->BitsSave(_menuRect, SCI_SCREEN_MASK_VISUAL); - - // Do the drawing - _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, 0); - _menuRect.left++; _menuRect.right--; _menuRect.bottom--; - _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, _screen->_colorWhite); - - _menuRect.left += 8; - topPos = _menuRect.top + 1; - listItemIterator = _itemList.begin(); - while (listItemIterator != listItemEnd) { - listItemEntry = *listItemIterator; - if (listItemEntry->menuId == newMenuId) { - if (!listItemEntry->separatorLine) { - _gfx->TextGreyedOutput(listItemEntry->enabled ? false : true); - _gfx->MoveTo(_menuRect.left, topPos); - _text->Draw_String(listItemEntry->text.c_str()); - _gfx->MoveTo(_menuRect.right - listItemEntry->textRightAlignedWidth - 5, topPos); - _text->Draw_String(listItemEntry->textRightAligned.c_str()); - } else { - // We dont 100% follow sierra here, we draw the line from left to right. Looks better - // BTW. SCI1.1 seems to put 2 pixels and then skip one, we don't do this at all (lsl6) - pixelPos.y = topPos + (_gfx->_curPort->fontHeight >> 1) - 1; - pixelPos.x = _menuRect.left - 7; - while (pixelPos.x < (_menuRect.right - 1)) { - _screen->putPixel(pixelPos.x, pixelPos.y, SCI_SCREEN_MASK_VISUAL, 0, 0, 0); - pixelPos.x += 2; - } - } - topPos += _gfx->_curPort->fontHeight; - } - listItemIterator++; - } - _gfx->TextGreyedOutput(false); - - - _menuRect.left -= 8; - _menuRect.left--; _menuRect.right++; _menuRect.bottom++; - _gfx->BitsShow(_menuRect); -} - -void SciGuiMenu::invertMenuSelection(uint16 itemId) { - Common::Rect itemRect = _menuRect; - - itemRect.top += (itemId - 1) * _gfx->_curPort->fontHeight; - itemRect.bottom = itemRect.top + _gfx->_curPort->fontHeight + 1; - itemRect.left++; itemRect.right--; - - _gfx->InvertRect(itemRect); - _gfx->BitsShow(itemRect); -} - -GuiMenuItemEntry *SciGuiMenu::interactiveWithKeyboard() { - sciEvent curEvent; - uint16 newMenuId = _curMenuId; - uint16 newItemId = _curItemId; - GuiMenuItemEntry *curItemEntry = findItem(_curMenuId, _curItemId); - GuiMenuItemEntry *newItemEntry = curItemEntry; - - // We don't 100% follow sierra here: we select last item instead of selecting first item of first menu everytime - - calculateTextWidth(); - _oldPort = _gfx->SetPort(_gfx->_menuPort); - _barSaveHandle = _gfx->BitsSave(_gfx->_menuBarRect, SCI_SCREEN_MASK_VISUAL); - - _gfx->PenColor(0); - _gfx->BackColor(_screen->_colorWhite); - - drawBar(); - drawMenu(0, curItemEntry->menuId); - invertMenuSelection(curItemEntry->id); - _gfx->BitsShow(_gfx->_menuBarRect); - _gfx->BitsShow(_menuRect); - - while (true) { - curEvent = _event->get(SCI_EVENT_ANY); - - switch (curEvent.type) { - case SCI_EVENT_KEYBOARD: - // We don't 100% follow sierra here: - sierra didn't wrap around when changing item id - // - sierra allowed item id to be 0, which didnt make any sense - do { - switch (curEvent.data) { - case SCI_KEY_ESC: - _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; - return NULL; - case SCI_KEY_ENTER: - if (curItemEntry->enabled) { - _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; - return curItemEntry; - } - break; - case SCI_KEY_LEFT: - newMenuId--; newItemId = 1; - break; - case SCI_KEY_RIGHT: - newMenuId++; newItemId = 1; - break; - case SCI_KEY_UP: - newItemId--; - break; - case SCI_KEY_DOWN: - newItemId++; - break; - } - if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { - // Selection changed, fix up new selection if required - newItemEntry = interactiveGetItem(newMenuId, newItemId, newMenuId != curItemEntry->menuId); - newMenuId = newItemEntry->menuId; newItemId = newItemEntry->id; - - // if we do this step again because of a separator line -> don't repeat left/right, but go down - switch (curEvent.data) { - case SCI_KEY_LEFT: - case SCI_KEY_RIGHT: - curEvent.data = SCI_KEY_DOWN; - } - } - } while (newItemEntry->separatorLine); - if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { - // paint old and new - if (newMenuId != curItemEntry->menuId) { - // Menu changed, remove cur menu and paint new menu - drawMenu(curItemEntry->menuId, newMenuId); - } else { - invertMenuSelection(curItemEntry->id); - } - invertMenuSelection(newItemId); - - curItemEntry = newItemEntry; - } - break; - - case SCI_EVENT_NONE: - kernel_sleep(_event, 2500 / 1000); - break; - } - } -} - -GuiMenuItemEntry *SciGuiMenu::interactiveWithMouse() { - calculateTextWidth(); - - // TODO - - return NULL; -} - -} // End of namespace Sci |