GUI: Fix tooltip behavior to be less interruptive

The tooltip will show only if mouse cursor was moved but not on a hovered focused editText field

Changes and implications in this commit:
- Fix _lastMousePosition coordinates and time being updated upon giving focus to the tooltip
- Check for mouse cursor movement first in the decision for showing the tooltip, then check if sufficient time for mouse resting position has passed (kTooltipDelay).
- Prevents showing a tooltip for a widget if it is an editable field (editText) and has both mouse hovering above it and the current focus.
This is so that typing text is not interrupted / slowed down by a periodical display of the tooltip, if the mouse is hovering over the same text field that the user is editing.
- If mouse cursor is moved but lands on the same widget as the one that had its tooltip shown last, then show the tooltip but after a different (larger) delay kTooltipSameWidgetDelay.
- Still shows tooltip for other widgets, including editText ones, if the mouse is hovered over them and they are not the current focused editText widget.

The bug was mentioned for the Android port on the forums here:
https://forums.scummvm.org/viewtopic.php?p=95531#p95531
However, it is not Android specific, even though the slowdown is a lot more noticeable on an Android device.
This commit is contained in:
antoniou79 2021-06-18 14:27:36 +03:00 committed by Eugene Sandulenko
parent c1702a0953
commit da461da6f6
6 changed files with 58 additions and 8 deletions

View File

@ -42,6 +42,8 @@ void Tooltip::setup(Dialog *parent, Widget *widget, int x, int y) {
_parent = parent;
setMouseUpdatedOnFocus(false);
_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);

View File

@ -49,6 +49,7 @@ Dialog::Dialog(int x, int y, int w, int h)
// started a 640x480 game with a non 1x scaler.
g_gui.checkScreenChange();
_mouseUpdatedOnFocus = true;
_result = -1;
}
@ -66,6 +67,7 @@ Dialog::Dialog(const Common::String &name)
// and bug #2903: "SCUMM: F5 crashes game (640x480)"
g_gui.checkScreenChange();
_mouseUpdatedOnFocus = true;
_result = -1;
}

View File

@ -57,6 +57,11 @@ protected:
Widget *_dragWidget;
Widget *_tickleWidget;
bool _visible;
// _mouseUpdatedOnFocus instructs gui-manager whether
// its lastMousePosition (time and x,y coordinates)
// should be updated, when this Dialog acquires focus.
// Default value is true.
bool _mouseUpdatedOnFocus;
ThemeEngine::DialogBackground _backgroundType;
@ -71,6 +76,8 @@ public:
bool isVisible() const override { return _visible; }
bool isMouseUpdatedOnFocus() const { return _mouseUpdatedOnFocus; }
void releaseFocus() override;
void setFocusWidget(Widget *widget);
Widget *getFocusWidget() { return _focusedWidget; }
@ -111,6 +118,7 @@ protected:
Widget *findWidget(const char *name);
void removeWidget(Widget *widget) override;
void setMouseUpdatedOnFocus(bool mouseUpdatedOnFocus) { _mouseUpdatedOnFocus = mouseUpdatedOnFocus; }
void setDefaultFocusedWidget();
void setResult(int result) { _result = result; }

View File

@ -53,7 +53,8 @@ namespace GUI {
enum {
kDoubleClickDelay = 500, // milliseconds
kCursorAnimateDelay = 250,
kTooltipDelay = 1250
kTooltipDelay = 1250,
kTooltipSameWidgetDelay = 7000
};
// Constructor
@ -440,13 +441,38 @@ void GuiManager::runLoop() {
++it;
}
if (_lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) {
// Handle tooltip for the widget under the mouse cursor.
// 1. Only try to show a tooltip if the mouse cursor was actually moved
// and sufficient time (kTooltipDelay) passed since mouse cursor rested in-place.
// Note, Dialog objects acquiring or losing focus lead to a _lastMousePosition update,
// which may lead to a change of its time and x,y coordinate values.
// See: GuiManager::giveFocusToDialog()
// We avoid updating _lastMousePosition when giving focus to the Tooltip object
// by having the Tooltip objects set a false value for their (inherited) member
// var _mouseUpdatedOnFocus (in Tooltip::setup()).
// However, when the tooltip loses focus, _lastMousePosition will be updated.
// If the mouse had stayed in the same position in the meantime,
// then at the time of the tooltip losing focus
// the _lastMousePosition.time will be new, but the x,y cordinates
// will be the same as the stored ones in _lastTooltipShown.
// 2. If the mouse was moved but ended on the same (tooltip enabled) widget,
// then delay showing the tooltip based on the value of kTooltipSameWidgetDelay.
uint32 systemMillisNowForTooltipCheck = _system->getMillis(true);
if ((_lastTooltipShown.x != _lastMousePosition.x || _lastTooltipShown.y != _lastMousePosition.y)
&& _lastMousePosition.time + kTooltipDelay < systemMillisNowForTooltipCheck) {
Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y);
if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {
Tooltip *tooltip = new Tooltip();
tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y);
tooltip->runModal();
delete tooltip;
if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)
&& (_lastTooltipShown.wdg != wdg || _lastTooltipShown.time + kTooltipSameWidgetDelay < systemMillisNowForTooltipCheck)) {
_lastTooltipShown.time = systemMillisNowForTooltipCheck;
_lastTooltipShown.wdg = wdg;
_lastTooltipShown.x = _lastMousePosition.x;
_lastTooltipShown.y = _lastMousePosition.y;
if (wdg->getType() != kEditTextWidget || activeDialog->getFocusWidget() != wdg) {
Tooltip *tooltip = new Tooltip();
tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y);
tooltip->runModal();
delete tooltip;
}
}
}
@ -690,7 +716,9 @@ void GuiManager::giveFocusToDialog(Dialog *dialog) {
int16 dialogX = _globalMousePosition.x - dialog->_x;
int16 dialogY = _globalMousePosition.y - dialog->_y;
dialog->receivedFocus(dialogX, dialogY);
setLastMousePos(dialogX, dialogY);
if (dialog->isMouseUpdatedOnFocus()) {
setLastMousePos(dialogX, dialogY);
}
}
void GuiManager::setLastMousePos(int16 x, int16 y) {

View File

@ -30,6 +30,7 @@
#include "common/list.h"
#include "gui/ThemeEngine.h"
#include "gui/widget.h"
class OSystem;
@ -166,6 +167,13 @@ protected:
int count; // How often was it already pressed?
} _lastClick, _lastMousePosition, _globalMousePosition;
struct TooltipData {
TooltipData() : x(-1), y(-1) { time = 0; wdg = nullptr; }
uint32 time; // Time
Widget *wdg; // Widget that had its tooltip shown
int16 x, y; // Position of mouse before tooltip was focused
} _lastTooltipShown;
// mouse cursor state
int _cursorAnimateCounter;
int _cursorAnimateTimer;

View File

@ -153,6 +153,8 @@ public:
void lostFocus() { _hasFocus = false; lostFocusWidget(); }
virtual bool wantsFocus() { return false; }
uint32 getType() const { return _type; }
void setFlags(int flags);
void clearFlags(int flags);
int getFlags() const { return _flags; }