diff options
Diffstat (limited to 'sword2/controls.cpp')
| -rw-r--r-- | sword2/controls.cpp | 1416 |
1 files changed, 0 insertions, 1416 deletions
diff --git a/sword2/controls.cpp b/sword2/controls.cpp deleted file mode 100644 index df1b38c83e..0000000000 --- a/sword2/controls.cpp +++ /dev/null @@ -1,1416 +0,0 @@ -/* Copyright (C) 1994-1998 Revolution Software Ltd. - * Copyright (C) 2003-2006 The ScummVM project - * - * 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/stdafx.h" -#include "common/rect.h" -#include "common/config-manager.h" -#include "common/system.h" - -#include "sword2/sword2.h" -#include "sword2/defs.h" -#include "sword2/controls.h" -#include "sword2/mouse.h" -#include "sword2/resman.h" -#include "sword2/sound.h" - -#define MAX_STRING_LEN 64 // 20 was too low; better to be safe ;) -#define CHARACTER_OVERLAP 2 // overlap characters by 3 pixels - -// our fonts start on SPACE character (32) -#define SIZE_OF_CHAR_SET (256 - 32) - -namespace Sword2 { - -static int baseSlot = 0; - -class Widget; - -/** - * Base class for all widgets. - */ - -class Widget { -protected: - Sword2Engine *_vm; - Dialog *_parent; - - SpriteInfo *_sprites; - - struct WidgetSurface { - byte *_surface; - bool _original; - }; - - WidgetSurface *_surfaces; - int _numStates; - int _state; - - Common::Rect _hitRect; - -public: - Widget(Dialog *parent, int states); - - virtual ~Widget(); - - void createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc); - void linkSurfaceImage(Widget *from, int state, int x, int y); - - void createSurfaceImages(uint32 res, int x, int y); - void linkSurfaceImages(Widget *from, int x, int y); - - void setHitRect(int x, int y, int width, int height); - bool isHit(int16 x, int16 y); - - void setState(int state); - int getState(); - - virtual void paint(Common::Rect *clipRect = NULL); - - virtual void onMouseEnter() {} - virtual void onMouseExit() {} - virtual void onMouseMove(int x, int y) {} - virtual void onMouseDown(int x, int y) {} - virtual void onMouseUp(int x, int y) {} - virtual void onWheelUp(int x, int y) {} - virtual void onWheelDown(int x, int y) {} - virtual void onKey(KeyboardEvent *ke) {} - virtual void onTick() {} - - virtual void releaseMouse(int x, int y) {} -}; - -/** - * This class is used to draw text in dialogs, buttons, etc. - */ - -class FontRendererGui { -private: - Sword2Engine *_vm; - - struct Glyph { - byte *_data; - int _width; - int _height; - }; - - Glyph _glyph[SIZE_OF_CHAR_SET]; - - int _fontId; - -public: - enum { - kAlignLeft, - kAlignRight, - kAlignCenter - }; - - FontRendererGui(Sword2Engine *vm, int fontId); - ~FontRendererGui(); - - void fetchText(uint32 textId, byte *buf); - - int getCharWidth(byte c); - int getCharHeight(byte c); - - int getTextWidth(byte *text); - int getTextWidth(uint32 textId); - - void drawText(byte *text, int x, int y, int alignment = kAlignLeft); - void drawText(uint32 textId, int x, int y, int alignment = kAlignLeft); -}; - -FontRendererGui::FontRendererGui(Sword2Engine *vm, int fontId) - : _vm(vm), _fontId(fontId) { - byte *font = _vm->_resman->openResource(fontId); - SpriteInfo sprite; - - sprite.type = RDSPR_NOCOMPRESSION | RDSPR_TRANS; - - for (int i = 0; i < SIZE_OF_CHAR_SET; i++) { - byte *frame = _vm->fetchFrameHeader(font, i); - - FrameHeader frame_head; - - frame_head.read(frame); - - sprite.data = frame + FrameHeader::size(); - sprite.w = frame_head.width; - sprite.h = frame_head.height; - _vm->_screen->createSurface(&sprite, &_glyph[i]._data); - _glyph[i]._width = frame_head.width; - _glyph[i]._height = frame_head.height; - } - - _vm->_resman->closeResource(fontId); -} - -FontRendererGui::~FontRendererGui() { - for (int i = 0; i < SIZE_OF_CHAR_SET; i++) - _vm->_screen->deleteSurface(_glyph[i]._data); -} - -void FontRendererGui::fetchText(uint32 textId, byte *buf) { - byte *data = _vm->fetchTextLine(_vm->_resman->openResource(textId / SIZE), textId & 0xffff); - int i; - - for (i = 0; data[i + 2]; i++) { - if (buf) - buf[i] = data[i + 2]; - } - - buf[i] = 0; - _vm->_resman->closeResource(textId / SIZE); -} - -int FontRendererGui::getCharWidth(byte c) { - if (c < 32) - return 0; - return _glyph[c - 32]._width; -} - -int FontRendererGui::getCharHeight(byte c) { - if (c < 32) - return 0; - return _glyph[c - 32]._height; -} - -int FontRendererGui::getTextWidth(byte *text) { - int textWidth = 0; - - for (int i = 0; text[i]; i++) - if (text[i] >= ' ') - textWidth += (getCharWidth(text[i]) - CHARACTER_OVERLAP); - return textWidth; -} - -int FontRendererGui::getTextWidth(uint32 textId) { - byte text[MAX_STRING_LEN]; - - fetchText(textId, text); - return getTextWidth(text); -} - -void FontRendererGui::drawText(byte *text, int x, int y, int alignment) { - SpriteInfo sprite; - int i; - - if (alignment != kAlignLeft) { - int textWidth = getTextWidth(text); - - switch (alignment) { - case kAlignRight: - x -= textWidth; - break; - case kAlignCenter: - x -= (textWidth / 2); - break; - } - } - - sprite.x = x; - sprite.y = y; - - for (i = 0; text[i]; i++) { - if (text[i] >= ' ') { - sprite.w = getCharWidth(text[i]); - sprite.h = getCharHeight(text[i]); - - _vm->_screen->drawSurface(&sprite, _glyph[text[i] - 32]._data); - - sprite.x += (getCharWidth(text[i]) - CHARACTER_OVERLAP); - } - } -} - -void FontRendererGui::drawText(uint32 textId, int x, int y, int alignment) { - byte text[MAX_STRING_LEN]; - - fetchText(textId, text); - drawText(text, x, y, alignment); -} - -// -// Dialog class functions -// - -Dialog::Dialog(Sword2Engine *vm) - : _numWidgets(0), _finish(false), _result(0), _vm(vm) { - _vm->_screen->setFullPalette(CONTROL_PANEL_PALETTE); - _vm->_screen->clearScene(); - _vm->_screen->updateDisplay(); - - // Usually the mouse pointer will already be "normal", but not always. - _vm->_mouse->setMouse(NORMAL_MOUSE_ID); -} - -Dialog::~Dialog() { - for (int i = 0; i < _numWidgets; i++) - delete _widgets[i]; - _vm->_screen->clearScene(); - _vm->_screen->updateDisplay(); -} - -void Dialog::registerWidget(Widget *widget) { - if (_numWidgets < MAX_WIDGETS) - _widgets[_numWidgets++] = widget; -} - -void Dialog::paint() { - _vm->_screen->clearScene(); - for (int i = 0; i < _numWidgets; i++) - _widgets[i]->paint(); -} - -void Dialog::setResult(int result) { - _result = result; - _finish = true; -} - -int Dialog::runModal() { - uint32 oldFilter = _vm->setInputEventFilter(0); - - int i; - - paint(); - - int oldMouseX = -1; - int oldMouseY = -1; - - while (!_finish) { - // So that the menu icons will reach their full size - _vm->_mouse->processMenu(); - _vm->_screen->updateDisplay(false); - - int newMouseX, newMouseY; - - _vm->_mouse->getPos(newMouseX, newMouseY); - - newMouseY += 40; - - MouseEvent *me = _vm->mouseEvent(); - KeyboardEvent *ke = _vm->keyboardEvent(); - - if (ke) { - if (ke->keycode == 27) - setResult(0); - else if (ke->keycode == '\n' || ke->keycode == '\r') - setResult(1); - } - - int oldHit = -1; - int newHit = -1; - - // Find out which widget the mouse was over the last time, and - // which it is currently over. This assumes the widgets do not - // overlap. - - for (i = 0; i < _numWidgets; i++) { - if (_widgets[i]->isHit(oldMouseX, oldMouseY)) - oldHit = i; - if (_widgets[i]->isHit(newMouseX, newMouseY)) - newHit = i; - } - - // Was the mouse inside a widget the last time? - - if (oldHit >= 0) { - if (newHit != oldHit) - _widgets[oldHit]->onMouseExit(); - } - - // Is the mouse currently in a widget? - - if (newHit >= 0) { - if (newHit != oldHit) - _widgets[newHit]->onMouseEnter(); - - if (me) { - switch (me->buttons) { - case RD_LEFTBUTTONDOWN: - _widgets[newHit]->onMouseDown(newMouseX, newMouseY); - break; - case RD_LEFTBUTTONUP: - _widgets[newHit]->onMouseUp(newMouseX, newMouseY); - break; - case RD_WHEELUP: - _widgets[newHit]->onWheelUp(newMouseX, newMouseY); - break; - case RD_WHEELDOWN: - _widgets[newHit]->onWheelDown(newMouseX, newMouseY); - break; - } - } - } - - // Some events are passed to the widgets regardless of where - // the mouse cursor is. - - for (i = 0; i < _numWidgets; i++) { - if (me && me->buttons == RD_LEFTBUTTONUP) { - // So that slider widgets will know when the - // user releases the mouse button, even if the - // cursor is outside of the slider's hit area. - _widgets[i]->releaseMouse(newMouseX, newMouseY); - } - - // This is to make it easier to drag the slider widget - - if (newMouseX != oldMouseX || newMouseY != oldMouseY) - _widgets[i]->onMouseMove(newMouseX, newMouseY); - - if (ke) - _widgets[i]->onKey(ke); - - _widgets[i]->onTick(); - } - - oldMouseX = newMouseX; - oldMouseY = newMouseY; - - _vm->_system->delayMillis(20); - - if (_vm->_quit) - setResult(0); - } - - _vm->setInputEventFilter(oldFilter); - return _result; -} - -// -// Widget functions -// - -Widget::Widget(Dialog *parent, int states) - : _vm(parent->_vm), _parent(parent), _numStates(states), _state(0) { - _sprites = (SpriteInfo *)calloc(states, sizeof(SpriteInfo)); - _surfaces = (WidgetSurface *)calloc(states, sizeof(WidgetSurface)); - - _hitRect.left = _hitRect.right = _hitRect.top = _hitRect.bottom = -1; -} - -Widget::~Widget() { - for (int i = 0; i < _numStates; i++) { - if (_surfaces[i]._original) - _vm->_screen->deleteSurface(_surfaces[i]._surface); - } - free(_sprites); - free(_surfaces); -} - -void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) { - byte *file, *colTablePtr = NULL; - AnimHeader anim_head; - FrameHeader frame_head; - CdtEntry cdt_entry; - uint32 spriteType = RDSPR_TRANS; - - // open anim resource file, point to base - file = _vm->_resman->openResource(res); - - byte *frame = _vm->fetchFrameHeader(file, pc); - - anim_head.read(_vm->fetchAnimHeader(file)); - cdt_entry.read(_vm->fetchCdtEntry(file, pc)); - frame_head.read(frame); - - // If the frame is flipped. (Only really applicable to frames using - // offsets.) - - if (cdt_entry.frameType & FRAME_FLIPPED) - spriteType |= RDSPR_FLIP; - - // Which compression was used? - - switch (anim_head.runTimeComp) { - case NONE: - spriteType |= RDSPR_NOCOMPRESSION; - break; - case RLE256: - spriteType |= RDSPR_RLE256; - break; - case RLE16: - spriteType |= RDSPR_RLE256; - // Points to just after last cdt_entry, i.e. start of colour - // table - colTablePtr = _vm->fetchAnimHeader(file) + AnimHeader::size() - + anim_head.noAnimFrames * CdtEntry::size(); - break; - } - - _sprites[state].x = x; - _sprites[state].y = y; - _sprites[state].w = frame_head.width; - _sprites[state].h = frame_head.height; - _sprites[state].scale = 0; - _sprites[state].type = spriteType; - _sprites[state].blend = anim_head.blend; - - // Points to just after frame header, ie. start of sprite data - _sprites[state].data = frame + FrameHeader::size(); - - _vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); - _surfaces[state]._original = true; - - // Release the anim resource - _vm->_resman->closeResource(res); -} - -void Widget::linkSurfaceImage(Widget *from, int state, int x, int y) { - _sprites[state].x = x; - _sprites[state].y = y; - _sprites[state].w = from->_sprites[state].w; - _sprites[state].h = from->_sprites[state].h; - _sprites[state].scale = from->_sprites[state].scale; - _sprites[state].type = from->_sprites[state].type; - _sprites[state].blend = from->_sprites[state].blend; - - _surfaces[state]._surface = from->_surfaces[state]._surface; - _surfaces[state]._original = false; -} - -void Widget::createSurfaceImages(uint32 res, int x, int y) { - for (int i = 0; i < _numStates; i++) - createSurfaceImage(i, res, x, y, i); -} - -void Widget::linkSurfaceImages(Widget *from, int x, int y) { - for (int i = 0; i < from->_numStates; i++) - linkSurfaceImage(from, i, x, y); -} - -void Widget::setHitRect(int x, int y, int width, int height) { - _hitRect.left = x; - _hitRect.right = x + width; - _hitRect.top = y; - _hitRect.bottom = y + height; -} - -bool Widget::isHit(int16 x, int16 y) { - return _hitRect.left >= 0 && _hitRect.contains(x, y); -} - -void Widget::setState(int state) { - if (state != _state) { - _state = state; - paint(); - } -} - -int Widget::getState() { - return _state; -} - -void Widget::paint(Common::Rect *clipRect) { - _vm->_screen->drawSurface(&_sprites[_state], _surfaces[_state]._surface, clipRect); -} - -/** - * Standard button class. - */ - -class Button : public Widget { -public: - Button(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2) { - setHitRect(x, y, w, h); - } - - virtual void onMouseExit() { - setState(0); - } - - virtual void onMouseDown(int x, int y) { - setState(1); - } - - virtual void onMouseUp(int x, int y) { - if (getState() != 0) { - setState(0); - _parent->onAction(this); - } - } -}; - -/** - * Scroll buttons are used to scroll the savegame list. The difference between - * this and a normal button is that we want this to repeat. - */ - -class ScrollButton : public Widget { -private: - uint32 _holdCounter; - -public: - ScrollButton(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _holdCounter(0) { - setHitRect(x, y, w, h); - } - - virtual void onMouseExit() { - setState(0); - } - - virtual void onMouseDown(int x, int y) { - setState(1); - _parent->onAction(this); - _holdCounter = 0; - } - - virtual void onMouseUp(int x, int y) { - setState(0); - } - - virtual void onTick() { - if (getState() != 0) { - _holdCounter++; - if (_holdCounter > 16 && (_holdCounter % 4) == 0) - _parent->onAction(this); - } - } -}; - -/** - * A switch is a button that changes state when clicked, and keeps that state - * until clicked again. - */ - -class Switch : public Widget { -private: - bool _holding, _value; - int _upState, _downState; - -public: - Switch(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _holding(false), _value(false), - _upState(0), _downState(1) { - setHitRect(x, y, w, h); - } - - // The sound mute switches have 0 as their "down" state and 1 as - // their "up" state, so this function is needed to get consistent - // behaviour. - - void reverseStates() { - _upState = 1; - _downState = 0; - } - - void setValue(bool value) { - _value = value; - if (_value) - setState(_downState); - else - setState(_upState); - } - - bool getValue() { - return _value; - } - - virtual void onMouseExit() { - if (_holding && !_value) - setState(_upState); - _holding = false; - } - - virtual void onMouseDown(int x, int y) { - _holding = true; - setState(_downState); - } - - virtual void onMouseUp(int x, int y) { - if (_holding) { - _holding = false; - _value = !_value; - if (_value) - setState(_downState); - else - setState(_upState); - _parent->onAction(this, getState()); - } - } -}; - -/** - * A slider is used to specify a value within a pre-defined range. - */ - -class Slider : public Widget { -private: - Widget *_background; - bool _dragging; - int _value, _targetValue; - int _maxValue; - int _valueStep; - int _dragOffset; - - int posFromValue(int value) { - return _hitRect.left + (value * (_hitRect.width() - 38)) / _maxValue; - } - - int valueFromPos(int x) { - return (int)((double)(_maxValue * (x - _hitRect.left)) / (double)(_hitRect.width() - 38) + 0.5); - } - -public: - Slider(Dialog *parent, Widget *background, int max, - int x, int y, int w, int h, int step, Widget *base = NULL) - : Widget(parent, 1), _background(background), - _dragging(false), _value(0), _targetValue(0), - _maxValue(max), _valueStep(step) { - setHitRect(x, y, w, h); - - if (_valueStep <= 0) - _valueStep = 1; - - if (base) - linkSurfaceImages(base, x, y); - else - createSurfaceImages(3406, x, y); - } - - virtual void paint(Common::Rect *clipRect = NULL) { - // This will redraw a bit more than is strictly necessary, - // but I doubt that will make any noticeable difference. - - _background->paint(&_hitRect); - Widget::paint(clipRect); - } - - void setValue(int value) { - _value = value; - _targetValue = value; - _sprites[0].x = posFromValue(_value); - paint(); - } - - int getValue() { - return _value; - } - - virtual void onMouseMove(int x, int y) { - if (_dragging) { - int newX = x - _dragOffset; - int newValue; - - if (newX < _hitRect.left) - newX = _hitRect.left; - else if (newX + 38 > _hitRect.right) - newX = _hitRect.right - 38; - - _sprites[0].x = newX; - - newValue = valueFromPos(newX); - if (newValue != _value) { - _value = newValue; - _targetValue = newValue; - _parent->onAction(this, newValue); - } - - paint(); - } - } - - virtual void onMouseDown(int x, int y) { - if (x >= _sprites[0].x && x < _sprites[0].x + 38) { - _dragging = true; - _dragOffset = x - _sprites[0].x; - } else if (x < _sprites[0].x) { - if (_targetValue >= _valueStep) - _targetValue -= _valueStep; - else - _targetValue = 0; - } else { - if (_targetValue < _maxValue - _valueStep) - _targetValue += _valueStep; - else - _targetValue = _maxValue; - } - } - - virtual void releaseMouse(int x, int y) { - if (_dragging) - _dragging = false; - } - - virtual void onTick() { - if (!_dragging) { - int target = posFromValue(_targetValue); - - if (target != _sprites[0].x) { - if (target < _sprites[0].x) { - _sprites[0].x -= 4; - if (_sprites[0].x < target) - _sprites[0].x = target; - } else if (target > _sprites[0].x) { - _sprites[0].x += 4; - if (_sprites[0].x > target) - _sprites[0].x = target; - } - - int newValue = valueFromPos(_sprites[0].x); - if (newValue != _value) { - _value = newValue; - _parent->onAction(this, newValue); - } - - paint(); - } - } - } -}; - -/** - * The "mini" dialog. - */ - -MiniDialog::MiniDialog(Sword2Engine *vm, uint32 headerTextId, uint32 okTextId, uint32 cancelTextId) : Dialog(vm) { - _headerTextId = headerTextId; - _okTextId = okTextId; - _cancelTextId = cancelTextId; - - _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(1996, 203, 104); - - _okButton = new Button(this, 243, 214, 24, 24); - _okButton->createSurfaceImages(2002, 243, 214); - - _cancelButton = new Button(this, 243, 276, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 243, 276); - - registerWidget(_panel); - registerWidget(_okButton); - registerWidget(_cancelButton); -} - -MiniDialog::~MiniDialog() { - delete _fr; -} - -void MiniDialog::paint() { - Dialog::paint(); - - if (_headerTextId) - _fr->drawText(_headerTextId, 310, 134, FontRendererGui::kAlignCenter); - _fr->drawText(_okTextId, 270, 214); - _fr->drawText(_cancelTextId, 270, 276); -} - -void MiniDialog::onAction(Widget *widget, int result) { - if (widget == _okButton) - setResult(1); - else if (widget == _cancelButton) - setResult(0); -} - -StartDialog::StartDialog(Sword2Engine *vm) : MiniDialog(vm, 0) {} - -int StartDialog::runModal() { - while (1) { - MiniDialog startDialog(_vm, 0, TEXT_RESTART, TEXT_RESTORE); - - if (startDialog.runModal()) - return 1; - - if (_vm->_quit) - return 0; - - RestoreDialog restoreDialog(_vm); - - if (restoreDialog.runModal()) - return 0; - - if (_vm->_quit) - return 0; - } - - return 1; -} - -/** - * The restart dialog. - */ - -RestartDialog::RestartDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_RESTART) {} - -int RestartDialog::runModal() { - int result = MiniDialog::runModal(); - - if (result) - _vm->restartGame(); - - return result; -} - -/** - * The quit dialog. - */ - -QuitDialog::QuitDialog(Sword2Engine *vm) : MiniDialog(vm, TEXT_QUIT) {} - -int QuitDialog::runModal() { - int result = MiniDialog::runModal(); - - if (result) - _vm->closeGame(); - - return result; -} - -/** - * The game settings dialog. - */ - -OptionsDialog::OptionsDialog(Sword2Engine *vm) : Dialog(vm) { - _fr = new FontRendererGui(_vm, _vm->_controlsFontId); - - _mixer = _vm->_mixer; - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(3405, 0, 40); - - _objectLabelsSwitch = new Switch(this, 304, 100, 53, 32); - _objectLabelsSwitch->createSurfaceImages(3687, 304, 100); - - _subtitlesSwitch = new Switch(this, 510, 100, 53, 32); - _subtitlesSwitch->linkSurfaceImages(_objectLabelsSwitch, 510, 100); - - _reverseStereoSwitch = new Switch(this, 304, 293, 53, 32); - _reverseStereoSwitch->linkSurfaceImages(_objectLabelsSwitch, 304, 293); - - _musicSwitch = new Switch(this, 516, 157, 40, 32); - _musicSwitch->createSurfaceImages(3315, 516, 157); - _musicSwitch->reverseStates(); - - _speechSwitch = new Switch(this, 516, 205, 40, 32); - _speechSwitch->linkSurfaceImages(_musicSwitch, 516, 205); - _speechSwitch->reverseStates(); - - _fxSwitch = new Switch(this, 516, 250, 40, 32); - _fxSwitch->linkSurfaceImages(_musicSwitch, 516, 250); - _fxSwitch->reverseStates(); - - int volStep = Audio::Mixer::kMaxMixerVolume / 10; - - _musicSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 161, 170, 27, volStep); - _speechSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 208, 170, 27, volStep, _musicSlider); - _fxSlider = new Slider(this, _panel, Audio::Mixer::kMaxMixerVolume, 309, 254, 170, 27, volStep, _musicSlider); - _gfxSlider = new Slider(this, _panel, 3, 309, 341, 170, 27, 1, _musicSlider); - - _gfxPreview = new Widget(this, 4); - _gfxPreview->createSurfaceImages(256, 495, 310); - - _okButton = new Button(this, 203, 382, 53, 32); - _okButton->createSurfaceImages(901, 203, 382); - - _cancelButton = new Button(this, 395, 382, 53, 32); - _cancelButton->linkSurfaceImages(_okButton, 395, 382); - - registerWidget(_panel); - registerWidget(_objectLabelsSwitch); - registerWidget(_subtitlesSwitch); - registerWidget(_reverseStereoSwitch); - registerWidget(_musicSwitch); - registerWidget(_speechSwitch); - registerWidget(_fxSwitch); - registerWidget(_musicSlider); - registerWidget(_speechSlider); - registerWidget(_fxSlider); - registerWidget(_gfxSlider); - registerWidget(_gfxPreview); - registerWidget(_okButton); - registerWidget(_cancelButton); - - _objectLabelsSwitch->setValue(_vm->_mouse->getObjectLabels()); - _subtitlesSwitch->setValue(_vm->getSubtitles()); - _reverseStereoSwitch->setValue(_vm->_sound->isReverseStereo()); - _musicSwitch->setValue(!_vm->_sound->isMusicMute()); - _speechSwitch->setValue(!_vm->_sound->isSpeechMute()); - _fxSwitch->setValue(!_vm->_sound->isFxMute()); - - _musicSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType)); - _speechSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType)); - _fxSlider->setValue(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType)); - - _gfxSlider->setValue(_vm->_screen->getRenderLevel()); - _gfxPreview->setState(_vm->_screen->getRenderLevel()); -} - -OptionsDialog::~OptionsDialog() { - delete _fr; -} - -void OptionsDialog::paint() { - Dialog::paint(); - - int maxWidth = 0; - int width; - - uint32 alignTextIds[] = { - TEXT_OBJECT_LABELS, - TEXT_MUSIC_VOLUME, - TEXT_SPEECH_VOLUME, - TEXT_FX_VOLUME, - TEXT_GFX_QUALITY, - TEXT_REVERSE_STEREO - }; - - for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) { - width = _fr->getTextWidth(alignTextIds[i]); - if (width > maxWidth) - maxWidth = width; - } - - _fr->drawText(TEXT_OPTIONS, 321, 55, FontRendererGui::kAlignCenter); - _fr->drawText(TEXT_SUBTITLES, 500, 103, FontRendererGui::kAlignRight); - _fr->drawText(TEXT_OBJECT_LABELS, 299 - maxWidth, 103); - _fr->drawText(TEXT_MUSIC_VOLUME, 299 - maxWidth, 161); - _fr->drawText(TEXT_SPEECH_VOLUME, 299 - maxWidth, 208); - _fr->drawText(TEXT_FX_VOLUME, 299 - maxWidth, 254); - _fr->drawText(TEXT_REVERSE_STEREO, 299 - maxWidth, 296); - _fr->drawText(TEXT_GFX_QUALITY, 299 - maxWidth, 341); - _fr->drawText(TEXT_OK, 193, 382, FontRendererGui::kAlignRight); - _fr->drawText(TEXT_CANCEL, 385, 382, FontRendererGui::kAlignRight); -} - -void OptionsDialog::onAction(Widget *widget, int result) { - // Since there is music playing while the dialog is displayed we need - // to update music volume immediately. - - if (widget == _musicSwitch) { - _vm->_sound->muteMusic(result != 0); - } else if (widget == _musicSlider) { - _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, result); - _vm->_sound->muteMusic(result == 0); - _musicSwitch->setValue(result != 0); - } else if (widget == _speechSlider) { - _speechSwitch->setValue(result != 0); - } else if (widget == _fxSlider) { - _fxSwitch->setValue(result != 0); - } else if (widget == _gfxSlider) { - _gfxPreview->setState(result); - _vm->_screen->setRenderLevel(result); - } else if (widget == _okButton) { - // Apply the changes - _vm->setSubtitles(_subtitlesSwitch->getValue()); - _vm->_mouse->setObjectLabels(_objectLabelsSwitch->getValue()); - _vm->_sound->muteMusic(!_musicSwitch->getValue()); - _vm->_sound->muteSpeech(!_speechSwitch->getValue()); - _vm->_sound->muteFx(!_fxSwitch->getValue()); - _vm->_sound->setReverseStereo(_reverseStereoSwitch->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _musicSlider->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _speechSlider->getValue()); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _fxSlider->getValue()); - _vm->_screen->setRenderLevel(_gfxSlider->getValue()); - - _vm->writeSettings(); - setResult(1); - } else if (widget == _cancelButton) { - // Revert the changes - _vm->readSettings(); - setResult(0); - } -} - -// Slot button actions. Note that keyboard input generates positive actions - -enum { - kSelectSlot = -1, - kDeselectSlot = -2, - kWheelDown = -3, - kWheelUp = -4, - kStartEditing = -5, - kCursorTick = -6 -}; - -class Slot : public Widget { -private: - int _mode; - FontRendererGui *_fr; - byte _text[SAVE_DESCRIPTION_LEN]; - bool _clickable; - bool _editable; - -public: - Slot(Dialog *parent, int x, int y, int w, int h) - : Widget(parent, 2), _clickable(false), _editable(false) { - setHitRect(x, y, w, h); - _text[0] = 0; - } - - void setMode(int mode) { - _mode = mode; - } - - void setClickable(bool clickable) { - _clickable = clickable; - } - - void setEditable(bool editable) { - _editable = editable; - _vm->_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, editable); - } - - bool isEditable() { - return _editable; - } - - void setText(FontRendererGui *fr, int slot, byte *text) { - _fr = fr; - if (text) - sprintf((char *)_text, "%d. %s", slot, text); - else - sprintf((char *)_text, "%d. ", slot); - } - - byte *getText() { - return &_text[0]; - } - - virtual void paint(Common::Rect *clipRect = NULL) { - Widget::paint(); - - // HACK: The main dialog is responsible for drawing the text - // when in editing mode. - - if (!_editable) - _fr->drawText(_text, _sprites[0].x + 16, _sprites[0].y + 4 + 2 * getState()); - } - - virtual void onMouseDown(int x, int y) { - if (_clickable) { - if (getState() == 0) { - setState(1); - _parent->onAction(this, kSelectSlot); - if (_mode == kSaveDialog) - _parent->onAction(this, kStartEditing); - } else if (_mode == kRestoreDialog) { - setState(0); - _parent->onAction(this, kDeselectSlot); - } - } - } - - virtual void onWheelUp(int x, int y) { - _parent->onAction(this, kWheelUp); - } - - virtual void onWheelDown(int x, int y) { - _parent->onAction(this, kWheelDown); - } - - virtual void onKey(KeyboardEvent *ke) { - if (_editable) { - if (ke->keycode == 8) - _parent->onAction(this, 8); - else if (ke->ascii >= ' ' && ke->ascii <= 255) { - // Accept the character if the font renderer - // has what looks like a valid glyph for it. - if (_fr->getCharWidth(ke->ascii)) - _parent->onAction(this, ke->ascii); - } - } - } - - virtual void onTick() { - if (_editable) - _parent->onAction(this, kCursorTick); - } - - void setY(int y) { - for (int i = 0; i < _numStates; i++) - _sprites[i].y = y; - setHitRect(_hitRect.left, y, _hitRect.width(), _hitRect.height()); - } - - int getY() { - return _sprites[0].y; - } -}; - -SaveRestoreDialog::SaveRestoreDialog(Sword2Engine *vm, int mode) : Dialog(vm) { - int i; - - _mode = mode; - _selectedSlot = -1; - - // FIXME: The "control font" and the "red font" are currently always - // the same font, so one should be eliminated. - - _fr1 = new FontRendererGui(_vm, _vm->_controlsFontId); - _fr2 = new FontRendererGui(_vm, _vm->_redFontId); - - _panel = new Widget(this, 1); - _panel->createSurfaceImages(2016, 0, 40); - - for (i = 0; i < 4; i++) { - _slotButton[i] = new Slot(this, 114, 0, 384, 36); - _slotButton[i]->createSurfaceImages(2006 + i, 114, 0); - _slotButton[i]->setMode(mode); - _slotButton[i + 4] = new Slot(this, 114, 0, 384, 36); - _slotButton[i + 4]->linkSurfaceImages(_slotButton[i], 114, 0); - _slotButton[i + 4]->setMode(mode); - } - - updateSlots(); - - _zupButton = new ScrollButton(this, 516, 65, 17, 17); - _zupButton->createSurfaceImages(1982, 516, 65); - - _upButton = new ScrollButton(this, 516, 85, 17, 17); - _upButton->createSurfaceImages(2067, 516, 85); - - _downButton = new ScrollButton(this, 516, 329, 17, 17); - _downButton->createSurfaceImages(1986, 516, 329); - - _zdownButton = new ScrollButton(this, 516, 350, 17, 17); - _zdownButton->createSurfaceImages(1988, 516, 350); - - _okButton = new Button(this, 130, 377, 24, 24); - _okButton->createSurfaceImages(2002, 130, 377); - - _cancelButton = new Button(this, 350, 377, 24, 24); - _cancelButton->linkSurfaceImages(_okButton, 350, 377); - - registerWidget(_panel); - - for (i = 0; i < 8; i++) - registerWidget(_slotButton[i]); - - registerWidget(_zupButton); - registerWidget(_upButton); - registerWidget(_downButton); - registerWidget(_zdownButton); - registerWidget(_okButton); - registerWidget(_cancelButton); -} - -SaveRestoreDialog::~SaveRestoreDialog() { - delete _fr1; - delete _fr2; -} - -// There aren't really a hundred different button objects of course, there are -// only eight. Re-arrange them to simulate scrolling. - -void SaveRestoreDialog::updateSlots() { - for (int i = 0; i < 8; i++) { - Slot *slot = _slotButton[(baseSlot + i) % 8]; - FontRendererGui *fr; - byte description[SAVE_DESCRIPTION_LEN]; - - slot->setY(72 + i * 36); - - if (baseSlot + i == _selectedSlot) { - slot->setEditable(_mode == kSaveDialog); - slot->setState(1); - fr = _fr2; - } else { - slot->setEditable(false); - slot->setState(0); - fr = _fr1; - } - - if (_vm->getSaveDescription(baseSlot + i, description) == SR_OK) { - slot->setText(fr, baseSlot + i, description); - slot->setClickable(true); - } else { - slot->setText(fr, baseSlot + i, NULL); - slot->setClickable(_mode == kSaveDialog); - } - - if (slot->isEditable()) - drawEditBuffer(slot); - else - slot->paint(); - } -} - -void SaveRestoreDialog::drawEditBuffer(Slot *slot) { - if (_selectedSlot == -1) - return; - - // This will redraw a bit more than is strictly necessary, but I doubt - // that will make any noticeable difference. - - slot->paint(); - _fr2->drawText(_editBuffer, 130, 78 + (_selectedSlot - baseSlot) * 36); -} - -void SaveRestoreDialog::onAction(Widget *widget, int result) { - if (widget == _zupButton) { - if (baseSlot > 0) { - if (baseSlot >= 8) - baseSlot -= 8; - else - baseSlot = 0; - updateSlots(); - } - } else if (widget == _upButton) { - if (baseSlot > 0) { - baseSlot--; - updateSlots(); - } - } else if (widget == _downButton) { - if (baseSlot < 92) { - baseSlot++; - updateSlots(); - } - } else if (widget == _zdownButton) { - if (baseSlot < 92) { - if (baseSlot <= 84) - baseSlot += 8; - else - baseSlot = 92; - updateSlots(); - } - } else if (widget == _okButton) { - setResult(1); - } else if (widget == _cancelButton) { - setResult(0); - } else { - Slot *slot = (Slot *)widget; - int textWidth; - byte tmp; - int i; - int j; - - switch (result) { - case kWheelUp: - onAction(_upButton); - break; - case kWheelDown: - onAction(_downButton); - break; - case kSelectSlot: - case kDeselectSlot: - if (result == kSelectSlot) - _selectedSlot = baseSlot + (slot->getY() - 72) / 35; - else if (result == kDeselectSlot) - _selectedSlot = -1; - - for (i = 0; i < 8; i++) - if (widget == _slotButton[i]) - break; - - for (j = 0; j < 8; j++) { - if (j != i) { - _slotButton[j]->setEditable(false); - _slotButton[j]->setState(0); - } - } - break; - case kStartEditing: - if (_selectedSlot >= 10) - _firstPos = 5; - else - _firstPos = 4; - - strcpy((char *)_editBuffer, (char *)slot->getText()); - _editPos = strlen((char *)_editBuffer); - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - _editBuffer[_editPos + 1] = 0; - slot->setEditable(true); - drawEditBuffer(slot); - break; - case kCursorTick: - _cursorTick++; - if (_cursorTick == 7) { - _editBuffer[_editPos] = ' '; - drawEditBuffer(slot); - } else if (_cursorTick == 14) { - _cursorTick = 0; - _editBuffer[_editPos] = '_'; - drawEditBuffer(slot); - } - break; - case 8: - if (_editPos > _firstPos) { - _editBuffer[_editPos - 1] = _editBuffer[_editPos]; - _editBuffer[_editPos--] = 0; - drawEditBuffer(slot); - } - break; - default: - tmp = _editBuffer[_editPos]; - _editBuffer[_editPos] = 0; - textWidth = _fr2->getTextWidth(_editBuffer); - _editBuffer[_editPos] = tmp; - - if (textWidth < 340 && _editPos < SAVE_DESCRIPTION_LEN - 2) { - _editBuffer[_editPos + 1] = _editBuffer[_editPos]; - _editBuffer[_editPos + 2] = 0; - _editBuffer[_editPos++] = result; - drawEditBuffer(slot); - } - break; - } - } -} - -void SaveRestoreDialog::paint() { - Dialog::paint(); - - _fr1->drawText((_mode == kRestoreDialog) ? TEXT_RESTORE : TEXT_SAVE, 165, 377); - _fr1->drawText(TEXT_CANCEL, 382, 377); -} - -void SaveRestoreDialog::setResult(int result) { - if (result) { - if (_selectedSlot == -1) - return; - - if (_mode == kSaveDialog) { - if (_editPos <= _firstPos) - return; - } - } - - Dialog::setResult(result); -} - -int SaveRestoreDialog::runModal() { - int result = Dialog::runModal(); - - if (result) { - switch (_mode) { - case kSaveDialog: - // Remove the cursor character from the savegame name - _editBuffer[_editPos] = 0; - - if (_vm->saveGame(_selectedSlot, (byte *)&_editBuffer[_firstPos]) != SR_OK) - result = 0; - break; - case kRestoreDialog: - if (_vm->restoreGame(_selectedSlot) != SR_OK) - result = 0; - break; - } - } - - return result; -} - -} // End of namespace Sword2 |
