mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Allow any window to be bounds-checked (#4802)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
37009e8e6b
commit
783c7530f3
9 changed files with 122 additions and 88 deletions
|
@ -458,6 +458,8 @@ set(SOURCE_FILES
|
|||
util/Twitch.cpp
|
||||
util/Twitch.hpp
|
||||
util/TypeName.hpp
|
||||
util/WidgetHelpers.cpp
|
||||
util/WidgetHelpers.hpp
|
||||
util/WindowsHelper.cpp
|
||||
util/WindowsHelper.hpp
|
||||
util/XDGDesktopFile.cpp
|
||||
|
|
|
@ -926,7 +926,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
|||
currentSplit);
|
||||
userPopup->setData(userName, channel);
|
||||
userPopup->moveTo(QCursor::pos(),
|
||||
BaseWindow::BoundsChecker::CursorPosition);
|
||||
widgets::BoundsChecking::CursorPosition);
|
||||
userPopup->show();
|
||||
return "";
|
||||
});
|
||||
|
|
82
src/util/WidgetHelpers.cpp
Normal file
82
src/util/WidgetHelpers.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "util/WidgetHelpers.hpp"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QGuiApplication>
|
||||
#include <QPoint>
|
||||
#include <QScreen>
|
||||
#include <QWidget>
|
||||
|
||||
namespace {
|
||||
|
||||
/// Move the `window` into the `screen` geometry if it's not already in there.
|
||||
void moveWithinScreen(QWidget *window, QScreen *screen, QPoint point)
|
||||
{
|
||||
if (screen == nullptr)
|
||||
{
|
||||
screen = QGuiApplication::primaryScreen();
|
||||
}
|
||||
|
||||
const QRect bounds = screen->availableGeometry();
|
||||
|
||||
bool stickRight = false;
|
||||
bool stickBottom = false;
|
||||
|
||||
const auto w = window->frameGeometry().width();
|
||||
const auto h = window->frameGeometry().height();
|
||||
|
||||
if (point.x() < bounds.left())
|
||||
{
|
||||
point.setX(bounds.left());
|
||||
}
|
||||
if (point.y() < bounds.top())
|
||||
{
|
||||
point.setY(bounds.top());
|
||||
}
|
||||
if (point.x() + w > bounds.right())
|
||||
{
|
||||
stickRight = true;
|
||||
point.setX(bounds.right() - w);
|
||||
}
|
||||
if (point.y() + h > bounds.bottom())
|
||||
{
|
||||
stickBottom = true;
|
||||
point.setY(bounds.bottom() - h);
|
||||
}
|
||||
|
||||
if (stickRight && stickBottom)
|
||||
{
|
||||
const QPoint globalCursorPos = QCursor::pos();
|
||||
point.setY(globalCursorPos.y() - window->height() - 16);
|
||||
}
|
||||
|
||||
window->move(point);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino::widgets {
|
||||
|
||||
void moveWindowTo(QWidget *window, QPoint position, BoundsChecking mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case BoundsChecking::Off: {
|
||||
window->move(position);
|
||||
}
|
||||
break;
|
||||
|
||||
case BoundsChecking::CursorPosition: {
|
||||
moveWithinScreen(window, QGuiApplication::screenAt(QCursor::pos()),
|
||||
position);
|
||||
}
|
||||
break;
|
||||
|
||||
case BoundsChecking::DesiredPosition: {
|
||||
moveWithinScreen(window, QGuiApplication::screenAt(position),
|
||||
position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino::widgets
|
29
src/util/WidgetHelpers.hpp
Normal file
29
src/util/WidgetHelpers.hpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
class QWidget;
|
||||
class QPoint;
|
||||
class QScreen;
|
||||
|
||||
namespace chatterino::widgets {
|
||||
|
||||
enum class BoundsChecking {
|
||||
/// Don't do any bounds checking (equivalent to `QWidget::move`).
|
||||
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,
|
||||
};
|
||||
|
||||
/// Moves the `window` to the (global) `position`
|
||||
/// while doing bounds-checking according to `mode` to ensure the window stays on one screen.
|
||||
///
|
||||
/// @param window The window to move.
|
||||
/// @param position The global position to move the window to.
|
||||
/// @param mode The desired bounds checking.
|
||||
void moveWindowTo(QWidget *window, QPoint position,
|
||||
BoundsChecking mode = BoundsChecking::DesiredPosition);
|
||||
|
||||
} // namespace chatterino::widgets
|
|
@ -503,28 +503,9 @@ void BaseWindow::leaveEvent(QEvent *)
|
|||
TooltipWidget::instance()->hide();
|
||||
}
|
||||
|
||||
void BaseWindow::moveTo(QPoint point, BoundsChecker boundsChecker)
|
||||
void BaseWindow::moveTo(QPoint point, widgets::BoundsChecking mode)
|
||||
{
|
||||
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;
|
||||
}
|
||||
widgets::moveWindowTo(this, point, mode);
|
||||
}
|
||||
|
||||
void BaseWindow::resizeEvent(QResizeEvent *)
|
||||
|
@ -580,51 +561,6 @@ void BaseWindow::showEvent(QShowEvent *)
|
|||
{
|
||||
}
|
||||
|
||||
void BaseWindow::moveWithinScreen(QPoint point, QPoint origin)
|
||||
{
|
||||
// move the widget into the screen geometry if it's not already in there
|
||||
auto *screen = QApplication::screenAt(origin);
|
||||
|
||||
if (screen == nullptr)
|
||||
{
|
||||
screen = QApplication::primaryScreen();
|
||||
}
|
||||
const QRect bounds = screen->availableGeometry();
|
||||
|
||||
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());
|
||||
}
|
||||
if (point.y() < bounds.top())
|
||||
{
|
||||
point.setY(bounds.top());
|
||||
}
|
||||
if (point.x() + w > bounds.right())
|
||||
{
|
||||
stickRight = true;
|
||||
point.setX(bounds.right() - w);
|
||||
}
|
||||
if (point.y() + h > bounds.bottom())
|
||||
{
|
||||
stickBottom = true;
|
||||
point.setY(bounds.bottom() - h);
|
||||
}
|
||||
|
||||
if (stickRight && stickBottom)
|
||||
{
|
||||
const QPoint globalCursorPos = QCursor::pos();
|
||||
point.setY(globalCursorPos.y() - this->height() - 16);
|
||||
}
|
||||
|
||||
this->move(point);
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||
qintptr *result)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/FlagsEnum.hpp"
|
||||
#include "util/WidgetHelpers.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
@ -36,17 +37,6 @@ 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,
|
||||
|
@ -65,7 +55,7 @@ public:
|
|||
void setActionOnFocusLoss(ActionOnFocusLoss value);
|
||||
ActionOnFocusLoss getActionOnFocusLoss() const;
|
||||
|
||||
void moveTo(QPoint point, BoundsChecker boundsChecker);
|
||||
void moveTo(QPoint point, widgets::BoundsChecking mode);
|
||||
|
||||
float scale() const override;
|
||||
float qtFontScale() const;
|
||||
|
@ -110,11 +100,6 @@ protected:
|
|||
private:
|
||||
void init();
|
||||
|
||||
/**
|
||||
*
|
||||
**/
|
||||
void moveWithinScreen(QPoint point, QPoint origin);
|
||||
|
||||
void calcButtonsSizes();
|
||||
void drawCustomWindowFrame(QPainter &painter);
|
||||
void onFocusLost();
|
||||
|
|
|
@ -207,7 +207,7 @@ EmotePopup::EmotePopup(QWidget *parent)
|
|||
{
|
||||
// this->setStayInScreenRect(true);
|
||||
this->moveTo(getApp()->windows->emotePopupPos(),
|
||||
BaseWindow::BoundsChecker::DesiredPosition);
|
||||
widgets::BoundsChecking::DesiredPosition);
|
||||
|
||||
auto *layout = new QVBoxLayout();
|
||||
this->getLayoutContainer()->setLayout(layout);
|
||||
|
|
|
@ -1832,7 +1832,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
|||
}
|
||||
|
||||
tooltipWidget->moveTo(event->globalPos() + QPoint(16, 16),
|
||||
BaseWindow::BoundsChecker::CursorPosition);
|
||||
widgets::BoundsChecking::CursorPosition);
|
||||
tooltipWidget->setWordWrap(isLinkValid);
|
||||
tooltipWidget->show();
|
||||
}
|
||||
|
@ -2687,7 +2687,7 @@ void ChannelView::showUserInfoPopup(const QString &userName,
|
|||
|
||||
QPoint offset(userPopup->width() / 3, userPopup->height() / 5);
|
||||
userPopup->moveTo(QCursor::pos() - offset,
|
||||
BaseWindow::BoundsChecker::CursorPosition);
|
||||
widgets::BoundsChecking::CursorPosition);
|
||||
userPopup->show();
|
||||
}
|
||||
|
||||
|
|
|
@ -956,7 +956,7 @@ void SplitHeader::enterEvent(QEvent *event)
|
|||
auto pos = this->mapToGlobal(this->rect().bottomLeft()) +
|
||||
QPoint((this->width() - tooltip->width()) / 2, 1);
|
||||
|
||||
tooltip->moveTo(pos, BaseWindow::BoundsChecker::CursorPosition);
|
||||
tooltip->moveTo(pos, widgets::BoundsChecking::CursorPosition);
|
||||
tooltip->show();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue