added ui scaling

This commit is contained in:
fourtf 2018-06-11 15:04:54 +02:00
parent 9b26fce781
commit ea9f9e7f18
27 changed files with 488 additions and 271 deletions

View file

@ -140,7 +140,6 @@ SOURCES += \
src/widgets/emotepopup.cpp \ src/widgets/emotepopup.cpp \
src/widgets/helper/channelview.cpp \ src/widgets/helper/channelview.cpp \
src/widgets/helper/droppreview.cpp \ src/widgets/helper/droppreview.cpp \
src/widgets/helper/label.cpp \
src/widgets/helper/notebookbutton.cpp \ src/widgets/helper/notebookbutton.cpp \
src/widgets/helper/notebooktab.cpp \ src/widgets/helper/notebooktab.cpp \
src/widgets/helper/resizingtextedit.cpp \ src/widgets/helper/resizingtextedit.cpp \
@ -217,7 +216,8 @@ SOURCES += \
src/util/emotemap.cpp \ src/util/emotemap.cpp \
src/providers/irc/ircconnection2.cpp \ src/providers/irc/ircconnection2.cpp \
src/widgets/userinfopopup.cpp \ src/widgets/userinfopopup.cpp \
src/widgets/welcomedialog.cpp src/widgets/welcomedialog.cpp \
src/widgets/label.cpp
HEADERS += \ HEADERS += \
src/precompiled_header.hpp \ src/precompiled_header.hpp \
@ -285,7 +285,6 @@ HEADERS += \
src/widgets/emotepopup.hpp \ src/widgets/emotepopup.hpp \
src/widgets/helper/channelview.hpp \ src/widgets/helper/channelview.hpp \
src/widgets/helper/droppreview.hpp \ src/widgets/helper/droppreview.hpp \
src/widgets/helper/label.hpp \
src/widgets/helper/notebookbutton.hpp \ src/widgets/helper/notebookbutton.hpp \
src/widgets/helper/notebooktab.hpp \ src/widgets/helper/notebooktab.hpp \
src/widgets/helper/resizingtextedit.hpp \ src/widgets/helper/resizingtextedit.hpp \
@ -377,7 +376,9 @@ HEADERS += \
src/providers/irc/ircconnection2.hpp \ src/providers/irc/ircconnection2.hpp \
src/widgets/helper/line.hpp \ src/widgets/helper/line.hpp \
src/widgets/userinfopopup.hpp \ src/widgets/userinfopopup.hpp \
src/widgets/welcomedialog.hpp src/widgets/welcomedialog.hpp \
src/util/clamp.hpp \
src/widgets/label.hpp
RESOURCES += \ RESOURCES += \
resources/resources.qrc resources/resources.qrc

View file

