/* 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 3 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, see . * */ #include "ultima/ultima4/views/menu.h" #include "ultima/ultima4/views/menuitem.h" #include "ultima/ultima4/core/settings.h" #include "ultima/ultima4/core/utils.h" namespace Ultima { namespace Ultima4 { MenuItem::MenuItem(const Common::String &t, short x, short y, int sc) : _id(-1), _x(x), _y(y), _text(t), _highlighted(false), _selected(false), _visible(true), _scOffset(sc), _closesMenu(false) { // if the sc/scOffset is outside the range of the text string, assert assertMsg(sc == -1 || (sc >= 0 && sc <= (int)_text.size()), "sc value of %d out of range!", sc); if (sc != -1) addShortcutKey(tolower(_text[sc])); } int MenuItem::getId() const { return _id; } short MenuItem::getX() const { return _x; } short MenuItem::getY() const { return _y; } int MenuItem::getScOffset() const { return _scOffset; } Common::String MenuItem::getText() const { return _text; } bool MenuItem::isHighlighted() const { return _highlighted; } bool MenuItem::isSelected() const { return _selected; } bool MenuItem::isVisible() const { return _visible; } bool MenuItem::hasShortcutKey(int sc) const { Common::Array::const_iterator begin = _shortcutKeys.begin(); Common::Array::const_iterator end = _shortcutKeys.end(); return (Common::find(begin, end, sc) != end); } bool MenuItem::getClosesMenu() const { return _closesMenu; } void MenuItem::setId(int i) { _id = i; } void MenuItem::setX(int x) { _x = x; } void MenuItem::setY(int y) { _y = y; } void MenuItem::setText(const Common::String &t) { _text = t; } void MenuItem::setHighlighted(bool h) { _highlighted = h; } void MenuItem::setSelected(bool s) { _selected = s; } void MenuItem::setVisible(bool v) { _visible = v; } void MenuItem::addShortcutKey(int sc) { if (!hasShortcutKey(sc)) _shortcutKeys.push_back(sc); } void MenuItem::setClosesMenu(bool closesMenu) { this->_closesMenu = closesMenu; } BoolMenuItem::BoolMenuItem(const Common::String &text, short xp, short yp, int shortcutKey, bool *val) : MenuItem(text, xp, yp, shortcutKey), _val(val), _on("On"), _off("Off") { } BoolMenuItem *BoolMenuItem::setValueStrings(const Common::String &onString, const Common::String &offString) { _on = onString; _off = offString; return this; } Common::String BoolMenuItem::getText() const { char buffer[64]; snprintf(buffer, sizeof(buffer), _text.c_str(), *_val ? _on.c_str() : _off.c_str()); return buffer; } void BoolMenuItem::activate(MenuEvent &event) { if (event.getType() == MenuEvent::DECREMENT || event.getType() == MenuEvent::INCREMENT || event.getType() == MenuEvent::ACTIVATE) *_val = !(*_val); } StringMenuItem::StringMenuItem(const Common::String &text, short xp, short yp, int shortcutKey, Common::String *val, const Std::vector &validSettings) : MenuItem(text, xp, yp, shortcutKey), _val(val), _validSettings(validSettings) { } Common::String StringMenuItem::getText() const { char buffer[64]; snprintf(buffer, sizeof(buffer), _text.c_str(), _val->c_str()); return buffer; } void StringMenuItem::activate(MenuEvent &event) { Std::vector::const_iterator current = find(_validSettings.begin(), _validSettings.end(), *_val); if (current == _validSettings.end()) error("Error: menu Common::String '%s' not a valid choice", _val->c_str()); if (event.getType() == MenuEvent::INCREMENT || event.getType() == MenuEvent::ACTIVATE) { /* move to the next valid choice, wrapping if necessary */ current++; if (current == _validSettings.end()) current = _validSettings.begin(); *_val = *current; } else if (event.getType() == MenuEvent::DECREMENT) { /* move back one, wrapping if necessary */ if (current == _validSettings.begin()) current = _validSettings.end(); current--; *_val = *current; } } IntMenuItem::IntMenuItem(const Common::String &text, short xp, short yp, int shortcutKey, int *val, int min, int max, int increment, menuOutputType output) : MenuItem(text, xp, yp, shortcutKey), _val(val), _min(min), _max(max), _increment(increment), _output(output) { } Common::String IntMenuItem::getText() const { // do custom formatting for some menu entries, // and generate a Common::String of the results char outputBuffer[20]; switch (_output) { case MENU_OUTPUT_REAGENT: snprintf(outputBuffer, sizeof(outputBuffer), "%2d", static_cast(*_val)); break; case MENU_OUTPUT_GAMMA: snprintf(outputBuffer, sizeof(outputBuffer), "%.1f", static_cast(*_val) / 100); break; case MENU_OUTPUT_SHRINE: /* * is this code really necessary? the increments/decrements can be handled by IntMenuItem(), * as well as the looping once the max is reached. more importantly, the minimum value is * inconstant, and based upon another setting that can be changed independent of this one. * This variable could be set to it's minimum value, but when the gameCyclesPerSecond setting * is changed, the value of this setting could become out of bounds. * * settings.shrineTime is only used in one function within shrine.cpp, and that code appears * to handle the min value, caping the minimum interval at 1. * // make sure that the setting we're trying for is even possible if (event.getType() == MenuEvent::INCREMENT || event.getType() == MenuEvent::ACTIVATE) { settingsChanged.shrineTime++; if (settingsChanged.shrineTime > MAX_SHRINE_TIME) settingsChanged.shrineTime = MEDITATION_MANTRAS_PER_CYCLE / settingsChanged.gameCyclesPerSecond; } else if (event.getType() == MenuEvent::DECREMENT) { settingsChanged.shrineTime--; if (settingsChanged.shrineTime < (MEDITATION_MANTRAS_PER_CYCLE / settingsChanged.gameCyclesPerSecond)) settingsChanged.shrineTime = MAX_SHRINE_TIME; } * */ snprintf(outputBuffer, sizeof(outputBuffer), "%d sec", *_val); break; case MENU_OUTPUT_SPELL: snprintf(outputBuffer, sizeof(outputBuffer), "%3g sec", static_cast(*_val) / 5); break; case MENU_OUTPUT_VOLUME: if (*_val == 0) { snprintf(outputBuffer, sizeof(outputBuffer), "Disabled"); } else if (*_val == MAX_VOLUME) { snprintf(outputBuffer, sizeof(outputBuffer), "Full"); } else { snprintf(outputBuffer, sizeof(outputBuffer), "%d%s%s", *_val * 10, "%", "%"); } break; default: break; } // the buffer must contain a field character %d or %s depending // on the menuOutputType selected. MENU_OUTPUT_INT always uses // %d, whereas all others use %s char buffer[64]; if (_output != MENU_OUTPUT_INT) snprintf(buffer, sizeof(buffer), _text.c_str(), outputBuffer); else snprintf(buffer, sizeof(buffer), _text.c_str(), *_val); return buffer; } void IntMenuItem::activate(MenuEvent &event) { if (event.getType() == MenuEvent::INCREMENT || event.getType() == MenuEvent::ACTIVATE) { *_val += _increment; if (*_val > _max) *_val = _min; } else if (event.getType() == MenuEvent::DECREMENT) { *_val -= _increment; if (*_val < _min) *_val = _max; } } } // End of namespace Ultima4 } // End of namespace Ultima