2016-10-26 16:43:13 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
2017-01-11 18:31:31 +00:00
|
|
|
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
2016-10-26 16:43:13 +00:00
|
|
|
*/
|
|
|
|
#include "ui/widgets/tooltip.h"
|
|
|
|
|
2017-02-23 10:59:19 +00:00
|
|
|
#include "mainwindow.h"
|
2016-12-23 13:21:01 +00:00
|
|
|
#include "styles/style_widgets.h"
|
2016-10-26 16:43:13 +00:00
|
|
|
|
|
|
|
namespace Ui {
|
|
|
|
|
|
|
|
Tooltip *TooltipInstance = nullptr;
|
|
|
|
|
2017-04-29 18:41:41 +00:00
|
|
|
bool AbstractTooltipShower::tooltipWindowActive() const {
|
|
|
|
if (auto window = App::wnd()) {
|
|
|
|
window->updateIsActive(0);
|
|
|
|
return window->isActive();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-23 13:21:01 +00:00
|
|
|
const style::Tooltip *AbstractTooltipShower::tooltipSt() const {
|
|
|
|
return &st::defaultTooltip;
|
|
|
|
}
|
|
|
|
|
2016-10-26 16:43:13 +00:00
|
|
|
AbstractTooltipShower::~AbstractTooltipShower() {
|
|
|
|
if (TooltipInstance && TooltipInstance->_shower == this) {
|
|
|
|
TooltipInstance->_shower = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Tooltip::Tooltip() : TWidget(nullptr) {
|
|
|
|
TooltipInstance = this;
|
|
|
|
|
|
|
|
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint);
|
|
|
|
setAttribute(Qt::WA_NoSystemBackground, true);
|
2016-12-23 13:21:01 +00:00
|
|
|
setAttribute(Qt::WA_TranslucentBackground, true);
|
2016-10-26 16:43:13 +00:00
|
|
|
|
|
|
|
_showTimer.setSingleShot(true);
|
|
|
|
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow()));
|
|
|
|
|
|
|
|
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::onShow() {
|
|
|
|
if (_shower) {
|
2017-04-29 18:41:41 +00:00
|
|
|
auto text = _shower->tooltipWindowActive() ? _shower->tooltipText() : QString();
|
2016-10-26 16:43:13 +00:00
|
|
|
if (text.isEmpty()) {
|
|
|
|
Hide();
|
|
|
|
} else {
|
|
|
|
TooltipInstance->popup(_shower->tooltipPos(), text, _shower->tooltipSt());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::onWndActiveChanged() {
|
|
|
|
if (!App::wnd() || !App::wnd()->windowHandle() || !App::wnd()->windowHandle()->isActive()) {
|
|
|
|
Tooltip::Hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Tooltip::eventFilter(QObject *o, QEvent *e) {
|
|
|
|
if (e->type() == QEvent::Leave) {
|
|
|
|
_hideByLeaveTimer.start(10);
|
|
|
|
} else if (e->type() == QEvent::Enter) {
|
|
|
|
_hideByLeaveTimer.stop();
|
|
|
|
} else if (e->type() == QEvent::MouseMove) {
|
|
|
|
if ((QCursor::pos() - _point).manhattanLength() > QApplication::startDragDistance()) {
|
|
|
|
Hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TWidget::eventFilter(o, e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::onHideByLeave() {
|
|
|
|
Hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
Tooltip::~Tooltip() {
|
|
|
|
if (TooltipInstance == this) {
|
|
|
|
TooltipInstance = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
|
|
|
if (!_hideByLeaveTimer.isSingleShot()) {
|
|
|
|
_hideByLeaveTimer.setSingleShot(true);
|
|
|
|
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
|
|
|
|
|
2017-02-23 10:59:19 +00:00
|
|
|
QCoreApplication::instance()->installEventFilter(this);
|
2016-10-26 16:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_point = m;
|
|
|
|
_st = st;
|
2016-12-23 13:21:01 +00:00
|
|
|
_text = Text(_st->textStyle, text, _textPlainOptions, _st->widthMax, true);
|
|
|
|
|
|
|
|
_useTransparency = Platform::TransparentWindowsSupported(_point);
|
|
|
|
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
|
2016-10-26 16:43:13 +00:00
|
|
|
|
|
|
|
int32 addw = 2 * st::lineWidth + _st->textPadding.left() + _st->textPadding.right();
|
|
|
|
int32 addh = 2 * st::lineWidth + _st->textPadding.top() + _st->textPadding.bottom();
|
|
|
|
|
|
|
|
// count tooltip size
|
|
|
|
QSize s(addw + _text.maxWidth(), addh + _text.minHeight());
|
|
|
|
if (s.width() > _st->widthMax) {
|
|
|
|
s.setWidth(addw + _text.countWidth(_st->widthMax - addw));
|
|
|
|
s.setHeight(addh + _text.countHeight(s.width() - addw));
|
|
|
|
}
|
2016-12-23 13:21:01 +00:00
|
|
|
int32 maxh = addh + (_st->linesMax * _st->textStyle.font->height);
|
2016-10-26 16:43:13 +00:00
|
|
|
if (s.height() > maxh) {
|
|
|
|
s.setHeight(maxh);
|
|
|
|
}
|
|
|
|
|
|
|
|
// count tooltip position
|
|
|
|
QPoint p(m + _st->shift);
|
|
|
|
if (rtl()) {
|
|
|
|
p.setX(m.x() - s.width() - _st->shift.x());
|
|
|
|
}
|
|
|
|
if (s.width() < 2 * _st->shift.x()) {
|
|
|
|
p.setX(m.x() - (s.width() / 2));
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust tooltip position
|
|
|
|
QRect r(QApplication::desktop()->screenGeometry(m));
|
|
|
|
if (r.x() + r.width() - _st->skip < p.x() + s.width() && p.x() + s.width() > m.x()) {
|
|
|
|
p.setX(qMax(r.x() + r.width() - int32(_st->skip) - s.width(), m.x() - s.width()));
|
|
|
|
}
|
|
|
|
if (r.x() + _st->skip > p.x() && p.x() < m.x()) {
|
|
|
|
p.setX(qMin(m.x(), r.x() + int32(_st->skip)));
|
|
|
|
}
|
|
|
|
if (r.y() + r.height() - _st->skip < p.y() + s.height()) {
|
|
|
|
p.setY(m.y() - s.height() - _st->skip);
|
|
|
|
}
|
|
|
|
if (r.y() > p.x()) {
|
|
|
|
p.setY(qMin(m.y() + _st->shift.y(), r.y() + r.height() - s.height()));
|
|
|
|
}
|
|
|
|
|
|
|
|
setGeometry(QRect(p, s));
|
|
|
|
|
|
|
|
_hideByLeaveTimer.stop();
|
|
|
|
show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::paintEvent(QPaintEvent *e) {
|
|
|
|
Painter p(this);
|
|
|
|
|
2017-01-15 13:12:35 +00:00
|
|
|
#ifdef OS_MAC_OLD
|
|
|
|
p.setCompositionMode(QPainter::CompositionMode_Source);
|
|
|
|
p.fillRect(e->rect(), Qt::transparent);
|
|
|
|
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
|
|
|
#endif // OS_MAC_OLD
|
|
|
|
|
2016-12-23 13:21:01 +00:00
|
|
|
if (_useTransparency) {
|
|
|
|
p.setPen(_st->textBorder);
|
|
|
|
p.setBrush(_st->textBg);
|
|
|
|
PainterHighQualityEnabler hq(p);
|
|
|
|
p.drawRoundedRect(QRectF(0.5, 0.5, width() - 1., height() - 1.), st::buttonRadius, st::buttonRadius);
|
|
|
|
} else {
|
|
|
|
p.fillRect(rect(), _st->textBg);
|
2016-10-26 16:43:13 +00:00
|
|
|
|
2016-12-23 13:21:01 +00:00
|
|
|
p.fillRect(QRect(0, 0, width(), st::lineWidth), _st->textBorder);
|
|
|
|
p.fillRect(QRect(0, height() - st::lineWidth, width(), st::lineWidth), _st->textBorder);
|
|
|
|
p.fillRect(QRect(0, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
|
|
|
p.fillRect(QRect(width() - st::lineWidth, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
|
|
|
}
|
|
|
|
int32 lines = qFloor((height() - 2 * st::lineWidth - _st->textPadding.top() - _st->textPadding.bottom()) / _st->textStyle.font->height);
|
2016-10-26 16:43:13 +00:00
|
|
|
|
|
|
|
p.setPen(_st->textFg);
|
|
|
|
_text.drawElided(p, st::lineWidth + _st->textPadding.left(), st::lineWidth + _st->textPadding.top(), width() - 2 * st::lineWidth - _st->textPadding.left() - _st->textPadding.right(), lines);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::hideEvent(QHideEvent *e) {
|
|
|
|
if (TooltipInstance == this) {
|
|
|
|
Hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::Show(int32 delay, const AbstractTooltipShower *shower) {
|
|
|
|
if (!TooltipInstance) {
|
|
|
|
new Tooltip();
|
|
|
|
}
|
|
|
|
TooltipInstance->_shower = shower;
|
|
|
|
if (delay >= 0) {
|
|
|
|
TooltipInstance->_showTimer.start(delay);
|
|
|
|
} else {
|
|
|
|
TooltipInstance->onShow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tooltip::Hide() {
|
|
|
|
if (auto instance = TooltipInstance) {
|
|
|
|
TooltipInstance = nullptr;
|
|
|
|
instance->_showTimer.stop();
|
|
|
|
instance->_hideByLeaveTimer.stop();
|
|
|
|
instance->hide();
|
|
|
|
instance->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Ui
|