Fix tooltip & popup positioning (#4740)

* Fix tooltip & popup positioning

This tries to ensure the tooltip & popups are created on the correct
monitor

* Add changelog entry

* Clean up debug output

* Use the full frame geometry to figure out screen bound movements

* Remove the now-unused `setStayInScreenRect` function

* Change the UserInfoPopup offset to be based on its width & height
instead

* Remove more debug output
This commit is contained in:
pajlada 2023-08-05 13:22:37 +02:00 committed by GitHub
parent b98be3b0f3
commit 9e2eb0dd29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 63 additions and 54 deletions

View file

@ -28,6 +28,7 @@
- Bugfix: Fix visual glitches with smooth scrolling. (#4501)
- Bugfix: Fixed pings firing for the "Your username" highlight when not signed in. (#4698)
- Bugfix: Fixed partially broken filters on Qt 6 builds. (#4702)
- Bugfix: Fixed tooltips & popups sometimes showing up on the wrong monitor. (#4740)
- Bugfix: Fixed some network errors having `0` as their HTTP status. (#4704)
- Bugfix: Fixed crash that could occurr when closing the usercard too quickly after blocking or unblocking a user. (#4711)
- Bugfix: Fixed highlights sometimes not working after changing sound device, or switching users in your operating system. (#4729)

View file

@ -923,7 +923,8 @@ void CommandController::initialize(Settings &, Paths &paths)
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())),
currentSplit);
userPopup->setData(userName, channel);
userPopup->move(QCursor::pos());
userPopup->moveTo(QCursor::pos(), false,
BaseWindow::BoundsChecker::CursorPosition);
userPopup->show();
return "";
});

View file

@ -10,6 +10,7 @@
#include "widgets/helper/EffectLabel.hpp"
#include "widgets/Label.hpp"
#include "widgets/TooltipWidget.hpp"
#include "widgets/Window.hpp"
#include <QApplication>
#include <QFont>
@ -240,18 +241,6 @@ void BaseWindow::init()
#endif
}
void BaseWindow::setStayInScreenRect(bool value)
{
this->stayInScreenRect_ = value;
this->moveIntoDesktopRect(this->pos());
}
bool BaseWindow::getStayInScreenRect() const
{
return this->stayInScreenRect_;
}
void BaseWindow::setActionOnFocusLoss(ActionOnFocusLoss value)
{
this->actionOnFocusLoss_ = value;
@ -514,7 +503,7 @@ void BaseWindow::leaveEvent(QEvent *)
TooltipWidget::instance()->hide();
}
void BaseWindow::moveTo(QWidget *parent, QPoint point, bool offset)
void BaseWindow::moveTo(QPoint point, bool offset, BoundsChecker boundsChecker)
{
if (offset)
{
@ -522,7 +511,26 @@ void BaseWindow::moveTo(QWidget *parent, QPoint point, bool offset)
point.ry() += 16;
}
this->moveIntoDesktopRect(point);
switch (boundsChecker)
{
case BoundsChecker::Off: {
// The bounds checker is off, *just* move the window
this->move(point);
}
break;
case BoundsChecker::CursorPosition: {
// The bounds checker is on, use the cursor position as the origin
this->moveWithinScreen(point, QCursor::pos());
}
break;
case BoundsChecker::DesiredPosition: {
// The bounds checker is on, use the desired position as the origin
this->moveWithinScreen(point, point);
}
break;
}
}
void BaseWindow::resizeEvent(QResizeEvent *)
@ -576,24 +584,13 @@ void BaseWindow::closeEvent(QCloseEvent *)
void BaseWindow::showEvent(QShowEvent *)
{
this->moveIntoDesktopRect(this->pos());
if (this->frameless_)
{
QTimer::singleShot(30, this, [this] {
this->moveIntoDesktopRect(this->pos());
});
}
}
void BaseWindow::moveIntoDesktopRect(QPoint point)
void BaseWindow::moveWithinScreen(QPoint point, QPoint origin)
{
if (!this->stayInScreenRect_)
{
return;
}
// move the widget into the screen geometry if it's not already in there
auto *screen = QApplication::screenAt(point);
auto *screen = QApplication::screenAt(origin);
if (screen == nullptr)
{
screen = QApplication::primaryScreen();
@ -603,6 +600,9 @@ void BaseWindow::moveIntoDesktopRect(QPoint point)
bool stickRight = false;
bool stickBottom = false;
const auto w = this->frameGeometry().width();
const auto h = this->frameGeometry().height();
if (point.x() < bounds.left())
{
point.setX(bounds.left());
@ -611,15 +611,15 @@ void BaseWindow::moveIntoDesktopRect(QPoint point)
{
point.setY(bounds.top());
}
if (point.x() + this->width() > bounds.right())
if (point.x() + w > bounds.right())
{
stickRight = true;
point.setX(bounds.right() - this->width());
point.setX(bounds.right() - w);
}
if (point.y() + this->height() > bounds.bottom())
if (point.y() + h > bounds.bottom())
{
stickBottom = true;
point.setY(bounds.bottom() - this->height());
point.setY(bounds.bottom() - h);
}
if (stickRight && stickBottom)

View file

@ -36,6 +36,17 @@ public:
DisableLayoutSave = 128,
};
enum class BoundsChecker {
// Don't attempt to do any "stay in screen" stuff, just move me!
Off,
// Attempt to keep the window within bounds of the screen the cursor is on
CursorPosition,
// Attempt to keep the window within bounds of the screen the desired position is on
DesiredPosition,
};
enum ActionOnFocusLoss { Nothing, Delete, Close, Hide };
explicit BaseWindow(FlagsEnum<Flags> flags_ = None,
@ -51,15 +62,12 @@ public:
std::function<void()> onClicked);
EffectLabel *addTitleBarLabel(std::function<void()> onClicked);
void setStayInScreenRect(bool value);
bool getStayInScreenRect() const;
void setActionOnFocusLoss(ActionOnFocusLoss value);
ActionOnFocusLoss getActionOnFocusLoss() const;
void moveTo(QWidget *widget, QPoint point, bool offset = true);
void moveTo(QPoint point, bool offset, BoundsChecker boundsChecker);
virtual float scale() const override;
float scale() const override;
float qtFontScale() const;
pajlada::Signals::NoArgSignal closing;
@ -101,7 +109,12 @@ protected:
private:
void init();
void moveIntoDesktopRect(QPoint point);
/**
*
**/
void moveWithinScreen(QPoint point, QPoint origin);
void calcButtonsSizes();
void drawCustomWindowFrame(QPainter &painter);
void onFocusLost();
@ -121,7 +134,6 @@ private:
bool enableCustomFrame_;
ActionOnFocusLoss actionOnFocusLoss_ = Nothing;
bool frameless_;
bool stayInScreenRect_ = false;
bool shown_ = false;
FlagsEnum<Flags> flags_;
float nativeScale_ = 1;

View file

@ -27,8 +27,6 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
this->setAttribute(Qt::WA_TranslucentBackground);
this->setWindowFlag(Qt::WindowStaysOnTopHint, true);
this->setStayInScreenRect(true);
// Default to using vertical layout
this->initializeVLayout();
this->setLayout(this->vLayout_);

View file

@ -206,8 +206,9 @@ EmotePopup::EmotePopup(QWidget *parent)
, search_(new QLineEdit())
, notebook_(new Notebook(this))
{
this->setStayInScreenRect(true);
this->moveTo(this, getApp()->windows->emotePopupPos(), false);
// this->setStayInScreenRect(true);
this->moveTo(getApp()->windows->emotePopupPos(), false,
BaseWindow::BoundsChecker::DesiredPosition);
auto *layout = new QVBoxLayout();
this->getLayoutContainer()->setLayout(layout);

View file

@ -29,7 +29,6 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
, split_(split)
{
this->setWindowTitle(QStringLiteral("Reply Thread"));
this->setStayInScreenRect(true);
HotkeyController::HotkeyMap actions{
{"delete",

View file

@ -142,7 +142,6 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
assert(split != nullptr &&
"split being nullptr causes lots of bugs down the road");
this->setWindowTitle("Usercard");
this->setStayInScreenRect(true);
HotkeyController::HotkeyMap actions{
{"delete",
@ -715,9 +714,6 @@ void UserInfoPopup::setData(const QString &name,
this->userStateChanged_.invoke();
this->updateLatestMessages();
QTimer::singleShot(1, this, [this] {
this->setStayInScreenRect(true);
});
}
void UserInfoPopup::updateLatestMessages()

View file

@ -46,7 +46,6 @@ QuickSwitcherPopup::QuickSwitcherPopup(QWidget *parent)
this->initWidgets();
this->setStayInScreenRect(true);
const QRect geom = parent->geometry();
// This places the popup in the middle of the parent widget
this->setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter,

View file

@ -1810,7 +1810,8 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
}
}
tooltipWidget->moveTo(this, event->globalPos());
tooltipWidget->moveTo(event->globalPos(), true,
BaseWindow::BoundsChecker::CursorPosition);
tooltipWidget->setWordWrap(isLinkValid);
tooltipWidget->show();
}
@ -2663,8 +2664,9 @@ void ChannelView::showUserInfoPopup(const QString &userName,
: this->underlyingChannel_;
userPopup->setData(userName, contextChannel, openingChannel);
QPoint offset(int(150 * this->scale()), int(70 * this->scale()));
userPopup->move(QCursor::pos() - offset);
QPoint offset(userPopup->width() / 3, userPopup->height() / 5);
userPopup->moveTo(QCursor::pos() - offset, false,
BaseWindow::BoundsChecker::CursorPosition);
userPopup->show();
}

View file

@ -964,7 +964,7 @@ void SplitHeader::enterEvent(QEvent *event)
auto pos = this->mapToGlobal(this->rect().bottomLeft()) +
QPoint((this->width() - tooltip->width()) / 2, 1);
tooltip->moveTo(this, pos, false);
tooltip->moveTo(pos, false, BaseWindow::BoundsChecker::CursorPosition);
tooltip->show();
}