feat(overlay): inherit zoom and add zoom factor (#6016)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -61,6 +61,7 @@ private:
|
||||
std::vector<BaseWidget *> widgets_;
|
||||
|
||||
friend class BaseWindow;
|
||||
friend class OverlayWindow; // for setScale()
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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 "
|
||||
|
||||
Reference in New Issue
Block a user