mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
6ea3a1df08
cstdint) Make MessageElement to a class to fit better with the derived classes. Make MessageLayoutElement to a class to fit better with the derived classes. Remove virtual from override functions Replace all instances of boost::signals2 with pajlada::Signals. This lets us properly use clang code model to check for issues. Add missing virtual destructor to AbstractIrcServer Add missing virtual destructor to MessageLayoutElement Remove unused "connectedConnection" connection in TwitchChannel Fix typo in TrimChannelName function Fix typo in MessageParseArgs Replace some raw pointers with unique pointers where it made more sense. This allowed us to remove some manually written destructors whose only purpose was to delete that raw pointer. Reformat: Add namespace comments Reformat: Add empty empty lines between main namespace beginning and end Reformat: Re-order includes Reformat: Fix some includes that used quotes where they should use angle brackets Reformat: Replace some typedef's with using's Filter out more useless warnings
428 lines
14 KiB
C++
428 lines
14 KiB
C++
#include "basewindow.hpp"
|
|
|
|
#include "debug/log.hpp"
|
|
#include "singletons/settingsmanager.hpp"
|
|
#include "util/nativeeventhelper.hpp"
|
|
#include "widgets/helper/rippleeffectlabel.hpp"
|
|
#include "widgets/tooltipwidget.hpp"
|
|
|
|
#include <QApplication>
|
|
#include <QDebug>
|
|
#include <QDesktopWidget>
|
|
#include <QIcon>
|
|
|
|
#ifdef USEWINSDK
|
|
#include <ObjIdl.h>
|
|
#include <Windows.h>
|
|
#include <dwmapi.h>
|
|
#include <gdiplus.h>
|
|
#include <windowsx.h>
|
|
#pragma comment(lib, "Dwmapi.lib")
|
|
|
|
#include <QHBoxLayout>
|
|
#include <QVBoxLayout>
|
|
|
|
#define WM_DPICHANGED 0x02E0
|
|
#endif
|
|
|
|
#include "widgets/helper/titlebarbutton.hpp"
|
|
|
|
namespace chatterino {
|
|
namespace widgets {
|
|
|
|
BaseWindow::BaseWindow(singletons::ThemeManager &_themeManager, QWidget *parent,
|
|
bool _enableCustomFrame)
|
|
: BaseWidget(_themeManager, parent, Qt::Window)
|
|
, enableCustomFrame(_enableCustomFrame)
|
|
{
|
|
this->init();
|
|
}
|
|
|
|
BaseWindow::BaseWindow(BaseWidget *parent, bool _enableCustomFrame)
|
|
: BaseWidget(parent, Qt::Window)
|
|
, enableCustomFrame(_enableCustomFrame)
|
|
{
|
|
this->init();
|
|
}
|
|
|
|
BaseWindow::BaseWindow(QWidget *parent, bool _enableCustomFrame)
|
|
: BaseWidget(singletons::ThemeManager::getInstance(), parent, Qt::Window)
|
|
, enableCustomFrame(_enableCustomFrame)
|
|
{
|
|
this->init();
|
|
}
|
|
|
|
void BaseWindow::init()
|
|
{
|
|
this->setWindowIcon(QIcon(":/images/icon.png"));
|
|
|
|
#ifdef USEWINSDK
|
|
if (this->hasCustomWindowFrame()) {
|
|
// CUSTOM WINDOW FRAME
|
|
QVBoxLayout *layout = new QVBoxLayout();
|
|
layout->setMargin(1);
|
|
layout->setSpacing(0);
|
|
this->setLayout(layout);
|
|
{
|
|
QHBoxLayout *buttonLayout = this->titlebarBox = new QHBoxLayout();
|
|
buttonLayout->setMargin(0);
|
|
layout->addLayout(buttonLayout);
|
|
|
|
// title
|
|
QLabel *title = new QLabel(" Chatterino");
|
|
buttonLayout->addWidget(title);
|
|
this->titleLabel = title;
|
|
|
|
// buttons
|
|
TitleBarButton *_minButton = new TitleBarButton;
|
|
_minButton->setScaleIndependantSize(46, 30);
|
|
_minButton->setButtonStyle(TitleBarButton::Minimize);
|
|
TitleBarButton *_maxButton = new TitleBarButton;
|
|
_maxButton->setScaleIndependantSize(46, 30);
|
|
_maxButton->setButtonStyle(TitleBarButton::Maximize);
|
|
TitleBarButton *_exitButton = new TitleBarButton;
|
|
_exitButton->setScaleIndependantSize(46, 30);
|
|
_exitButton->setButtonStyle(TitleBarButton::Close);
|
|
|
|
QObject::connect(_minButton, &TitleBarButton::clicked, this, [this] {
|
|
this->setWindowState(Qt::WindowMinimized | this->windowState());
|
|
});
|
|
QObject::connect(_maxButton, &TitleBarButton::clicked, this, [this] {
|
|
this->setWindowState(this->windowState() == Qt::WindowMaximized
|
|
? Qt::WindowActive
|
|
: Qt::WindowMaximized);
|
|
});
|
|
QObject::connect(_exitButton, &TitleBarButton::clicked, this,
|
|
[this] { this->close(); });
|
|
|
|
this->minButton = _minButton;
|
|
this->maxButton = _maxButton;
|
|
this->exitButton = _exitButton;
|
|
|
|
this->buttons.push_back(_minButton);
|
|
this->buttons.push_back(_maxButton);
|
|
this->buttons.push_back(_exitButton);
|
|
|
|
buttonLayout->addStretch(1);
|
|
buttonLayout->addWidget(_minButton);
|
|
buttonLayout->addWidget(_maxButton);
|
|
buttonLayout->addWidget(_exitButton);
|
|
buttonLayout->setSpacing(0);
|
|
}
|
|
this->layoutBase = new BaseWidget(this);
|
|
layout->addWidget(this->layoutBase);
|
|
}
|
|
|
|
// DPI
|
|
auto dpi = util::getWindowDpi(this->winId());
|
|
|
|
if (dpi) {
|
|
this->scale = dpi.value() / 96.f;
|
|
}
|
|
|
|
this->scaleChangedEvent(this->scale);
|
|
#endif
|
|
|
|
if (singletons::SettingManager::getInstance().windowTopMost.getValue()) {
|
|
this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint);
|
|
}
|
|
}
|
|
|
|
void BaseWindow::setStayInScreenRect(bool value)
|
|
{
|
|
this->stayInScreenRect = value;
|
|
}
|
|
|
|
bool BaseWindow::getStayInScreenRect() const
|
|
{
|
|
return this->stayInScreenRect;
|
|
}
|
|
|
|
QWidget *BaseWindow::getLayoutContainer()
|
|
{
|
|
if (this->hasCustomWindowFrame()) {
|
|
return this->layoutBase;
|
|
} else {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
bool BaseWindow::hasCustomWindowFrame()
|
|
{
|
|
#ifdef USEWINSDK
|
|
return this->enableCustomFrame;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void BaseWindow::themeRefreshEvent()
|
|
{
|
|
if (this->enableCustomFrame) {
|
|
QPalette palette;
|
|
palette.setColor(QPalette::Background, this->themeManager.windowBg);
|
|
palette.setColor(QPalette::Foreground, this->themeManager.windowText);
|
|
this->setPalette(palette);
|
|
|
|
for (RippleEffectButton *button : this->buttons) {
|
|
button->setMouseEffectColor(this->themeManager.windowText);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseWindow::addTitleBarButton(const TitleBarButton::Style &style,
|
|
std::function<void()> onClicked)
|
|
{
|
|
TitleBarButton *button = new TitleBarButton;
|
|
button->setScaleIndependantSize(30, 30);
|
|
|
|
this->buttons.push_back(button);
|
|
this->titlebarBox->insertWidget(2, button);
|
|
button->setButtonStyle(style);
|
|
|
|
QObject::connect(button, &TitleBarButton::clicked, this, [onClicked] { onClicked(); });
|
|
}
|
|
|
|
RippleEffectLabel *BaseWindow::addTitleBarLabel(std::function<void()> onClicked)
|
|
{
|
|
RippleEffectLabel *button = new RippleEffectLabel;
|
|
button->setScaleIndependantHeight(30);
|
|
|
|
this->buttons.push_back(button);
|
|
this->titlebarBox->insertWidget(2, button);
|
|
|
|
QObject::connect(button, &RippleEffectLabel::clicked, this, [onClicked] { onClicked(); });
|
|
|
|
return button;
|
|
}
|
|
|
|
void BaseWindow::changeEvent(QEvent *)
|
|
{
|
|
TooltipWidget::getInstance()->hide();
|
|
|
|
#ifdef USEWINSDK
|
|
if (this->hasCustomWindowFrame()) {
|
|
this->maxButton->setButtonStyle(this->windowState() & Qt::WindowMaximized
|
|
? TitleBarButton::Unmaximize
|
|
: TitleBarButton::Maximize);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void BaseWindow::leaveEvent(QEvent *)
|
|
{
|
|
TooltipWidget::getInstance()->hide();
|
|
}
|
|
|
|
void BaseWindow::moveTo(QWidget *parent, QPoint point)
|
|
{
|
|
point.rx() += 16;
|
|
point.ry() += 16;
|
|
|
|
this->move(point);
|
|
this->moveIntoDesktopRect(parent);
|
|
}
|
|
|
|
void BaseWindow::resizeEvent(QResizeEvent *)
|
|
{
|
|
this->moveIntoDesktopRect(this);
|
|
}
|
|
|
|
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->screenGeometry(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);
|
|
}
|
|
|
|
#ifdef USEWINSDK
|
|
bool BaseWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
|
|
{
|
|
MSG *msg = reinterpret_cast<MSG *>(message);
|
|
|
|
switch (msg->message) {
|
|
case WM_DPICHANGED: {
|
|
int dpi = HIWORD(msg->wParam);
|
|
|
|
float oldScale = this->scale;
|
|
float _scale = dpi / 96.f;
|
|
float resizeScale = _scale / oldScale;
|
|
|
|
this->resize(static_cast<int>(this->width() * resizeScale),
|
|
static_cast<int>(this->height() * resizeScale));
|
|
|
|
this->setScale(_scale);
|
|
|
|
return true;
|
|
}
|
|
case WM_NCCALCSIZE: {
|
|
if (this->hasCustomWindowFrame()) {
|
|
// this kills the window frame and title bar we added with
|
|
// WS_THICKFRAME and WS_CAPTION
|
|
*result = 0;
|
|
return true;
|
|
} else {
|
|
return QWidget::nativeEvent(eventType, message, result);
|
|
}
|
|
break;
|
|
}
|
|
case WM_NCHITTEST: {
|
|
if (this->hasCustomWindowFrame()) {
|
|
*result = 0;
|
|
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);
|
|
|
|
bool resizeWidth = minimumWidth() != maximumWidth();
|
|
bool resizeHeight = minimumHeight() != maximumHeight();
|
|
|
|
if (resizeWidth) {
|
|
// left border
|
|
if (x >= winrect.left && x < winrect.left + border_width) {
|
|
*result = HTLEFT;
|
|
}
|
|
// right border
|
|
if (x < winrect.right && x >= winrect.right - border_width) {
|
|
*result = HTRIGHT;
|
|
}
|
|
}
|
|
if (resizeHeight) {
|
|
// bottom border
|
|
if (y < winrect.bottom && y >= winrect.bottom - border_width) {
|
|
*result = HTBOTTOM;
|
|
}
|
|
// top border
|
|
if (y >= winrect.top && 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;
|
|
|
|
QPoint point(x - winrect.left, y - winrect.top);
|
|
for (QWidget *widget : this->buttons) {
|
|
if (widget->geometry().contains(point)) {
|
|
client = true;
|
|
}
|
|
}
|
|
|
|
if (this->layoutBase->geometry().contains(point)) {
|
|
client = true;
|
|
}
|
|
|
|
if (client) {
|
|
*result = HTCLIENT;
|
|
} else {
|
|
*result = HTCAPTION;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return QWidget::nativeEvent(eventType, message, result);
|
|
}
|
|
break;
|
|
} // end case WM_NCHITTEST
|
|
case WM_CLOSE: {
|
|
// if (this->enableCustomFrame) {
|
|
// this->close();
|
|
// }
|
|
return QWidget::nativeEvent(eventType, message, result);
|
|
break;
|
|
}
|
|
default:
|
|
return QWidget::nativeEvent(eventType, message, result);
|
|
}
|
|
}
|
|
|
|
void BaseWindow::showEvent(QShowEvent *event)
|
|
{
|
|
if (!this->shown && this->isVisible() && this->hasCustomWindowFrame()) {
|
|
this->shown = true;
|
|
SetWindowLongPtr((HWND)this->winId(), GWL_STYLE,
|
|
WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
|
|
|
|
const MARGINS shadow = {1, 1, 1, 1};
|
|
DwmExtendFrameIntoClientArea((HWND)this->winId(), &shadow);
|
|
|
|
SetWindowPos((HWND)this->winId(), 0, 0, 0, 0, 0,
|
|
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
|
|
BaseWidget::showEvent(event);
|
|
}
|
|
|
|
void BaseWindow::paintEvent(QPaintEvent *event)
|
|
{
|
|
if (this->hasCustomWindowFrame()) {
|
|
BaseWidget::paintEvent(event);
|
|
|
|
QPainter painter(this);
|
|
|
|
bool windowFocused = this->window() == QApplication::activeWindow();
|
|
|
|
QLinearGradient gradient(0, 0, 10, 250);
|
|
gradient.setColorAt(1, this->themeManager.tabs.selected.backgrounds.unfocused.color());
|
|
|
|
if (windowFocused) {
|
|
gradient.setColorAt(.4, this->themeManager.tabs.selected.backgrounds.regular.color());
|
|
} else {
|
|
gradient.setColorAt(.4, this->themeManager.tabs.selected.backgrounds.unfocused.color());
|
|
}
|
|
painter.setPen(QPen(QBrush(gradient), 1));
|
|
|
|
painter.drawRect(0, 0, this->width() - 1, this->height() - 1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} // namespace widgets
|
|
} // namespace chatterino
|