moved BaseWindow and related files into appbase
This commit is contained in:
@@ -1,154 +0,0 @@
|
||||
#include "singletons/Fonts.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "debug/AssertInGuiThread.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
# define DEFAULT_FONT_FAMILY "Segoe UI"
|
||||
# define DEFAULT_FONT_SIZE 10
|
||||
#else
|
||||
# ifdef Q_OS_MACOS
|
||||
# define DEFAULT_FONT_FAMILY "Helvetica Neue"
|
||||
# define DEFAULT_FONT_SIZE 12
|
||||
# else
|
||||
# define DEFAULT_FONT_FAMILY "Arial"
|
||||
# define DEFAULT_FONT_SIZE 11
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
Fonts::Fonts()
|
||||
: chatFontFamily("/appearance/currentFontFamily", DEFAULT_FONT_FAMILY)
|
||||
, chatFontSize("/appearance/currentFontSize", DEFAULT_FONT_SIZE)
|
||||
{
|
||||
this->fontsByType_.resize(size_t(FontStyle::EndType));
|
||||
}
|
||||
|
||||
void Fonts::initialize(Settings &, Paths &)
|
||||
{
|
||||
this->chatFontFamily.connect(
|
||||
[this]() {
|
||||
assertInGuiThread();
|
||||
|
||||
for (auto &map : this->fontsByType_)
|
||||
{
|
||||
map.clear();
|
||||
}
|
||||
this->fontChanged.invoke();
|
||||
},
|
||||
false);
|
||||
|
||||
this->chatFontSize.connect(
|
||||
[this]() {
|
||||
assertInGuiThread();
|
||||
|
||||
for (auto &map : this->fontsByType_)
|
||||
{
|
||||
map.clear();
|
||||
}
|
||||
this->fontChanged.invoke();
|
||||
},
|
||||
false);
|
||||
|
||||
getSettings()->boldScale.connect(
|
||||
[this]() {
|
||||
assertInGuiThread();
|
||||
|
||||
getApp()->windows->incGeneration();
|
||||
|
||||
for (auto &map : this->fontsByType_)
|
||||
{
|
||||
map.clear();
|
||||
}
|
||||
this->fontChanged.invoke();
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
||||
QFont Fonts::getFont(FontStyle type, float scale)
|
||||
{
|
||||
return this->getOrCreateFontData(type, scale).font;
|
||||
}
|
||||
|
||||
QFontMetrics Fonts::getFontMetrics(FontStyle type, float scale)
|
||||
{
|
||||
return this->getOrCreateFontData(type, scale).metrics;
|
||||
}
|
||||
|
||||
Fonts::FontData &Fonts::getOrCreateFontData(FontStyle type, float scale)
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
assert(type < FontStyle::EndType);
|
||||
|
||||
auto &map = this->fontsByType_[size_t(type)];
|
||||
|
||||
// find element
|
||||
auto it = map.find(scale);
|
||||
if (it != map.end())
|
||||
{
|
||||
// return if found
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// emplace new element
|
||||
auto result = map.emplace(scale, this->createFontData(type, scale));
|
||||
assert(result.second);
|
||||
|
||||
return result.first->second;
|
||||
}
|
||||
|
||||
Fonts::FontData Fonts::createFontData(FontStyle type, float scale)
|
||||
{
|
||||
// check if it's a chat (scale the setting)
|
||||
if (type >= FontStyle::ChatStart && type <= FontStyle::ChatEnd)
|
||||
{
|
||||
static std::unordered_map<FontStyle, ChatFontData> sizeScale{
|
||||
{FontStyle::ChatSmall, {0.6f, false, QFont::Normal}},
|
||||
{FontStyle::ChatMediumSmall, {0.8f, false, QFont::Normal}},
|
||||
{FontStyle::ChatMedium, {1, false, QFont::Normal}},
|
||||
{FontStyle::ChatMediumBold,
|
||||
{1, false, QFont::Weight(getSettings()->boldScale.getValue())}},
|
||||
{FontStyle::ChatMediumItalic, {1, true, QFont::Normal}},
|
||||
{FontStyle::ChatLarge, {1.2f, false, QFont::Normal}},
|
||||
{FontStyle::ChatVeryLarge, {1.4f, false, QFont::Normal}},
|
||||
};
|
||||
sizeScale[FontStyle::ChatMediumBold] = {
|
||||
1, false, QFont::Weight(getSettings()->boldScale.getValue())};
|
||||
auto data = sizeScale[type];
|
||||
return FontData(
|
||||
QFont(this->chatFontFamily.getValue(),
|
||||
int(this->chatFontSize.getValue() * data.scale * scale),
|
||||
data.weight, data.italic));
|
||||
}
|
||||
|
||||
// normal Ui font (use pt size)
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
constexpr float multiplier = 0.8f;
|
||||
#else
|
||||
constexpr float multiplier = 1.f;
|
||||
#endif
|
||||
|
||||
static std::unordered_map<FontStyle, UiFontData> defaultSize{
|
||||
{FontStyle::Tiny, {8, "Monospace", false, QFont::Normal}},
|
||||
{FontStyle::UiMedium,
|
||||
{int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
|
||||
{FontStyle::UiTabs,
|
||||
{int(9 * multiplier), DEFAULT_FONT_FAMILY, false, QFont::Normal}},
|
||||
};
|
||||
|
||||
UiFontData &data = defaultSize[type];
|
||||
QFont font(data.name, int(data.size * scale), data.weight, data.italic);
|
||||
return FontData(font);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/ChatterinoSetting.hpp"
|
||||
#include "common/Singleton.hpp"
|
||||
|
||||
#include <QFont>
|
||||
#include <QFontDatabase>
|
||||
#include <QFontMetrics>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Settings;
|
||||
class Paths;
|
||||
|
||||
enum class FontStyle : uint8_t {
|
||||
Tiny,
|
||||
ChatSmall,
|
||||
ChatMediumSmall,
|
||||
ChatMedium,
|
||||
ChatMediumBold,
|
||||
ChatMediumItalic,
|
||||
ChatLarge,
|
||||
ChatVeryLarge,
|
||||
|
||||
UiMedium,
|
||||
UiTabs,
|
||||
|
||||
// don't remove this value
|
||||
EndType,
|
||||
|
||||
// make sure to update these values accordingly!
|
||||
ChatStart = ChatSmall,
|
||||
ChatEnd = ChatVeryLarge,
|
||||
};
|
||||
|
||||
class Fonts final : public Singleton
|
||||
{
|
||||
public:
|
||||
Fonts();
|
||||
|
||||
virtual void initialize(Settings &settings, Paths &paths) override;
|
||||
|
||||
// font data gets set in createFontData(...)
|
||||
|
||||
QFont getFont(FontStyle type, float scale);
|
||||
QFontMetrics getFontMetrics(FontStyle type, float scale);
|
||||
|
||||
QStringSetting chatFontFamily;
|
||||
IntSetting chatFontSize;
|
||||
|
||||
pajlada::Signals::NoArgSignal fontChanged;
|
||||
|
||||
private:
|
||||
struct FontData {
|
||||
FontData(const QFont &_font)
|
||||
: font(_font)
|
||||
, metrics(_font)
|
||||
{
|
||||
}
|
||||
|
||||
const QFont font;
|
||||
const QFontMetrics metrics;
|
||||
};
|
||||
|
||||
struct ChatFontData {
|
||||
float scale;
|
||||
bool italic;
|
||||
QFont::Weight weight;
|
||||
};
|
||||
|
||||
struct UiFontData {
|
||||
float size;
|
||||
const char *name;
|
||||
bool italic;
|
||||
QFont::Weight weight;
|
||||
};
|
||||
|
||||
FontData &getOrCreateFontData(FontStyle type, float scale);
|
||||
FontData createFontData(FontStyle type, float scale);
|
||||
|
||||
std::vector<std::unordered_map<float, FontData>> fontsByType_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -17,7 +17,7 @@ class Theme final : public Singleton
|
||||
public:
|
||||
Theme();
|
||||
|
||||
inline bool isLightTheme() const
|
||||
bool isLightTheme() const
|
||||
{
|
||||
return this->isLight_;
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define async_exec(a) \
|
||||
QThreadPool::globalInstance()->start(new LambdaRunnable(a));
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class LambdaRunnable : public QRunnable
|
||||
{
|
||||
public:
|
||||
LambdaRunnable(std::function<void()> action)
|
||||
{
|
||||
this->action_ = action;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
this->action_();
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> action_;
|
||||
};
|
||||
|
||||
// Taken from
|
||||
// https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style
|
||||
// Qt 5/4 - preferred, has least allocations
|
||||
template <typename F>
|
||||
static void postToThread(F &&fun, QObject *obj = qApp)
|
||||
{
|
||||
struct Event : public QEvent {
|
||||
using Fun = typename std::decay<F>::type;
|
||||
Fun fun;
|
||||
Event(Fun &&fun)
|
||||
: QEvent(QEvent::None)
|
||||
, fun(std::move(fun))
|
||||
{
|
||||
}
|
||||
Event(const Fun &fun)
|
||||
: QEvent(QEvent::None)
|
||||
, fun(fun)
|
||||
{
|
||||
}
|
||||
~Event() override
|
||||
{
|
||||
fun();
|
||||
}
|
||||
};
|
||||
QCoreApplication::postEvent(obj, new Event(std::forward<F>(fun)));
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <pajlada/serialize.hpp>
|
||||
|
||||
namespace pajlada {
|
||||
|
||||
template <>
|
||||
struct Serialize<QString> {
|
||||
static rapidjson::Value get(const QString &value,
|
||||
rapidjson::Document::AllocatorType &a)
|
||||
{
|
||||
return rapidjson::Value(value.toUtf8(), a);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Deserialize<QString> {
|
||||
static QString get(const rapidjson::Value &value, bool *error = nullptr)
|
||||
{
|
||||
if (!value.IsString())
|
||||
{
|
||||
PAJLADA_REPORT_ERROR(error)
|
||||
return QString{};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return QString::fromUtf8(value.GetString(),
|
||||
value.GetStringLength());
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
// int x = 5;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// int y = 5;
|
||||
}
|
||||
|
||||
return QString{};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace pajlada
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "WindowsHelper.hpp"
|
||||
|
||||
#ifdef USEWINSDK
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
typedef enum MONITOR_DPI_TYPE {
|
||||
MDT_EFFECTIVE_DPI = 0,
|
||||
MDT_ANGULAR_DPI = 1,
|
||||
MDT_RAW_DPI = 2,
|
||||
MDT_DEFAULT = MDT_EFFECTIVE_DPI
|
||||
} MONITOR_DPI_TYPE;
|
||||
|
||||
typedef HRESULT(CALLBACK *GetDpiForMonitor_)(HMONITOR, MONITOR_DPI_TYPE, UINT *,
|
||||
UINT *);
|
||||
|
||||
boost::optional<UINT> getWindowDpi(HWND hwnd)
|
||||
{
|
||||
static HINSTANCE shcore = LoadLibrary(L"Shcore.dll");
|
||||
if (shcore != nullptr)
|
||||
{
|
||||
if (auto getDpiForMonitor =
|
||||
GetDpiForMonitor_(GetProcAddress(shcore, "GetDpiForMonitor")))
|
||||
{
|
||||
HMONITOR monitor =
|
||||
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
UINT xScale, yScale;
|
||||
|
||||
getDpiForMonitor(monitor, MDT_DEFAULT, &xScale, &yScale);
|
||||
|
||||
return xScale;
|
||||
}
|
||||
}
|
||||
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
typedef HRESULT(CALLBACK *OleFlushClipboard_)();
|
||||
|
||||
void flushClipboard()
|
||||
{
|
||||
static HINSTANCE ole32 = LoadLibrary(L"Ole32.dll");
|
||||
if (ole32 != nullptr)
|
||||
{
|
||||
if (auto oleFlushClipboard =
|
||||
OleFlushClipboard_(GetProcAddress(ole32, "OleFlushClipboard")))
|
||||
{
|
||||
oleFlushClipboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USEWINSDK
|
||||
|
||||
# include <Windows.h>
|
||||
# include <boost/optional.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
boost::optional<UINT> getWindowDpi(HWND hwnd);
|
||||
void flushClipboard();
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
#endif
|
||||
@@ -1,895 +0,0 @@
|
||||
#include "BaseWindow.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "boost/algorithm/algorithm.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "singletons/Settings.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
#include "singletons/WindowManager.hpp"
|
||||
#include "util/PostToThread.hpp"
|
||||
#include "util/WindowsHelper.hpp"
|
||||
#include "widgets/Label.hpp"
|
||||
#include "widgets/TooltipWidget.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QDesktopWidget>
|
||||
#include <QIcon>
|
||||
#include <functional>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
# include <ObjIdl.h>
|
||||
# include <VersionHelpers.h>
|
||||
# include <Windows.h>
|
||||
# include <dwmapi.h>
|
||||
# include <gdiplus.h>
|
||||
# include <windowsx.h>
|
||||
|
||||
//#include <ShellScalingApi.h>
|
||||
# pragma comment(lib, "Dwmapi.lib")
|
||||
|
||||
# include <QHBoxLayout>
|
||||
# include <QVBoxLayout>
|
||||
|
||||
# define WM_DPICHANGED 0x02E0
|
||||
#endif
|
||||
|
||||
#include "widgets/helper/TitlebarButton.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
BaseWindow::BaseWindow(QWidget *parent, Flags _flags)
|
||||
: BaseWidget(parent,
|
||||
Qt::Window | ((_flags & TopMost) ? Qt::WindowStaysOnTopHint
|
||||
: Qt::WindowFlags()))
|
||||
, enableCustomFrame_(_flags & EnableCustomFrame)
|
||||
, frameless_(_flags & Frameless)
|
||||
, flags_(_flags)
|
||||
{
|
||||
if (this->frameless_)
|
||||
{
|
||||
this->enableCustomFrame_ = false;
|
||||
this->setWindowFlag(Qt::FramelessWindowHint);
|
||||
}
|
||||
|
||||
this->init();
|
||||
|
||||
getSettings()->uiScale.connect(
|
||||
[this]() { postToThread([this] { this->updateScale(); }); },
|
||||
this->connections_);
|
||||
|
||||
this->updateScale();
|
||||
|
||||
createWindowShortcut(this, "CTRL+0",
|
||||
[] { getSettings()->uiScale.setValue(0); });
|
||||
|
||||
// QTimer::this->scaleChangedEvent(this->getScale());
|
||||
}
|
||||
|
||||
float BaseWindow::scale() const
|
||||
{
|
||||
return this->overrideScale().value_or(this->scale_);
|
||||
}
|
||||
|
||||
BaseWindow::Flags BaseWindow::getFlags()
|
||||
{
|
||||
return this->flags_;
|
||||
}
|
||||
|
||||
void BaseWindow::init()
|
||||
{
|
||||
this->setWindowIcon(QIcon(":/images/icon.png"));
|
||||
|
||||
#ifdef USEWINSDK
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
// CUSTOM WINDOW FRAME
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
this->ui_.windowLayout = layout;
|
||||
layout->setContentsMargins(0, 1, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
this->setLayout(layout);
|
||||
{
|
||||
if (!this->frameless_)
|
||||
{
|
||||
QHBoxLayout *buttonLayout = this->ui_.titlebarBox =
|
||||
new QHBoxLayout();
|
||||
buttonLayout->setMargin(0);
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
// title
|
||||
Label *title = new Label("Chatterino");
|
||||
QObject::connect(
|
||||
this, &QWidget::windowTitleChanged,
|
||||
[title](const QString &text) { title->setText(text); });
|
||||
|
||||
QSizePolicy policy(QSizePolicy::Ignored,
|
||||
QSizePolicy::Preferred);
|
||||
policy.setHorizontalStretch(1);
|
||||
title->setSizePolicy(policy);
|
||||
buttonLayout->addWidget(title);
|
||||
this->ui_.titleLabel = title;
|
||||
|
||||
// buttons
|
||||
TitleBarButton *_minButton = new TitleBarButton;
|
||||
_minButton->setButtonStyle(TitleBarButtonStyle::Minimize);
|
||||
TitleBarButton *_maxButton = new TitleBarButton;
|
||||
_maxButton->setButtonStyle(TitleBarButtonStyle::Maximize);
|
||||
TitleBarButton *_exitButton = new TitleBarButton;
|
||||
_exitButton->setButtonStyle(TitleBarButtonStyle::Close);
|
||||
|
||||
QObject::connect(_minButton, &TitleBarButton::leftClicked, this,
|
||||
[this] {
|
||||
this->setWindowState(Qt::WindowMinimized |
|
||||
this->windowState());
|
||||
});
|
||||
QObject::connect(_maxButton, &TitleBarButton::leftClicked, this,
|
||||
[this, _maxButton] {
|
||||
this->setWindowState(
|
||||
_maxButton->getButtonStyle() !=
|
||||
TitleBarButtonStyle::Maximize
|
||||
? Qt::WindowActive
|
||||
: Qt::WindowMaximized);
|
||||
});
|
||||
QObject::connect(_exitButton, &TitleBarButton::leftClicked,
|
||||
this, [this] { this->close(); });
|
||||
|
||||
this->ui_.minButton = _minButton;
|
||||
this->ui_.maxButton = _maxButton;
|
||||
this->ui_.exitButton = _exitButton;
|
||||
|
||||
this->ui_.buttons.push_back(_minButton);
|
||||
this->ui_.buttons.push_back(_maxButton);
|
||||
this->ui_.buttons.push_back(_exitButton);
|
||||
|
||||
// buttonLayout->addStretch(1);
|
||||
buttonLayout->addWidget(_minButton);
|
||||
buttonLayout->addWidget(_maxButton);
|
||||
buttonLayout->addWidget(_exitButton);
|
||||
buttonLayout->setSpacing(0);
|
||||
}
|
||||
}
|
||||
this->ui_.layoutBase = new BaseWidget(this);
|
||||
layout->addWidget(this->ui_.layoutBase);
|
||||
}
|
||||
|
||||
// DPI
|
||||
// auto dpi = getWindowDpi(this->winId());
|
||||
|
||||
// if (dpi) {
|
||||
// this->scale = dpi.value() / 96.f;
|
||||
// }
|
||||
#endif
|
||||
|
||||
#ifdef USEWINSDK
|
||||
// fourtf: don't ask me why we need to delay this
|
||||
if (!(this->flags_ & Flags::TopMost))
|
||||
{
|
||||
QTimer::singleShot(1, this, [this] {
|
||||
getSettings()->windowTopMost.connect(
|
||||
[this](bool topMost, auto) {
|
||||
::SetWindowPos(HWND(this->winId()),
|
||||
topMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,
|
||||
0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
},
|
||||
this->managedConnections_);
|
||||
});
|
||||
}
|
||||
#else
|
||||
// if (getSettings()->windowTopMost.getValue()) {
|
||||
// this->setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseWindow::setStayInScreenRect(bool value)
|
||||
{
|
||||
this->stayInScreenRect_ = value;
|
||||
|
||||
this->moveIntoDesktopRect(this);
|
||||
}
|
||||
|
||||
bool BaseWindow::getStayInScreenRect() const
|
||||
{
|
||||
return this->stayInScreenRect_;
|
||||
}
|
||||
|
||||
void BaseWindow::setActionOnFocusLoss(ActionOnFocusLoss value)
|
||||
{
|
||||
this->actionOnFocusLoss_ = value;
|
||||
}
|
||||
|
||||
BaseWindow::ActionOnFocusLoss BaseWindow::getActionOnFocusLoss() const
|
||||
{
|
||||
return this->actionOnFocusLoss_;
|
||||
}
|
||||
|
||||
QWidget *BaseWindow::getLayoutContainer()
|
||||
{
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
return this->ui_.layoutBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseWindow::hasCustomWindowFrame()
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
static bool isWin8 = IsWindows8OrGreater();
|
||||
|
||||
return isWin8 && this->enableCustomFrame_;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseWindow::themeChangedEvent()
|
||||
{
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Background, QColor(0, 0, 0, 0));
|
||||
palette.setColor(QPalette::Foreground, this->theme->window.text);
|
||||
this->setPalette(palette);
|
||||
|
||||
if (this->ui_.titleLabel)
|
||||
{
|
||||
QPalette palette_title;
|
||||
palette_title.setColor(
|
||||
QPalette::Foreground,
|
||||
this->theme->isLightTheme() ? "#333" : "#ccc");
|
||||
this->ui_.titleLabel->setPalette(palette_title);
|
||||
}
|
||||
|
||||
for (Button *button : this->ui_.buttons)
|
||||
{
|
||||
button->setMouseEffectColor(this->theme->window.text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Background, this->theme->window.background);
|
||||
palette.setColor(QPalette::Foreground, this->theme->window.text);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseWindow::event(QEvent *event)
|
||||
{
|
||||
if (event->type() ==
|
||||
QEvent::WindowDeactivate /*|| event->type() == QEvent::FocusOut*/)
|
||||
{
|
||||
this->onFocusLost();
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void BaseWindow::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
if (event->orientation() != Qt::Vertical)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->modifiers() & Qt::ControlModifier)
|
||||
{
|
||||
if (event->delta() > 0)
|
||||
{
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
getSettings()->uiScale.setValue(WindowManager::clampUiScale(
|
||||
getSettings()->uiScale.getValue() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaseWindow::onFocusLost()
|
||||
{
|
||||
switch (this->getActionOnFocusLoss())
|
||||
{
|
||||
case Delete:
|
||||
{
|
||||
this->deleteLater();
|
||||
}
|
||||
break;
|
||||
|
||||
case Close:
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
break;
|
||||
|
||||
case Hide:
|
||||
{
|
||||
this->hide();
|
||||
}
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseWindow::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
#ifndef Q_OS_WIN
|
||||
if (this->flags_ & FramelessDraggable)
|
||||
{
|
||||
this->movingRelativePos = event->localPos();
|
||||
if (auto widget =
|
||||
this->childAt(event->localPos().x(), event->localPos().y()))
|
||||
{
|
||||
std::function<bool(QWidget *)> recursiveCheckMouseTracking;
|
||||
recursiveCheckMouseTracking = [&](QWidget *widget) {
|
||||
if (widget == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (widget->hasMouseTracking())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return recursiveCheckMouseTracking(widget->parentWidget());
|
||||
};
|
||||
|
||||
if (!recursiveCheckMouseTracking(widget))
|
||||
{
|
||||
log("Start moving");
|
||||
this->moving = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void BaseWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
#ifndef Q_OS_WIN
|
||||
if (this->flags_ & FramelessDraggable)
|
||||
{
|
||||
if (this->moving)
|
||||
{
|
||||
log("Stop moving");
|
||||
this->moving = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void BaseWindow::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
#ifndef Q_OS_WIN
|
||||
if (this->flags_ & FramelessDraggable)
|
||||
{
|
||||
if (this->moving)
|
||||
{
|
||||
const auto &newPos = event->screenPos() - this->movingRelativePos;
|
||||
this->move(newPos.x(), newPos.y());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
TitleBarButton *BaseWindow::addTitleBarButton(const TitleBarButtonStyle &style,
|
||||
std::function<void()> onClicked)
|
||||
{
|
||||
TitleBarButton *button = new TitleBarButton;
|
||||
button->setScaleIndependantSize(30, 30);
|
||||
|
||||
this->ui_.buttons.push_back(button);
|
||||
this->ui_.titlebarBox->insertWidget(1, button);
|
||||
button->setButtonStyle(style);
|
||||
|
||||
QObject::connect(button, &TitleBarButton::leftClicked, this,
|
||||
[onClicked] { onClicked(); });
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
EffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
|
||||
{
|
||||
EffectLabel *button = new EffectLabel;
|
||||
button->setScaleIndependantHeight(30);
|
||||
|
||||
this->ui_.buttons.push_back(button);
|
||||
this->ui_.titlebarBox->insertWidget(1, button);
|
||||
|
||||
QObject::connect(button, &EffectLabel::leftClicked, this,
|
||||
[onClicked] { onClicked(); });
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
void BaseWindow::changeEvent(QEvent *)
|
||||
{
|
||||
TooltipWidget::getInstance()->hide();
|
||||
|
||||
#ifdef USEWINSDK
|
||||
if (this->ui_.maxButton)
|
||||
{
|
||||
this->ui_.maxButton->setButtonStyle(
|
||||
this->windowState() & Qt::WindowMaximized
|
||||
? TitleBarButtonStyle::Unmaximize
|
||||
: TitleBarButtonStyle::Maximize);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
this->update();
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseWindow::leaveEvent(QEvent *)
|
||||
{
|
||||
TooltipWidget::getInstance()->hide();
|
||||
}
|
||||
|
||||
void BaseWindow::moveTo(QWidget *parent, QPoint point, bool offset)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
point.rx() += 16;
|
||||
point.ry() += 16;
|
||||
}
|
||||
|
||||
this->move(point);
|
||||
this->moveIntoDesktopRect(parent);
|
||||
}
|
||||
|
||||
void BaseWindow::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
// Queue up save because: Window resized
|
||||
getApp()->windows->queueSave();
|
||||
|
||||
this->moveIntoDesktopRect(this);
|
||||
|
||||
this->calcButtonsSizes();
|
||||
}
|
||||
|
||||
void BaseWindow::moveEvent(QMoveEvent *event)
|
||||
{
|
||||
// Queue up save because: Window position changed
|
||||
getApp()->windows->queueSave();
|
||||
|
||||
BaseWidget::moveEvent(event);
|
||||
}
|
||||
|
||||
void BaseWindow::closeEvent(QCloseEvent *)
|
||||
{
|
||||
this->closing.invoke();
|
||||
}
|
||||
|
||||
void BaseWindow::moveIntoDesktopRect(QWidget *parent)
|
||||
{
|
||||
if (!this->stayInScreenRect_)
|
||||
return;
|
||||
|
||||
// move the widget into the screen geometry if it's not already in there
|
||||
QDesktopWidget *desktop = QApplication::desktop();
|
||||
|
||||
QRect s = desktop->availableGeometry(parent);
|
||||
QPoint p = this->pos();
|
||||
|
||||
if (p.x() < s.left())
|
||||
{
|
||||
p.setX(s.left());
|
||||
}
|
||||
if (p.y() < s.top())
|
||||
{
|
||||
p.setY(s.top());
|
||||
}
|
||||
if (p.x() + this->width() > s.right())
|
||||
{
|
||||
p.setX(s.right() - this->width());
|
||||
}
|
||||
if (p.y() + this->height() > s.bottom())
|
||||
{
|
||||
p.setY(s.bottom() - this->height());
|
||||
}
|
||||
|
||||
if (p != this->pos())
|
||||
this->move(p);
|
||||
}
|
||||
|
||||
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message,
|
||||
long *result)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
# if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
|
||||
MSG *msg = *reinterpret_cast<MSG **>(message);
|
||||
# else
|
||||
MSG *msg = reinterpret_cast<MSG *>(message);
|
||||
# endif
|
||||
|
||||
bool returnValue = false;
|
||||
|
||||
switch (msg->message)
|
||||
{
|
||||
case WM_DPICHANGED:
|
||||
returnValue = handleDPICHANGED(msg);
|
||||
break;
|
||||
|
||||
case WM_SHOWWINDOW:
|
||||
returnValue = this->handleSHOWWINDOW(msg);
|
||||
break;
|
||||
|
||||
case WM_NCCALCSIZE:
|
||||
returnValue = this->handleNCCALCSIZE(msg, result);
|
||||
break;
|
||||
|
||||
case WM_SIZE:
|
||||
returnValue = this->handleSIZE(msg);
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST:
|
||||
returnValue = this->handleNCHITTEST(msg, result);
|
||||
break;
|
||||
|
||||
default:
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
}
|
||||
|
||||
QWidget::nativeEvent(eventType, message, result);
|
||||
|
||||
return returnValue;
|
||||
#else
|
||||
return QWidget::nativeEvent(eventType, message, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseWindow::scaleChangedEvent(float)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
this->calcButtonsSizes();
|
||||
#endif
|
||||
}
|
||||
|
||||
void BaseWindow::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
if (this->frameless_)
|
||||
{
|
||||
painter.setPen(QColor("#999"));
|
||||
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
||||
}
|
||||
|
||||
this->drawCustomWindowFrame(painter);
|
||||
}
|
||||
|
||||
void BaseWindow::updateScale()
|
||||
{
|
||||
auto scale =
|
||||
this->nativeScale_ * (this->flags_ & DisableCustomScaling
|
||||
? 1
|
||||
: getApp()->windows->getUiScaleValue());
|
||||
this->setScale(scale);
|
||||
|
||||
for (auto child : this->findChildren<BaseWidget *>())
|
||||
{
|
||||
child->setScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseWindow::calcButtonsSizes()
|
||||
{
|
||||
if (!this->shown_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((this->width() / this->scale()) < 300)
|
||||
{
|
||||
if (this->ui_.minButton)
|
||||
this->ui_.minButton->setScaleIndependantSize(30, 30);
|
||||
if (this->ui_.maxButton)
|
||||
this->ui_.maxButton->setScaleIndependantSize(30, 30);
|
||||
if (this->ui_.exitButton)
|
||||
this->ui_.exitButton->setScaleIndependantSize(30, 30);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->ui_.minButton)
|
||||
this->ui_.minButton->setScaleIndependantSize(46, 30);
|
||||
if (this->ui_.maxButton)
|
||||
this->ui_.maxButton->setScaleIndependantSize(46, 30);
|
||||
if (this->ui_.exitButton)
|
||||
this->ui_.exitButton->setScaleIndependantSize(46, 30);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseWindow::drawCustomWindowFrame(QPainter &painter)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
QColor bg = this->overrideBackgroundColor_.value_or(
|
||||
this->theme->window.background);
|
||||
|
||||
painter.fillRect(QRect(0, 1, this->width() - 0, this->height() - 0),
|
||||
bg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BaseWindow::handleDPICHANGED(MSG *msg)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
int dpi = HIWORD(msg->wParam);
|
||||
|
||||
float _scale = dpi / 96.f;
|
||||
|
||||
static bool firstResize = true;
|
||||
|
||||
if (!firstResize)
|
||||
{
|
||||
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);
|
||||
}
|
||||
firstResize = false;
|
||||
|
||||
this->nativeScale_ = _scale;
|
||||
this->updateScale();
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BaseWindow::handleSHOWWINDOW(MSG *msg)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
if (auto dpi = getWindowDpi(msg->hwnd))
|
||||
{
|
||||
this->nativeScale_ = dpi.get() / 96.f;
|
||||
this->updateScale();
|
||||
}
|
||||
|
||||
if (!this->shown_ && this->isVisible() && this->hasCustomWindowFrame())
|
||||
{
|
||||
this->shown_ = true;
|
||||
|
||||
const MARGINS shadow = {8, 8, 8, 8};
|
||||
DwmExtendFrameIntoClientArea(HWND(this->winId()), &shadow);
|
||||
}
|
||||
|
||||
this->calcButtonsSizes();
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BaseWindow::handleNCCALCSIZE(MSG *msg, long *result)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
// int cx = GetSystemMetrics(SM_CXSIZEFRAME);
|
||||
// int cy = GetSystemMetrics(SM_CYSIZEFRAME);
|
||||
|
||||
if (msg->wParam == TRUE)
|
||||
{
|
||||
NCCALCSIZE_PARAMS *ncp =
|
||||
(reinterpret_cast<NCCALCSIZE_PARAMS *>(msg->lParam));
|
||||
ncp->lppos->flags |= SWP_NOREDRAW;
|
||||
RECT *clientRect = &ncp->rgrc[0];
|
||||
|
||||
clientRect->left += 1;
|
||||
clientRect->top += 0;
|
||||
clientRect->right -= 1;
|
||||
clientRect->bottom -= 1;
|
||||
}
|
||||
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BaseWindow::handleSIZE(MSG *msg)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
if (this->ui_.windowLayout)
|
||||
{
|
||||
if (this->frameless_)
|
||||
{
|
||||
//
|
||||
}
|
||||
else if (this->hasCustomWindowFrame())
|
||||
{
|
||||
if (msg->wParam == SIZE_MAXIMIZED)
|
||||
{
|
||||
auto offset = int(this->scale() * 8);
|
||||
|
||||
this->ui_.windowLayout->setContentsMargins(offset, offset,
|
||||
offset, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ui_.windowLayout->setContentsMargins(0, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BaseWindow::handleNCHITTEST(MSG *msg, long *result)
|
||||
{
|
||||
#ifdef USEWINSDK
|
||||
const LONG border_width = 8; // in pixels
|
||||
RECT winrect;
|
||||
GetWindowRect(HWND(winId()), &winrect);
|
||||
|
||||
long x = GET_X_LPARAM(msg->lParam);
|
||||
long y = GET_Y_LPARAM(msg->lParam);
|
||||
|
||||
QPoint point(x - winrect.left, y - winrect.top);
|
||||
|
||||
if (this->hasCustomWindowFrame())
|
||||
{
|
||||
*result = 0;
|
||||
|
||||
bool resizeWidth = minimumWidth() != maximumWidth();
|
||||
bool resizeHeight = minimumHeight() != maximumHeight();
|
||||
|
||||
if (resizeWidth)
|
||||
{
|
||||
// left border
|
||||
if (x < winrect.left + border_width)
|
||||
{
|
||||
*result = HTLEFT;
|
||||
}
|
||||
// right border
|
||||
if (x >= winrect.right - border_width)
|
||||
{
|
||||
*result = HTRIGHT;
|
||||
}
|
||||
}
|
||||
if (resizeHeight)
|
||||
{
|
||||
// bottom border
|
||||
if (y >= winrect.bottom - border_width)
|
||||
{
|
||||
*result = HTBOTTOM;
|
||||
}
|
||||
// top border
|
||||
if (y < winrect.top + border_width)
|
||||
{
|
||||
*result = HTTOP;
|
||||
}
|
||||
}
|
||||
if (resizeWidth && resizeHeight)
|
||||
{
|
||||
// bottom left corner
|
||||
if (x >= winrect.left && x < winrect.left + border_width &&
|
||||
y < winrect.bottom && y >= winrect.bottom - border_width)
|
||||
{
|
||||
*result = HTBOTTOMLEFT;
|
||||
}
|
||||
// bottom right corner
|
||||
if (x < winrect.right && x >= winrect.right - border_width &&
|
||||
y < winrect.bottom && y >= winrect.bottom - border_width)
|
||||
{
|
||||
*result = HTBOTTOMRIGHT;
|
||||
}
|
||||
// top left corner
|
||||
if (x >= winrect.left && x < winrect.left + border_width &&
|
||||
y >= winrect.top && y < winrect.top + border_width)
|
||||
{
|
||||
*result = HTTOPLEFT;
|
||||
}
|
||||
// top right corner
|
||||
if (x < winrect.right && x >= winrect.right - border_width &&
|
||||
y >= winrect.top && y < winrect.top + border_width)
|
||||
{
|
||||
*result = HTTOPRIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (*result == 0)
|
||||
{
|
||||
bool client = false;
|
||||
|
||||
for (QWidget *widget : this->ui_.buttons)
|
||||
{
|
||||
if (widget->geometry().contains(point))
|
||||
{
|
||||
client = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->ui_.layoutBase->geometry().contains(point))
|
||||
{
|
||||
client = true;
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
*result = HTCLIENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = HTCAPTION;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (this->flags_ & FramelessDraggable)
|
||||
{
|
||||
*result = 0;
|
||||
bool client = false;
|
||||
|
||||
if (auto widget = this->childAt(point))
|
||||
{
|
||||
std::function<bool(QWidget *)> recursiveCheckMouseTracking;
|
||||
recursiveCheckMouseTracking = [&](QWidget *widget) {
|
||||
if (widget == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (widget->hasMouseTracking())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return recursiveCheckMouseTracking(widget->parentWidget());
|
||||
};
|
||||
|
||||
if (recursiveCheckMouseTracking(widget))
|
||||
{
|
||||
client = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
*result = HTCLIENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = HTCAPTION;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,120 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
||||
class QHBoxLayout;
|
||||
struct tagMSG;
|
||||
typedef struct tagMSG MSG;
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class Button;
|
||||
class EffectLabel;
|
||||
class TitleBarButton;
|
||||
enum class TitleBarButtonStyle;
|
||||
|
||||
class BaseWindow : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Flags {
|
||||
None = 0,
|
||||
EnableCustomFrame = 1,
|
||||
Frameless = 2,
|
||||
TopMost = 4,
|
||||
DisableCustomScaling = 8,
|
||||
FramelessDraggable = 16,
|
||||
};
|
||||
|
||||
enum ActionOnFocusLoss { Nothing, Delete, Close, Hide };
|
||||
|
||||
explicit BaseWindow(QWidget *parent = nullptr, Flags flags_ = None);
|
||||
|
||||
QWidget *getLayoutContainer();
|
||||
bool hasCustomWindowFrame();
|
||||
TitleBarButton *addTitleBarButton(const TitleBarButtonStyle &style,
|
||||
std::function<void()> onClicked);
|
||||
EffectLabel *addTitleBarLabel(std::function<void()> onClicked);
|
||||
|
||||
void setStayInScreenRect(bool value);
|
||||
bool getStayInScreenRect() const;
|
||||
|
||||
void setActionOnFocusLoss(ActionOnFocusLoss value);
|
||||
ActionOnFocusLoss getActionOnFocusLoss() const;
|
||||
|
||||
void moveTo(QWidget *widget, QPoint point, bool offset = true);
|
||||
|
||||
virtual float scale() const override;
|
||||
|
||||
Flags getFlags();
|
||||
|
||||
pajlada::Signals::NoArgSignal closing;
|
||||
|
||||
protected:
|
||||
virtual bool nativeEvent(const QByteArray &eventType, void *message,
|
||||
long *result) override;
|
||||
virtual void scaleChangedEvent(float) override;
|
||||
|
||||
virtual void paintEvent(QPaintEvent *) override;
|
||||
|
||||
virtual void changeEvent(QEvent *) override;
|
||||
virtual void leaveEvent(QEvent *) override;
|
||||
virtual void resizeEvent(QResizeEvent *) override;
|
||||
virtual void moveEvent(QMoveEvent *) override;
|
||||
virtual void closeEvent(QCloseEvent *) override;
|
||||
|
||||
virtual void themeChangedEvent() override;
|
||||
virtual bool event(QEvent *event) override;
|
||||
virtual void wheelEvent(QWheelEvent *event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
QPointF movingRelativePos;
|
||||
bool moving{};
|
||||
|
||||
void updateScale();
|
||||
|
||||
boost::optional<QColor> overrideBackgroundColor_;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void moveIntoDesktopRect(QWidget *parent);
|
||||
void calcButtonsSizes();
|
||||
void drawCustomWindowFrame(QPainter &painter);
|
||||
void onFocusLost();
|
||||
|
||||
bool handleDPICHANGED(MSG *msg);
|
||||
bool handleSHOWWINDOW(MSG *msg);
|
||||
bool handleNCCALCSIZE(MSG *msg, long *result);
|
||||
bool handleSIZE(MSG *msg);
|
||||
bool handleNCHITTEST(MSG *msg, long *result);
|
||||
|
||||
bool enableCustomFrame_;
|
||||
ActionOnFocusLoss actionOnFocusLoss_ = Nothing;
|
||||
bool frameless_;
|
||||
bool stayInScreenRect_ = false;
|
||||
bool shown_ = false;
|
||||
Flags flags_;
|
||||
float nativeScale_ = 1;
|
||||
|
||||
struct {
|
||||
QLayout *windowLayout = nullptr;
|
||||
QHBoxLayout *titlebarBox = nullptr;
|
||||
QWidget *titleLabel = nullptr;
|
||||
TitleBarButton *minButton = nullptr;
|
||||
TitleBarButton *maxButton = nullptr;
|
||||
TitleBarButton *exitButton = nullptr;
|
||||
QWidget *layoutBase = nullptr;
|
||||
std::vector<Button *> buttons;
|
||||
} ui_;
|
||||
|
||||
pajlada::Signals::SignalHolder connections_;
|
||||
std::vector<pajlada::Signals::ScopedConnection> managedConnections_;
|
||||
}; // namespace chatterino
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,138 +0,0 @@
|
||||
#include "Label.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
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();
|
||||
|
||||
this->connections_.managedConnect(app->fonts->fontChanged,
|
||||
[this] { this->updateSize(); });
|
||||
}
|
||||
|
||||
const QString &Label::getText() const
|
||||
{
|
||||
return this->text_;
|
||||
}
|
||||
|
||||
void Label::setText(const QString &text)
|
||||
{
|
||||
if (this->text_ != text)
|
||||
{
|
||||
this->text_ = text;
|
||||
this->updateSize();
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
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 scale)
|
||||
{
|
||||
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->scale() * 96.f / this->logicalDpiX() *
|
||||
this->devicePixelRatioF());
|
||||
painter.setFont(app->fonts->getFont(
|
||||
this->getFontStyle(), this->scale() * 96.f / this->logicalDpiX() *
|
||||
this->devicePixelRatioF()));
|
||||
|
||||
int offset = this->getOffset();
|
||||
|
||||
// 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);
|
||||
|
||||
#if 0
|
||||
painter.setPen(QColor(255, 0, 0));
|
||||
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Label::updateSize()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
QFontMetrics metrics =
|
||||
app->fonts->getFontMetrics(this->fontStyle_, this->scale());
|
||||
|
||||
int width = metrics.width(this->text_) + (2 * this->getOffset());
|
||||
int height = metrics.height();
|
||||
this->preferedSize_ = QSize(width, height);
|
||||
|
||||
this->updateGeometry();
|
||||
}
|
||||
|
||||
int Label::getOffset()
|
||||
{
|
||||
return this->hasOffset_ ? int(8 * this->scale()) : 0;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "singletons/Fonts.hpp"
|
||||
#include "widgets/BaseWidget.hpp"
|
||||
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
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 hasOffset);
|
||||
|
||||
protected:
|
||||
virtual void scaleChangedEvent(float scale_) override;
|
||||
virtual void paintEvent(QPaintEvent *) override;
|
||||
|
||||
virtual QSize sizeHint() const override;
|
||||
virtual QSize minimumSizeHint() const override;
|
||||
|
||||
private:
|
||||
void updateSize();
|
||||
int getOffset();
|
||||
|
||||
QString text_;
|
||||
FontStyle fontStyle_;
|
||||
QSize preferedSize_;
|
||||
bool centered_ = false;
|
||||
bool hasOffset_ = true;
|
||||
|
||||
pajlada::Signals::SignalHolder connections_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "widgets/dialogs/SettingsDialog.hpp"
|
||||
#include "widgets/helper/NotebookButton.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
#include "util/Shortcut.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#include "TooltipWidget.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "singletons/Fonts.hpp"
|
||||
#include "singletons/Theme.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDesktopWidget>
|
||||
#include <QStyle>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#ifdef USEWINSDK
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
TooltipWidget *TooltipWidget::getInstance()
|
||||
{
|
||||
static TooltipWidget *tooltipWidget = nullptr;
|
||||
if (tooltipWidget == nullptr)
|
||||
{
|
||||
tooltipWidget = new TooltipWidget();
|
||||
}
|
||||
return tooltipWidget;
|
||||
}
|
||||
|
||||
TooltipWidget::TooltipWidget(BaseWidget *parent)
|
||||
: BaseWindow(parent, BaseWindow::TopMost)
|
||||
, displayText_(new QLabel())
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->setStyleSheet("color: #fff; background: #000");
|
||||
this->setWindowOpacity(0.8);
|
||||
this->updateFont();
|
||||
this->setStayInScreenRect(true);
|
||||
|
||||
this->setAttribute(Qt::WA_ShowWithoutActivating);
|
||||
this->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint |
|
||||
Qt::X11BypassWindowManagerHint |
|
||||
Qt::BypassWindowManagerHint);
|
||||
|
||||
displayText_->setAlignment(Qt::AlignHCenter);
|
||||
displayText_->setText("tooltip text");
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(10, 5, 10, 5);
|
||||
layout->addWidget(displayText_);
|
||||
this->setLayout(layout);
|
||||
|
||||
this->fontChangedConnection_ =
|
||||
app->fonts->fontChanged.connect([this] { this->updateFont(); });
|
||||
}
|
||||
|
||||
TooltipWidget::~TooltipWidget()
|
||||
{
|
||||
this->fontChangedConnection_.disconnect();
|
||||
}
|
||||
|
||||
#ifdef USEWINSDK
|
||||
void TooltipWidget::raise()
|
||||
{
|
||||
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void TooltipWidget::themeChangedEvent()
|
||||
{
|
||||
this->setStyleSheet("color: #fff; background: #000");
|
||||
}
|
||||
|
||||
void TooltipWidget::scaleChangedEvent(float)
|
||||
{
|
||||
this->updateFont();
|
||||
}
|
||||
|
||||
void TooltipWidget::updateFont()
|
||||
{
|
||||
auto app = getApp();
|
||||
|
||||
this->setFont(
|
||||
app->fonts->getFont(FontStyle::ChatMediumSmall, this->scale()));
|
||||
}
|
||||
|
||||
void TooltipWidget::setText(QString text)
|
||||
{
|
||||
this->displayText_->setText(text);
|
||||
}
|
||||
|
||||
void TooltipWidget::setWordWrap(bool wrap)
|
||||
{
|
||||
this->displayText_->setWordWrap(wrap);
|
||||
}
|
||||
|
||||
void TooltipWidget::changeEvent(QEvent *)
|
||||
{
|
||||
// clear parents event
|
||||
}
|
||||
|
||||
void TooltipWidget::leaveEvent(QEvent *)
|
||||
{
|
||||
// clear parents event
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "widgets/BaseWindow.hpp"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QWidget>
|
||||
#include <pajlada/signals/signal.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
class TooltipWidget : public BaseWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static TooltipWidget *getInstance();
|
||||
|
||||
TooltipWidget(BaseWidget *parent = nullptr);
|
||||
virtual ~TooltipWidget() override;
|
||||
|
||||
void setText(QString text);
|
||||
void setWordWrap(bool wrap);
|
||||
|
||||
#ifdef USEWINSDK
|
||||
void raise();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *) override;
|
||||
void leaveEvent(QEvent *) override;
|
||||
void themeChangedEvent() override;
|
||||
void scaleChangedEvent(float) override;
|
||||
|
||||
private:
|
||||
void updateFont();
|
||||
|
||||
QLabel *displayText_;
|
||||
pajlada::Signals::Connection fontChangedConnection_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "widgets/dialogs/WelcomeDialog.hpp"
|
||||
#include "widgets/helper/EffectLabel.hpp"
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
#include "util/Shortcut.hpp"
|
||||
#include "widgets/helper/TitlebarButton.hpp"
|
||||
#include "widgets/splits/ClosedSplits.hpp"
|
||||
#include "widgets/splits/Split.hpp"
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QWidget>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
template <typename WidgetType, typename Func>
|
||||
inline void createShortcut(WidgetType *w, const char *key, Func func)
|
||||
{
|
||||
auto s = new QShortcut(QKeySequence(key), w);
|
||||
s->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, w, func);
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename Func>
|
||||
inline void createWindowShortcut(WidgetType *w, const char *key, Func func)
|
||||
{
|
||||
auto s = new QShortcut(QKeySequence(key), w);
|
||||
s->setContext(Qt::WindowShortcut);
|
||||
QObject::connect(s, &QShortcut::activated, w, func);
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "widgets/helper/NotebookTab.hpp"
|
||||
#include "widgets/helper/ResizingTextEdit.hpp"
|
||||
#include "widgets/helper/SearchPopup.hpp"
|
||||
#include "widgets/helper/Shortcut.hpp"
|
||||
#include "util/Shortcut.hpp"
|
||||
#include "widgets/splits/ClosedSplits.hpp"
|
||||
#include "widgets/splits/SplitContainer.hpp"
|
||||
#include "widgets/splits/SplitHeader.hpp"
|
||||
|
||||
Reference in New Issue
Block a user