diff options
Diffstat (limited to 'engines/sherlock/tattoo/widget_tooltip.cpp')
-rw-r--r-- | engines/sherlock/tattoo/widget_tooltip.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/engines/sherlock/tattoo/widget_tooltip.cpp b/engines/sherlock/tattoo/widget_tooltip.cpp new file mode 100644 index 0000000000..b1c13c7a29 --- /dev/null +++ b/engines/sherlock/tattoo/widget_tooltip.cpp @@ -0,0 +1,220 @@ +/* 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. + * + */ + +#include "sherlock/tattoo/widget_tooltip.h" +#include "sherlock/tattoo/tattoo_map.h" +#include "sherlock/tattoo/tattoo_user_interface.h" +#include "sherlock/tattoo/tattoo.h" + +namespace Sherlock { + +namespace Tattoo { + +#define MAX_TOOLTIP_WIDTH 150 + +void WidgetTooltipBase::draw() { + Screen &screen = *_vm->_screen; + + // If there was a previously drawn frame in a different position that hasn't yet been erased, then erase it + if (_oldBounds.width() > 0 && _oldBounds != _bounds) + erase(); + + if (_bounds.width() > 0 && !_surface.empty()) { + restrictToScreen(); + + // Blit the affected area to the screen + screen.slamRect(_bounds); + + // Draw the widget directly onto the screen. Unlike other widgets, we don't draw to the back buffer, + // since nothing should be drawing on top of tooltips, so there's no need to store in the back buffer + screen.transBlitFrom(_surface, Common::Point(_bounds.left - screen._currentScroll.x, + _bounds.top - screen._currentScroll.y)); + + // Store a copy of the drawn area for later erasing + _oldBounds = _bounds; + } +} + +void WidgetTooltipBase::erase() { + Screen &screen = *_vm->_screen; + + if (_oldBounds.width() > 0) { + // Restore the affected area from the back buffer to the screen + screen.slamRect(_oldBounds); + + // Reset the old bounds so it won't be erased again + _oldBounds = Common::Rect(0, 0, 0, 0); + } +} + +/*----------------------------------------------------------------*/ + +WidgetTooltip::WidgetTooltip(SherlockEngine *vm) : WidgetTooltipBase (vm) { +} + +void WidgetTooltip::setText(const Common::String &str) { + Events &events = *_vm->_events; + Common::Point mousePos = events.mousePos(); + bool reset = false; + + // Make sure that the description is present + if (!str.empty()) { + int width = _surface.stringWidth(str) + 2; + int height = _surface.stringHeight(str) + 2; + Common::String line1 = str, line2 = ""; + + // See if we need to split it into two lines + if (width > MAX_TOOLTIP_WIDTH) { + // Go forward word by word to find out where to split the line + const char *s = str.c_str(); + const char *space = nullptr; + int dif = 10000; + + for (;;) { + // Find end of next word + s = strchr(s + 1, ' '); + + if (s == nullptr) { + // Reached end of string + if (space != nullptr) { + line1 = Common::String(str.c_str(), space); + line2 = Common::String(space + 1); + height = _surface.stringHeight(line1) + _surface.stringHeight(line2) + 4; + } + break; + } + + // Found space separating words, so see what width the string up to now is + Common::String tempLine1 = Common::String(str.c_str(), s); + Common::String tempLine2 = Common::String(s + 1); + int width1 = _surface.stringWidth(tempLine1); + int width2 = _surface.stringWidth(tempLine2); + + // See if we've found a split point that results in a less overall width + if (ABS(width1 - width2) < dif) { + // Found a better split point + dif = ABS(width1 - width2); + space = s; + line1 = tempLine1; + line2 = tempLine2; + } + } + } else { + // No line split needed + height = _surface.stringHeight(str) + 2; + } + + // Reallocate the text surface with the new size + _surface.create(width, height); + _surface.fill(TRANSPARENCY); + + if (line2.empty()) { + // Only a single line + _surface.writeFancyString(str, Common::Point(0, 0), BLACK, INFO_TOP); + } else { + // Two lines to display + int xp, yp; + xp = (width - _surface.stringWidth(line1) - 2) / 2; + _surface.writeFancyString(line1, Common::Point(xp, 0), BLACK, INFO_TOP); + + xp = (width - _surface.stringWidth(line2) - 2) / 2; + yp = _surface.stringHeight(line1) + 2; + _surface.writeFancyString(line2, Common::Point(xp, yp), BLACK, INFO_TOP); + } + + // Set the initial display position for the tooltip text + int tagX = mousePos.x - width / 2; + int tagY = mousePos.y - height; + + _bounds = Common::Rect(tagX, tagY, tagX + width, tagY + height); + } else { + reset = true; + } + + if (reset && !_surface.empty()) { + _surface.free(); + } +} + +void WidgetTooltip::handleEvents() { + Events &events = *_vm->_events; + Common::Point mousePos = events.mousePos(); + + // Set the new position for the tooltip + int xp = mousePos.x - _bounds.width() / 2; + int yp = mousePos.y - _bounds.height(); + + _bounds.moveTo(xp, yp); +} + +/*----------------------------------------------------------------*/ + +void WidgetSceneTooltip::handleEvents() { + Events &events = *_vm->_events; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; + Common::Point mousePos = events.mousePos(); + + // See if thay are pointing at a different object and we need to regenerate the tooltip text + if (ui._bgFound != ui._oldBgFound || (ui._bgFound != -1 && _surface.empty()) || + ui._arrowZone != ui._oldArrowZone || (ui._arrowZone != -1 && _surface.empty())) { + // See if there is a new object to display text for + if ((ui._bgFound != -1 && (ui._bgFound != ui._oldBgFound || (ui._bgFound != -1 && _surface.empty()))) || + (ui._arrowZone != -1 && (ui._arrowZone != ui._oldArrowZone || (ui._arrowZone != -1 && _surface.empty())))) { + Common::String str; + if (ui._bgFound != -1) { + // Clear the Arrow Zone fields so it won't think we're displaying an Arrow Zone cursor + if (scene._currentScene != 90) // RRR Take out the cludge for room 90 + ui._arrowZone = ui._oldArrowZone = -1; + + // Get the description string + str = (ui._bgFound < 1000) ? scene._bgShapes[ui._bgFound]._description : + people[ui._bgFound - 1000]._description; + } else { + // Get the exit zone description + str = scene._exits[ui._arrowZone]._dest; + } + + setText(str.hasPrefix(" ") ? Common::String() : str); + } else if ((ui._bgFound == -1 && ui._oldBgFound != -1) || (ui._arrowZone == -1 && ui._oldArrowZone != -1)) { + setText(""); + } + + ui._oldBgFound = ui._bgFound; + } else { + + // Set the new position for the tooltip + int tagX = CLIP(mousePos.x - _bounds.width() / 2, 0, SHERLOCK_SCREEN_WIDTH - _bounds.width()); + int tagY = MAX(mousePos.y - _bounds.height(), 0); + + _bounds.moveTo(tagX, tagY); + } + + ui._oldArrowZone = ui._arrowZone; + + WidgetTooltip::handleEvents(); +} + +} // End of namespace Tattoo + +} // End of namespace Sherlock |