mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Use Qt's High-DPI scaling on Windows (#4868)
This commit is contained in:
parent
8202cd0d99
commit
febcf464fe
21 changed files with 459 additions and 320 deletions
|
@ -3,8 +3,10 @@
|
||||||
## Unversioned
|
## Unversioned
|
||||||
|
|
||||||
- Major: Release plugins alpha. (#5288)
|
- Major: Release plugins alpha. (#5288)
|
||||||
|
- Major: Improve high-DPI support on Windows. (#4868)
|
||||||
- Minor: Add option to customise Moderation buttons with images. (#5369)
|
- Minor: Add option to customise Moderation buttons with images. (#5369)
|
||||||
- Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378)
|
- Bugfix: If a network request errors with 200 OK, Qt's error code is now reported instead of the HTTP status. (#5378)
|
||||||
|
- Dev: Use Qt's high DPI scaling. (#4868)
|
||||||
- Dev: Add doxygen build target. (#5377)
|
- Dev: Add doxygen build target. (#5377)
|
||||||
- Dev: Make printing of strings in tests easier. (#5379)
|
- Dev: Make printing of strings in tests easier. (#5379)
|
||||||
- Dev: Refactor and document `Scrollbar`. (#5334)
|
- Dev: Refactor and document `Scrollbar`. (#5334)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
* {
|
* {
|
||||||
font-size: <font-size>px;
|
font-size: 14px;
|
||||||
font-family: "Segoe UI";
|
font-family: "Segoe UI";
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator {
|
||||||
width: <checkbox-size>px;
|
width: 14px;
|
||||||
height: <checkbox-size>px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatterino--ComboBox {
|
chatterino--ComboBox {
|
||||||
|
|
|
@ -86,10 +86,6 @@ namespace {
|
||||||
QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, true);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
||||||
|
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
|
|
|
@ -26,11 +26,6 @@ using namespace chatterino;
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
// TODO: This is a temporary fix (see #4552).
|
|
||||||
#if defined(Q_OS_WINDOWS) && QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
qputenv("QT_ENABLE_HIGHDPI_SCALING", "0");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
QCoreApplication::setApplicationName("chatterino");
|
QCoreApplication::setApplicationName("chatterino");
|
||||||
|
|
|
@ -155,8 +155,8 @@ void EmoteElement::addToContainer(MessageLayoutContainer &container,
|
||||||
{
|
{
|
||||||
if (flags.has(MessageElementFlag::EmoteImages))
|
if (flags.has(MessageElementFlag::EmoteImages))
|
||||||
{
|
{
|
||||||
auto image =
|
auto image = this->emote_->images.getImageOrLoaded(
|
||||||
this->emote_->images.getImageOrLoaded(container.getScale());
|
container.getImageScale());
|
||||||
if (image->isEmpty())
|
if (image->isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -210,7 +210,7 @@ void LayeredEmoteElement::addToContainer(MessageLayoutContainer &container,
|
||||||
{
|
{
|
||||||
if (flags.has(MessageElementFlag::EmoteImages))
|
if (flags.has(MessageElementFlag::EmoteImages))
|
||||||
{
|
{
|
||||||
auto images = this->getLoadedImages(container.getScale());
|
auto images = this->getLoadedImages(container.getImageScale());
|
||||||
if (images.empty())
|
if (images.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -364,7 +364,7 @@ void BadgeElement::addToContainer(MessageLayoutContainer &container,
|
||||||
if (flags.hasAny(this->getFlags()))
|
if (flags.hasAny(this->getFlags()))
|
||||||
{
|
{
|
||||||
auto image =
|
auto image =
|
||||||
this->emote_->images.getImageOrLoaded(container.getScale());
|
this->emote_->images.getImageOrLoaded(container.getImageScale());
|
||||||
if (image->isEmpty())
|
if (image->isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -798,7 +798,7 @@ void ScalingImageElement::addToContainer(MessageLayoutContainer &container,
|
||||||
if (flags.hasAny(this->getFlags()))
|
if (flags.hasAny(this->getFlags()))
|
||||||
{
|
{
|
||||||
const auto &image =
|
const auto &image =
|
||||||
this->images_.getImageOrLoaded(container.getScale());
|
this->images_.getImageOrLoaded(container.getImageScale());
|
||||||
if (image->isEmpty())
|
if (image->isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -74,7 +74,8 @@ int MessageLayout::getWidth() const
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
// return true if redraw is required
|
// return true if redraw is required
|
||||||
bool MessageLayout::layout(int width, float scale, MessageElementFlags flags,
|
bool MessageLayout::layout(int width, float scale, float imageScale,
|
||||||
|
MessageElementFlags flags,
|
||||||
bool shouldInvalidateBuffer)
|
bool shouldInvalidateBuffer)
|
||||||
{
|
{
|
||||||
// BenchmarkGuard benchmark("MessageLayout::layout()");
|
// BenchmarkGuard benchmark("MessageLayout::layout()");
|
||||||
|
@ -106,6 +107,8 @@ bool MessageLayout::layout(int width, float scale, MessageElementFlags flags,
|
||||||
// check if dpi changed
|
// check if dpi changed
|
||||||
layoutRequired |= this->scale_ != scale;
|
layoutRequired |= this->scale_ != scale;
|
||||||
this->scale_ = scale;
|
this->scale_ = scale;
|
||||||
|
layoutRequired |= this->imageScale_ != imageScale;
|
||||||
|
this->imageScale_ = imageScale;
|
||||||
|
|
||||||
if (!layoutRequired)
|
if (!layoutRequired)
|
||||||
{
|
{
|
||||||
|
@ -148,7 +151,8 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags)
|
||||||
bool hideSimilar = getSettings()->hideSimilar;
|
bool hideSimilar = getSettings()->hideSimilar;
|
||||||
bool hideReplies = !flags.has(MessageElementFlag::RepliedMessage);
|
bool hideReplies = !flags.has(MessageElementFlag::RepliedMessage);
|
||||||
|
|
||||||
this->container_.beginLayout(width, this->scale_, messageFlags);
|
this->container_.beginLayout(width, this->scale_, this->imageScale_,
|
||||||
|
messageFlags);
|
||||||
|
|
||||||
for (const auto &element : this->message_->elements)
|
for (const auto &element : this->message_->elements)
|
||||||
{
|
{
|
||||||
|
@ -288,16 +292,11 @@ QPixmap *MessageLayout::ensureBuffer(QPainter &painter, int width)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new buffer
|
// Create new buffer
|
||||||
#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
|
|
||||||
this->buffer_ = std::make_unique<QPixmap>(
|
this->buffer_ = std::make_unique<QPixmap>(
|
||||||
int(width * painter.device()->devicePixelRatioF()),
|
int(width * painter.device()->devicePixelRatioF()),
|
||||||
int(this->container_.getHeight() *
|
int(this->container_.getHeight() *
|
||||||
painter.device()->devicePixelRatioF()));
|
painter.device()->devicePixelRatioF()));
|
||||||
this->buffer_->setDevicePixelRatio(painter.device()->devicePixelRatioF());
|
this->buffer_->setDevicePixelRatio(painter.device()->devicePixelRatioF());
|
||||||
#else
|
|
||||||
this->buffer_ = std::make_unique<QPixmap>(
|
|
||||||
width, std::max(16, this->container_.getHeight()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
this->bufferValid_ = false;
|
this->bufferValid_ = false;
|
||||||
DebugCount::increase("message drawing buffers");
|
DebugCount::increase("message drawing buffers");
|
||||||
|
|
|
@ -56,8 +56,8 @@ public:
|
||||||
|
|
||||||
MessageLayoutFlags flags;
|
MessageLayoutFlags flags;
|
||||||
|
|
||||||
bool layout(int width, float scale_, MessageElementFlags flags,
|
bool layout(int width, float scale_, float imageScale,
|
||||||
bool shouldInvalidateBuffer);
|
MessageElementFlags flags, bool shouldInvalidateBuffer);
|
||||||
|
|
||||||
// Painting
|
// Painting
|
||||||
MessagePaintResult paint(const MessagePaintContext &ctx);
|
MessagePaintResult paint(const MessagePaintContext &ctx);
|
||||||
|
@ -128,6 +128,7 @@ private:
|
||||||
int currentLayoutWidth_ = -1;
|
int currentLayoutWidth_ = -1;
|
||||||
int layoutState_ = -1;
|
int layoutState_ = -1;
|
||||||
float scale_ = -1;
|
float scale_ = -1;
|
||||||
|
float imageScale_ = -1.F;
|
||||||
MessageElementFlags currentWordFlags_;
|
MessageElementFlags currentWordFlags_;
|
||||||
|
|
||||||
#ifdef FOURTF
|
#ifdef FOURTF
|
||||||
|
|
|
@ -30,7 +30,7 @@ constexpr const QMargins MARGIN{8, 4, 8, 4};
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
void MessageLayoutContainer::beginLayout(int width, float scale,
|
void MessageLayoutContainer::beginLayout(int width, float scale,
|
||||||
MessageFlags flags)
|
float imageScale, MessageFlags flags)
|
||||||
{
|
{
|
||||||
this->elements_.clear();
|
this->elements_.clear();
|
||||||
this->lines_.clear();
|
this->lines_.clear();
|
||||||
|
@ -45,6 +45,7 @@ void MessageLayoutContainer::beginLayout(int width, float scale,
|
||||||
this->width_ = width;
|
this->width_ = width;
|
||||||
this->height_ = 0;
|
this->height_ = 0;
|
||||||
this->scale_ = scale;
|
this->scale_ = scale;
|
||||||
|
this->imageScale_ = imageScale;
|
||||||
this->flags_ = flags;
|
this->flags_ = flags;
|
||||||
auto mediumFontMetrics =
|
auto mediumFontMetrics =
|
||||||
getIApp()->getFonts()->getFontMetrics(FontStyle::ChatMedium, scale);
|
getIApp()->getFonts()->getFontMetrics(FontStyle::ChatMedium, scale);
|
||||||
|
@ -526,6 +527,11 @@ float MessageLayoutContainer::getScale() const
|
||||||
return this->scale_;
|
return this->scale_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float MessageLayoutContainer::getImageScale() const
|
||||||
|
{
|
||||||
|
return this->imageScale_;
|
||||||
|
}
|
||||||
|
|
||||||
bool MessageLayoutContainer::isCollapsed() const
|
bool MessageLayoutContainer::isCollapsed() const
|
||||||
{
|
{
|
||||||
return this->isCollapsed_;
|
return this->isCollapsed_;
|
||||||
|
|
|
@ -32,7 +32,8 @@ struct MessageLayoutContainer {
|
||||||
* This will reset all line calculations, and will be considered incomplete
|
* This will reset all line calculations, and will be considered incomplete
|
||||||
* until the accompanying end function has been called
|
* until the accompanying end function has been called
|
||||||
*/
|
*/
|
||||||
void beginLayout(int width_, float scale_, MessageFlags flags_);
|
void beginLayout(int width, float scale, float imageScale,
|
||||||
|
MessageFlags flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the layout process of this message
|
* Finish the layout process of this message
|
||||||
|
@ -146,6 +147,11 @@ struct MessageLayoutContainer {
|
||||||
*/
|
*/
|
||||||
float getScale() const;
|
float getScale() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the image scale
|
||||||
|
*/
|
||||||
|
float getImageScale() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this message is collapsed
|
* Returns true if this message is collapsed
|
||||||
*/
|
*/
|
||||||
|
@ -270,6 +276,10 @@ private:
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
float scale_ = 1.F;
|
float scale_ = 1.F;
|
||||||
|
/**
|
||||||
|
* Scale factor for images
|
||||||
|
*/
|
||||||
|
float imageScale_ = 1.F;
|
||||||
int width_ = 0;
|
int width_ = 0;
|
||||||
MessageFlags flags_{};
|
MessageFlags flags_{};
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -270,20 +270,22 @@ void AttachedWindow::updateWindowRect(void *_attachedPtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
float scale = 1.f;
|
float scale = 1.f;
|
||||||
|
float ourScale = 1.F;
|
||||||
if (auto dpi = getWindowDpi(attached))
|
if (auto dpi = getWindowDpi(attached))
|
||||||
{
|
{
|
||||||
scale = *dpi / 96.f;
|
scale = *dpi / 96.f;
|
||||||
|
ourScale = scale / this->devicePixelRatio();
|
||||||
|
|
||||||
for (auto w : this->ui_.split->findChildren<BaseWidget *>())
|
for (auto w : this->ui_.split->findChildren<BaseWidget *>())
|
||||||
{
|
{
|
||||||
w->setOverrideScale(scale);
|
w->setOverrideScale(ourScale);
|
||||||
}
|
}
|
||||||
this->ui_.split->setOverrideScale(scale);
|
this->ui_.split->setOverrideScale(ourScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->height_ != -1)
|
if (this->height_ != -1)
|
||||||
{
|
{
|
||||||
this->ui_.split->setFixedWidth(int(this->width_ * scale));
|
this->ui_.split->setFixedWidth(int(this->width_ * ourScale));
|
||||||
|
|
||||||
// offset
|
// offset
|
||||||
int o = this->fullscreen_ ? 0 : 8;
|
int o = this->fullscreen_ ? 0 : 8;
|
||||||
|
|
|
@ -120,19 +120,6 @@ void BaseWidget::setScaleIndependantHeight(int value)
|
||||||
QSize(this->scaleIndependantSize_.width(), value));
|
QSize(this->scaleIndependantSize_.width(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
float BaseWidget::qtFontScale() const
|
|
||||||
{
|
|
||||||
if (auto *window = dynamic_cast<BaseWindow *>(this->window()))
|
|
||||||
{
|
|
||||||
// ensure no div by 0
|
|
||||||
return this->scale() / std::max<float>(0.01f, window->nativeScale_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return this->scale();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWidget::childEvent(QChildEvent *event)
|
void BaseWidget::childEvent(QChildEvent *event)
|
||||||
{
|
{
|
||||||
if (event->added())
|
if (event->added())
|
||||||
|
|
|
@ -34,8 +34,6 @@ public:
|
||||||
void setScaleIndependantWidth(int value);
|
void setScaleIndependantWidth(int value);
|
||||||
void setScaleIndependantHeight(int value);
|
void setScaleIndependantHeight(int value);
|
||||||
|
|
||||||
float qtFontScale() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void childEvent(QChildEvent *) override;
|
void childEvent(QChildEvent *) override;
|
||||||
void showEvent(QShowEvent *) override;
|
void showEvent(QShowEvent *) override;
|
||||||
|
|
|
@ -29,12 +29,163 @@
|
||||||
# pragma comment(lib, "Dwmapi.lib")
|
# pragma comment(lib, "Dwmapi.lib")
|
||||||
|
|
||||||
# include <QHBoxLayout>
|
# include <QHBoxLayout>
|
||||||
|
# include <QOperatingSystemVersion>
|
||||||
# define WM_DPICHANGED 0x02E0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "widgets/helper/TitlebarButton.hpp"
|
#include "widgets/helper/TitlebarButton.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#ifdef USEWINSDK
|
||||||
|
|
||||||
|
// From kHiddenTaskbarSize in Firefox
|
||||||
|
constexpr UINT HIDDEN_TASKBAR_SIZE = 2;
|
||||||
|
|
||||||
|
bool isWindows11OrGreater()
|
||||||
|
{
|
||||||
|
static const bool result = [] {
|
||||||
|
// This calls RtlGetVersion under the hood so we don't have to.
|
||||||
|
// The micro version corresponds to dwBuildNumber.
|
||||||
|
auto version = QOperatingSystemVersion::current();
|
||||||
|
return (version.majorVersion() > 10) ||
|
||||||
|
(version.microVersion() >= 22000);
|
||||||
|
}();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the taskbar HWND on a specific monitor (or any)
|
||||||
|
HWND findTaskbarWindow(LPRECT rcMon = nullptr)
|
||||||
|
{
|
||||||
|
HWND taskbar = nullptr;
|
||||||
|
RECT taskbarRect;
|
||||||
|
// return value of IntersectRect, unused
|
||||||
|
RECT intersectionRect;
|
||||||
|
|
||||||
|
while ((taskbar = FindWindowEx(nullptr, taskbar, L"Shell_TrayWnd",
|
||||||
|
nullptr)) != nullptr)
|
||||||
|
{
|
||||||
|
if (!rcMon)
|
||||||
|
{
|
||||||
|
// no monitor was specified, return the first encountered window
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GetWindowRect(taskbar, &taskbarRect) != 0 &&
|
||||||
|
IntersectRect(&intersectionRect, &taskbarRect, rcMon) != 0)
|
||||||
|
{
|
||||||
|
// taskbar intersects with the monitor - this is the one
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return taskbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the edge of the taskbar if it's automatically hidden
|
||||||
|
std::optional<UINT> hiddenTaskbarEdge(LPRECT rcMon = nullptr)
|
||||||
|
{
|
||||||
|
HWND taskbar = findTaskbarWindow(rcMon);
|
||||||
|
if (!taskbar)
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
APPBARDATA state = {sizeof(state), taskbar};
|
||||||
|
APPBARDATA pos = {sizeof(pos), taskbar};
|
||||||
|
|
||||||
|
auto appBarState =
|
||||||
|
static_cast<LRESULT>(SHAppBarMessage(ABM_GETSTATE, &state));
|
||||||
|
if ((appBarState & ABS_AUTOHIDE) == 0)
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHAppBarMessage(ABM_GETTASKBARPOS, &pos) == 0)
|
||||||
|
{
|
||||||
|
qCDebug(chatterinoApp) << "Failed to get taskbar pos";
|
||||||
|
return ABE_BOTTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos.uEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Gets the window borders for @a hwnd
|
||||||
|
///
|
||||||
|
/// Each side of the returned RECT has the correct sign, so they can be added
|
||||||
|
/// to a window rect.
|
||||||
|
/// Shrinking by 1px would return {left: 1, top: 1, right: -1, left: -1}.
|
||||||
|
RECT windowBordersFor(HWND hwnd, bool isMaximized)
|
||||||
|
{
|
||||||
|
RECT margins{0, 0, 0, 0};
|
||||||
|
|
||||||
|
auto addBorders = isMaximized || isWindows11OrGreater();
|
||||||
|
if (addBorders)
|
||||||
|
{
|
||||||
|
auto dpi = GetDpiForWindow(hwnd);
|
||||||
|
auto systemMetric = [&](auto index) {
|
||||||
|
if (dpi != 0)
|
||||||
|
{
|
||||||
|
return GetSystemMetricsForDpi(index, dpi);
|
||||||
|
}
|
||||||
|
return GetSystemMetrics(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto paddedBorder = systemMetric(SM_CXPADDEDBORDER);
|
||||||
|
auto borderWidth = systemMetric(SM_CXSIZEFRAME) + paddedBorder;
|
||||||
|
auto borderHeight = systemMetric(SM_CYSIZEFRAME) + paddedBorder;
|
||||||
|
|
||||||
|
margins.left += borderWidth;
|
||||||
|
margins.right -= borderWidth;
|
||||||
|
if (isMaximized)
|
||||||
|
{
|
||||||
|
margins.top += borderHeight;
|
||||||
|
}
|
||||||
|
margins.bottom -= borderHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMaximized)
|
||||||
|
{
|
||||||
|
auto *hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
|
MONITORINFO mi;
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
auto *monitor = [&]() -> LPRECT {
|
||||||
|
if (GetMonitorInfo(hMonitor, &mi))
|
||||||
|
{
|
||||||
|
return &mi.rcMonitor;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}();
|
||||||
|
|
||||||
|
auto edge = hiddenTaskbarEdge(monitor);
|
||||||
|
if (edge)
|
||||||
|
{
|
||||||
|
switch (*edge)
|
||||||
|
{
|
||||||
|
case ABE_LEFT:
|
||||||
|
margins.left += HIDDEN_TASKBAR_SIZE;
|
||||||
|
break;
|
||||||
|
case ABE_RIGHT:
|
||||||
|
margins.right -= HIDDEN_TASKBAR_SIZE;
|
||||||
|
break;
|
||||||
|
case ABE_TOP:
|
||||||
|
margins.top += HIDDEN_TASKBAR_SIZE;
|
||||||
|
break;
|
||||||
|
case ABE_BOTTOM:
|
||||||
|
margins.bottom -= HIDDEN_TASKBAR_SIZE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return margins;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
|
|
||||||
BaseWindow::BaseWindow(FlagsEnum<Flags> _flags, QWidget *parent)
|
BaseWindow::BaseWindow(FlagsEnum<Flags> _flags, QWidget *parent)
|
||||||
|
@ -117,95 +268,80 @@ float BaseWindow::scale() const
|
||||||
return std::max<float>(0.01f, this->overrideScale().value_or(this->scale_));
|
return std::max<float>(0.01f, this->overrideScale().value_or(this->scale_));
|
||||||
}
|
}
|
||||||
|
|
||||||
float BaseWindow::qtFontScale() const
|
|
||||||
{
|
|
||||||
return this->scale() / std::max<float>(0.01F, this->nativeScale_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWindow::init()
|
void BaseWindow::init()
|
||||||
{
|
{
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
if (this->hasCustomWindowFrame())
|
if (this->hasCustomWindowFrame())
|
||||||
{
|
{
|
||||||
// CUSTOM WINDOW FRAME
|
// CUSTOM WINDOW FRAME
|
||||||
QVBoxLayout *layout = new QVBoxLayout();
|
auto *layout = new QVBoxLayout(this);
|
||||||
this->ui_.windowLayout = layout;
|
this->ui_.windowLayout = layout;
|
||||||
layout->setContentsMargins(1, 1, 1, 1);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
this->setLayout(layout);
|
|
||||||
|
if (!this->frameless_)
|
||||||
{
|
{
|
||||||
if (!this->frameless_)
|
QHBoxLayout *buttonLayout = this->ui_.titlebarBox =
|
||||||
{
|
new QHBoxLayout();
|
||||||
QHBoxLayout *buttonLayout = this->ui_.titlebarBox =
|
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
new QHBoxLayout();
|
layout->addLayout(buttonLayout);
|
||||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
|
||||||
layout->addLayout(buttonLayout);
|
|
||||||
|
|
||||||
// title
|
// title
|
||||||
Label *title = new Label;
|
Label *title = new Label;
|
||||||
QObject::connect(this, &QWidget::windowTitleChanged,
|
QObject::connect(this, &QWidget::windowTitleChanged,
|
||||||
[title](const QString &text) {
|
[title](const QString &text) {
|
||||||
title->setText(text);
|
title->setText(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
QSizePolicy policy(QSizePolicy::Ignored,
|
QSizePolicy policy(QSizePolicy::Ignored, QSizePolicy::Preferred);
|
||||||
QSizePolicy::Preferred);
|
policy.setHorizontalStretch(1);
|
||||||
policy.setHorizontalStretch(1);
|
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;
|
auto *minButton = new TitleBarButton;
|
||||||
_minButton->setButtonStyle(TitleBarButtonStyle::Minimize);
|
minButton->setButtonStyle(TitleBarButtonStyle::Minimize);
|
||||||
TitleBarButton *_maxButton = new TitleBarButton;
|
auto *maxButton = new TitleBarButton;
|
||||||
_maxButton->setButtonStyle(TitleBarButtonStyle::Maximize);
|
maxButton->setButtonStyle(TitleBarButtonStyle::Maximize);
|
||||||
TitleBarButton *_exitButton = new TitleBarButton;
|
auto *exitButton = new TitleBarButton;
|
||||||
_exitButton->setButtonStyle(TitleBarButtonStyle::Close);
|
exitButton->setButtonStyle(TitleBarButtonStyle::Close);
|
||||||
|
|
||||||
QObject::connect(_minButton, &TitleBarButton::leftClicked, this,
|
QObject::connect(minButton, &TitleBarButton::leftClicked, this,
|
||||||
[this] {
|
[this] {
|
||||||
this->setWindowState(Qt::WindowMinimized |
|
this->setWindowState(Qt::WindowMinimized |
|
||||||
this->windowState());
|
this->windowState());
|
||||||
});
|
});
|
||||||
QObject::connect(_maxButton, &TitleBarButton::leftClicked, this,
|
QObject::connect(
|
||||||
[this, _maxButton] {
|
maxButton, &TitleBarButton::leftClicked, this,
|
||||||
this->setWindowState(
|
[this, maxButton] {
|
||||||
_maxButton->getButtonStyle() !=
|
this->setWindowState(maxButton->getButtonStyle() !=
|
||||||
TitleBarButtonStyle::Maximize
|
TitleBarButtonStyle::Maximize
|
||||||
? Qt::WindowActive
|
? Qt::WindowActive
|
||||||
: Qt::WindowMaximized);
|
: Qt::WindowMaximized);
|
||||||
});
|
});
|
||||||
QObject::connect(_exitButton, &TitleBarButton::leftClicked,
|
QObject::connect(exitButton, &TitleBarButton::leftClicked, this,
|
||||||
this, [this] {
|
[this] {
|
||||||
this->close();
|
this->close();
|
||||||
});
|
});
|
||||||
|
|
||||||
this->ui_.titlebarButtons = new TitleBarButtons(
|
this->ui_.titlebarButtons =
|
||||||
this, _minButton, _maxButton, _exitButton);
|
new TitleBarButtons(this, minButton, maxButton, 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->addWidget(minButton);
|
||||||
buttonLayout->addWidget(_minButton);
|
buttonLayout->addWidget(maxButton);
|
||||||
buttonLayout->addWidget(_maxButton);
|
buttonLayout->addWidget(exitButton);
|
||||||
buttonLayout->addWidget(_exitButton);
|
buttonLayout->setSpacing(0);
|
||||||
buttonLayout->setSpacing(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->ui_.layoutBase = new BaseWidget(this);
|
this->ui_.layoutBase = new BaseWidget(this);
|
||||||
this->ui_.layoutBase->setContentsMargins(1, 0, 1, 1);
|
this->ui_.layoutBase->setContentsMargins(1, 0, 1, 1);
|
||||||
layout->addWidget(this->ui_.layoutBase);
|
layout->addWidget(this->ui_.layoutBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DPI
|
|
||||||
// auto dpi = getWindowDpi(this->safeHWND());
|
|
||||||
|
|
||||||
// if (dpi) {
|
|
||||||
// this->scale = dpi.value() / 96.f;
|
|
||||||
// }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TopMost flag overrides setting
|
// TopMost flag overrides setting
|
||||||
|
@ -571,29 +707,8 @@ void BaseWindow::resizeEvent(QResizeEvent *)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
if (this->hasCustomWindowFrame() && !this->isResizeFixing_)
|
|
||||||
{
|
|
||||||
this->isResizeFixing_ = true;
|
|
||||||
QTimer::singleShot(50, this, [this] {
|
|
||||||
auto hwnd = this->safeHWND();
|
|
||||||
if (!hwnd)
|
|
||||||
{
|
|
||||||
this->isResizeFixing_ = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RECT rect;
|
|
||||||
::GetWindowRect(*hwnd, &rect);
|
|
||||||
::SetWindowPos(*hwnd, nullptr, 0, 0, rect.right - rect.left + 1,
|
|
||||||
rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
|
|
||||||
::SetWindowPos(*hwnd, nullptr, 0, 0, rect.right - rect.left,
|
|
||||||
rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
|
|
||||||
QTimer::singleShot(10, this, [this] {
|
|
||||||
this->isResizeFixing_ = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this->calcButtonsSizes();
|
this->calcButtonsSizes();
|
||||||
|
this->updateRealSize();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,10 +770,6 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||||
|
|
||||||
switch (msg->message)
|
switch (msg->message)
|
||||||
{
|
{
|
||||||
case WM_DPICHANGED:
|
|
||||||
returnValue = this->handleDPICHANGED(msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WM_SHOWWINDOW:
|
case WM_SHOWWINDOW:
|
||||||
returnValue = this->handleSHOWWINDOW(msg);
|
returnValue = this->handleSHOWWINDOW(msg);
|
||||||
break;
|
break;
|
||||||
|
@ -697,12 +808,15 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||||
{
|
{
|
||||||
*result = 0;
|
*result = 0;
|
||||||
returnValue = true;
|
returnValue = true;
|
||||||
long x = GET_X_LPARAM(msg->lParam);
|
|
||||||
long y = GET_Y_LPARAM(msg->lParam);
|
|
||||||
|
|
||||||
RECT winrect;
|
POINT p{GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||||
GetWindowRect(msg->hwnd, &winrect);
|
ScreenToClient(msg->hwnd, &p);
|
||||||
QPoint globalPos(x, y);
|
|
||||||
|
QPoint globalPos(p.x, p.y);
|
||||||
|
globalPos /= this->devicePixelRatio();
|
||||||
|
globalPos = this->mapToGlobal(globalPos);
|
||||||
|
|
||||||
|
// TODO(nerix): use TrackMouseEvent here
|
||||||
this->ui_.titlebarButtons->hover(msg->wParam, globalPos);
|
this->ui_.titlebarButtons->hover(msg->wParam, globalPos);
|
||||||
this->lastEventWasNcMouseMove_ = true;
|
this->lastEventWasNcMouseMove_ = true;
|
||||||
}
|
}
|
||||||
|
@ -748,12 +862,14 @@ bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||||
*result = 0;
|
*result = 0;
|
||||||
|
|
||||||
auto ht = msg->wParam;
|
auto ht = msg->wParam;
|
||||||
long x = GET_X_LPARAM(msg->lParam);
|
|
||||||
long y = GET_Y_LPARAM(msg->lParam);
|
|
||||||
|
|
||||||
RECT winrect;
|
POINT p{GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||||
GetWindowRect(msg->hwnd, &winrect);
|
ScreenToClient(msg->hwnd, &p);
|
||||||
QPoint globalPos(x, y);
|
|
||||||
|
QPoint globalPos(p.x, p.y);
|
||||||
|
globalPos /= this->devicePixelRatio();
|
||||||
|
globalPos = this->mapToGlobal(globalPos);
|
||||||
|
|
||||||
if (msg->message == WM_NCLBUTTONDOWN)
|
if (msg->message == WM_NCLBUTTONDOWN)
|
||||||
{
|
{
|
||||||
this->ui_.titlebarButtons->mousePress(ht, globalPos);
|
this->ui_.titlebarButtons->mousePress(ht, globalPos);
|
||||||
|
@ -784,7 +900,7 @@ void BaseWindow::scaleChangedEvent(float scale)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
this->setFont(
|
this->setFont(
|
||||||
getIApp()->getFonts()->getFont(FontStyle::UiTabs, this->qtFontScale()));
|
getIApp()->getFonts()->getFont(FontStyle::UiTabs, this->scale()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseWindow::paintEvent(QPaintEvent *)
|
void BaseWindow::paintEvent(QPaintEvent *)
|
||||||
|
@ -802,10 +918,9 @@ void BaseWindow::paintEvent(QPaintEvent *)
|
||||||
|
|
||||||
void BaseWindow::updateScale()
|
void BaseWindow::updateScale()
|
||||||
{
|
{
|
||||||
auto scale =
|
auto scale = this->flags_.has(DisableCustomScaling)
|
||||||
this->nativeScale_ * (this->flags_.has(DisableCustomScaling)
|
? 1
|
||||||
? 1
|
: getSettings()->getClampedUiScale();
|
||||||
: getSettings()->getClampedUiScale());
|
|
||||||
|
|
||||||
this->setScale(scale);
|
this->setScale(scale);
|
||||||
|
|
||||||
|
@ -815,6 +930,22 @@ void BaseWindow::updateScale()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USEWINSDK
|
||||||
|
void BaseWindow::updateRealSize()
|
||||||
|
{
|
||||||
|
auto hwnd = this->safeHWND();
|
||||||
|
if (!hwnd)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT real;
|
||||||
|
::GetWindowRect(*hwnd, &real);
|
||||||
|
this->realBounds_ = QRect(real.left, real.top, real.right - real.left,
|
||||||
|
real.bottom - real.top);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void BaseWindow::calcButtonsSizes()
|
void BaseWindow::calcButtonsSizes()
|
||||||
{
|
{
|
||||||
if (!this->shown_)
|
if (!this->shown_)
|
||||||
|
@ -846,34 +977,28 @@ void BaseWindow::drawCustomWindowFrame(QPainter &painter)
|
||||||
{
|
{
|
||||||
QColor bg = this->overrideBackgroundColor_.value_or(
|
QColor bg = this->overrideBackgroundColor_.value_or(
|
||||||
this->theme->window.background);
|
this->theme->window.background);
|
||||||
painter.fillRect(QRect(1, 2, this->width() - 2, this->height() - 3),
|
if (this->isMaximized_)
|
||||||
bg);
|
{
|
||||||
|
painter.fillRect(this->rect(), bg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw a border that's exactly 1px wide
|
||||||
|
//
|
||||||
|
// There is a bug where the border can get <dpr>px wide while dragging.
|
||||||
|
// this "fixes" itself when deselecting the window.
|
||||||
|
auto dpr = this->devicePixelRatio();
|
||||||
|
if (dpr != 1)
|
||||||
|
{
|
||||||
|
painter.setTransform(QTransform::fromScale(1 / dpr, 1 / dpr));
|
||||||
|
}
|
||||||
|
painter.fillRect(1, 1, this->realBounds_.width() - 2,
|
||||||
|
this->realBounds_.height() - 2, bg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseWindow::handleDPICHANGED(MSG *msg)
|
|
||||||
{
|
|
||||||
#ifdef USEWINSDK
|
|
||||||
int dpi = HIWORD(msg->wParam);
|
|
||||||
|
|
||||||
float _scale = dpi / 96.f;
|
|
||||||
|
|
||||||
auto *prcNewWindow = reinterpret_cast<RECT *>(msg->lParam);
|
|
||||||
SetWindowPos(msg->hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
|
|
||||||
prcNewWindow->right - prcNewWindow->left,
|
|
||||||
prcNewWindow->bottom - prcNewWindow->top,
|
|
||||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
||||||
|
|
||||||
this->nativeScale_ = _scale;
|
|
||||||
this->updateScale();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseWindow::handleSHOWWINDOW(MSG *msg)
|
bool BaseWindow::handleSHOWWINDOW(MSG *msg)
|
||||||
{
|
{
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
|
@ -883,16 +1008,6 @@ bool BaseWindow::handleSHOWWINDOW(MSG *msg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto dpi = getWindowDpi(msg->hwnd))
|
|
||||||
{
|
|
||||||
float currentScale = (float)dpi.value() / 96.F;
|
|
||||||
if (currentScale != this->nativeScale_)
|
|
||||||
{
|
|
||||||
this->nativeScale_ = currentScale;
|
|
||||||
this->updateScale();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->shown_)
|
if (!this->shown_)
|
||||||
{
|
{
|
||||||
this->shown_ = true;
|
this->shown_ = true;
|
||||||
|
@ -906,14 +1021,12 @@ bool BaseWindow::handleSHOWWINDOW(MSG *msg)
|
||||||
|
|
||||||
if (!this->initalBounds_.isNull())
|
if (!this->initalBounds_.isNull())
|
||||||
{
|
{
|
||||||
::SetWindowPos(msg->hwnd, nullptr, this->initalBounds_.x(),
|
this->setGeometry(this->initalBounds_);
|
||||||
this->initalBounds_.y(), this->initalBounds_.width(),
|
|
||||||
this->initalBounds_.height(),
|
|
||||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
|
||||||
this->currentBounds_ = this->initalBounds_;
|
this->currentBounds_ = this->initalBounds_;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->calcButtonsSizes();
|
this->calcButtonsSizes();
|
||||||
|
this->updateRealSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -929,23 +1042,54 @@ bool BaseWindow::handleNCCALCSIZE(MSG *msg, long *result)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
if (this->hasCustomWindowFrame())
|
if (!this->hasCustomWindowFrame())
|
||||||
{
|
{
|
||||||
if (msg->wParam == TRUE)
|
return false;
|
||||||
{
|
}
|
||||||
// remove 1 extra pixel on top of custom frame
|
|
||||||
auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg->lParam);
|
|
||||||
if (ncp)
|
|
||||||
{
|
|
||||||
ncp->lppos->flags |= SWP_NOREDRAW;
|
|
||||||
ncp->rgrc[0].top -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (msg->wParam != TRUE)
|
||||||
|
{
|
||||||
*result = 0;
|
*result = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
auto *params = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg->lParam);
|
||||||
|
auto *r = ¶ms->rgrc[0];
|
||||||
|
|
||||||
|
WINDOWPLACEMENT wp;
|
||||||
|
wp.length = sizeof(WINDOWPLACEMENT);
|
||||||
|
this->isMaximized_ = GetWindowPlacement(msg->hwnd, &wp) != 0 &&
|
||||||
|
(wp.showCmd == SW_SHOWMAXIMIZED);
|
||||||
|
|
||||||
|
auto borders = windowBordersFor(msg->hwnd, this->isMaximized_);
|
||||||
|
r->left += borders.left;
|
||||||
|
r->top += borders.top;
|
||||||
|
r->right += borders.right;
|
||||||
|
r->bottom += borders.bottom;
|
||||||
|
|
||||||
|
if (borders.left != 0 || borders.top != 0 || borders.right != 0 ||
|
||||||
|
borders.bottom != 0)
|
||||||
|
{
|
||||||
|
// We added borders -> we changed the rect, so we can't return
|
||||||
|
// WVR_VALIDRECTS
|
||||||
|
*result = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an attempt at telling Windows to not redraw (or at least to do a
|
||||||
|
// better job at redrawing) the window. There is a long list of tricks
|
||||||
|
// people tried to prevent this at
|
||||||
|
// https://stackoverflow.com/q/53000291/16300717
|
||||||
|
//
|
||||||
|
// We set the source and destination rectangles to a 1x1 rectangle at the
|
||||||
|
// top left. Windows is instructed by WVR_VALIDRECTS to copy and preserve
|
||||||
|
// some parts of the window image.
|
||||||
|
QPoint fixed = {r->left, r->top};
|
||||||
|
params->rgrc[1] = {fixed.x(), fixed.y(), fixed.x() + 1, fixed.y() + 1};
|
||||||
|
params->rgrc[2] = {fixed.x(), fixed.y(), fixed.x() + 1, fixed.y() + 1};
|
||||||
|
*result = WVR_VALIDRECTS;
|
||||||
|
|
||||||
|
return true;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -962,28 +1106,11 @@ bool BaseWindow::handleSIZE(MSG *msg)
|
||||||
}
|
}
|
||||||
else if (this->hasCustomWindowFrame())
|
else if (this->hasCustomWindowFrame())
|
||||||
{
|
{
|
||||||
if (msg->wParam == SIZE_MAXIMIZED)
|
|
||||||
{
|
|
||||||
auto offset =
|
|
||||||
int(getWindowDpi(msg->hwnd).value_or(96) * 8 / 96);
|
|
||||||
|
|
||||||
this->ui_.windowLayout->setContentsMargins(offset, offset,
|
|
||||||
offset, offset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->ui_.windowLayout->setContentsMargins(0, 1, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->isNotMinimizedOrMaximized_ = msg->wParam == SIZE_RESTORED;
|
this->isNotMinimizedOrMaximized_ = msg->wParam == SIZE_RESTORED;
|
||||||
|
|
||||||
if (this->isNotMinimizedOrMaximized_)
|
if (this->isNotMinimizedOrMaximized_)
|
||||||
{
|
{
|
||||||
RECT rect;
|
this->currentBounds_ = this->geometry();
|
||||||
::GetWindowRect(msg->hwnd, &rect);
|
|
||||||
this->currentBounds_ =
|
|
||||||
QRect(QPoint(rect.left, rect.top),
|
|
||||||
QPoint(rect.right - 1, rect.bottom - 1));
|
|
||||||
}
|
}
|
||||||
this->useNextBounds_.stop();
|
this->useNextBounds_.stop();
|
||||||
|
|
||||||
|
@ -993,6 +1120,12 @@ bool BaseWindow::handleSIZE(MSG *msg)
|
||||||
// the minimize button, so we have to emulate it.
|
// the minimize button, so we have to emulate it.
|
||||||
this->ui_.titlebarButtons->leave();
|
this->ui_.titlebarButtons->leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RECT real;
|
||||||
|
::GetWindowRect(msg->hwnd, &real);
|
||||||
|
this->realBounds_ =
|
||||||
|
QRect(real.left, real.top, real.right - real.left,
|
||||||
|
real.bottom - real.top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1006,11 +1139,7 @@ bool BaseWindow::handleMOVE(MSG *msg)
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
if (this->isNotMinimizedOrMaximized_)
|
if (this->isNotMinimizedOrMaximized_)
|
||||||
{
|
{
|
||||||
RECT rect;
|
this->nextBounds_ = this->geometry();
|
||||||
::GetWindowRect(msg->hwnd, &rect);
|
|
||||||
this->nextBounds_ = QRect(QPoint(rect.left, rect.top),
|
|
||||||
QPoint(rect.right - 1, rect.bottom - 1));
|
|
||||||
|
|
||||||
this->useNextBounds_.start(10);
|
this->useNextBounds_.start(10);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1024,31 +1153,37 @@ bool BaseWindow::handleNCHITTEST(MSG *msg, long *result)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
const LONG border_width = 8; // in pixels
|
const LONG borderWidth = 8; // in device independent pixels
|
||||||
RECT winrect;
|
|
||||||
GetWindowRect(msg->hwnd, &winrect);
|
|
||||||
|
|
||||||
long x = GET_X_LPARAM(msg->lParam);
|
auto rect = this->rect();
|
||||||
long y = GET_Y_LPARAM(msg->lParam);
|
|
||||||
|
|
||||||
QPoint point(x - winrect.left, y - winrect.top);
|
POINT p{GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)};
|
||||||
|
ScreenToClient(msg->hwnd, &p);
|
||||||
|
|
||||||
|
QPoint point(p.x, p.y);
|
||||||
|
point /= this->devicePixelRatio();
|
||||||
|
|
||||||
|
auto x = point.x();
|
||||||
|
auto y = point.y();
|
||||||
|
|
||||||
if (this->hasCustomWindowFrame())
|
if (this->hasCustomWindowFrame())
|
||||||
{
|
{
|
||||||
*result = 0;
|
*result = 0;
|
||||||
|
|
||||||
bool resizeWidth = minimumWidth() != maximumWidth();
|
bool resizeWidth =
|
||||||
bool resizeHeight = minimumHeight() != maximumHeight();
|
minimumWidth() != maximumWidth() && !this->isMaximized();
|
||||||
|
bool resizeHeight =
|
||||||
|
minimumHeight() != maximumHeight() && !this->isMaximized();
|
||||||
|
|
||||||
if (resizeWidth)
|
if (resizeWidth)
|
||||||
{
|
{
|
||||||
// left border
|
// left border
|
||||||
if (x < winrect.left + border_width)
|
if (x < rect.left() + borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTLEFT;
|
*result = HTLEFT;
|
||||||
}
|
}
|
||||||
// right border
|
// right border
|
||||||
if (x >= winrect.right - border_width)
|
if (x >= rect.right() - borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTRIGHT;
|
*result = HTRIGHT;
|
||||||
}
|
}
|
||||||
|
@ -1056,12 +1191,12 @@ bool BaseWindow::handleNCHITTEST(MSG *msg, long *result)
|
||||||
if (resizeHeight)
|
if (resizeHeight)
|
||||||
{
|
{
|
||||||
// bottom border
|
// bottom border
|
||||||
if (y >= winrect.bottom - border_width)
|
if (y >= rect.bottom() - borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTBOTTOM;
|
*result = HTBOTTOM;
|
||||||
}
|
}
|
||||||
// top border
|
// top border
|
||||||
if (y < winrect.top + border_width)
|
if (y < rect.top() + borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTTOP;
|
*result = HTTOP;
|
||||||
}
|
}
|
||||||
|
@ -1069,26 +1204,26 @@ bool BaseWindow::handleNCHITTEST(MSG *msg, long *result)
|
||||||
if (resizeWidth && resizeHeight)
|
if (resizeWidth && resizeHeight)
|
||||||
{
|
{
|
||||||
// bottom left corner
|
// bottom left corner
|
||||||
if (x >= winrect.left && x < winrect.left + border_width &&
|
if (x >= rect.left() && x < rect.left() + borderWidth &&
|
||||||
y < winrect.bottom && y >= winrect.bottom - border_width)
|
y < rect.bottom() && y >= rect.bottom() - borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTBOTTOMLEFT;
|
*result = HTBOTTOMLEFT;
|
||||||
}
|
}
|
||||||
// bottom right corner
|
// bottom right corner
|
||||||
if (x < winrect.right && x >= winrect.right - border_width &&
|
if (x < rect.right() && x >= rect.right() - borderWidth &&
|
||||||
y < winrect.bottom && y >= winrect.bottom - border_width)
|
y < rect.bottom() && y >= rect.bottom() - borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTBOTTOMRIGHT;
|
*result = HTBOTTOMRIGHT;
|
||||||
}
|
}
|
||||||
// top left corner
|
// top left corner
|
||||||
if (x >= winrect.left && x < winrect.left + border_width &&
|
if (x >= rect.left() && x < rect.left() + borderWidth &&
|
||||||
y >= winrect.top && y < winrect.top + border_width)
|
y >= rect.top() && y < rect.top() + borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTTOPLEFT;
|
*result = HTTOPLEFT;
|
||||||
}
|
}
|
||||||
// top right corner
|
// top right corner
|
||||||
if (x < winrect.right && x >= winrect.right - border_width &&
|
if (x < rect.right() && x >= rect.right() - borderWidth &&
|
||||||
y >= winrect.top && y < winrect.top + border_width)
|
y >= rect.top() && y < rect.top() + borderWidth)
|
||||||
{
|
{
|
||||||
*result = HTTOPRIGHT;
|
*result = HTTOPRIGHT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,6 @@ public:
|
||||||
bool applyLastBoundsCheck();
|
bool applyLastBoundsCheck();
|
||||||
|
|
||||||
float scale() const override;
|
float scale() const override;
|
||||||
float qtFontScale() const;
|
|
||||||
|
|
||||||
/// @returns true if the window is the top-most window.
|
/// @returns true if the window is the top-most window.
|
||||||
/// Either #setTopMost was called or the `TopMost` flag is set which overrides this
|
/// Either #setTopMost was called or the `TopMost` flag is set which overrides this
|
||||||
|
@ -132,7 +131,6 @@ private:
|
||||||
void drawCustomWindowFrame(QPainter &painter);
|
void drawCustomWindowFrame(QPainter &painter);
|
||||||
void onFocusLost();
|
void onFocusLost();
|
||||||
|
|
||||||
bool handleDPICHANGED(MSG *msg);
|
|
||||||
bool handleSHOWWINDOW(MSG *msg);
|
bool handleSHOWWINDOW(MSG *msg);
|
||||||
bool handleSIZE(MSG *msg);
|
bool handleSIZE(MSG *msg);
|
||||||
bool handleMOVE(MSG *msg);
|
bool handleMOVE(MSG *msg);
|
||||||
|
@ -149,8 +147,6 @@ private:
|
||||||
bool frameless_;
|
bool frameless_;
|
||||||
bool shown_ = false;
|
bool shown_ = false;
|
||||||
FlagsEnum<Flags> flags_;
|
FlagsEnum<Flags> flags_;
|
||||||
float nativeScale_ = 1;
|
|
||||||
bool isResizeFixing_ = false;
|
|
||||||
bool isTopMost_ = false;
|
bool isTopMost_ = false;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -168,6 +164,7 @@ private:
|
||||||
widgets::BoundsChecking lastBoundsCheckMode_ = widgets::BoundsChecking::Off;
|
widgets::BoundsChecking lastBoundsCheckMode_ = widgets::BoundsChecking::Off;
|
||||||
|
|
||||||
#ifdef USEWINSDK
|
#ifdef USEWINSDK
|
||||||
|
void updateRealSize();
|
||||||
/// @brief Returns the HWND of this window if it has one
|
/// @brief Returns the HWND of this window if it has one
|
||||||
///
|
///
|
||||||
/// A QWidget only has an HWND if it has been created. Before that,
|
/// A QWidget only has an HWND if it has been created. Before that,
|
||||||
|
@ -193,6 +190,10 @@ private:
|
||||||
QTimer useNextBounds_;
|
QTimer useNextBounds_;
|
||||||
bool isNotMinimizedOrMaximized_{};
|
bool isNotMinimizedOrMaximized_{};
|
||||||
bool lastEventWasNcMouseMove_ = false;
|
bool lastEventWasNcMouseMove_ = false;
|
||||||
|
/// The real bounds of the window as returned by
|
||||||
|
/// GetWindowRect. Used for drawing.
|
||||||
|
QRect realBounds_;
|
||||||
|
bool isMaximized_ = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pajlada::Signals::SignalHolder connections_;
|
pajlada::Signals::SignalHolder connections_;
|
||||||
|
|
|
@ -88,23 +88,10 @@ void Label::paintEvent(QPaintEvent *)
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
qreal deviceDpi =
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
this->devicePixelRatioF();
|
|
||||||
#else
|
|
||||||
1.0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QFontMetrics metrics = getIApp()->getFonts()->getFontMetrics(
|
QFontMetrics metrics = getIApp()->getFonts()->getFontMetrics(
|
||||||
this->getFontStyle(),
|
this->getFontStyle(), this->scale());
|
||||||
this->scale() * 96.f /
|
painter.setFont(
|
||||||
std::max<float>(
|
getIApp()->getFonts()->getFont(this->getFontStyle(), this->scale()));
|
||||||
0.01F, static_cast<float>(this->logicalDpiX() * deviceDpi)));
|
|
||||||
painter.setFont(getIApp()->getFonts()->getFont(
|
|
||||||
this->getFontStyle(),
|
|
||||||
this->scale() * 96.f /
|
|
||||||
std::max<float>(
|
|
||||||
0.02F, static_cast<float>(this->logicalDpiX() * deviceDpi))));
|
|
||||||
|
|
||||||
int offset = this->getOffset();
|
int offset = this->getOffset();
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ bool TooltipEntryWidget::refreshPixmap()
|
||||||
this->attemptRefresh_ = true;
|
this->attemptRefresh_ = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
pixmap->setDevicePixelRatio(this->devicePixelRatio());
|
||||||
|
|
||||||
if (this->customImgWidth_ > 0 || this->customImgHeight_ > 0)
|
if (this->customImgWidth_ > 0 || this->customImgHeight_ > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,10 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
||||||
|
|
||||||
this->resize(915, 600);
|
this->resize(915, 600);
|
||||||
this->themeChangedEvent();
|
this->themeChangedEvent();
|
||||||
this->scaleChangedEvent(this->scale());
|
QFile styleFile(":/qss/settings.qss");
|
||||||
|
styleFile.open(QFile::ReadOnly);
|
||||||
|
QString stylesheet = QString::fromUtf8(styleFile.readAll());
|
||||||
|
this->setStyleSheet(stylesheet);
|
||||||
|
|
||||||
this->initUi();
|
this->initUi();
|
||||||
this->addTabs();
|
this->addTabs();
|
||||||
|
@ -396,25 +399,19 @@ void SettingsDialog::refresh()
|
||||||
|
|
||||||
void SettingsDialog::scaleChangedEvent(float newDpi)
|
void SettingsDialog::scaleChangedEvent(float newDpi)
|
||||||
{
|
{
|
||||||
QFile file(":/qss/settings.qss");
|
assert(newDpi == 1.F &&
|
||||||
file.open(QFile::ReadOnly);
|
"Scaling is disabled for the settings dialog - its scale should "
|
||||||
QString styleSheet = QLatin1String(file.readAll());
|
"always be 1");
|
||||||
styleSheet.replace("<font-size>", QString::number(int(14 * newDpi)));
|
|
||||||
styleSheet.replace("<checkbox-size>", QString::number(int(14 * newDpi)));
|
|
||||||
|
|
||||||
for (SettingsDialogTab *tab : this->tabs_)
|
for (SettingsDialogTab *tab : this->tabs_)
|
||||||
{
|
{
|
||||||
tab->setFixedHeight(int(30 * newDpi));
|
tab->setFixedHeight(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setStyleSheet(styleSheet);
|
|
||||||
|
|
||||||
if (this->ui_.tabContainerContainer)
|
if (this->ui_.tabContainerContainer)
|
||||||
{
|
{
|
||||||
this->ui_.tabContainerContainer->setFixedWidth(int(150 * newDpi));
|
this->ui_.tabContainerContainer->setFixedWidth(150);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->dpi_ = newDpi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::themeChangedEvent()
|
void SettingsDialog::themeChangedEvent()
|
||||||
|
|
|
@ -8,26 +8,44 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
|
||||||
namespace chatterino {
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// returns a new resized image or the old one if the size didn't change
|
QSizeF deviceIndependentSize(const QPixmap &pixmap)
|
||||||
auto resizePixmap(const QPixmap ¤t, const QPixmap resized,
|
{
|
||||||
const QSize &size) -> QPixmap
|
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 0)
|
||||||
|
return QSizeF(pixmap.width(), pixmap.height()) / pixmap.devicePixelRatio();
|
||||||
|
#else
|
||||||
|
return pixmap.deviceIndependentSize();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes a pixmap to a desired size.
|
||||||
|
* Does nothing if the target pixmap is already sized correctly.
|
||||||
|
*
|
||||||
|
* @param target The target pixmap.
|
||||||
|
* @param source The unscaled pixmap.
|
||||||
|
* @param size The desired device independent size.
|
||||||
|
* @param dpr The device pixel ratio of the target area. The size of the target in pixels will be `size * dpr`.
|
||||||
|
*/
|
||||||
|
void resizePixmap(QPixmap &target, const QPixmap &source, const QSize &size,
|
||||||
|
qreal dpr)
|
||||||
|
{
|
||||||
|
if (deviceIndependentSize(target) == size)
|
||||||
{
|
{
|
||||||
if (resized.size() == size)
|
return;
|
||||||
{
|
|
||||||
return resized;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return current.scaled(size, Qt::IgnoreAspectRatio,
|
|
||||||
Qt::SmoothTransformation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPixmap resized = source;
|
||||||
|
resized.setDevicePixelRatio(dpr);
|
||||||
|
target = resized.scaled(size * dpr, Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace chatterino {
|
||||||
|
|
||||||
Button::Button(BaseWidget *parent)
|
Button::Button(BaseWidget *parent)
|
||||||
: BaseWidget(parent)
|
: BaseWidget(parent)
|
||||||
{
|
{
|
||||||
|
@ -47,6 +65,12 @@ void Button::setMouseEffectColor(std::optional<QColor> color)
|
||||||
|
|
||||||
void Button::setPixmap(const QPixmap &_pixmap)
|
void Button::setPixmap(const QPixmap &_pixmap)
|
||||||
{
|
{
|
||||||
|
// Avoid updates if the pixmap didn't change
|
||||||
|
if (_pixmap.cacheKey() == this->pixmap_.cacheKey())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->pixmap_ = _pixmap;
|
this->pixmap_ = _pixmap;
|
||||||
this->resizedPixmap_ = {};
|
this->resizedPixmap_ = {};
|
||||||
this->update();
|
this->update();
|
||||||
|
@ -158,8 +182,8 @@ void Button::paintButton(QPainter &painter)
|
||||||
|
|
||||||
QRect rect = this->rect();
|
QRect rect = this->rect();
|
||||||
|
|
||||||
this->resizedPixmap_ =
|
resizePixmap(this->resizedPixmap_, this->pixmap_, rect.size(),
|
||||||
resizePixmap(this->pixmap_, this->resizedPixmap_, rect.size());
|
this->devicePixelRatio());
|
||||||
|
|
||||||
int margin = this->height() < 22 * this->scale() ? 3 : 6;
|
int margin = this->height() < 22 * this->scale() ? 3 : 6;
|
||||||
|
|
||||||
|
|
|
@ -615,7 +615,7 @@ void ChannelView::scaleChangedEvent(float scale)
|
||||||
|
|
||||||
if (this->goToBottom_)
|
if (this->goToBottom_)
|
||||||
{
|
{
|
||||||
auto factor = this->qtFontScale();
|
auto factor = this->scale();
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
factor = scale * 80.F /
|
factor = scale * 80.F /
|
||||||
std::max<float>(
|
std::max<float>(
|
||||||
|
@ -703,8 +703,10 @@ void ChannelView::layoutVisibleMessages(
|
||||||
{
|
{
|
||||||
const auto &message = messages[i];
|
const auto &message = messages[i];
|
||||||
|
|
||||||
redrawRequired |= message->layout(layoutWidth, this->scale(), flags,
|
redrawRequired |= message->layout(
|
||||||
this->bufferInvalidationQueued_);
|
layoutWidth, this->scale(),
|
||||||
|
this->scale() * static_cast<float>(this->devicePixelRatio()),
|
||||||
|
flags, this->bufferInvalidationQueued_);
|
||||||
|
|
||||||
y += message->getHeight();
|
y += message->getHeight();
|
||||||
}
|
}
|
||||||
|
@ -738,7 +740,10 @@ void ChannelView::updateScrollbar(
|
||||||
{
|
{
|
||||||
auto *message = messages[i].get();
|
auto *message = messages[i].get();
|
||||||
|
|
||||||
message->layout(layoutWidth, this->scale(), flags, false);
|
message->layout(
|
||||||
|
layoutWidth, this->scale(),
|
||||||
|
this->scale() * static_cast<float>(this->devicePixelRatio()), flags,
|
||||||
|
false);
|
||||||
|
|
||||||
h -= message->getHeight();
|
h -= message->getHeight();
|
||||||
|
|
||||||
|
@ -1720,9 +1725,11 @@ void ChannelView::wheelEvent(QWheelEvent *event)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snapshot[i - 1]->layout(this->getLayoutWidth(),
|
snapshot[i - 1]->layout(
|
||||||
this->scale(), this->getFlags(),
|
this->getLayoutWidth(), this->scale(),
|
||||||
false);
|
this->scale() *
|
||||||
|
static_cast<float>(this->devicePixelRatio()),
|
||||||
|
this->getFlags(), false);
|
||||||
scrollFactor = 1;
|
scrollFactor = 1;
|
||||||
currentScrollLeft = snapshot[i - 1]->getHeight();
|
currentScrollLeft = snapshot[i - 1]->getHeight();
|
||||||
}
|
}
|
||||||
|
@ -1755,9 +1762,11 @@ void ChannelView::wheelEvent(QWheelEvent *event)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snapshot[i + 1]->layout(this->getLayoutWidth(),
|
snapshot[i + 1]->layout(
|
||||||
this->scale(), this->getFlags(),
|
this->getLayoutWidth(), this->scale(),
|
||||||
false);
|
this->scale() *
|
||||||
|
static_cast<float>(this->devicePixelRatio()),
|
||||||
|
this->getFlags(), false);
|
||||||
|
|
||||||
scrollFactor = 1;
|
scrollFactor = 1;
|
||||||
currentScrollLeft = snapshot[i + 1]->getHeight();
|
currentScrollLeft = snapshot[i + 1]->getHeight();
|
||||||
|
|
|
@ -27,15 +27,6 @@
|
||||||
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace {
|
namespace {
|
||||||
qreal deviceDpi(QWidget *widget)
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
return widget->devicePixelRatioF();
|
|
||||||
#else
|
|
||||||
return 1.0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translates the given rectangle by an amount in the direction to appear like the tab is selected.
|
// Translates the given rectangle by an amount in the direction to appear like the tab is selected.
|
||||||
// For example, if location is Top, the rectangle will be translated in the negative Y direction,
|
// For example, if location is Top, the rectangle will be translated in the negative Y direction,
|
||||||
// or "up" on the screen, by amount.
|
// or "up" on the screen, by amount.
|
||||||
|
@ -196,8 +187,8 @@ int NotebookTab::normalTabWidth()
|
||||||
float scale = this->scale();
|
float scale = this->scale();
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
auto metrics = getIApp()->getFonts()->getFontMetrics(
|
QFontMetrics metrics =
|
||||||
FontStyle::UiTabs, float(qreal(this->scale()) * deviceDpi(this)));
|
getIApp()->getFonts()->getFontMetrics(FontStyle::UiTabs, scale);
|
||||||
|
|
||||||
if (this->hasXButton())
|
if (this->hasXButton())
|
||||||
{
|
{
|
||||||
|
@ -439,11 +430,9 @@ void NotebookTab::paintEvent(QPaintEvent *)
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
float scale = this->scale();
|
float scale = this->scale();
|
||||||
|
|
||||||
auto div = std::max<float>(0.01f, this->logicalDpiX() * deviceDpi(this));
|
painter.setFont(app->getFonts()->getFont(FontStyle::UiTabs, scale));
|
||||||
painter.setFont(
|
|
||||||
getIApp()->getFonts()->getFont(FontStyle::UiTabs, scale * 96.f / div));
|
|
||||||
QFontMetrics metrics =
|
QFontMetrics metrics =
|
||||||
app->getFonts()->getFontMetrics(FontStyle::UiTabs, scale * 96.f / div);
|
app->getFonts()->getFontMetrics(FontStyle::UiTabs, scale);
|
||||||
|
|
||||||
int height = int(scale * NOTEBOOK_TAB_HEIGHT);
|
int height = int(scale * NOTEBOOK_TAB_HEIGHT);
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
builder.append(
|
builder.append(
|
||||||
std::make_unique<TextElement>(text, MessageElementFlag::Text));
|
std::make_unique<TextElement>(text, MessageElementFlag::Text));
|
||||||
this->layout = std::make_unique<MessageLayout>(builder.release());
|
this->layout = std::make_unique<MessageLayout>(builder.release());
|
||||||
this->layout->layout(WIDTH, 1, MessageElementFlag::Text, false);
|
this->layout->layout(WIDTH, 1, 1, MessageElementFlag::Text, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MockApplication mockApplication;
|
MockApplication mockApplication;
|
||||||
|
|
Loading…
Reference in a new issue