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
src
|
@ -458,6 +458,8 @@ set(SOURCE_FILES
|
||||||
util/Twitch.cpp
|
util/Twitch.cpp
|
||||||
util/Twitch.hpp
|
util/Twitch.hpp
|
||||||
util/TypeName.hpp
|
util/TypeName.hpp
|
||||||
|
util/WidgetHelpers.cpp
|
||||||
|
util/WidgetHelpers.hpp
|
||||||
util/WindowsHelper.cpp
|
util/WindowsHelper.cpp
|
||||||
util/WindowsHelper.hpp
|
util/WindowsHelper.hpp
|
||||||
util/XDGDesktopFile.cpp
|
util/XDGDesktopFile.cpp
|
||||||
|
|
|
@ -926,7 +926,7 @@ void CommandController::initialize(Settings &, Paths &paths)
|
||||||
currentSplit);
|
currentSplit);
|
||||||
userPopup->setData(userName, channel);
|
userPopup->setData(userName, channel);
|
||||||
userPopup->moveTo(QCursor::pos(),
|
userPopup->moveTo(QCursor::pos(),
|
||||||
BaseWindow::BoundsChecker::CursorPosition);
|
widgets::BoundsChecking::CursorPosition);
|
||||||
userPopup->show();
|
userPopup->show();
|
||||||
return "";
|
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();
|
TooltipWidget::instance()->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseWindow::moveTo(QPoint point, BoundsChecker boundsChecker)
|
void BaseWindow::moveTo(QPoint point, widgets::BoundsChecking mode)
|
||||||
{
|
{
|
||||||
switch (boundsChecker)
|
widgets::moveWindowTo(this, point, mode);
|
||||||
{
|
|
||||||
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 *)
|
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)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||||
qintptr *result)
|
qintptr *result)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/FlagsEnum.hpp"
|
#include "common/FlagsEnum.hpp"
|
||||||
|
#include "util/WidgetHelpers.hpp"
|
||||||
#include "widgets/BaseWidget.hpp"
|
#include "widgets/BaseWidget.hpp"
|
||||||
|
|
||||||
#include <pajlada/signals/signalholder.hpp>
|
#include <pajlada/signals/signalholder.hpp>
|
||||||
|
@ -36,17 +37,6 @@ public:
|
||||||
DisableLayoutSave = 128,
|
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 };
|
enum ActionOnFocusLoss { Nothing, Delete, Close, Hide };
|
||||||
|
|
||||||
explicit BaseWindow(FlagsEnum<Flags> flags_ = None,
|
explicit BaseWindow(FlagsEnum<Flags> flags_ = None,
|
||||||
|
@ -65,7 +55,7 @@ public:
|
||||||
void setActionOnFocusLoss(ActionOnFocusLoss value);
|
void setActionOnFocusLoss(ActionOnFocusLoss value);
|
||||||
ActionOnFocusLoss getActionOnFocusLoss() const;
|
ActionOnFocusLoss getActionOnFocusLoss() const;
|
||||||
|
|
||||||
void moveTo(QPoint point, BoundsChecker boundsChecker);
|
void moveTo(QPoint point, widgets::BoundsChecking mode);
|
||||||
|
|
||||||
float scale() const override;
|
float scale() const override;
|
||||||
float qtFontScale() const;
|
float qtFontScale() const;
|
||||||
|
@ -110,11 +100,6 @@ protected:
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
void moveWithinScreen(QPoint point, QPoint origin);
|
|
||||||
|
|
||||||
void calcButtonsSizes();
|
void calcButtonsSizes();
|
||||||
void drawCustomWindowFrame(QPainter &painter);
|
void drawCustomWindowFrame(QPainter &painter);
|
||||||
void onFocusLost();
|
void onFocusLost();
|
||||||
|
|
|
@ -207,7 +207,7 @@ EmotePopup::EmotePopup(QWidget *parent)
|
||||||
{
|
{
|
||||||
// this->setStayInScreenRect(true);
|
// this->setStayInScreenRect(true);
|
||||||
this->moveTo(getApp()->windows->emotePopupPos(),
|
this->moveTo(getApp()->windows->emotePopupPos(),
|
||||||
BaseWindow::BoundsChecker::DesiredPosition);
|
widgets::BoundsChecking::DesiredPosition);
|
||||||
|
|
||||||
auto *layout = new QVBoxLayout();
|
auto *layout = new QVBoxLayout();
|
||||||
this->getLayoutContainer()->setLayout(layout);
|
this->getLayoutContainer()->setLayout(layout);
|
||||||
|
|
|
@ -1832,7 +1832,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
tooltipWidget->moveTo(event->globalPos() + QPoint(16, 16),
|
tooltipWidget->moveTo(event->globalPos() + QPoint(16, 16),
|
||||||
BaseWindow::BoundsChecker::CursorPosition);
|
widgets::BoundsChecking::CursorPosition);
|
||||||
tooltipWidget->setWordWrap(isLinkValid);
|
tooltipWidget->setWordWrap(isLinkValid);
|
||||||
tooltipWidget->show();
|
tooltipWidget->show();
|
||||||
}
|
}
|
||||||
|
@ -2687,7 +2687,7 @@ void ChannelView::showUserInfoPopup(const QString &userName,
|
||||||
|
|
||||||
QPoint offset(userPopup->width() / 3, userPopup->height() / 5);
|
QPoint offset(userPopup->width() / 3, userPopup->height() / 5);
|
||||||
userPopup->moveTo(QCursor::pos() - offset,
|
userPopup->moveTo(QCursor::pos() - offset,
|
||||||
BaseWindow::BoundsChecker::CursorPosition);
|
widgets::BoundsChecking::CursorPosition);
|
||||||
userPopup->show();
|
userPopup->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -956,7 +956,7 @@ void SplitHeader::enterEvent(QEvent *event)
|
||||||
auto pos = this->mapToGlobal(this->rect().bottomLeft()) +
|
auto pos = this->mapToGlobal(this->rect().bottomLeft()) +
|
||||||
QPoint((this->width() - tooltip->width()) / 2, 1);
|
QPoint((this->width() - tooltip->width()) / 2, 1);
|
||||||
|
|
||||||
tooltip->moveTo(pos, BaseWindow::BoundsChecker::CursorPosition);
|
tooltip->moveTo(pos, widgets::BoundsChecking::CursorPosition);
|
||||||
tooltip->show();
|
tooltip->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue