GUI: Fix tooltip drawing

With help of Tanoku tooltips were switched from widgets to dialogs
which helped to fix nasty bug with background not being restored.
Although it is basically a hack around inconsistent font backbuffering
in our GUI code, for the time being it is feasible.

The patch was extended with way to specify tooltip background in the
theme file.

svn-id: r51217
This commit is contained in:
Eugene Sandulenko 2010-07-23 19:36:47 +00:00
parent 0e5aa06db0
commit d6695e180c
14 changed files with 207 additions and 120 deletions

View File

@ -45,11 +45,12 @@ namespace GUI {
enum {
kDoubleClickDelay = 500, // milliseconds
kCursorAnimateDelay = 250
kCursorAnimateDelay = 250,
kTooltipDelay = 1250
};
// Constructor
GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled), _tooltipCheck(false),
_stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
_theme = 0;
_useStdCursor = false;
@ -77,7 +78,7 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
}
}
_tooltip = new Tooltip(this);
_tooltip = 0;
}
GuiManager::~GuiManager() {
@ -224,13 +225,6 @@ Dialog *GuiManager::getTopDialog() const {
return _dialogStack.top();
}
static void tooltipCallback(void *ref) {
GuiManager *guiManager = (GuiManager *)ref;
guiManager->getTooltip()->setVisible(true);
g_system->getTimerManager()->removeTimerProc(&tooltipCallback);
}
void GuiManager::runLoop() {
Dialog *activeDialog = getTopDialog();
bool didSaveState = false;
@ -321,7 +315,14 @@ void GuiManager::runLoop() {
break;
case Common::EVENT_MOUSEMOVE:
activeDialog->handleMouseMoved(mouse.x, mouse.y, 0);
_tooltip->setMouseXY(mouse.x, mouse.y);
if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) {
_lastMousePosition.x = mouse.x;
_lastMousePosition.y = mouse.y;
_lastMousePosition.time = _system->getMillis();
}
_tooltipCheck = true;
eventTookplace = true;
break;
// We don't distinguish between mousebuttons (for now at least)
@ -367,11 +368,16 @@ void GuiManager::runLoop() {
}
}
if (eventTookplace) {
_tooltip->setVisible(false);
if (_tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) {
if (_tooltip == 0)
_tooltip = new Tooltip();
_system->getTimerManager()->removeTimerProc(&tooltipCallback);
_system->getTimerManager()->installTimerProc(&tooltipCallback, 2*1000000, this);
_tooltipCheck = false;
_tooltip->tooltipModal(_lastMousePosition.x, _lastMousePosition.y);
}
if (eventTookplace && _tooltip) {
_tooltip->mustClose();
}
// Delay for a moment

View File

@ -33,6 +33,7 @@
#include "graphics/font.h"
#include "gui/widget.h"
#include "gui/Tooltip.h"
#include "gui/ThemeEngine.h"
class OSystem;
@ -93,8 +94,6 @@ public:
*/
bool checkScreenChange();
Tooltip *getTooltip() { return _tooltip; }
protected:
enum RedrawStatus {
kRedrawDisabled = 0,
@ -119,13 +118,14 @@ protected:
bool _useStdCursor;
Tooltip *_tooltip;
bool _tooltipCheck;
// position and time of last mouse click (used to detect double clicks)
struct {
int16 x, y; // Position of mouse when the click occurred
uint32 time; // Time
int count; // How often was it already pressed?
} _lastClick;
} _lastClick, _lastMousePosition;
// mouse cursor state
int _cursorAnimateCounter;

View File

@ -165,6 +165,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDMainDialogBackground, "mainmenu_bg", true, kDDNone},
{kDDSpecialColorBackground, "special_bg", true, kDDNone},
{kDDPlainColorBackground, "plain_bg", true, kDDNone},
{kDDTooltipBackground, "tooltip_bg", true, kDDNone},
{kDDDefaultBackground, "default_bg", true, kDDNone},
{kDDTextSelectionBackground, "text_selection", false, kDDNone},
{kDDTextSelectionFocusBackground, "text_selection_focus", false, kDDNone},
@ -984,6 +985,10 @@ void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground b
queueDD(kDDPlainColorBackground, r);
break;
case kDialogBackgroundTooltip:
queueDD(kDDTooltipBackground, r);
break;
case kDialogBackgroundDefault:
queueDD(kDDDefaultBackground, r);
break;

View File

@ -61,6 +61,7 @@ enum DrawData {
kDDMainDialogBackground,
kDDSpecialColorBackground,
kDDPlainColorBackground,
kDDTooltipBackground,
kDDDefaultBackground,
kDDTextSelectionBackground,
kDDTextSelectionFocusBackground,
@ -162,6 +163,7 @@ public:
kDialogBackgroundMain,
kDialogBackgroundSpecial,
kDialogBackgroundPlain,
kDialogBackgroundTooltip,
kDialogBackgroundDefault
};

101
gui/Tooltip.cpp Normal file
View File

@ -0,0 +1,101 @@
/* 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.
*
* $URL$
* $Id$
*/
#include "common/util.h"
#include "graphics/fontman.h"
#include "gui/widget.h"
#include "gui/dialog.h"
#include "gui/GuiManager.h"
#include "gui/Tooltip.h"
#include "gui/ThemeEval.h"
namespace GUI {
Tooltip::Tooltip() :
Dialog(-1, -1, -1, -1), _maxWidth(-1) {
_backgroundType = GUI::ThemeEngine::kDialogBackgroundTooltip;
}
void Tooltip::mustClose() {
if (isVisible())
Dialog::close();
}
bool Tooltip::tooltipModal(int x, int y) {
Widget *wdg;
if (!g_gui.getTopDialog())
return false;
wdg = g_gui.getTopDialog()->findWidget(x, y);
if (!wdg || !wdg->getTooltip())
return false;
if (_maxWidth == -1) {
_maxWidth = g_gui.xmlEval()->getVar("Globals.Tooltip.MaxWidth", 100);
_xdelta = g_gui.xmlEval()->getVar("Globals.Tooltip.XDelta", 0);
_ydelta = g_gui.xmlEval()->getVar("Globals.Tooltip.YDelta", 0);
}
const Graphics::Font *tooltipFont = g_gui.theme()->getFont(ThemeEngine::kFontStyleTooltip);
_wrappedLines.clear();
_w = tooltipFont->wordWrapText(wdg->getTooltip(), _maxWidth - 4, _wrappedLines);
_h = (tooltipFont->getFontHeight() + 2) * _wrappedLines.size();
_x = MIN<int16>(g_gui.getTopDialog()->_x + x + _xdelta, g_gui.getWidth() - _w - 3);
_y = MIN<int16>(g_gui.getTopDialog()->_y + y + _ydelta, g_gui.getHeight() - _h - 3);
open();
g_gui.runLoop();
return true;
}
void Tooltip::drawDialog() {
int num = 0;
int h = g_gui.theme()->getFontHeight(ThemeEngine::kFontStyleTooltip) + 2;
Dialog::drawDialog();
for (Common::StringArray::const_iterator i = _wrappedLines.begin(); i != _wrappedLines.end(); ++i, ++num) {
g_gui.theme()->drawText(
Common::Rect(_x + 1, _y + 1 + num * h, _x + 1 +_w, _y + 1+ (num + 1) * h), *i,
ThemeEngine::kStateEnabled,
Graphics::kTextAlignLeft,
ThemeEngine::kTextInversionNone,
0,
false,
ThemeEngine::kFontStyleTooltip,
ThemeEngine::kFontColorNormal,
false
);
}
}
}

50
gui/Tooltip.h Normal file
View File

@ -0,0 +1,50 @@
/* 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.
*
* $URL$
* $Id$
*/
#ifndef GUI_TOOLTIP_H
#define GUI_TOOLTIP_H
#include "gui/dialog.h"
namespace GUI {
class Tooltip : public Dialog {
public:
Tooltip();
~Tooltip() {}
void drawDialog();
bool tooltipModal(int x, int y);
void mustClose();
protected:
Common::String _text;
int _maxWidth;
int _xdelta, _ydelta;
Common::StringArray _wrappedLines;
};
}
#endif

View File

@ -25,6 +25,7 @@ MODULE_OBJS := \
ThemeEval.o \
ThemeLayout.o \
ThemeParser.o \
Tooltip.o \
widget.o
ifdef MACOSX

View File

@ -877,6 +877,13 @@
"bevel='2' "
"/> "
"</drawdata> "
"<drawdata id='tooltip_bg' cache='false'> "
"<drawstep func='bevelsq' "
"bevel='2' "
"fill='foreground' "
"fg_color='black' "
"/> "
"</drawdata> "
"<drawdata id='separator' cache='false'> "
"<drawstep func='square' "
"fill='foreground' "

Binary file not shown.

View File

@ -142,6 +142,14 @@
/>
</drawdata>
<drawdata id = 'tooltip_bg' cache = 'false'>
<drawstep func = 'bevelsq'
bevel = '2'
fill = 'foreground'
fg_color = 'black'
/>
</drawdata>
<drawdata id = 'separator' cache = 'false'>
<drawstep func = 'square'
fill = 'foreground'

Binary file not shown.

View File

@ -516,6 +516,15 @@
/>
</drawdata>
<!-- Tooltip -->
<drawdata id = 'tooltip_bg' cache = 'false'>
<drawstep func = 'square'
fill = 'foreground'
fg_color = 'blandyellow'
shadow = '3'
/>
</drawdata>
<!-- Idle button -->
<drawdata id = 'button_idle' cache = 'false'>
<text font = 'text_button'

View File

@ -224,83 +224,6 @@ Common::String Widget::cleanupHotkey(const Common::String &label) {
#pragma mark -
Tooltip::Tooltip(GuiManager *guiManager) : GuiObject(0, 0, 0, 0) {
_guiManager = guiManager;
_visible = false;
_maxWidth = -1;
_storedState = 0;
}
void Tooltip::draw() {
int num = 0;
int h = g_gui.theme()->getFontHeight(ThemeEngine::kFontStyleTooltip) + 2;
// Make Rect bigger for compensating the shadow
_storedState = g_gui.theme()->storeState(Common::Rect(_x - 5, _y - 5, _x + _w + 5, _y + _h + 5));
g_gui.theme()->startBuffering();
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorderSmall);
for (Common::StringArray::const_iterator i = _wrappedLines.begin(); i != _wrappedLines.end(); ++i, ++num) {
g_gui.theme()->drawText(Common::Rect(_x + 1, _y + 1 + num * h, _x + 1 +_w, _y + 1+ (num + 1) * h), *i, ThemeEngine::kStateEnabled, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleTooltip, ThemeEngine::kFontColorNormal, false);
}
g_gui.theme()->finishBuffering();
}
void Tooltip::reflowLayout() {
}
void Tooltip::setMouseXY(int x, int y) {
_mouseX = x;
_mouseY = y;
}
void Tooltip::setVisible(bool state) {
if (state == _visible)
return;
if (state) {
if (!_guiManager->getTopDialog())
return;
Widget *wdg = _guiManager->getTopDialog()->findWidget(_mouseX, _mouseY);
if (!wdg)
return;
if (wdg->getTooltip()) {
_visible = state;
// Cache config values.
// NOTE: we cannot do it in the consturctor
if (_maxWidth == -1) {
_maxWidth = g_gui.xmlEval()->getVar("Globals.Tooltip.MaxWidth", 100);
_xdelta = g_gui.xmlEval()->getVar("Globals.Tooltip.XDelta", 0);
_ydelta = g_gui.xmlEval()->getVar("Globals.Tooltip.YDelta", 0);
}
const Graphics::Font *tooltipFont = g_gui.theme()->getFont(ThemeEngine::kFontStyleTooltip);
_wrappedLines.clear();
_w = tooltipFont->wordWrapText(wdg->getTooltip(), _maxWidth - 4, _wrappedLines);
_h = (tooltipFont->getFontHeight() + 2) * _wrappedLines.size();
_x = MIN<int16>(_guiManager->getTopDialog()->_x + _mouseX + _xdelta, g_gui.getWidth() - _w - 3);
_y = MIN<int16>(_guiManager->getTopDialog()->_y + _mouseY + _ydelta, g_gui.getHeight() - _h - 3);
draw();
}
} else {
_visible = state;
g_gui.theme()->restoreState(_storedState);
delete _storedState;
}
}
#pragma mark -
StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip)
: Widget(boss, x, y, w, h, tooltip), _align(align) {
setFlags(WIDGET_ENABLED);

View File

@ -159,31 +159,6 @@ protected:
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { assert(_boss); _boss->handleCommand(sender, cmd, data); }
};
class GuiManager;
class Tooltip : public GuiObject {
public:
Tooltip(GuiManager *guiManager);
bool isVisible() const { return _visible; }
void draw();
void reflowLayout();
void releaseFocus() {}
void setVisible(bool state);
void setMouseXY(int x, int y);
protected:
Common::String _text;
GuiManager *_guiManager;
bool _visible;
int _mouseX, _mouseY;
int _maxWidth;
int _xdelta, _ydelta;
Common::StringArray _wrappedLines;
ThemeEngine::StoredState *_storedState;
};
/* StaticTextWidget */
class StaticTextWidget : public Widget {
protected: