feat(overlay): inherit zoom and add zoom factor (#6016)

This commit is contained in:
nerix
2025-03-02 15:28:47 +01:00
committed by GitHub
parent 49a6d75180
commit 13dfe716b8
9 changed files with 172 additions and 45 deletions
+1
View File
@@ -11,6 +11,7 @@
- Minor: Improved error messaging of the `/clip` command. (#5879)
- Minor: Added Linux support for Live Notifications toasts. (#5881, #5971)
- Minor: Messages can now be deleted from the context menu in a channel. (#5956)
- Minor: Overlay windows now inherit the global zoom level and can be zoomed independently. (#6016)
- Bugfix: Fixed a potential way to escape the Lua Plugin sandbox. (#5846)
- Bugfix: Fixed a crash relating to Lua HTTP. (#5800)
- Bugfix: Fixed a crash that could occur on Linux and macOS when clicking "Install" from the update prompt. (#5818)
+10
View File
@@ -285,6 +285,16 @@ void Settings::setClampedUiScale(float value)
this->uiScale.setValue(std::clamp(value, 0.2F, 10.F));
}
float Settings::getClampedOverlayScale() const
{
return std::clamp(this->overlayScaleFactor.getValue(), 0.2F, 10.F);
}
void Settings::setClampedOverlayScale(float value)
{
this->overlayScaleFactor.setValue(std::clamp(value, 0.2F, 10.F));
}
Settings &Settings::instance()
{
assert(instance_ != nullptr);
+4
View File
@@ -190,6 +190,7 @@ public:
// BoolSetting useCustomWindowFrame = {"/appearance/useCustomWindowFrame",
// false};
FloatSetting overlayScaleFactor = {"/appearance/overlay/scaleFactor", 1};
IntSetting overlayBackgroundOpacity = {
"/appearance/overlay/backgroundOpacity", 50};
BoolSetting enableOverlayShadow = {"/appearance/overlay/shadow", true};
@@ -202,6 +203,9 @@ public:
IntSetting overlayShadowOffsetY = {"/appearance/overlay/shadowOffsetY", 2};
IntSetting overlayShadowRadius = {"/appearance/overlay/shadowRadius", 8};
float getClampedOverlayScale() const;
void setClampedOverlayScale(float value);
// Badges
BoolSetting showBadgesGlobalAuthority = {
"/appearance/badges/GlobalAuthority", true};
+1
View File
@@ -61,6 +61,7 @@ private:
std::vector<BaseWidget *> widgets_;
friend class BaseWindow;
friend class OverlayWindow; // for setScale()
};
} // namespace chatterino
+27 -7
View File
@@ -39,6 +39,8 @@
namespace {
using namespace chatterino;
#ifdef USEWINSDK
// From kHiddenTaskbarSize in Firefox
@@ -194,14 +196,29 @@ RECT windowBordersFor(HWND hwnd, bool isMaximized)
#endif
Qt::WindowFlags windowFlagsFor(FlagsEnum<BaseWindow::Flags> flags)
{
Qt::WindowFlags out;
if (flags.has(BaseWindow::Dialog))
{
out.setFlag(Qt::Dialog);
}
else
{
out.setFlag(Qt::Window);
}
out.setFlag(Qt::WindowStaysOnTopHint, flags.has(BaseWindow::TopMost));
out.setFlag(Qt::FramelessWindowHint, flags.has(BaseWindow::Frameless));
return out;
}
} // namespace
namespace chatterino {
BaseWindow::BaseWindow(FlagsEnum<Flags> _flags, QWidget *parent)
: BaseWidget(parent, (_flags.has(Dialog) ? Qt::Dialog : Qt::Window) |
(_flags.has(TopMost) ? Qt::WindowStaysOnTopHint
: Qt::WindowFlags()))
: BaseWidget(parent, windowFlagsFor(_flags))
, enableCustomFrame_(_flags.has(EnableCustomFrame))
, frameless_(_flags.has(Frameless))
, flags_(_flags)
@@ -209,7 +226,6 @@ BaseWindow::BaseWindow(FlagsEnum<Flags> _flags, QWidget *parent)
if (this->frameless_)
{
this->enableCustomFrame_ = false;
this->setWindowFlag(Qt::FramelessWindowHint);
}
if (_flags.has(DontFocus))
@@ -955,11 +971,15 @@ void BaseWindow::paintEvent(QPaintEvent *)
this->drawCustomWindowFrame(painter);
}
float BaseWindow::desiredScale() const
{
return getSettings()->getClampedUiScale();
}
void BaseWindow::updateScale()
{
auto scale = this->flags_.has(DisableCustomScaling)
? 1
: getSettings()->getClampedUiScale();
auto scale =
this->flags_.has(DisableCustomScaling) ? 1 : this->desiredScale();
this->setScale(scale);
+2
View File
@@ -121,6 +121,8 @@ protected:
QPointF movingRelativePos;
bool moving{};
/// @returns The scale this window wants to be at.
virtual float desiredScale() const;
void updateScale();
std::optional<QColor> overrideBackgroundColor_;
+100 -30
View File
@@ -3,6 +3,7 @@
#include "Application.hpp"
#include "common/FlagsEnum.hpp"
#include "common/Literals.hpp"
#include "common/QLogging.hpp"
#include "controllers/hotkeys/HotkeyController.hpp"
#include "singletons/Emotes.hpp"
#include "singletons/Settings.hpp"
@@ -89,8 +90,11 @@ using namespace std::chrono_literals;
OverlayWindow::OverlayWindow(IndirectChannel channel,
const QList<QUuid> &filterIDs)
: QWidget(nullptr,
Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)
: BaseWindow({
BaseWindow::Frameless,
BaseWindow::TopMost,
BaseWindow::DisableLayoutSave,
})
#ifdef Q_OS_WIN
, sizeAllCursor_(::LoadCursor(nullptr, IDC_SIZEALL))
#endif
@@ -123,9 +127,10 @@ OverlayWindow::OverlayWindow(IndirectChannel channel,
this->channelView_.setChannel(this->channel_.get());
this->channelView_.setIsOverlay(true); // use overlay colors
this->channelView_.setAttribute(Qt::WA_TranslucentBackground);
this->holder_.managedConnect(this->channel_.getChannelChanged(), [this]() {
this->channelView_.setChannel(this->channel_.get());
});
this->signalHolder_.managedConnect(
this->channel_.getChannelChanged(), [this]() {
this->channelView_.setChannel(this->channel_.get());
});
this->channelView_.scrollbar()->setHideThumb(true);
this->channelView_.scrollbar()->setHideHighlights(true);
@@ -150,24 +155,40 @@ OverlayWindow::OverlayWindow(IndirectChannel channel,
}
this->applyTheme();
},
this->holder_);
this->signalHolder_);
settings->overlayBackgroundOpacity.connect(
[this] {
this->channelView_.updateColorTheme();
this->update();
},
this->holder_, false);
this->signalHolder_, false);
auto applyIt = [this](auto /*unused*/) {
this->applyTheme();
};
settings->overlayShadowOffsetX.connect(applyIt, this->holder_, false);
settings->overlayShadowOffsetY.connect(applyIt, this->holder_, false);
settings->overlayShadowOpacity.connect(applyIt, this->holder_, false);
settings->overlayShadowRadius.connect(applyIt, this->holder_, false);
settings->overlayShadowColor.connect(applyIt, this->holder_, false);
settings->overlayShadowOffsetX.connect(applyIt, this->signalHolder_, false);
settings->overlayShadowOffsetY.connect(applyIt, this->signalHolder_, false);
settings->overlayShadowOpacity.connect(applyIt, this->signalHolder_, false);
settings->overlayShadowRadius.connect(applyIt, this->signalHolder_, false);
settings->overlayShadowColor.connect(applyIt, this->signalHolder_, false);
this->addShortcuts();
this->signalHolder_.managedConnect(getApp()->getHotkeys()->onItemsUpdated,
[this]() {
this->clearShortcuts();
this->addShortcuts();
});
settings->overlayScaleFactor.connect(
[this] {
this->updateScale();
},
this->signalHolder_, false);
std::ignore = this->scaleChanged.connect([this](float /*scale*/) {
this->channelView_.queueLayout();
});
this->updateScale();
this->triggerFirstActivation();
getApp()->getEmotes()->getGIFTimer().registerOpenOverlayWindow();
}
@@ -197,6 +218,12 @@ void OverlayWindow::applyTheme()
this->update();
}
float OverlayWindow::desiredScale() const
{
return getSettings()->getClampedUiScale() *
getSettings()->getClampedOverlayScale();
}
bool OverlayWindow::eventFilter(QObject * /*object*/, QEvent *event)
{
#ifndef OVERLAY_NATIVE_MOVE
@@ -323,11 +350,9 @@ bool OverlayWindow::nativeEvent(const QByteArray &eventType, void *message,
break;
default:
return QWidget::nativeEvent(eventType, message, result);
return BaseWindow::nativeEvent(eventType, message, result);
}
QWidget::nativeEvent(eventType, message, result);
return returnValue;
}
@@ -464,23 +489,68 @@ void OverlayWindow::triggerFirstActivation()
void OverlayWindow::addShortcuts()
{
auto [seq, allOverlays] = toggleIntertiaShortcut();
if (seq.isEmpty())
{
return;
}
HotkeyController::HotkeyMap actions{
{"zoom",
[](const std::vector<QString> &arguments) -> QString {
if (arguments.size() == 0)
{
qCWarning(chatterinoHotkeys)
<< "zoom shortcut called without arguments. Takes "
"only "
"one argument: \"in\", \"out\", or \"reset\"";
return "zoom shortcut called without arguments. Takes "
"only "
"one argument: \"in\", \"out\", or \"reset\"";
}
auto change = 0.0F;
const auto &direction = arguments.at(0);
if (direction == "reset")
{
getSettings()->uiScale.setValue(1);
return "";
}
auto *shortcut = new QShortcut(seq, this);
if (allOverlays)
if (direction == u"in")
{
change = 0.1F;
}
else if (direction == u"out")
{
change = -0.1F;
}
else
{
qCWarning(chatterinoHotkeys)
<< "Invalid zoom direction, use \"in\", \"out\", or "
"\"reset\"";
return "Invalid zoom direction, use \"in\", \"out\", or "
"\"reset\"";
}
getSettings()->setClampedOverlayScale(
getSettings()->getClampedOverlayScale() + change);
return {};
}},
};
this->shortcuts_ = getApp()->getHotkeys()->shortcutsForCategory(
HotkeyCategory::Window, actions, this);
auto [seq, allOverlays] = toggleIntertiaShortcut();
if (!seq.isEmpty())
{
QObject::connect(shortcut, &QShortcut::activated, this, [] {
getApp()->getWindows()->toggleAllOverlayInertia();
});
}
else
{
QObject::connect(shortcut, &QShortcut::activated, this,
&OverlayWindow::toggleInertia);
auto *inertiaShortcut = new QShortcut(seq, this);
if (allOverlays)
{
QObject::connect(inertiaShortcut, &QShortcut::activated, this, [] {
getApp()->getWindows()->toggleAllOverlayInertia();
});
}
else
{
QObject::connect(inertiaShortcut, &QShortcut::activated, this,
&OverlayWindow::toggleInertia);
}
this->shortcuts_.push_back(inertiaShortcut);
}
}
+6 -4
View File
@@ -1,6 +1,7 @@
#pragma once
#include "common/Channel.hpp"
#include "widgets/BaseWindow.hpp"
#include "widgets/helper/ChannelView.hpp"
#include "widgets/helper/OverlayInteraction.hpp"
@@ -17,7 +18,7 @@ class QGraphicsDropShadowEffect;
namespace chatterino {
class OverlayWindow : public QWidget
class OverlayWindow : public BaseWindow
{
Q_OBJECT
public:
@@ -52,11 +53,13 @@ protected:
NativeResult *result) override;
#endif
void addShortcuts() override;
float desiredScale() const override;
private:
void triggerFirstActivation();
void addShortcuts();
void startInteraction();
void startShortInteraction();
void endInteraction();
@@ -70,7 +73,6 @@ private:
#endif
IndirectChannel channel_;
pajlada::Signals::SignalHolder holder_;
ChannelView channelView_;
QGraphicsDropShadowEffect *dropShadow_;
+21 -4
View File
@@ -45,6 +45,11 @@ const QString META_KEY = u"Windows"_s;
const QString META_KEY = u"Meta"_s;
#endif
const QStringList ZOOM_LEVELS = {
"0.5x", "0.6x", "0.7x", "0.8x", "0.9x", "Default", "1.2x", "1.4x",
"1.6x", "1.8x", "2x", "2.33x", "2.66x", "3x", "3.5x", "4x",
};
void addKeyboardModifierSetting(GeneralPageView &layout, const QString &title,
EnumSetting<Qt::KeyboardModifier> &setting)
{
@@ -184,10 +189,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
return fuzzyToInt(args.value, 10);
});
layout.addDropdown<float>(
"Zoom",
{"0.5x", "0.6x", "0.7x", "0.8x", "0.9x", "Default", "1.2x", "1.4x",
"1.6x", "1.8x", "2x", "2.33x", "2.66x", "3x", "3.5x", "4x"},
s.uiScale,
"Zoom", ZOOM_LEVELS, s.uiScale,
[](auto val) {
if (val == 1)
{
@@ -1030,6 +1032,21 @@ void GeneralPage::initLayout(GeneralPageView &layout)
->addTo(layout);
layout.addSubtitle("Overlay");
layout.addDropdown<float>(
"Zoom factor", ZOOM_LEVELS, s.overlayScaleFactor,
[](auto val) {
if (val == 1)
{
return u"Default"_s;
}
return QString::number(val) + 'x';
},
[](const auto &args) {
return fuzzyToFloat(args.value, 1.F);
},
true,
"The final scale of the messages in the overlay is computed by "
"multiplying this zoom factor with the global zoom level.");
layout.addIntInput(
"Background opacity (0-255)", s.overlayBackgroundOpacity, 0, 255, 1,
"Controls the opacity of the (possibly alternating) background behind "