xref: /glogg/src/menuactiontooltipbehavior.cpp (revision 821cac888d515a4e41b5d4ba4130c56db4463501)
1 /*
2  * Copyright (C) 2009, 2010 Nicolas Bonnefon and other contributors
3  *
4  * This file is part of glogg.
5  *
6  * glogg is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * glogg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <QAction>
21 #include <QMenu>
22 #include <QTimerEvent>
23 #include <QToolTip>
24 
25 #include "menuactiontooltipbehavior.h"
26 
27 // It would be nice to only need action, and have action be the parent,
28 // however implementation needs the parent menu (see showToolTip), and
29 // since neither action nor parent is guaranteed to die before the other,
30 // for memory-management purposes the parent will have to be specified
31 // explicity (probably, the window owning the action and the menu).
32 MenuActionToolTipBehavior::MenuActionToolTipBehavior(QAction *action,
33                                                      QMenu *parentMenu,
34                                                      QObject *parent = 0)
35     : QObject(parent),
36       action(action),
37       parentMenu(parentMenu),
38       toolTipDelayMs(1000),
39       timerId(0),
40       hoverPoint()
41 {
42     connect(action, SIGNAL(hovered()), this, SLOT(onActionHovered()));
43 }
44 
45 int MenuActionToolTipBehavior::toolTipDelay()
46 {
47     return toolTipDelayMs;
48 }
49 
50 void MenuActionToolTipBehavior::setToolTipDelay(int delayMs)
51 {
52     toolTipDelayMs = delayMs;
53 }
54 
55 void MenuActionToolTipBehavior::timerEvent(QTimerEvent *event)
56 {
57     // Not ours, don't touch
58     if (event->timerId() != timerId) {
59         QObject::timerEvent(event);
60         return;
61     }
62 
63     killTimer(timerId); // interested in a single shot
64     timerId = 0;
65 
66     // Has the mouse waited unmoved in one location for 'delay' ms?
67     const QPoint &mousePos = QCursor::pos();
68     if (hoverPoint == mousePos)
69         showToolTip(hoverPoint);
70 }
71 
72 void MenuActionToolTipBehavior::onActionHovered()
73 {
74     const QPoint &mousePos = QCursor::pos();
75 
76     // Hover is fired on keyboard focus over action in menu, ignore it
77     const QPoint &relativeMousePos = parentMenu->mapFromGlobal(mousePos);
78     if (!parentMenu->actionGeometry(action).contains(relativeMousePos)) {
79         if (timerId != 0) { // once timer expires its check will fail anyway
80             killTimer(timerId);
81             timerId = 0;
82         }
83         QToolTip::hideText(); // there might be one currently shown
84         return;
85     }
86 
87     // Record location
88     hoverPoint = mousePos;
89 
90     // Restart timer
91     if (timerId != 0)
92         killTimer(timerId);
93     timerId = startTimer(toolTipDelayMs);
94 }
95 
96 void MenuActionToolTipBehavior::showToolTip(const QPoint &position)
97 {
98     const QString &toolTip = action->toolTip();
99     // Show tooltip until mouse moves at all
100     // NOTE: using action->parentWidget() which is the MainWindow,
101     // does not work (tooltip is not cleared when upon leaving the
102     // region). This is the only reason we need parentMenu here. Just
103     // a wild guess: maybe it isn't cleared because it would be
104     // cleared on a mouse move over the designated widget, but mouse
105     // move doesn't happen over MainWindow, since the mouse is over
106     // the menu even when out of the activeRegion.
107     QPoint relativePos = parentMenu->mapFromGlobal(position);
108     QRect activeRegion(relativePos.x(), relativePos.y(), 1, 1);
109     QToolTip::showText(position, toolTip, parentMenu, activeRegion);
110 }
111