1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "QTrackingTooltip.h"
6 #include <QApplication>
7 #include <QDesktopWidget>
9 QSharedPointer
<QTrackingTooltip
> QTrackingTooltip::m_instance
;
11 QTrackingTooltip::QTrackingTooltip(QWidget
* parent
)
14 , m_cursorOffset(0, 0)
17 setWindowFlags(Qt::ToolTip
| Qt::FramelessWindowHint
| Qt::WindowStaysOnTopHint
);
18 setFocusPolicy(Qt::FocusPolicy::NoFocus
);
19 setAttribute(Qt::WA_ShowWithoutActivating
);
20 setAttribute(Qt::WA_TransparentForMouseEvents
);
23 QTrackingTooltip::~QTrackingTooltip(void)
27 void QTrackingTooltip::Show()
33 void QTrackingTooltip::ShowTextTooltip(const QString
& str
, const QPoint
& p
)
37 if (!str
.isEmpty() && m_instance
->SetText(str
))
39 m_instance
->SetPos(p
);
43 QTrackingTooltip::HideTooltip();
48 m_instance
= QSharedPointer
<QTrackingTooltip
>(new QTrackingTooltip(), &QObject::deleteLater
);
49 m_instance
->SetText(str
);
51 m_instance
->SetPos(p
);
55 void QTrackingTooltip::ShowTrackingTooltip(QSharedPointer
<QTrackingTooltip
>& tooltip
, const QPoint
& cursorOffset
)
57 if (m_instance
&& m_instance
!= tooltip
)
59 QTrackingTooltip::HideTooltip();
67 if (!cursorOffset
.isNull())
68 m_instance
->SetPosCursorOffset(cursorOffset
);
69 else if (m_instance
->GetCursorOffset().isNull())
70 m_instance
->SetPosCursorOffset(QPoint(25, 25));
72 m_instance
->SetPosCursorOffset();
74 m_instance
->m_isTracking
= true;
75 qApp
->installEventFilter(m_instance
.data());
79 void QTrackingTooltip::HideTooltip()
83 qApp
->removeEventFilter(m_instance
.data());
84 m_instance
->m_isTracking
= false;
85 m_instance
->setVisible(false);
90 void QTrackingTooltip::HideTooltip(QTrackingTooltip
* tooltip
)
92 if (m_instance
== tooltip
)
96 bool QTrackingTooltip::SetText(const QString
& str
)
98 QLabel
* label
= findChild
<QLabel
*>("QTrackingTooltipLabel");
109 label
= new QLabel(this, Qt::WindowStaysOnTopHint
);
110 label
->setFrameStyle(QFrame::Panel
);
111 label
->setFont(QToolTip::font());
112 label
->setPalette(QToolTip::palette());
114 label
->setObjectName("QTrackingTooltipLabel");
117 auto layout
= new QVBoxLayout();
118 layout
->setMargin(1);
119 layout
->addWidget(label
);
124 bool QTrackingTooltip::SetPixmap(const QPixmap
& pixmap
)
126 QLabel
* label
= findChild
<QLabel
*>("QTrackingTooltipLabel");
129 label
->setPixmap(pixmap
);
137 label
= new QLabel();
138 label
->setFrameStyle(QFrame::Panel
);
139 label
->setPixmap(pixmap
);
140 label
->setObjectName("QTrackingTooltipLabel");
143 auto layout
= new QVBoxLayout();
144 layout
->setMargin(1);
145 layout
->addWidget(label
);
150 void QTrackingTooltip::SetPos(const QPoint
& p
)
152 move(AdjustPosition(p
));
155 void QTrackingTooltip::SetPosCursorOffset(const QPoint
& p
)
160 SetPos(QCursor::pos() + m_cursorOffset
);
163 QPoint
QTrackingTooltip::AdjustPosition(QPoint p
) const
165 //The tooltip position may never overlap the cursor (otherwise we have a leave event and the tooltip disappears)
167 QRect rect
= this->rect();
168 QRect screen
= QApplication::desktop()->screenGeometry(GetToolTipScreen());
171 if (p
.x() + rect
.width() > screen
.x() + screen
.width())
172 p
.rx() -= 4 + rect
.width();
173 if (p
.y() + rect
.height() > screen
.y() + screen
.height())
174 p
.ry() -= 24 + rect
.height();
175 if (p
.y() < screen
.y())
177 if (p
.x() + rect
.width() > screen
.x() + screen
.width())
178 p
.setX(screen
.x() + screen
.width() - rect
.width());
179 if (p
.x() < screen
.x())
181 if (p
.y() + rect
.height() > screen
.y() + screen
.height())
182 p
.setY(screen
.y() + screen
.height() - rect
.height());
184 QRect
futureRect(p
.x(), p
.y(), rect
.width(), rect
.height());
185 const auto cursor
= QCursor::pos();
186 if (futureRect
.contains(cursor
))
191 int diff
= cursor
.x() - futureRect
.left();
193 offset
= QPoint(diff
+ abs(m_cursorOffset
.x()) + 1, 0);
195 diff
= futureRect
.right() - cursor
.x();
199 offset
= QPoint(-diff
- abs(m_cursorOffset
.x()) - 1, 0);
202 diff
= cursor
.y() - futureRect
.top();
206 offset
= QPoint(0, diff
+ abs(m_cursorOffset
.y()) + 1);
209 diff
= futureRect
.bottom() - cursor
.y();
213 offset
= QPoint(0, -diff
- abs(m_cursorOffset
.y()) - 1);
218 CRY_ASSERT(!QRect(p
.x(), p
.y(), rect
.width(), rect
.height()).contains(cursor
));
224 int QTrackingTooltip::GetToolTipScreen() const
226 if (QApplication::desktop()->isVirtualDesktop())
227 return QApplication::desktop()->screenNumber(QCursor::pos());
229 return QApplication::desktop()->screenNumber(this);
232 //Inspired from qtooltip.cpp
233 //Note that this code originally had special cases for macOS and QNX.
234 bool QTrackingTooltip::eventFilter(QObject
* object
, QEvent
* event
)
236 switch (event
->type())
239 //Note: here we may actually want to start a hide timer instead,
240 //as we could still be wanting to display the same tooltip.
241 //Not useful yet but will be.
242 case QEvent::WindowActivate
:
243 case QEvent::WindowDeactivate
:
244 case QEvent::FocusIn
:
245 case QEvent::FocusOut
:
246 case QEvent::MouseButtonPress
:
247 case QEvent::MouseButtonRelease
:
248 case QEvent::MouseButtonDblClick
:
252 QTrackingTooltip::HideTooltip();
255 case QEvent::MouseMove
:
258 SetPosCursorOffset(m_cursorOffset
);
266 void QTrackingTooltip::resizeEvent(QResizeEvent
* resizeEvent
)
270 SetPosCursorOffset(m_cursorOffset
);