/* 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_user_interface.h" #include "sherlock/tattoo/tattoo.h" namespace Sherlock { namespace Tattoo { WidgetTooltip::WidgetTooltip(SherlockEngine *vm) : WidgetBase(vm) { } void WidgetTooltip::execute() { Events &events = *_vm->_events; People &people = *_vm->_people; Scene &scene = *_vm->_scene; Screen &screen = *_vm->_screen; TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; Common::Point mousePos = events.mousePos(); bool reset = false; // 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())) { // Keep track of the last place we drew the text _oldBounds = _bounds; // See if there is a new object to be displayed 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; } // Make sure that the description is present if (!str.empty() && !str.hasPrefix(" ")) { int width = screen.stringWidth(str) + 2; int height = screen.stringHeight(str) + 2; Common::String line1 = str, line2 = ""; // See if we need to split it into two lines if (width > 150) { // 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 = screen.stringHeight(line1) + screen.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 = screen.stringWidth(tempLine1); int width2 = screen.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 = screen.stringHeight(str) + 2; } // Reallocate the text surface with the new size _surface.create(width, height, _vm->getPlatform()); _surface.fill(TRANSPARENCY); if (line2.empty()) { // Only a single line _surface.writeString(str, Common::Point(0, 0), BLACK); _surface.writeString(str, Common::Point(1, 0), BLACK); _surface.writeString(str, Common::Point(2, 0), BLACK); _surface.writeString(str, Common::Point(0, 1), BLACK); _surface.writeString(str, Common::Point(2, 1), BLACK); _surface.writeString(str, Common::Point(0, 2), BLACK); _surface.writeString(str, Common::Point(1, 2), BLACK); _surface.writeString(str, Common::Point(2, 2), BLACK); _surface.writeString(str, Common::Point(1, 1), INFO_TOP); } else { // Two lines to display int xp, yp; xp = (width - screen.stringWidth(line1) - 2) / 2; _surface.writeString(line1, Common::Point(xp, 0), BLACK); _surface.writeString(line1, Common::Point(xp + 1, 0), BLACK); _surface.writeString(line1, Common::Point(xp + 2, 0), BLACK); _surface.writeString(line1, Common::Point(xp, 1), BLACK); _surface.writeString(line1, Common::Point(xp + 2, 1), BLACK); _surface.writeString(line1, Common::Point(xp, 2), BLACK); _surface.writeString(line1, Common::Point(xp + 1, 2), BLACK); _surface.writeString(line1, Common::Point(xp + 2, 2), BLACK); _surface.writeString(line1, Common::Point(xp + 1, 1), INFO_TOP); xp = (width - screen.stringWidth(line2) - 2) / 2; yp = screen.stringHeight(line1) + 2; _surface.writeString(line2, Common::Point(xp, yp), BLACK); _surface.writeString(line2, Common::Point(xp + 1, yp), BLACK); _surface.writeString(line2, Common::Point(xp + 2, yp), BLACK); _surface.writeString(line2, Common::Point(xp, yp + 1), BLACK); _surface.writeString(line2, Common::Point(xp + 2, yp + 1), BLACK); _surface.writeString(line2, Common::Point(xp, yp + 2), BLACK); _surface.writeString(line2, Common::Point(xp + 1, yp + 2), BLACK); _surface.writeString(line2, Common::Point(xp + 2, yp + 2), BLACK); _surface.writeString(line2, Common::Point(xp + 1, yp + 1), INFO_TOP); } // Set the initial display position for the tooltip text int tagX = CLIP(mousePos.x - width / 2, 0, SHERLOCK_SCREEN_WIDTH - width); int tagY = MAX(mousePos.y - height, 0); _bounds = Common::Rect(tagX, tagY, tagX + width, tagY + height); } else { reset = true; } } else if ((ui._bgFound == -1 && ui._oldBgFound != -1) || (ui._arrowZone == -1 && ui._oldArrowZone != -1)) { reset = true; } if (reset && !_surface.empty()) { _surface.free(); } ui._oldBgFound = ui._bgFound; } else { // Keep track of the last place we drew the Text _oldBounds = _bounds; // Set the New position of the Text Tag 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; } void WidgetTooltip::draw() { Screen &screen = *_vm->_screen; if (!_surface.empty()) screen._backBuffer1.transBlitFrom(_surface, Common::Point(_bounds.left, _bounds.top)); } void WidgetTooltip::erase() { Screen &screen = *_vm->_screen; TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; if (_bounds.width() > 0) { screen.slamArea(_oldBounds.left - ui._currentScroll.x, _oldBounds.top, _oldBounds.width(), _oldBounds.height()); // If there's no text actually being displayed, then reset bounds so we don't keep restoring the area if (_surface.empty()) { _bounds.left = _bounds.top = _bounds.right = _bounds.bottom = 0; _oldBounds.left = _oldBounds.top = _oldBounds.right = _oldBounds.bottom = 0; } } if (!_surface.empty()) screen.slamArea(_bounds.left - ui._currentScroll.x, _bounds.top, _bounds.width(), _bounds.height()); } void WidgetTooltip::erasePrevious() { Screen &screen = *_vm->_screen; if (_oldBounds.width() > 0) screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds); } } // End of namespace Tattoo } // End of namespace Sherlock