diff options
-rw-r--r-- | engines/sherlock/tattoo/tattoo_user_interface.cpp | 45 | ||||
-rw-r--r-- | engines/sherlock/tattoo/tattoo_user_interface.h | 6 | ||||
-rw-r--r-- | engines/sherlock/tattoo/widget_base.cpp | 79 | ||||
-rw-r--r-- | engines/sherlock/tattoo/widget_base.h | 14 | ||||
-rw-r--r-- | engines/sherlock/tattoo/widget_text.cpp | 53 | ||||
-rw-r--r-- | engines/sherlock/tattoo/widget_text.h | 2 |
6 files changed, 197 insertions, 2 deletions
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp index 29a570478b..4dd8513967 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.cpp +++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp @@ -172,6 +172,8 @@ void TattooUserInterface::printObjectDesc(const Common::String &str, bool firstT events._oldButtons = 0; } } else { + events._pressed = events._released = events._rightReleased = false;; + // Show text dialog _textWidget.load(str); @@ -186,6 +188,11 @@ void TattooUserInterface::doJournal() { // TODO } +void TattooUserInterface::reset() { + UserInterface::reset(); + _lookPos = Common::Point(SHERLOCK_SCREEN_WIDTH / 2, SHERLOCK_SCREEN_HEIGHT / 2); +} + void TattooUserInterface::handleInput() { TattooEngine &vm = *(TattooEngine *)_vm; Events &events = *_vm->_events; @@ -527,7 +534,43 @@ void TattooUserInterface::doStandardControl() { } void TattooUserInterface::doLookControl() { - warning("TODO: ui control (look)"); + Events &events = *_vm->_events; + TattooScene &scene = *(TattooScene *)_vm->_scene; + Sound &sound = *_vm->_sound; + + // See if a mouse button was released or a key pressed, and we want to initiate an action + // TODO: Not sure about _soundOn.. should be check for speaking voice for text being complete + if (events._released || events._rightReleased || _keyState.keycode || (sound._voices && !sound._soundOn)) { + // See if we were looking at an inventory object + if (!_invLookFlag) { + // See if there is any more text to display + if (!_textWidget._remainingText.empty()) { + printObjectDesc(_textWidget._remainingText, false); + } else { + // Otherwise restore the background and go back into STD_MODE + freeMenu(); + _key = -1; + _menuMode = scene._labTableScene ? LAB_MODE : STD_MODE; + + events.setCursor(ARROW); + events._pressed = events._released = events._rightReleased = false; + events._oldButtons = 0; + } + } else { + // We were looking at a Inventory object + // Erase the text window, and then redraw the inventory window + _textWidget.banishWindow(); + + warning("TODO: re-show inventory"); + + _invLookFlag = false; + _key = -1; + + events.setCursor(ARROW); + events._pressed = events._released = events._rightReleased = false; + events._oldButtons = 0; + } + } } void TattooUserInterface::doFileControl() { diff --git a/engines/sherlock/tattoo/tattoo_user_interface.h b/engines/sherlock/tattoo/tattoo_user_interface.h index 0f71803b52..0ccdc6701f 100644 --- a/engines/sherlock/tattoo/tattoo_user_interface.h +++ b/engines/sherlock/tattoo/tattoo_user_interface.h @@ -136,6 +136,7 @@ public: bool _personFound; int _activeObj; Common::KeyState _keyState; + Common::Point _lookPos; public: TattooUserInterface(SherlockEngine *vm); virtual ~TattooUserInterface() {} @@ -188,6 +189,11 @@ public: void pickUpObject(int objNum); public: /** + * Resets the user interface + */ + virtual void reset(); + + /** * Main input handler for the user interface */ virtual void handleInput(); diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp index 49ad4092cb..16f02a144d 100644 --- a/engines/sherlock/tattoo/widget_base.cpp +++ b/engines/sherlock/tattoo/widget_base.cpp @@ -22,12 +22,14 @@ #include "sherlock/tattoo/widget_base.h" #include "sherlock/tattoo/tattoo.h" +#include "sherlock/tattoo/tattoo_talk.h" namespace Sherlock { namespace Tattoo { WidgetBase::WidgetBase(SherlockEngine *vm) : _vm(vm) { + _images = nullptr; } void WidgetBase::summonWindow() { @@ -39,6 +41,83 @@ void WidgetBase::banishWindow() { _surface.free(); } +Common::String WidgetBase::splitLines(const Common::String &str, Common::StringArray &lines, int maxWidth, uint maxLines) { + Talk &talk = *_vm->_talk; + const char *strP = str.c_str(); + + // Loop counting up lines + lines.clear(); + while (lines.size() < maxLines) { + int width = 0; + const char *spaceP = nullptr; + const char *lineStartP = strP; + + // Find how many characters will fit on the next line + while (width < maxWidth && *strP && (*strP < 170 || *strP == 225)) { + width += _surface.charWidth(*strP); + + // Keep track of the last space + if (*strP == ' ') + spaceP = strP; + ++strP; + } + + // If the line was too wide to fit on a single line, go back to the last space + // if there was one, or otherwise simply break the line at this point + if (width >= maxWidth && spaceP != nullptr) + strP = spaceP; + + // Add the line to the output array + lines.push_back(Common::String(lineStartP, strP)); + + // Move the string ahead to the next line + if (*strP == ' ' || *strP == 13) + ++strP; + } while (*strP && (*strP < talk._opcodes[OP_SWITCH_SPEAKER] || *strP == 225)); + + // Return any remaining text left over + return *strP ? Common::String(strP) : Common::String(); +} + +void WidgetBase::checkMenuPosition() { + if (_bounds.left < 0) + _bounds.moveTo(0, _bounds.top); + if (_bounds.top < 0) + _bounds.moveTo(_bounds.left, 0); + if (_bounds.right > SHERLOCK_SCREEN_WIDTH) + _bounds.moveTo(SHERLOCK_SCREEN_WIDTH - _bounds.width(), _bounds.top); + if (_bounds.bottom > SHERLOCK_SCREEN_HEIGHT) + _bounds.moveTo(_bounds.left, SHERLOCK_SCREEN_HEIGHT - _bounds.height()); +} + +void WidgetBase::makeInfoArea() { + // Draw the four corners of the Info Box + _surface.transBlitFrom((*_images)[0], Common::Point(0, 0)); + _surface.transBlitFrom((*_images)[1], Common::Point(_bounds.width() - (*_images)[1]._width, 0)); + _surface.transBlitFrom((*_images)[2], Common::Point(0, _bounds.height() - (*_images)[2]._height)); + _surface.transBlitFrom((*_images)[3], Common::Point(_bounds.width() - (*_images)[3]._width, _bounds.height())); + + // Draw the top of the Info Box + _surface.hLine((*_images)[0]._width, 0, _bounds.width() - (*_images)[1]._width, INFO_TOP); + _surface.hLine((*_images)[0]._width, 1, _bounds.width() - (*_images)[1]._width, INFO_MIDDLE); + _surface.hLine((*_images)[0]._width, 2, _bounds.width() - (*_images)[1]._width, INFO_BOTTOM); + + // Draw the bottom of the Info Box + _surface.hLine((*_images)[0]._width, _bounds.height()- 3, _bounds.width() - (*_images)[1]._width, INFO_TOP); + _surface.hLine((*_images)[0]._width, _bounds.height()- 2, _bounds.width() - (*_images)[1]._width, INFO_MIDDLE); + _surface.hLine((*_images)[0]._width, _bounds.height()- 1, _bounds.width() - (*_images)[1]._width, INFO_BOTTOM); + + // Draw the left Side of the Info Box + _surface.vLine(0, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_TOP); + _surface.vLine(1, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_MIDDLE); + _surface.vLine(2, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_BOTTOM); + + // Draw the right Side of the Info Box + _surface.vLine(_bounds.width() - 3, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_TOP); + _surface.vLine(_bounds.width() - 2, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_MIDDLE); + _surface.vLine(_bounds.width() - 1, (*_images)[0]._height, _bounds.height()- (*_images)[2]._height, INFO_BOTTOM); +} + } // End of namespace Tattoo } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/widget_base.h b/engines/sherlock/tattoo/widget_base.h index 2a9988bc49..38b6d04b20 100644 --- a/engines/sherlock/tattoo/widget_base.h +++ b/engines/sherlock/tattoo/widget_base.h @@ -31,6 +31,7 @@ namespace Sherlock { class SherlockEngine; +class ImageFile; namespace Tattoo { @@ -39,6 +40,19 @@ protected: SherlockEngine *_vm; Common::Rect _bounds, _oldBounds; Surface _surface; + ImageFile *_images; + + /** + * Used by descendent classes to split up long text for display across multiple lines + */ + Common::String splitLines(const Common::String &str, Common::StringArray &lines, int maxWidth, uint maxLines); + + /** + * Ensure that menu is drawn entirely on-screen + */ + void checkMenuPosition(); + + void makeInfoArea(); public: WidgetBase(SherlockEngine *vm); virtual ~WidgetBase() {} diff --git a/engines/sherlock/tattoo/widget_text.cpp b/engines/sherlock/tattoo/widget_text.cpp index 928dbbf7cf..2c4fef0f2a 100644 --- a/engines/sherlock/tattoo/widget_text.cpp +++ b/engines/sherlock/tattoo/widget_text.cpp @@ -32,7 +32,58 @@ WidgetText::WidgetText(SherlockEngine *vm) : WidgetBase(vm) { } void WidgetText::load(const Common::String &str) { - // TODO + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; + Common::StringArray lines; + + // If bounds for a window have not yet been calculated, figure them out + if (_surface.empty()) { + int width = SHERLOCK_SCREEN_WIDTH / 3; + int height; + + for (;;) { + _remainingText = splitLines(str, lines, width - _surface.widestChar() * 2, 100); + height = (screen.fontHeight() + 1) * lines.size() + 9; + + if ((width - _surface.widestChar() * 2 > height * 3 / 2) || (width - _surface.widestChar() * 2 + > SHERLOCK_SCREEN_WIDTH * 3 / 4)) + break; + + width += (width / 4); + } + + // See if it's only a single line long + if (height == _surface.fontHeight() + 10) { + width = _surface.widestChar() * 2 + 6; + + const char *strP = str.c_str(); + while (*strP && (*strP < talk._opcodes[OP_SWITCH_SPEAKER] || *strP == 225)) + width += _surface.charWidth(*strP++); + } + + _bounds.setWidth(width); + _bounds.setHeight(height); + _bounds.translate(ui._lookPos.x - width / 2, ui._lookPos.y - height / 2); + checkMenuPosition(); + } else { + // Split up the string into lines in preparation for drawing + _remainingText = splitLines(str, lines, _bounds.width() - _surface.widestChar() * 2, + (_bounds.height() - _surface.fontHeight() / 2) / (_surface.fontHeight() + 1)); + } + + // Allocate a surface for the window + _surface.create(_bounds.width(), _bounds.height()); + + // Form the background for the new window + _surface.fillRect(Common::Rect(0, 0, _surface.w(), _surface.h()), TRANSPARENCY); + makeInfoArea(); + + int yp = 5; + for (int lineNum = 0; yp < (_bounds.height() - _surface.fontHeight() / 2); ++lineNum) { + _surface.writeString(lines[lineNum], Common::Point(_surface.widestChar(), yp), INFO_TOP); + yp += _surface.fontHeight() + 1; + } } } // End of namespace Tattoo diff --git a/engines/sherlock/tattoo/widget_text.h b/engines/sherlock/tattoo/widget_text.h index 9765e1bb6e..2608d75b32 100644 --- a/engines/sherlock/tattoo/widget_text.h +++ b/engines/sherlock/tattoo/widget_text.h @@ -34,6 +34,8 @@ namespace Tattoo { class WidgetText: public WidgetBase { public: + Common::String _remainingText; +public: WidgetText(SherlockEngine *vm); virtual ~WidgetText() {} |