/* 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 "m4/m4_views.h" #include "m4/events.h" #include "m4/font.h" #include "m4/globals.h" #include "m4/m4.h" namespace M4 { GUIInventory::GUIInventory(View *owner, M4Engine *vm, const Common::Rect &bounds, int horizCells, int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) { _vm = vm; _cellCount.x = horizCells; _cellCount.y = vertCells; _cellSize.x = cellWidth; _cellSize.y = cellHeight; // Validate the cell settings if ((_cellCount.x * _cellSize.x > _bounds.width()) || (_cellCount.y * _cellSize.y > _bounds.height())) error("Cell settings for inventory display exceeded control size"); _visible = true; _scrollPosition = 0; _scrollable = false; _highlightedIndex = -1; _selectedIndex = -1; } void GUIInventory::onRefresh() { _parent->fillRect(_bounds, _vm->_palette->BLACK); //_parent->frameRect(_bounds, _vm->_palette->LIGHT_GRAY); if (_visible) { //kernel_trigger_dispatch(kernel_trigger_create(TRIG_INV_CLICK)); _scrollable = false; // Get to the starting inventory position for display ItemsIterator i = _inventoryItems.begin(); int index = _scrollPosition; while (index-- > 0) ++i; // Loop through displaying entries for (index = 0; (i != _inventoryItems.end()) && (index < _cellCount.x * _cellCount.y); ++index, ++i) { GUIInventoryItem *item = (*i).get(); const Common::Point cellPos = getCellPosition(index); /* Common::Rect cellBounds(_bounds.left + cellPos.x + xOffset, _bounds.top + cellPos.y + yOffset, _bounds.left + cellPos.x + xOffset + _cellSize.x, _bounds.top + cellPos.y + _cellSize.y);*/ Common::Rect cellBounds(_bounds.left + cellPos.x, _bounds.top + cellPos.y, _bounds.left + cellPos.x + _cellSize.x, _bounds.top + cellPos.y + _cellSize.y); Common::Point iconPt( cellBounds.left + (cellBounds.width() - item->icon->width()) / 2, cellBounds.top + (cellBounds.height() - item->icon->height()) / 2); item->icon->copyTo(_parent, iconPt.x, iconPt.y, 0); if (_highlightedIndex == index) _parent->frameRect(Common::Rect(iconPt.x - 2, iconPt.y - 2, iconPt.x + item->icon->width() + 2, iconPt.y + item->icon->height() + 2), _vm->_palette->LIGHT_GRAY); } } } bool GUIInventory::onEvent(M4EventType eventType, int param, int x, int y, GUIObject *¤tItem) { bool result = false; int overIndex = getInsideIndex(x, y); bool isPressed = (eventType == MEVENT_LEFT_CLICK) || (eventType == MEVENT_LEFT_HOLD) || (eventType == MEVENT_LEFT_DRAG); ItemsIterator curItem = _inventoryItems.begin(); if (isPressed) { if (_selectedIndex == -1 && overIndex != -1) { setHighlight(overIndex); _selectedIndex = overIndex; for (int i = 0; i < _scrollPosition + _selectedIndex; i++) ++curItem; if (_scrollPosition + _selectedIndex < (int)_inventoryItems.size()) _vm->_mouse->setCursorNum(curItem->get()->iconIndex); result = true; } else { // We are over something being tracked if (_selectedIndex == overIndex) { setHighlight(overIndex); result = true; } else { // Otherwise reset highlighting setHighlight(-1); result = false; } } } else { // No button pressed if (_selectedIndex == overIndex) { result = (_selectedIndex != -1); } else { result = (overIndex + _scrollPosition < (int)_inventoryItems.size()); if (result) { for (int i = 0; i < overIndex + _scrollPosition; i++) ++curItem; _vm->_interfaceView->setStatusText(curItem->get()->name); } } // Stop tracking anything setHighlight(overIndex); } return result; } void GUIInventory::add(const char *name, const char *verb, M4Surface *icon, int iconIndex) { // First scan through the list to prevent duplicate objects for (ItemsIterator i = _inventoryItems.begin(); i != _inventoryItems.end(); ++i) { if (!strcmp(name, ((*i).get())->name)) return; } _inventoryItems.push_back(InventoryList::value_type(new GUIInventoryItem(name, verb, icon, iconIndex))); } bool GUIInventory::remove(const char *name) { for (ItemsIterator i = _inventoryItems.begin(); i != _inventoryItems.end(); ++i) { if (!strcmp(name, ((*i).get())->name)) { _inventoryItems.erase(i); _scrollPosition = 0; return true; } } return false; } int GUIInventory::getInsideIndex(int x, int y) { if (!_bounds.contains(x, y)) return -1; int localX = x - _bounds.left; int localY = y - _bounds.top; return (localX / _cellSize.x) * _cellCount.y + (localY / _cellSize.y); } const char *GUIInventory::getSelectedObjectName() { if (_selectedIndex != -1) { ItemsIterator curItem = _inventoryItems.begin(); for (int i = 0; i < _selectedIndex; i++) ++curItem; return curItem->get()->name; } else { return NULL; } } const Common::Point &GUIInventory::getCellPosition(int index) { static Common::Point result; if (_cellCount.x > _cellCount.y) { // Horizontal orientation result.x = (index / _cellCount.y) * _cellSize.x; result.y = (index % _cellCount.y) * _cellSize.x; } else { // Vertical orientation result.x = (index / _cellCount.x) * _cellSize.y; result.y = (index % _cellCount.x) * _cellSize.y; } return result; } void GUIInventory::setHighlight(int index) { if (_highlightedIndex == index) return; _highlightedIndex = index; } void GUIInventory::setScrollPosition(int value) { if (value < 0) return; else if (value >= (int)_inventoryItems.size() - (_cellCount.x * _cellCount.y)) return; _scrollPosition = value; } //-------------------------------------------------------------------------- const char *INTERFACE_SERIES = "999intr"; #define SPR(x) _sprites->getFrame(x) GameInterfaceView::GameInterfaceView(M4Engine *vm): View(vm, Common::Rect(0, vm->_screen->height() - INTERFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())), _statusText(GUITextField(this, Common::Rect(200, 1, 450, 21))), _inventory(GUIInventory(this, vm, Common::Rect(188, 22, 539, 97), 9, 1, 39, 75, 3)) { _screenType = VIEWID_INTERFACE; _screenFlags.layer = LAYER_INTERFACE; _screenFlags.visible = false; _screenFlags.get = SCREVENT_MOUSE; _highlightedIndex = -1; _selected = false; Common::SeekableReadStream *data = _vm->res()->get(INTERFACE_SERIES); RGB8 *palette; _sprites = new SpriteAsset(_vm, data, data->size(), INTERFACE_SERIES); palette = _sprites->getPalette(); //Palette.setPalette(palette, 0, _sprites->getColorCount()); _vm->res()->toss(INTERFACE_SERIES); // Setup the interface buttons _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(15, 35, 47, 66), 0, SPR(0), SPR(1), SPR(2)))); // look _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(60, 35, 92, 66), 1, SPR(3), SPR(4), SPR(5)))); // take _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(105, 35, 137, 66), 2, SPR(6), SPR(7), SPR(8)))); // manipulate _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(580, 10, 620, 69), 3, SPR(69), SPR(70), SPR(71)))); // abduction _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(582, 70, 619, 105), 4, SPR(76), SPR(77), SPR(78)))); // menu _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(168, 22, 188, 97), 5, SPR(60), SPR(61), SPR(62)))); // Scroll left _buttons.push_back(ButtonList::value_type(new GUIButton(this, Common::Rect(539, 22, 559, 97), 6, SPR(64), SPR(65), SPR(66)))); // Scroll right } #undef SPR GameInterfaceView::~GameInterfaceView() { delete _sprites; } void GameInterfaceView::setHighlightedButton(int index) { if (index == _highlightedIndex) return; _selected = (index == -1); _highlightedIndex = index; } bool GameInterfaceView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) { static bool selectionFlag = false; if (eventType == MEVENT_LEFT_RELEASE) selectionFlag = false; captureEvents = isInside(x, y); if (!captureEvents) return false; int localX = x - _coords.left; int localY = y - _coords.top; GUIObject *currentItem; _statusText.onEvent(eventType, param, localX, localY, currentItem); _inventory.onEvent(eventType, param, localX, localY, currentItem); if (_vm->_mouse->getCursorNum() != CURSOR_LOOK && _vm->_mouse->getCursorNum() != CURSOR_TAKE && _vm->_mouse->getCursorNum() != CURSOR_USE && _vm->_interfaceView->_inventory.getSelectedIndex() == -1) { if (_vm->_mouse->getCursorNum() != 0) _vm->_mouse->setCursorNum(0); } for (ButtonsIterator i = _buttons.begin(); i != _buttons.end(); ++i) { GUIButton *btn = (*i).get(); btn->onEvent(eventType, param, localX, localY, currentItem); if ((btn->getState() == BUTTON_PRESSED) && !selectionFlag) { selectionFlag = true; _highlightedIndex = btn->getTag(); switch (_highlightedIndex) { case 0: _vm->_mouse->setCursorNum(CURSOR_LOOK); break; case 1: _vm->_mouse->setCursorNum(CURSOR_TAKE); break; case 2: _vm->_mouse->setCursorNum(CURSOR_USE); break; case 3: // TODO: Jump to abduction break; case 4: _vm->loadMenu(GAME_MENU); break; case 5: _inventory.scrollLeft(); break; case 6: _inventory.scrollRight(); break; default: break; } } } return true; } void GameInterfaceView::onRefresh(RectList *rects, M4Surface *destSurface) { clear(); _statusText.onRefresh(); _inventory.onRefresh(); for (ButtonsIterator i = _buttons.begin(); i != _buttons.end(); ++i) ((*i).get())->onRefresh(); View::onRefresh(rects, destSurface); } } // End of namespace M4