@ -121,7 +121,7 @@ FontManager::FontData FontManager::createFontData(Type type, float scale)
static std::unordered_map<Type, UiFontData> defaultSize{ static std::unordered_map<Type, UiFontData> defaultSize{
{Tiny, {8, "Monospace", false, QFont::Normal}}, {Tiny, {8, "Monospace", false, QFont::Normal}},
{UiMedium, {int(12 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}}, {UiMedium, {int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
{UiTabs, {int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}}, {UiTabs, {int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
}; };

View file

@ -44,6 +44,7 @@ public:
IntSetting collpseMessagesMinLines = {"/appearance/messages/collapseMessagesMinLines", 0}; IntSetting collpseMessagesMinLines = {"/appearance/messages/collapseMessagesMinLines", 0};
BoolSetting alternateMessageBackground = {"/appearance/messages/alternateMessageBackground", BoolSetting alternateMessageBackground = {"/appearance/messages/alternateMessageBackground",
false}; false};
IntSetting uiScale = {"/appearance/uiScale", 0};
BoolSetting windowTopMost = {"/appearance/windowAlwaysOnTop", false}; BoolSetting windowTopMost = {"/appearance/windowAlwaysOnTop", false};
BoolSetting showTabCloseButton = {"/appearance/showTabCloseButton", true}; BoolSetting showTabCloseButton = {"/appearance/showTabCloseButton", true};
BoolSetting hidePreferencesButton = {"/appearance/hidePreferencesButton", false}; BoolSetting hidePreferencesButton = {"/appearance/hidePreferencesButton", false};

View file

@ -7,6 +7,7 @@
#include "singletons/pathmanager.hpp" #include "singletons/pathmanager.hpp"
#include "singletons/thememanager.hpp" #include "singletons/thememanager.hpp"
#include "util/assertinguithread.hpp" #include "util/assertinguithread.hpp"
#include "util/clamp.hpp"
#include "widgets/accountswitchpopupwidget.hpp" #include "widgets/accountswitchpopupwidget.hpp"
#include "widgets/settingsdialog.hpp" #include "widgets/settingsdialog.hpp"
@ -410,5 +411,53 @@ void WindowManager::incGeneration()
this->generation++; this->generation++;
} }
int WindowManager::clampUiScale(int scale)
{
return util::clamp(scale, uiScaleMin, uiScaleMax);
}
float WindowManager::getUiScaleValue()
{
return getUiScaleValue(getApp()->settings->uiScale.getValue());
}
float WindowManager::getUiScaleValue(int scale)
{
switch (clampUiScale(scale)) {
case -5:
return 0.5f;
case -4:
return 0.6f;
case -3:
return 0.7f;
case -2:
return 0.8f;
case -1:
return 0.9f;
case 0:
return 1;
case 1:
return 1.2f;
case 2:
return 1.4f;
case 3:
return 1.6f;
case 4:
return 1.6f;
case 5:
return 2;
case 6:
return 2.33f;
case 7:
return 2.66f;
case 8:
return 3;
case 9:
return 3.5f;
case 10:
return 4;
}
}
} // namespace singletons } // namespace singletons
} // namespace chatterino } // namespace chatterino

View file

@ -42,6 +42,12 @@ public:
pajlada::Signals::NoArgSignal repaintGifs; pajlada::Signals::NoArgSignal repaintGifs;
pajlada::Signals::Signal<Channel *> layout; pajlada::Signals::Signal<Channel *> layout;
static const int uiScaleMin = -5;
static const int uiScaleMax = 10;
static int clampUiScale(int scale);
static float getUiScaleValue();
static float getUiScaleValue(int scale);
private: private:
bool initialized = false; bool initialized = false;

23
src/util/clamp.hpp Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include <algorithm>
namespace chatterino {
namespace util {
// http://en.cppreference.com/w/cpp/algorithm/clamp
template <class T>
constexpr const T &clamp(const T &v, const T &lo, const T &hi)
{
return clamp(v, lo, hi, std::less<>());
}
template <class T, class Compare>
constexpr const T &clamp(const T &v, const T &lo, const T &hi, Compare comp)
{
return assert(!comp(hi, lo)), comp(v, lo) ? lo : comp(hi, v) ? hi : v;
}
} // namespace util
} // namespace chatterino

View file

@ -1,10 +1,15 @@
#include "basewindow.hpp" #include "basewindow.hpp"
#include "application.hpp" #include "application.hpp"
#include "boost/algorithm/algorithm.hpp"
#include "debug/log.hpp" #include "debug/log.hpp"
#include "singletons/settingsmanager.hpp" #include "singletons/settingsmanager.hpp"
#include "singletons/windowmanager.hpp"
#include "util/nativeeventhelper.hpp" #include "util/nativeeventhelper.hpp"
#include "util/posttothread.hpp"
#include "widgets/helper/rippleeffectlabel.hpp" #include "widgets/helper/rippleeffectlabel.hpp"
#include "widgets/helper/shortcut.hpp"
#include "widgets/label.hpp"
#include "widgets/tooltipwidget.hpp" #include "widgets/tooltipwidget.hpp"
#include <QApplication> #include <QApplication>
@ -35,25 +40,33 @@ namespace widgets {
BaseWindow::BaseWindow(QWidget *parent, Flags _flags) BaseWindow::BaseWindow(QWidget *parent, Flags _flags)
: BaseWidget(parent, : BaseWidget(parent,
Qt::Window | ((_flags & TopMost) ? Qt::WindowStaysOnTopHint : Qt::WindowFlags())) Qt::Window | ((_flags & TopMost) ? Qt::WindowStaysOnTopHint : Qt::WindowFlags()))
, enableCustomFrame(_flags & EnableCustomFrame) , enableCustomFrame_(_flags & EnableCustomFrame)
, frameless(_flags & Frameless) , frameless_(_flags & Frameless)
, flags(_flags) , flags_(_flags)
{ {
if (this->frameless) { if (this->frameless_) {
this->enableCustomFrame = false; this->enableCustomFrame_ = false;
this->setWindowFlag(Qt::FramelessWindowHint); this->setWindowFlag(Qt::FramelessWindowHint);
} }
if (this->flags & DeleteOnFocusOut) { if (this->flags_ & DeleteOnFocusOut) {
this->setAttribute(Qt::WA_DeleteOnClose); this->setAttribute(Qt::WA_DeleteOnClose);
} }
this->init(); this->init();
this->connections_.managedConnect(
getApp()->settings->uiScale.getValueChangedSignal(),
[this](auto, auto) { util::postToThread([this] { this->updateScale(); }); });
this->updateScale();
CreateWindowShortcut(this, "CTRL+0", [] { getApp()->settings->uiScale.setValue(1); });
} }
BaseWindow::Flags BaseWindow::getFlags() BaseWindow::Flags BaseWindow::getFlags()
{ {
return this->flags; return this->flags_;
} }
void BaseWindow::init() void BaseWindow::init()
@ -68,23 +81,23 @@ void BaseWindow::init()
layout->setSpacing(0); layout->setSpacing(0);
this->setLayout(layout); this->setLayout(layout);
{ {
if (!this->frameless) { if (!this->frameless_) {
QHBoxLayout *buttonLayout = this->ui.titlebarBox = new QHBoxLayout(); QHBoxLayout *buttonLayout = this->ui_.titlebarBox = new QHBoxLayout();
buttonLayout->setMargin(0); buttonLayout->setMargin(0);
layout->addLayout(buttonLayout); layout->addLayout(buttonLayout);
// title // title
QLabel *title = new QLabel(" Chatterino"); Label *title = new Label("Chatterino");
QObject::connect(this, &QWidget::windowTitleChanged, QObject::connect(this, &QWidget::windowTitleChanged,
[title](const QString &text) { title->setText(" " + text); }); [title](const QString &text) { title->setText(text); });
QSizePolicy policy(QSizePolicy::Ignored, QSizePolicy::Preferred); QSizePolicy policy(QSizePolicy::Ignored, QSizePolicy::Preferred);
policy.setHorizontalStretch(1); policy.setHorizontalStretch(1);
// title->setBaseSize(0, 0); // title->setBaseSize(0, 0);
title->setScaledContents(true); // title->setScaledContents(true);
title->setSizePolicy(policy); title->setSizePolicy(policy);
buttonLayout->addWidget(title); buttonLayout->addWidget(title);
this->ui.titleLabel = title; this->ui_.titleLabel = title;
// buttons // buttons
TitleBarButton *_minButton = new TitleBarButton; TitleBarButton *_minButton = new TitleBarButton;
@ -105,13 +118,13 @@ void BaseWindow::init()
QObject::connect(_exitButton, &TitleBarButton::clicked, this, QObject::connect(_exitButton, &TitleBarButton::clicked, this,
[this] { this->close(); }); [this] { this->close(); });
this->ui.minButton = _minButton; this->ui_.minButton = _minButton;
this->ui.maxButton = _maxButton; this->ui_.maxButton = _maxButton;
this->ui.exitButton = _exitButton; this->ui_.exitButton = _exitButton;
this->ui.buttons.push_back(_minButton); this->ui_.buttons.push_back(_minButton);
this->ui.buttons.push_back(_maxButton); this->ui_.buttons.push_back(_maxButton);
this->ui.buttons.push_back(_exitButton); this->ui_.buttons.push_back(_exitButton);
// buttonLayout->addStretch(1); // buttonLayout->addStretch(1);
buttonLayout->addWidget(_minButton); buttonLayout->addWidget(_minButton);
@ -120,8 +133,8 @@ void BaseWindow::init()
buttonLayout->setSpacing(0); buttonLayout->setSpacing(0);
} }
} }
this->ui.layoutBase = new BaseWidget(this); this->ui_.layoutBase = new BaseWidget(this);
layout->addWidget(this->ui.layoutBase); layout->addWidget(this->ui_.layoutBase);
} }
// DPI // DPI
@ -134,7 +147,7 @@ void BaseWindow::init()
#ifdef USEWINSDK #ifdef USEWINSDK
// fourtf: don't ask me why we need to delay this // fourtf: don't ask me why we need to delay this
if (!(this->flags & Flags::TopMost)) { if (!(this->flags_ & Flags::TopMost)) {
QTimer::singleShot(1, this, [this] { QTimer::singleShot(1, this, [this] {
getApp()->settings->windowTopMost.connect([this](bool topMost, auto) { getApp()->settings->windowTopMost.connect([this](bool topMost, auto) {
::SetWindowPos(HWND(this->winId()), topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, ::SetWindowPos(HWND(this->winId()), topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0,
@ -151,18 +164,18 @@ void BaseWindow::init()
void BaseWindow::setStayInScreenRect(bool value) void BaseWindow::setStayInScreenRect(bool value)
{ {
this->stayInScreenRect = value; this->stayInScreenRect_ = value;
} }
bool BaseWindow::getStayInScreenRect() const bool BaseWindow::getStayInScreenRect() const
{ {
return this->stayInScreenRect; return this->stayInScreenRect_;
} }
QWidget *BaseWindow::getLayoutContainer() QWidget *BaseWindow::getLayoutContainer()
{ {
if (this->hasCustomWindowFrame()) { if (this->hasCustomWindowFrame()) {
return this->ui.layoutBase; return this->ui_.layoutBase;
} else { } else {
return this; return this;
} }
@ -173,7 +186,7 @@ bool BaseWindow::hasCustomWindowFrame()
#ifdef USEWINSDK #ifdef USEWINSDK
static bool isWin8 = IsWindows8OrGreater(); static bool isWin8 = IsWindows8OrGreater();
return isWin8 && this->enableCustomFrame; return isWin8 && this->enableCustomFrame_;
#else #else
return false; return false;
#endif #endif
@ -187,14 +200,14 @@ void BaseWindow::themeRefreshEvent()
palette.setColor(QPalette::Foreground, this->themeManager->window.text); palette.setColor(QPalette::Foreground, this->themeManager->window.text);
this->setPalette(palette); this->setPalette(palette);
if (this->ui.titleLabel) { if (this->ui_.titleLabel) {
QPalette palette_title; QPalette palette_title;
palette_title.setColor(QPalette::Foreground, palette_title.setColor(QPalette::Foreground,
this->themeManager->isLightTheme() ? "#333" : "#ccc"); this->themeManager->isLightTheme() ? "#333" : "#ccc");
this->ui.titleLabel->setPalette(palette_title); this->ui_.titleLabel->setPalette(palette_title);
} }
for (RippleEffectButton *button : this->ui.buttons) { for (RippleEffectButton *button : this->ui_.buttons) {
button->setMouseEffectColor(this->themeManager->window.text); button->setMouseEffectColor(this->themeManager->window.text);
} }
} else { } else {
@ -208,7 +221,7 @@ void BaseWindow::themeRefreshEvent()
bool BaseWindow::event(QEvent *event) bool BaseWindow::event(QEvent *event)
{ {
if (event->type() == QEvent::WindowDeactivate /*|| event->type() == QEvent::FocusOut*/) { if (event->type() == QEvent::WindowDeactivate /*|| event->type() == QEvent::FocusOut*/) {
if (this->flags & DeleteOnFocusOut) { if (this->flags_ & DeleteOnFocusOut) {
this->close(); this->close();
} }
} }
@ -216,14 +229,27 @@ bool BaseWindow::event(QEvent *event)
return QWidget::event(event); return QWidget::event(event);
} }
void BaseWindow::wheelEvent(QWheelEvent *event)
{
if (event->modifiers() & Qt::ControlModifier) {
if (event->delta() > 0) {
getApp()->settings->uiScale.setValue(singletons::WindowManager::clampUiScale(
getApp()->settings->uiScale.getValue() + 1));
} else {
getApp()->settings->uiScale.setValue(singletons::WindowManager::clampUiScale(
getApp()->settings->uiScale.getValue() - 1));
}
}
}
void BaseWindow::addTitleBarButton(const TitleBarButton::Style &style, void BaseWindow::addTitleBarButton(const TitleBarButton::Style &style,
std::function<void()> onClicked) std::function<void()> onClicked)
{ {
TitleBarButton *button = new TitleBarButton; TitleBarButton *button = new TitleBarButton;
button->setScaleIndependantSize(30, 30); button->setScaleIndependantSize(30, 30);
this->ui.buttons.push_back(button); this->ui_.buttons.push_back(button);
this->ui.titlebarBox->insertWidget(1, button); this->ui_.titlebarBox->insertWidget(1, button);
button->setButtonStyle(style); button->setButtonStyle(style);
QObject::connect(button, &TitleBarButton::clicked, this, [onClicked] { onClicked(); }); QObject::connect(button, &TitleBarButton::clicked, this, [onClicked] { onClicked(); });
@ -234,8 +260,8 @@ RippleEffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
RippleEffectLabel *button = new RippleEffectLabel; RippleEffectLabel *button = new RippleEffectLabel;
button->setScaleIndependantHeight(30); button->setScaleIndependantHeight(30);
this->ui.buttons.push_back(button); this->ui_.buttons.push_back(button);
this->ui.titlebarBox->insertWidget(1, button); this->ui_.titlebarBox->insertWidget(1, button);
QObject::connect(button, &RippleEffectLabel::clicked, this, [onClicked] { onClicked(); }); QObject::connect(button, &RippleEffectLabel::clicked, this, [onClicked] { onClicked(); });
@ -247,8 +273,8 @@ void BaseWindow::changeEvent(QEvent *)
TooltipWidget::getInstance()->hide(); TooltipWidget::getInstance()->hide();
#ifdef USEWINSDK #ifdef USEWINSDK
if (this->ui.maxButton) { if (this->ui_.maxButton) {
this->ui.maxButton->setButtonStyle(this->windowState() & Qt::WindowMaximized this->ui_.maxButton->setButtonStyle(this->windowState() & Qt::WindowMaximized
? TitleBarButton::Unmaximize ? TitleBarButton::Unmaximize
: TitleBarButton::Maximize); : TitleBarButton::Maximize);
} }
@ -284,7 +310,7 @@ void BaseWindow::resizeEvent(QResizeEvent *)
void BaseWindow::moveIntoDesktopRect(QWidget *parent) void BaseWindow::moveIntoDesktopRect(QWidget *parent)
{ {
if (!this->stayInScreenRect) if (!this->stayInScreenRect_)
return; return;
// move the widget into the screen geometry if it's not already in there // move the widget into the screen geometry if it's not already in there
@ -326,7 +352,8 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message, long *r
this->resize(static_cast<int>(this->width() * resizeScale), this->resize(static_cast<int>(this->width() * resizeScale),
static_cast<int>(this->height() * resizeScale)); static_cast<int>(this->height() * resizeScale));
this->setScale(_scale); this->nativeScale_ = _scale;
this->updateScale();
return true; return true;
} }
@ -419,13 +446,13 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message, long *r
bool client = false; bool client = false;
QPoint point(x - winrect.left, y - winrect.top); QPoint point(x - winrect.left, y - winrect.top);
for (QWidget *widget : this->ui.buttons) { for (QWidget *widget : this->ui_.buttons) {
if (widget->geometry().contains(point)) { if (widget->geometry().contains(point)) {
client = true; client = true;
} }
} }
if (this->ui.layoutBase->geometry().contains(point)) { if (this->ui_.layoutBase->geometry().contains(point)) {
client = true; client = true;
} }
@ -449,8 +476,8 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message, long *r
void BaseWindow::showEvent(QShowEvent *event) void BaseWindow::showEvent(QShowEvent *event)
{ {
if (!this->shown && this->isVisible() && this->hasCustomWindowFrame()) { if (!this->shown_ && this->isVisible() && this->hasCustomWindowFrame()) {
this->shown = true; this->shown_ = true;
// SetWindowLongPtr((HWND)this->winId(), GWL_STYLE, // SetWindowLongPtr((HWND)this->winId(), GWL_STYLE,
// WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX | // WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX |
// WS_MINIMIZEBOX); // WS_MINIMIZEBOX);
@ -470,7 +497,7 @@ void BaseWindow::scaleChangedEvent(float)
void BaseWindow::paintEvent(QPaintEvent *) void BaseWindow::paintEvent(QPaintEvent *)
{ {
if (this->frameless) { if (this->frameless_) {
QPainter painter(this); QPainter painter(this);
painter.setPen(QColor("#999")); painter.setPen(QColor("#999"));
@ -489,25 +516,32 @@ void BaseWindow::paintEvent(QPaintEvent *)
#endif #endif
} }
void BaseWindow::updateScale()
{
this->setScale(this->nativeScale_ * (this->flags_ & DisableCustomScaling
? 1
: getApp()->windows->getUiScaleValue()));
}
void BaseWindow::calcButtonsSizes() void BaseWindow::calcButtonsSizes()
{ {
if (!this->shown) { if (!this->shown_) {
return; return;
} }
if ((this->width() / this->getScale()) < 300) { if ((this->width() / this->getScale()) < 300) {
if (this->ui.minButton) if (this->ui_.minButton)
this->ui.minButton->setScaleIndependantSize(30, 30); this->ui_.minButton->setScaleIndependantSize(30, 30);
if (this->ui.maxButton) if (this->ui_.maxButton)
this->ui.maxButton->setScaleIndependantSize(30, 30); this->ui_.maxButton->setScaleIndependantSize(30, 30);
if (this->ui.exitButton) if (this->ui_.exitButton)
this->ui.exitButton->setScaleIndependantSize(30, 30); this->ui_.exitButton->setScaleIndependantSize(30, 30);
} else { } else {
if (this->ui.minButton) if (this->ui_.minButton)
this->ui.minButton->setScaleIndependantSize(46, 30); this->ui_.minButton->setScaleIndependantSize(46, 30);
if (this->ui.maxButton) if (this->ui_.maxButton)
this->ui.maxButton->setScaleIndependantSize(46, 30); this->ui_.maxButton->setScaleIndependantSize(46, 30);
if (this->ui.exitButton) if (this->ui_.exitButton)
this->ui.exitButton->setScaleIndependantSize(46, 30); this->ui_.exitButton->setScaleIndependantSize(46, 30);
} }
} }
} // namespace widgets } // namespace widgets

View file

@ -4,6 +4,7 @@
#include "widgets/helper/titlebarbutton.hpp" #include "widgets/helper/titlebarbutton.hpp"
#include <functional> #include <functional>
#include <pajlada/signals/signalholder.hpp>
class QHBoxLayout; class QHBoxLayout;
@ -24,10 +25,11 @@ public:
EnableCustomFrame = 1, EnableCustomFrame = 1,
Frameless = 2, Frameless = 2,
TopMost = 4, TopMost = 4,
DeleteOnFocusOut = 8 DeleteOnFocusOut = 8,
DisableCustomScaling = 16,
}; };
explicit BaseWindow(QWidget *parent = nullptr, Flags flags = None); explicit BaseWindow(QWidget *parent = nullptr, Flags flags_ = None);
QWidget *getLayoutContainer(); QWidget *getLayoutContainer();
bool hasCustomWindowFrame(); bool hasCustomWindowFrame();
@ -56,17 +58,21 @@ protected:
virtual void themeRefreshEvent() override; virtual void themeRefreshEvent() override;
virtual bool event(QEvent *event) override; virtual bool event(QEvent *event) override;
virtual void wheelEvent(QWheelEvent *event) override;
void updateScale();
private: private:
void init(); void init();
void moveIntoDesktopRect(QWidget *parent); void moveIntoDesktopRect(QWidget *parent);
void calcButtonsSizes(); void calcButtonsSizes();
bool enableCustomFrame; bool enableCustomFrame_;
bool frameless; bool frameless_;
bool stayInScreenRect = false; bool stayInScreenRect_ = false;
bool shown = false; bool shown_ = false;
Flags flags; Flags flags_;
float nativeScale_ = 1;
struct { struct {
QHBoxLayout *titlebarBox = nullptr; QHBoxLayout *titlebarBox = nullptr;
@ -76,7 +82,9 @@ private:
TitleBarButton *exitButton = nullptr; TitleBarButton *exitButton = nullptr;
QWidget *layoutBase = nullptr; QWidget *layoutBase = nullptr;
std::vector<RippleEffectButton *> buttons; std::vector<RippleEffectButton *> buttons;
} ui; } ui_;
pajlada::Signals::SignalHolder connections_;
}; };
} // namespace widgets } // namespace widgets

View file

@ -660,6 +660,11 @@ void ChannelView::drawMessages(QPainter &painter)
void ChannelView::wheelEvent(QWheelEvent *event) void ChannelView::wheelEvent(QWheelEvent *event)
{ {
if (event->modifiers() & Qt::ControlModifier) {
event->ignore();
return;
}
this->pausedBySelection = false; this->pausedBySelection = false;
this->pausedTemporarily = false; this->pausedTemporarily = false;

View file

@ -1,86 +0,0 @@
#include "label.hpp"
#include "application.hpp"
#include "singletons/fontmanager.hpp"
#include <QPainter>
namespace chatterino {
namespace widgets {
Label::Label(BaseWidget *parent)
: BaseWidget(parent)
{
auto app = getApp();
app->fonts->fontChanged.connect([=]() {
this->scaleChangedEvent(this->getScale()); //
});
}
const QString &Label::getText() const
{
return this->text;
}
void Label::setText(const QString &value)
{
this->text = value;
this->scaleChangedEvent(this->getScale());
}
FontStyle Label::getFontStyle() const
{
return this->fontStyle;
}
void Label::setFontStyle(FontStyle style)
{
this->fontStyle = style;
this->scaleChangedEvent(this->getScale());
}
void Label::scaleChangedEvent(float scale)
{
auto app = getApp();
QFontMetrics metrics = app->fonts->getFontMetrics(this->fontStyle, scale);
this->preferedSize = QSize(metrics.width(this->text), metrics.height());
this->updateGeometry();
}
QSize Label::sizeHint() const
{
return this->preferedSize;
}
QSize Label::minimumSizeHint() const
{
return this->preferedSize;
}
void Label::paintEvent(QPaintEvent *)
{
auto app = getApp();
QPainter painter(this);
painter.setFont(app->fonts->getFont(this->fontStyle,
this->getScale() / painter.device()->devicePixelRatioF()));
int width = app->fonts->getFontMetrics(this->fontStyle, this->getScale()).width(this->text);
int flags = Qt::TextSingleLine;
if (this->width() < width) {
flags |= Qt::AlignLeft | Qt::AlignVCenter;
} else {
flags |= Qt::AlignCenter;
}
painter.drawText(this->rect(), flags, this->text);
}
} // namespace widgets
} // namespace chatterino

View file

@ -1,34 +0,0 @@
#pragma once
#include "singletons/fontmanager.hpp"
#include "widgets/basewidget.hpp"
namespace chatterino {
namespace widgets {
class Label : public BaseWidget
{
public:
Label(BaseWidget *parent);
const QString &getText() const;
void setText(const QString &text);
FontStyle getFontStyle() const;
void setFontStyle(FontStyle style);
protected:
virtual void scaleChangedEvent(float scale) override;
virtual void paintEvent(QPaintEvent *event) override;
virtual QSize sizeHint() const override;
virtual QSize minimumSizeHint() const override;
private:
QSize preferedSize;
QString text;
FontStyle fontStyle = FontStyle::ChatMedium;
};
} // namespace widgets
} // namespace chatterino

View file

@ -5,6 +5,7 @@
#include "debug/log.hpp" #include "debug/log.hpp"
#include "singletons/settingsmanager.hpp" #include "singletons/settingsmanager.hpp"
#include "singletons/thememanager.hpp" #include "singletons/thememanager.hpp"
#include "util/clamp.hpp"
#include "util/helpers.hpp" #include "util/helpers.hpp"
#include "widgets/notebook.hpp" #include "widgets/notebook.hpp"
#include "widgets/settingsdialog.hpp" #include "widgets/settingsdialog.hpp"
@ -78,12 +79,12 @@ void NotebookTab::updateSize()
FontStyle::UiTabs, float(qreal(this->getScale()) * this->devicePixelRatioF())); FontStyle::UiTabs, float(qreal(this->getScale()) * this->devicePixelRatioF()));
if (this->hasXButton()) { if (this->hasXButton()) {
width = int((metrics.width(this->getTitle()) + 32) * scale); width = (metrics.width(this->getTitle()) + int(32 * scale));
} else { } else {
width = int((metrics.width(this->getTitle()) + 16) * scale); width = (metrics.width(this->getTitle()) + int(16 * scale));
} }
width = std::max<int>(this->height(), std::min(int(150 * scale), width)); width = util::clamp(width, this->height(), int(150 * scale));
if (this->width() != width) { if (this->width() != width) {
this->resize(width, int(NOTEBOOK_TAB_HEIGHT * scale)); this->resize(width, int(NOTEBOOK_TAB_HEIGHT * scale));

View file

@ -7,7 +7,7 @@
#include "singletons/thememanager.hpp" #include "singletons/thememanager.hpp"
#include "util/layoutcreator.hpp" #include "util/layoutcreator.hpp"
#include "util/urlfetch.hpp" #include "util/urlfetch.hpp"
#include "widgets/helper/label.hpp" #include "widgets/label.hpp"
#include "widgets/split.hpp" #include "widgets/split.hpp"
#include "widgets/splitcontainer.hpp" #include "widgets/splitcontainer.hpp"
#include "widgets/tooltipwidget.hpp" #include "widgets/tooltipwidget.hpp"
@ -48,19 +48,11 @@ SplitHeader::SplitHeader(Split *_split)
}); });
}); });
layout->addStretch(1);
// channel name label // channel name label
// auto title = layout.emplace<Label>(this).assign(&this->titleLabel); auto title = layout.emplace<Label>().assign(&this->titleLabel);
auto title = layout.emplace<QLabel>().assign(&this->titleLabel);
title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
// title->setMouseTracking(true); title->setCentered(true);
// QObject::connect(this->titleLabel, &SignalLabel::mouseDoubleClick, this, title->setHasOffset(false);
// &SplitHeader::mouseDoubleClickEvent);
// QObject::connect(this->titleLabel, &SignalLabel::mouseMove, this,
// &SplitHeader::mouseMoveEvent);
layout->addStretch(1);
// mode button // mode button
auto mode = layout.emplace<RippleEffectLabel>(this).assign(&this->modeButton); auto mode = layout.emplace<RippleEffectLabel>(this).assign(&this->modeButton);

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "widgets/basewidget.hpp" #include "widgets/basewidget.hpp"
#include "widgets/helper/label.hpp"
#include "widgets/helper/rippleeffectlabel.hpp" #include "widgets/helper/rippleeffectlabel.hpp"
#include "widgets/helper/signallabel.hpp" #include "widgets/helper/signallabel.hpp"
@ -23,6 +22,7 @@ namespace chatterino {
namespace widgets { namespace widgets {
class Split; class Split;
class Label;
class SplitHeader : public BaseWidget, pajlada::Signals::SignalHolder class SplitHeader : public BaseWidget, pajlada::Signals::SignalHolder
{ {
@ -61,7 +61,7 @@ private:
RippleEffectButton *dropdownButton; RippleEffectButton *dropdownButton;
// Label *titleLabel; // Label *titleLabel;
QLabel *titleLabel; Label *titleLabel;
RippleEffectLabel *modeButton; RippleEffectLabel *modeButton;
RippleEffectButton *moderationButton; RippleEffectButton *moderationButton;

View file

@ -112,6 +112,7 @@ void SplitInput::scaleChangedEvent(float scale)
// set maximum height // set maximum height
this->setMaximumHeight(int(150 * this->getScale())); this->setMaximumHeight(int(150 * this->getScale()));
this->ui_.textEdit->setFont(getApp()->fonts->getFont(FontStyle::ChatMedium, this->getScale()));
} }
void SplitInput::themeRefreshEvent() void SplitInput::themeRefreshEvent()

121
src/widgets/label.cpp Normal file
View file

@ -0,0 +1,121 @@
#include "label.hpp"
#include "application.hpp"
#include <QPainter>
namespace chatterino {
namespace widgets {
Label::Label(QString text, FontStyle style)
: Label(nullptr, text, style)
{
}
Label::Label(BaseWidget *parent, QString text, FontStyle style)
: BaseWidget(parent)
, text_(text)
, fontStyle_(style)
{
auto app = getApp();
app->fonts->fontChanged.connect([=] { this->updateSize(); });
}
const QString &Label::getText() const
{
return this->text_;
}
void Label::setText(const QString &text)
{
this->text_ = text;
this->updateSize();
}
FontStyle Label::getFontStyle() const
{
return this->fontStyle_;
}
bool Label::getCentered() const
{
return this->centered_;
}
void Label::setCentered(bool centered)
{
this->centered_ = centered;
this->updateSize();
}
bool Label::getHasOffset() const
{
return this->hasOffset_;
}
void Label::setHasOffset(bool hasOffset)
{
this->hasOffset_ = hasOffset;
this->updateSize();
}
void Label::setFontStyle(FontStyle style)
{
this->fontStyle_ = style;
this->updateSize();
}
void Label::scaleChangedEvent(float)
{
this->updateSize();
}
QSize Label::sizeHint() const
{
return this->preferedSize_;
}
QSize Label::minimumSizeHint() const
{
return this->preferedSize_;
}
void Label::paintEvent(QPaintEvent *)
{
auto app = getApp();
QPainter painter(this);
QFontMetrics metrics = app->fonts->getFontMetrics(this->getFontStyle(),
this->getScale() * this->devicePixelRatioF());
painter.setFont(
app->fonts->getFont(this->getFontStyle(), this->getScale() * this->devicePixelRatioF()));
int offset = this->hasOffset_ ? int(8 * this->getScale()) : 0;
// draw text
QRect textRect(offset, 0, this->width() - offset - offset, this->height());
int width = metrics.width(this->text_);
Qt::Alignment alignment = !this->centered_ || width > textRect.width()
? Qt::AlignLeft | Qt::AlignVCenter
: Qt::AlignCenter;
QTextOption option(alignment);
option.setWrapMode(QTextOption::NoWrap);
painter.drawText(textRect, this->text_, option);
}
void Label::updateSize()
{
auto app = getApp();
QFontMetrics metrics = app->fonts->getFontMetrics(this->fontStyle_, this->getScale());
this->preferedSize_ = QSize(metrics.width(this->text_), metrics.height());
this->updateGeometry();
}
} // namespace widgets
} // namespace chatterino

46
src/widgets/label.hpp Normal file
View file

@ -0,0 +1,46 @@
#pragma once
#include "singletons/fontmanager.hpp"
#include "widgets/basewidget.hpp"
namespace chatterino {
namespace widgets {
class Label : public BaseWidget
{
public:
explicit Label(QString text = QString(), FontStyle style = FontStyle::UiMedium);
explicit Label(BaseWidget *parent, QString text = QString(),
FontStyle style = FontStyle::UiMedium);
const QString &getText() const;
void setText(const QString &text);
FontStyle getFontStyle() const;
void setFontStyle(FontStyle style);
bool getCentered() const;
void setCentered(bool centered);
bool getHasOffset() const;
void setHasOffset(bool centered);
protected:
virtual void scaleChangedEvent(float scale) override;
virtual void paintEvent(QPaintEvent *) override;
virtual QSize sizeHint() const override;
virtual QSize minimumSizeHint() const override;
private:
QString text_;
FontStyle fontStyle_;
QSize preferedSize_;
bool centered_ = false;
bool hasOffset_ = true;
void updateSize();
};
} // namespace widgets
} // namespace chatterino

View file

@ -340,7 +340,7 @@ void Notebook::performLayout(bool animated)
x += i->tab->width(); x += i->tab->width();
} }
x += 1; x += int(scale * 2);
first = false; first = false;
} }

View file

@ -8,23 +8,23 @@ namespace widgets {
QualityPopup::QualityPopup(const QString &_channelName, QStringList options) QualityPopup::QualityPopup(const QString &_channelName, QStringList options)
: channelName(_channelName) : channelName(_channelName)
{ {
this->ui.okButton.setText("OK"); this->ui_.okButton.setText("OK");
this->ui.cancelButton.setText("Cancel"); this->ui_.cancelButton.setText("Cancel");
QObject::connect(&this->ui.okButton, &QPushButton::clicked, this, QObject::connect(&this->ui_.okButton, &QPushButton::clicked, this,
&QualityPopup::okButtonClicked); &QualityPopup::okButtonClicked);
QObject::connect(&this->ui.cancelButton, &QPushButton::clicked, this, QObject::connect(&this->ui_.cancelButton, &QPushButton::clicked, this,
&QualityPopup::cancelButtonClicked); &QualityPopup::cancelButtonClicked);
this->ui.buttonBox.addButton(&this->ui.okButton, QDialogButtonBox::ButtonRole::AcceptRole); this->ui_.buttonBox.addButton(&this->ui_.okButton, QDialogButtonBox::ButtonRole::AcceptRole);
this->ui.buttonBox.addButton(&this->ui.cancelButton, QDialogButtonBox::ButtonRole::RejectRole); this->ui_.buttonBox.addButton(&this->ui_.cancelButton, QDialogButtonBox::ButtonRole::RejectRole);
this->ui.selector.addItems(options); this->ui_.selector.addItems(options);
this->ui.vbox.addWidget(&this->ui.selector); this->ui_.vbox.addWidget(&this->ui_.selector);
this->ui.vbox.addWidget(&this->ui.buttonBox); this->ui_.vbox.addWidget(&this->ui_.buttonBox);
this->setLayout(&this->ui.vbox); this->setLayout(&this->ui_.vbox);
} }
void QualityPopup::showDialog(const QString &channelName, QStringList options) void QualityPopup::showDialog(const QString &channelName, QStringList options)
@ -44,7 +44,7 @@ void QualityPopup::okButtonClicked()
QString channelURL = "twitch.tv/" + this->channelName; QString channelURL = "twitch.tv/" + this->channelName;
try { try {
streamlink::OpenStreamlink(channelURL, this->ui.selector.currentText()); streamlink::OpenStreamlink(channelURL, this->ui_.selector.currentText());
} catch (const streamlink::Exception &ex) { } catch (const streamlink::Exception &ex) {
debug::Log("Exception caught trying to open streamlink: {}", ex.what()); debug::Log("Exception caught trying to open streamlink: {}", ex.what());
} }

View file

@ -23,7 +23,7 @@ private:
QDialogButtonBox buttonBox; QDialogButtonBox buttonBox;
QPushButton okButton; QPushButton okButton;
QPushButton cancelButton; QPushButton cancelButton;
} ui; } ui_;
QString channelName; QString channelName;

View file

@ -26,7 +26,7 @@ SelectChannelDialog::SelectChannelDialog()
util::LayoutCreator<QWidget> layoutWidget(this->getLayoutContainer()); util::LayoutCreator<QWidget> layoutWidget(this->getLayoutContainer());
auto layout = layoutWidget.setLayoutType<QVBoxLayout>().withoutMargin(); auto layout = layoutWidget.setLayoutType<QVBoxLayout>().withoutMargin();
auto notebook = layout.emplace<Notebook>(this).assign(&this->ui.notebook); auto notebook = layout.emplace<Notebook>(this).assign(&this->ui_.notebook);
// twitch // twitch
{ {
@ -34,10 +34,10 @@ SelectChannelDialog::SelectChannelDialog()
auto vbox = obj.setLayoutType<QVBoxLayout>(); auto vbox = obj.setLayoutType<QVBoxLayout>();
// channel_btn // channel_btn
auto channel_btn = vbox.emplace<QRadioButton>("Channel").assign(&this->ui.twitch.channel); auto channel_btn = vbox.emplace<QRadioButton>("Channel").assign(&this->ui_.twitch.channel);
auto channel_lbl = vbox.emplace<QLabel>("Join a twitch channel by its name.").hidden(); auto channel_lbl = vbox.emplace<QLabel>("Join a twitch channel by its name.").hidden();
channel_lbl->setWordWrap(true); channel_lbl->setWordWrap(true);
auto channel_edit = vbox.emplace<QLineEdit>().hidden().assign(&this->ui.twitch.channelName); auto channel_edit = vbox.emplace<QLineEdit>().hidden().assign(&this->ui_.twitch.channelName);
QObject::connect(*channel_btn, &QRadioButton::toggled, [=](bool enabled) mutable { QObject::connect(*channel_btn, &QRadioButton::toggled, [=](bool enabled) mutable {
if (enabled) { if (enabled) {
@ -54,7 +54,7 @@ SelectChannelDialog::SelectChannelDialog()
// whispers_btn // whispers_btn
auto whispers_btn = auto whispers_btn =
vbox.emplace<QRadioButton>("Whispers").assign(&this->ui.twitch.whispers); vbox.emplace<QRadioButton>("Whispers").assign(&this->ui_.twitch.whispers);
auto whispers_lbl = auto whispers_lbl =
vbox.emplace<QLabel>("Shows the whispers that you receive while chatterino is running.") vbox.emplace<QLabel>("Shows the whispers that you receive while chatterino is running.")
.hidden(); .hidden();
@ -67,7 +67,7 @@ SelectChannelDialog::SelectChannelDialog()
// mentions_btn // mentions_btn
auto mentions_btn = auto mentions_btn =
vbox.emplace<QRadioButton>("Mentions").assign(&this->ui.twitch.mentions); vbox.emplace<QRadioButton>("Mentions").assign(&this->ui_.twitch.mentions);
auto mentions_lbl = auto mentions_lbl =
vbox.emplace<QLabel>("Shows all the messages that highlight you from any channel.") vbox.emplace<QLabel>("Shows all the messages that highlight you from any channel.")
.hidden(); .hidden();
@ -80,7 +80,7 @@ SelectChannelDialog::SelectChannelDialog()
// watching_btn // watching_btn
auto watching_btn = auto watching_btn =
vbox.emplace<QRadioButton>("Watching").assign(&this->ui.twitch.watching); vbox.emplace<QRadioButton>("Watching").assign(&this->ui_.twitch.watching);
auto watching_lbl = auto watching_lbl =
vbox.emplace<QLabel>("Requires the chatterino browser extension.").hidden(); vbox.emplace<QLabel>("Requires the chatterino browser extension.").hidden();
@ -151,25 +151,25 @@ void SelectChannelDialog::setSelectedChannel(IndirectChannel _channel)
switch (_channel.getType()) { switch (_channel.getType()) {
case Channel::Twitch: { case Channel::Twitch: {
this->ui.notebook->selectIndex(TAB_TWITCH); this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui.twitch.channel->setFocus(); this->ui_.twitch.channel->setFocus();
this->ui.twitch.channelName->setText(channel->name); this->ui_.twitch.channelName->setText(channel->name);
} break; } break;
case Channel::TwitchWatching: { case Channel::TwitchWatching: {
this->ui.notebook->selectIndex(TAB_TWITCH); this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui.twitch.watching->setFocus(); this->ui_.twitch.watching->setFocus();
} break; } break;
case Channel::TwitchMentions: { case Channel::TwitchMentions: {
this->ui.notebook->selectIndex(TAB_TWITCH); this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui.twitch.mentions->setFocus(); this->ui_.twitch.mentions->setFocus();
} break; } break;
case Channel::TwitchWhispers: { case Channel::TwitchWhispers: {
this->ui.notebook->selectIndex(TAB_TWITCH); this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui.twitch.whispers->setFocus(); this->ui_.twitch.whispers->setFocus();
} break; } break;
default: { default: {
this->ui.notebook->selectIndex(TAB_TWITCH); this->ui_.notebook->selectIndex(TAB_TWITCH);
this->ui.twitch.channel->setFocus(); this->ui_.twitch.channel->setFocus();
} }
} }
@ -184,15 +184,15 @@ IndirectChannel SelectChannelDialog::getSelectedChannel() const
auto app = getApp(); auto app = getApp();
switch (this->ui.notebook->getSelectedIndex()) { switch (this->ui_.notebook->getSelectedIndex()) {
case TAB_TWITCH: { case TAB_TWITCH: {
if (this->ui.twitch.channel->isChecked()) { if (this->ui_.twitch.channel->isChecked()) {
return app->twitch.server->getOrAddChannel(this->ui.twitch.channelName->text()); return app->twitch.server->getOrAddChannel(this->ui_.twitch.channelName->text());
} else if (this->ui.twitch.watching->isChecked()) { } else if (this->ui_.twitch.watching->isChecked()) {
return app->twitch.server->watchingChannel; return app->twitch.server->watchingChannel;
} else if (this->ui.twitch.mentions->isChecked()) { } else if (this->ui_.twitch.mentions->isChecked()) {
return app->twitch.server->mentionsChannel; return app->twitch.server->mentionsChannel;
} else if (this->ui.twitch.whispers->isChecked()) { } else if (this->ui_.twitch.whispers->isChecked()) {
return app->twitch.server->whispersChannel; return app->twitch.server->whispersChannel;
} }
} }
@ -226,8 +226,8 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched, QEvent *eve
QKeyEvent *event_key = static_cast<QKeyEvent *>(event); QKeyEvent *event_key = static_cast<QKeyEvent *>(event);
if ((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Down) && if ((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Down) &&
event_key->modifiers() == Qt::NoModifier) { event_key->modifiers() == Qt::NoModifier) {
if (widget == this->dialog->ui.twitch.channelName) { if (widget == this->dialog->ui_.twitch.channelName) {
this->dialog->ui.twitch.whispers->setFocus(); this->dialog->ui_.twitch.whispers->setFocus();
return true; return true;
} else { } else {
widget->nextInFocusChain()->setFocus(); widget->nextInFocusChain()->setFocus();
@ -236,11 +236,11 @@ bool SelectChannelDialog::EventFilter::eventFilter(QObject *watched, QEvent *eve
} else if (((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Backtab) && } else if (((event_key->key() == Qt::Key_Tab || event_key->key() == Qt::Key_Backtab) &&
event_key->modifiers() == Qt::ShiftModifier) || event_key->modifiers() == Qt::ShiftModifier) ||
((event_key->key() == Qt::Key_Up) && event_key->modifiers() == Qt::NoModifier)) { ((event_key->key() == Qt::Key_Up) && event_key->modifiers() == Qt::NoModifier)) {
if (widget == this->dialog->ui.twitch.channelName) { if (widget == this->dialog->ui_.twitch.channelName) {
this->dialog->ui.twitch.watching->setFocus(); this->dialog->ui_.twitch.watching->setFocus();
return true; return true;
} else if (widget == this->dialog->ui.twitch.whispers) { } else if (widget == this->dialog->ui_.twitch.whispers) {
this->dialog->ui.twitch.channel->setFocus(); this->dialog->ui_.twitch.channel->setFocus();
return true; return true;
} }

View file

@ -46,7 +46,7 @@ private:
QRadioButton *mentions; QRadioButton *mentions;
QRadioButton *watching; QRadioButton *watching;
} twitch; } twitch;
} ui; } ui_;
EventFilter tabFilter; EventFilter tabFilter;

View file

@ -25,7 +25,7 @@ namespace widgets {
SettingsDialog *SettingsDialog::handle = nullptr; SettingsDialog *SettingsDialog::handle = nullptr;
SettingsDialog::SettingsDialog() SettingsDialog::SettingsDialog()
: BaseWindow() : BaseWindow(nullptr, BaseWindow::DisableCustomScaling)
{ {
this->initUi(); this->initUi();
@ -40,30 +40,30 @@ void SettingsDialog::initUi()
// tab pages // tab pages
layoutCreator.emplace<QWidget>() layoutCreator.emplace<QWidget>()
.assign(&this->ui.tabContainerContainer) .assign(&this->ui_.tabContainerContainer)
.emplace<QVBoxLayout>() .emplace<QVBoxLayout>()
.withoutMargin() .withoutMargin()
.assign(&this->ui.tabContainer); .assign(&this->ui_.tabContainer);
// right side layout // right side layout
auto right = layoutCreator.emplace<QVBoxLayout>().withoutMargin(); auto right = layoutCreator.emplace<QVBoxLayout>().withoutMargin();
{ {
right.emplace<QStackedLayout>().assign(&this->ui.pageStack).withoutMargin(); right.emplace<QStackedLayout>().assign(&this->ui_.pageStack).withoutMargin();
auto buttons = right.emplace<QDialogButtonBox>(Qt::Horizontal); auto buttons = right.emplace<QDialogButtonBox>(Qt::Horizontal);
{ {
this->ui.okButton = buttons->addButton("Ok", QDialogButtonBox::YesRole); this->ui_.okButton = buttons->addButton("Ok", QDialogButtonBox::YesRole);
this->ui.cancelButton = buttons->addButton("Cancel", QDialogButtonBox::NoRole); this->ui_.cancelButton = buttons->addButton("Cancel", QDialogButtonBox::NoRole);
} }
} }
// ---- misc // ---- misc
this->ui.tabContainerContainer->setObjectName("tabWidget"); this->ui_.tabContainerContainer->setObjectName("tabWidget");
this->ui.pageStack->setObjectName("pages"); this->ui_.pageStack->setObjectName("pages");
QObject::connect(this->ui.okButton, &QPushButton::clicked, this, QObject::connect(this->ui_.okButton, &QPushButton::clicked, this,
&SettingsDialog::okButtonClicked); &SettingsDialog::okButtonClicked);
QObject::connect(this->ui.cancelButton, &QPushButton::clicked, this, QObject::connect(this->ui_.cancelButton, &QPushButton::clicked, this,
&SettingsDialog::cancelButtonClicked); &SettingsDialog::cancelButtonClicked);
} }
@ -74,23 +74,23 @@ SettingsDialog *SettingsDialog::getHandle()
void SettingsDialog::addTabs() void SettingsDialog::addTabs()
{ {
this->ui.tabContainer->setSpacing(0); this->ui_.tabContainer->setSpacing(0);
this->addTab(new settingspages::AccountsPage); this->addTab(new settingspages::AccountsPage);
this->ui.tabContainer->addSpacing(16); this->ui_.tabContainer->addSpacing(16);
this->addTab(new settingspages::AppearancePage); this->addTab(new settingspages::AppearancePage);
this->addTab(new settingspages::BehaviourPage); this->addTab(new settingspages::BehaviourPage);
this->ui.tabContainer->addSpacing(16); this->ui_.tabContainer->addSpacing(16);
this->addTab(new settingspages::CommandPage); this->addTab(new settingspages::CommandPage);
// this->addTab(new settingspages::EmotesPage); // this->addTab(new settingspages::EmotesPage);
this->addTab(new settingspages::HighlightingPage); this->addTab(new settingspages::HighlightingPage);
this->addTab(new settingspages::IgnoreUsersPage); this->addTab(new settingspages::IgnoreUsersPage);
this->ui.tabContainer->addSpacing(16); this->ui_.tabContainer->addSpacing(16);
this->addTab(new settingspages::KeyboardSettingsPage); this->addTab(new settingspages::KeyboardSettingsPage);
// this->addTab(new settingspages::LogsPage); // this->addTab(new settingspages::LogsPage);
@ -98,7 +98,7 @@ void SettingsDialog::addTabs()
// this->addTab(new settingspages::SpecialChannelsPage); // this->addTab(new settingspages::SpecialChannelsPage);
this->addTab(new settingspages::ExternalToolsPage); this->addTab(new settingspages::ExternalToolsPage);
this->ui.tabContainer->addStretch(1); this->ui_.tabContainer->addStretch(1);
this->addTab(new settingspages::AboutPage, Qt::AlignBottom); this->addTab(new settingspages::AboutPage, Qt::AlignBottom);
} }
@ -106,8 +106,8 @@ void SettingsDialog::addTab(settingspages::SettingsPage *page, Qt::Alignment ali
{ {
auto tab = new SettingsDialogTab(this, page, page->getIconResource()); auto tab = new SettingsDialogTab(this, page, page->getIconResource());
this->ui.pageStack->addWidget(page); this->ui_.pageStack->addWidget(page);
this->ui.tabContainer->addWidget(tab, 0, alignment); this->ui_.tabContainer->addWidget(tab, 0, alignment);
this->tabs.push_back(tab); this->tabs.push_back(tab);
if (this->tabs.size() == 1) { if (this->tabs.size() == 1) {
@ -117,7 +117,7 @@ void SettingsDialog::addTab(settingspages::SettingsPage *page, Qt::Alignment ali
void SettingsDialog::select(SettingsDialogTab *tab) void SettingsDialog::select(SettingsDialogTab *tab)
{ {
this->ui.pageStack->setCurrentWidget(tab->getSettingsPage()); this->ui_.pageStack->setCurrentWidget(tab->getSettingsPage());
if (this->selectedTab != nullptr) { if (this->selectedTab != nullptr) {
this->selectedTab->setSelected(false); this->selectedTab->setSelected(false);
@ -171,7 +171,7 @@ void SettingsDialog::scaleChangedEvent(float newDpi)
this->setStyleSheet(styleSheet); this->setStyleSheet(styleSheet);
this->ui.tabContainerContainer->setFixedWidth((int)(200 * newDpi)); this->ui_.tabContainerContainer->setFixedWidth((int)(200 * newDpi));
} }
void SettingsDialog::themeRefreshEvent() void SettingsDialog::themeRefreshEvent()

View file

@ -45,7 +45,7 @@ private:
QStackedLayout *pageStack; QStackedLayout *pageStack;
QPushButton *okButton; QPushButton *okButton;
QPushButton *cancelButton; QPushButton *cancelButton;
} ui; } ui_;
std::vector<SettingsDialogTab *> tabs; std::vector<SettingsDialogTab *> tabs;

View file

@ -56,6 +56,7 @@ AppearancePage::AppearancePage()
form->addRow("Theme:", theme); form->addRow("Theme:", theme);
// form->addRow("Theme color:", this->createThemeColorChanger()); // form->addRow("Theme color:", this->createThemeColorChanger());
form->addRow("UI Scaling:", this->createUiScaleSlider());
form->addRow("Font:", this->createFontChanger()); form->addRow("Font:", this->createFontChanger());
form->addRow("Tabs:", this->createCheckBox(TAB_X, app->settings->showTabCloseButton)); form->addRow("Tabs:", this->createCheckBox(TAB_X, app->settings->showTabCloseButton));
@ -240,6 +241,33 @@ QLayout *AppearancePage::createFontChanger()
return layout; return layout;
} }
QLayout *AppearancePage::createUiScaleSlider()
{
auto layout = new QHBoxLayout();
auto slider = new QSlider(Qt::Horizontal);
auto label = new QLabel();
layout->addWidget(slider);
layout->addWidget(label);
slider->setMinimum(singletons::WindowManager::uiScaleMin);
slider->setMaximum(singletons::WindowManager::uiScaleMax);
slider->setValue(
singletons::WindowManager::clampUiScale(getApp()->settings->uiScale.getValue()));
label->setMinimumWidth(100);
QObject::connect(slider, &QSlider::valueChanged,
[](auto value) { getApp()->settings->uiScale.setValue(value); });
getApp()->settings->uiScale.connect(
[label](auto, auto) {
label->setText(QString::number(singletons::WindowManager::getUiScaleValue()));
},
this->connections_);
return layout;
}
} // namespace settingspages } // namespace settingspages
} // namespace widgets } // namespace widgets
} // namespace chatterino } // namespace chatterino

View file

@ -3,6 +3,7 @@
#include "widgets/settingspages/settingspage.hpp" #include "widgets/settingspages/settingspage.hpp"
#include <QScrollArea> #include <QScrollArea>
#include <pajlada/signals/signalholder.hpp>
namespace chatterino { namespace chatterino {
namespace widgets { namespace widgets {
@ -15,6 +16,9 @@ public:
QLayout *createThemeColorChanger(); QLayout *createThemeColorChanger();
QLayout *createFontChanger(); QLayout *createFontChanger();
QLayout *createUiScaleSlider();
std::vector<pajlada::Signals::ScopedConnection> connections_;
}; };
} // namespace settingspages } // namespace settingspages

View file

@ -96,6 +96,23 @@ Window::Window(WindowType _type)
CreateWindowShortcut(this, "CTRL+8", [this] { this->notebook.selectIndex(7); }); CreateWindowShortcut(this, "CTRL+8", [this] { this->notebook.selectIndex(7); });
CreateWindowShortcut(this, "CTRL+9", [this] { this->notebook.selectIndex(8); }); CreateWindowShortcut(this, "CTRL+9", [this] { this->notebook.selectIndex(8); });
{
auto s = new QShortcut(QKeySequence::ZoomIn, this);
s->setContext(Qt::WindowShortcut);
QObject::connect(s, &QShortcut::activated, this, [] {
getApp()->settings->uiScale.setValue(singletons::WindowManager::clampUiScale(
getApp()->settings->uiScale.getValue() + 1));
});
}
{
auto s = new QShortcut(QKeySequence::ZoomOut, this);
s->setContext(Qt::WindowShortcut);
QObject::connect(s, &QShortcut::activated, this, [] {
getApp()->settings->uiScale.setValue(singletons::WindowManager::clampUiScale(
getApp()->settings->uiScale.getValue() - 1));
});
}
// CTRL+SHIFT+T: New tab // CTRL+SHIFT+T: New tab
CreateWindowShortcut(this, "CTRL+SHIFT+T", [this] { this->notebook.addPage(true); }); CreateWindowShortcut(this, "CTRL+SHIFT+T", [this] { this->notebook.addPage(true); });