File indexing completed on 2025-04-27 03:58:31
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2007-23-03 0007 * Description : A tool tip widget which follows cursor movements. 0008 * Tool tip content is displayed without delay. 0009 * 0010 * SPDX-FileCopyrightText: 2007-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2009-2010 by Andi Clemens <andi dot clemens at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "dcursortracker.h" 0018 0019 // Qt includes 0020 0021 #include <QStyle> 0022 #include <QStylePainter> 0023 #include <QStyleOptionFrame> 0024 #include <QFrame> 0025 #include <QMouseEvent> 0026 #include <QPointer> 0027 #include <QTimer> 0028 #include <QToolTip> 0029 0030 namespace Digikam 0031 { 0032 0033 class Q_DECL_HIDDEN DCursorTracker::Private 0034 { 0035 0036 public: 0037 0038 explicit Private() 0039 : alignment (Qt::AlignCenter), 0040 enable (true), 0041 keepOpen (false), 0042 autoHideTimer(nullptr), 0043 parent (nullptr) 0044 { 0045 } 0046 0047 Qt::Alignment alignment; 0048 bool enable; 0049 bool keepOpen; 0050 QTimer* autoHideTimer; 0051 QPointer<QWidget> parent; 0052 }; 0053 0054 DCursorTracker::DCursorTracker(const QString& txt, QWidget* const parent, Qt::Alignment align) 0055 : QLabel(txt, parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget), 0056 d(new Private) 0057 { 0058 setBackgroundRole(QPalette::ToolTipBase); 0059 setPalette(QToolTip::palette()); 0060 ensurePolished(); 0061 const int fwidth = 1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, nullptr, this); 0062 setContentsMargins(fwidth, fwidth, fwidth, fwidth); 0063 setFrameStyle(QFrame::NoFrame); 0064 setAlignment(Qt::AlignLeft | Qt::AlignTop); 0065 setIndent(1); 0066 setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0); 0067 0068 d->alignment = align; 0069 d->parent = parent; 0070 d->parent->setMouseTracking(true); 0071 d->parent->installEventFilter(this); 0072 0073 d->autoHideTimer = new QTimer(this); 0074 d->autoHideTimer->setSingleShot(true); 0075 0076 connect(d->autoHideTimer, SIGNAL(timeout()), 0077 this, SLOT(slotAutoHide())); 0078 } 0079 0080 DCursorTracker::~DCursorTracker() 0081 { 0082 delete d; 0083 } 0084 0085 /** 0086 * Overload to make sure the widget size is correct 0087 */ 0088 void DCursorTracker::setText(const QString& txt) 0089 { 0090 QLabel::setText(txt); 0091 adjustSize(); 0092 } 0093 0094 void DCursorTracker::setEnable(bool b) 0095 { 0096 d->enable = b; 0097 } 0098 0099 void DCursorTracker::setKeepOpen(bool b) 0100 { 0101 d->keepOpen = b; 0102 } 0103 0104 void DCursorTracker::setTrackerAlignment(Qt::Alignment alignment) 0105 { 0106 d->alignment = alignment; 0107 } 0108 0109 void DCursorTracker::triggerAutoShow(int timeout) 0110 { 0111 if (canBeDisplayed()) 0112 { 0113 show(); 0114 moveToParent(d->parent); 0115 d->autoHideTimer->start(timeout); 0116 } 0117 } 0118 0119 void DCursorTracker::refresh() 0120 { 0121 moveToParent(d->parent); 0122 } 0123 0124 void DCursorTracker::slotAutoHide() 0125 { 0126 hide(); 0127 } 0128 0129 bool DCursorTracker::eventFilter(QObject* object, QEvent* e) 0130 { 0131 QWidget* const widget = static_cast<QWidget*>(object); 0132 0133 switch (e->type()) 0134 { 0135 case QEvent::MouseMove: 0136 { 0137 QMouseEvent* event = static_cast<QMouseEvent*>(e); 0138 0139 if (canBeDisplayed() && (widget->rect().contains(event->pos()) || 0140 (event->buttons() & Qt::LeftButton))) 0141 { 0142 show(); 0143 moveToParent(widget); 0144 } 0145 else if (!d->keepOpen) 0146 { 0147 hide(); 0148 } 0149 0150 break; 0151 } 0152 0153 case QEvent::Leave: 0154 { 0155 if (!d->keepOpen) 0156 { 0157 hide(); 0158 } 0159 0160 break; 0161 } 0162 0163 default: 0164 break; 0165 } 0166 0167 return false; 0168 } 0169 0170 void DCursorTracker::moveToParent(QWidget* const parent) 0171 { 0172 if (!parent) 0173 { 0174 return; 0175 } 0176 0177 switch (d->alignment) 0178 { 0179 case Qt::AlignLeft: 0180 { 0181 QPoint p = parent->mapToGlobal(QPoint(0, 0)); 0182 int y = p.y() - height(); 0183 move(p.x(), (y < 0) ? (p.y() + parent->height()) : y); 0184 break; 0185 } 0186 0187 case Qt::AlignRight: 0188 { 0189 QPoint p = parent->mapToGlobal(QPoint(parent->width(), 0)); 0190 int y = p.y() - height(); 0191 move(p.x()-width(), (y < 0) ? (p.y() + parent->height()) : y); 0192 break; 0193 } 0194 0195 case Qt::AlignCenter: 0196 default: 0197 { 0198 QPoint p = parent->mapToGlobal(QPoint(parent->width()/2, 0)); 0199 int y = p.y() - height(); 0200 move(p.x()-width()/2, (y < 0) ? (p.y() + parent->height()) : y); 0201 break; 0202 } 0203 } 0204 } 0205 0206 void DCursorTracker::paintEvent(QPaintEvent* e) 0207 { 0208 QStylePainter p(this); 0209 QStyleOptionFrame opt; 0210 opt.initFrom(this); 0211 p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); 0212 p.end(); 0213 0214 QLabel::paintEvent(e); 0215 } 0216 0217 bool DCursorTracker::canBeDisplayed() 0218 { 0219 return (d->enable && d->parent->isVisible()); 0220 } 0221 0222 } // namespace Digikam 0223 0224 #include "moc_dcursortracker.cpp"