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