diff --git a/chatterino.pro b/chatterino.pro index 31ed2b8c1..eabd8d396 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -178,21 +178,21 @@ win32 { } # Optional dependency on windows sdk 7.1 -#win32:exists(C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\Windows.h) { -# LIBS += -L"C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib" \ -# -ldwmapi \ -# -lgdi32 -# +win32:exists(C:\Program Files\Microsoft SDKs\Windows\v7.1\Include\Windows.h) { + LIBS += -L"C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib" \ + -ldwmapi \ + -lgdi32 + # SOURCES += platform/borderless/qwinwidget.cpp \ # platform/borderless/winnativewindow.cpp \ # platform/borderless/widget.cpp -# + # HEADERS += platform/borderless/qwinwidget.h \ # platform/borderless/winnativewindow.h \ # platform/borderless/widget.h -# -# DEFINES += "USEWINSDK" -#} + + DEFINES += "USEWINSDK" +} macx { INCLUDEPATH += /usr/local/include diff --git a/resources/qt.conf b/resources/qt.conf new file mode 100644 index 000000000..310dd86ab --- /dev/null +++ b/resources/qt.conf @@ -0,0 +1,2 @@ +[Platforms] +WindowArguments = dpiawareness=2 diff --git a/resources/resources.qrc b/resources/resources.qrc index e1e4f1a76..e09f97853 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -33,4 +33,7 @@ images/VSO_Link_blue_16x.png sounds/ping2.wav + + qt.conf + diff --git a/src/main.cpp b/src/main.cpp index 54f8a118f..d5dd70da4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,41 @@ #include "application.hpp" +#include #include #include +#include #include #include +#ifdef USEWINSDK +#include "windows.h" +#endif + namespace { +#ifdef USEWINSDK +class DpiNativeEventFilter : public QAbstractNativeEventFilter +{ +public: + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override + { + MSG *msg = reinterpret_cast(message); + + if (msg->message == WM_NCCREATE) { + typedef BOOL(WINAPI * EnableNonClientDpiScaling)(HWND); + QLibrary user32("user32.dll", NULL); + + EnableNonClientDpiScaling enableNonClientDpiScaling = + (EnableNonClientDpiScaling)user32.resolve("EnableNonClientDpiScaling"); + + if (enableNonClientDpiScaling) + enableNonClientDpiScaling(msg->hwnd); + } + return false; + } +}; +#endif + inline bool initSettings(bool portable) { QString settingsPath; @@ -38,6 +67,10 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); +#ifdef USEWINSDK + a.installNativeEventFilter(new DpiNativeEventFilter); +#endif + a.setAttribute(Qt::AA_EnableHighDpiScaling, true); // Options diff --git a/src/widgets/channelview.cpp b/src/widgets/channelview.cpp index 8e9f4f58c..1594f76c9 100644 --- a/src/widgets/channelview.cpp +++ b/src/widgets/channelview.cpp @@ -42,13 +42,24 @@ ChannelView::ChannelView(WindowManager &windowManager, BaseWidget *parent) this->scrollBar.getCurrentValueChanged().connect([this] { // Whenever the scrollbar value has been changed, re-render the ChatWidgetView - this->update(); - this->layoutMessages(); + + this->goToBottom->setVisible(this->scrollBar.isVisible() && !this->scrollBar.isAtBottom()); + + this->update(); }); this->repaintGifsConnection = windowManager.repaintGifs.connect([&] { this->updateGifEmotes(); }); + this->layoutConnection = windowManager.repaintGifs.connect([&] { this->layout(); }); + + this->goToBottom = new RippleEffectLabel(this, 0); + this->goToBottom->setStyleSheet("background-color: rgba(0,0,0,0.5); color: #FFF;"); + this->goToBottom->getLabel().setText("Jump to bottom"); + this->goToBottom->setVisible(false); + + connect(goToBottom, &RippleEffectLabel::clicked, this, + [this] { QTimer::singleShot(180, [this] { this->scrollBar.scrollToBottom(); }); }); } ChannelView::~ChannelView() @@ -340,6 +351,10 @@ void ChannelView::resizeEvent(QResizeEvent *) this->scrollBar.resize(this->scrollBar.width(), height()); this->scrollBar.move(width() - this->scrollBar.width(), 0); + this->goToBottom->setGeometry(0, this->height() - 32, this->width(), 32); + + this->scrollBar.raise(); + layoutMessages(); this->update(); diff --git a/src/widgets/channelview.hpp b/src/widgets/channelview.hpp index c472dc1bf..d232b5813 100644 --- a/src/widgets/channelview.hpp +++ b/src/widgets/channelview.hpp @@ -7,6 +7,7 @@ #include "messages/word.hpp" #include "widgets/accountpopup.hpp" #include "widgets/basewidget.hpp" +#include "widgets/rippleeffectlabel.hpp" #include "widgets/scrollbar.hpp" #include @@ -135,6 +136,7 @@ private: std::vector gifEmotes; ScrollBar scrollBar; + RippleEffectLabel *goToBottom; // This variable can be used to decide whether or not we should render the "Show latest // messages" button @@ -155,6 +157,7 @@ private: boost::signals2::connection messageAppendedConnection; boost::signals2::connection messageRemovedConnection; boost::signals2::connection repaintGifsConnection; + boost::signals2::connection layoutConnection; private slots: void wordTypeMaskChanged() diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index b468520d5..674478b6f 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -9,6 +9,7 @@ #include "widgets/channelview.hpp" #include "widgets/chatwidgetheader.hpp" #include "widgets/chatwidgetinput.hpp" +#include "widgets/rippleeffectlabel.hpp" #include #include diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index 7a3380101..9107b0c44 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -7,13 +7,14 @@ #include "widgets/settingsdialog.hpp" #include +#include #include #include #include #include #ifdef USEWINSDK -#include "Windows.hpp" +#include "windows.h" #endif namespace chatterino { @@ -70,24 +71,18 @@ MainWindow::~MainWindow() { } -void MainWindow::layoutVisibleChatWidgets(Channel *channel) +#ifdef USEWINSDK +bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { - auto *page = this->notebook.getSelectedPage(); + MSG *msg = reinterpret_cast(message); - if (page == nullptr) { - return; + if (msg->message == 0x02E0) { + qDebug() << "dpi changed"; } - const std::vector &widgets = page->getChatWidgets(); - - for (auto it = widgets.begin(); it != widgets.end(); ++it) { - ChatWidget *widget = *it; - - if (channel == nullptr || channel == widget->getChannel().get()) { - widget->layoutMessages(); - } - } + return QWidget::nativeEvent(eventType, message, result); } +#endif void MainWindow::repaintVisibleChatWidgets(Channel *channel) { diff --git a/src/widgets/mainwindow.hpp b/src/widgets/mainwindow.hpp index 758fc7898..6e96a0ea4 100644 --- a/src/widgets/mainwindow.hpp +++ b/src/widgets/mainwindow.hpp @@ -4,9 +4,9 @@ #include "widgets/notebook.hpp" #include "widgets/titlebar.hpp" -#ifdef USEWINSDK -#include -#endif +//#ifdef USEWINSDK +//#include +//#endif #include #include @@ -30,7 +30,6 @@ public: CompletionManager &_completionManager); ~MainWindow(); - void layoutVisibleChatWidgets(Channel *channel = nullptr); void repaintVisibleChatWidgets(Channel *channel = nullptr); void load(const boost::property_tree::ptree &tree); @@ -43,6 +42,9 @@ public: protected: virtual void closeEvent(QCloseEvent *event) override; +#ifdef USEWINSDK + virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; +#endif private: virtual void refreshTheme() override; diff --git a/src/widgets/notebookbutton.cpp b/src/widgets/notebookbutton.cpp index 875ba9cfb..3b355e461 100644 --- a/src/widgets/notebookbutton.cpp +++ b/src/widgets/notebookbutton.cpp @@ -11,7 +11,7 @@ namespace chatterino { namespace widgets { NotebookButton::NotebookButton(BaseWidget *parent) - : FancyButton(parent) + : RippleEffectButton(parent) { setMouseEffectColor(QColor(0, 0, 0)); } @@ -99,7 +99,7 @@ void NotebookButton::mouseReleaseEvent(QMouseEvent *event) emit clicked(); } - FancyButton::mouseReleaseEvent(event); + RippleEffectButton::mouseReleaseEvent(event); } } // namespace widgets diff --git a/src/widgets/notebookbutton.hpp b/src/widgets/notebookbutton.hpp index 769dadd8c..811c21667 100644 --- a/src/widgets/notebookbutton.hpp +++ b/src/widgets/notebookbutton.hpp @@ -7,7 +7,7 @@ namespace chatterino { namespace widgets { -class NotebookButton : public FancyButton +class NotebookButton : public RippleEffectButton { Q_OBJECT diff --git a/src/widgets/rippleeffectbutton.cpp b/src/widgets/rippleeffectbutton.cpp index 53d338921..93d84e862 100644 --- a/src/widgets/rippleeffectbutton.cpp +++ b/src/widgets/rippleeffectbutton.cpp @@ -6,29 +6,29 @@ namespace chatterino { namespace widgets { -FancyButton::FancyButton(BaseWidget *parent) +RippleEffectButton::RippleEffectButton(BaseWidget *parent) : BaseWidget(parent) { - connect(&effectTimer, &QTimer::timeout, this, &FancyButton::onMouseEffectTimeout); + connect(&effectTimer, &QTimer::timeout, this, &RippleEffectButton::onMouseEffectTimeout); this->effectTimer.setInterval(20); this->effectTimer.start(); } -void FancyButton::setMouseEffectColor(QColor color) +void RippleEffectButton::setMouseEffectColor(QColor color) { this->mouseEffectColor = color; } -void FancyButton::paintEvent(QPaintEvent *) +void RippleEffectButton::paintEvent(QPaintEvent *) { QPainter painter(this); this->fancyPaint(painter); } -void FancyButton::fancyPaint(QPainter &painter) +void RippleEffectButton::fancyPaint(QPainter &painter) { QColor &c = this->mouseEffectColor; @@ -58,17 +58,17 @@ void FancyButton::fancyPaint(QPainter &painter) } } -void FancyButton::enterEvent(QEvent *) +void RippleEffectButton::enterEvent(QEvent *) { this->mouseOver = true; } -void FancyButton::leaveEvent(QEvent *) +void RippleEffectButton::leaveEvent(QEvent *) { this->mouseOver = false; } -void FancyButton::mousePressEvent(QMouseEvent *event) +void RippleEffectButton::mousePressEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) { return; @@ -79,7 +79,7 @@ void FancyButton::mousePressEvent(QMouseEvent *event) this->mouseDown = true; } -void FancyButton::mouseReleaseEvent(QMouseEvent *event) +void RippleEffectButton::mouseReleaseEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) { return; @@ -92,12 +92,12 @@ void FancyButton::mouseReleaseEvent(QMouseEvent *event) } } -void FancyButton::mouseMoveEvent(QMouseEvent *event) +void RippleEffectButton::mouseMoveEvent(QMouseEvent *event) { this->mousePos = event->pos(); } -void FancyButton::onMouseEffectTimeout() +void RippleEffectButton::onMouseEffectTimeout() { bool performUpdate = false; diff --git a/src/widgets/rippleeffectbutton.hpp b/src/widgets/rippleeffectbutton.hpp index c61a9cac7..2ce38f9b0 100644 --- a/src/widgets/rippleeffectbutton.hpp +++ b/src/widgets/rippleeffectbutton.hpp @@ -11,7 +11,7 @@ namespace chatterino { namespace widgets { -class FancyButton : public BaseWidget +class RippleEffectButton : public BaseWidget { Q_OBJECT @@ -26,7 +26,7 @@ class FancyButton : public BaseWidget }; public: - FancyButton(BaseWidget *parent); + RippleEffectButton(BaseWidget *parent); void setMouseEffectColor(QColor color); diff --git a/src/widgets/rippleeffectlabel.cpp b/src/widgets/rippleeffectlabel.cpp index 2addd2973..5e64f03e0 100644 --- a/src/widgets/rippleeffectlabel.cpp +++ b/src/widgets/rippleeffectlabel.cpp @@ -9,7 +9,7 @@ namespace chatterino { namespace widgets { RippleEffectLabel::RippleEffectLabel(BaseWidget *parent, int spacing) - : FancyButton(parent) + : RippleEffectButton(parent) { setLayout(&this->ui.hbox); diff --git a/src/widgets/rippleeffectlabel.hpp b/src/widgets/rippleeffectlabel.hpp index 88175f142..bafd21ac1 100644 --- a/src/widgets/rippleeffectlabel.hpp +++ b/src/widgets/rippleeffectlabel.hpp @@ -15,7 +15,7 @@ class ColorScheme; namespace widgets { -class RippleEffectLabel : public FancyButton +class RippleEffectLabel : public RippleEffectButton { public: explicit RippleEffectLabel(BaseWidget *parent, int spacing = 6); diff --git a/src/widgets/settingsdialog.cpp b/src/widgets/settingsdialog.cpp index 90d861033..d9939622e 100644 --- a/src/widgets/settingsdialog.cpp +++ b/src/widgets/settingsdialog.cpp @@ -301,9 +301,11 @@ void SettingsDialog::addTabs() auto form = new QFormLayout(); form->addRow("Window:", createCheckbox("Window always on top", settings.windowTopMost)); - form->addRow("Messages:", createCheckbox("Mention users with a @ (except in commands)", - settings.mentionUsersWithAt)); - form->addRow("", createCheckbox("Hide input box if empty", settings.hideEmptyInput)); + // form->addRow("Messages:", createCheckbox("Mention users with a @ (except in + // commands)", + // settings.mentionUsersWithAt)); + form->addRow("Messages:", + createCheckbox("Hide input box if empty", settings.hideEmptyInput)); form->addRow("", createCheckbox("Show last read message indicator", settings.showLastMessageIndicator)); diff --git a/src/windowmanager.cpp b/src/windowmanager.cpp index f71c5ca7f..3792a42d4 100644 --- a/src/windowmanager.cpp +++ b/src/windowmanager.cpp @@ -27,9 +27,7 @@ static const std::string &getSettingsPath() void WindowManager::layoutVisibleChatWidgets(Channel *channel) { - if (this->mainWindow != nullptr) { - this->mainWindow->layoutVisibleChatWidgets(channel); - } + this->layout(); } void WindowManager::repaintVisibleChatWidgets(Channel *channel) diff --git a/src/windowmanager.hpp b/src/windowmanager.hpp index c5f1231d3..441e7b319 100644 --- a/src/windowmanager.hpp +++ b/src/windowmanager.hpp @@ -31,6 +31,7 @@ public: void save(); boost::signals2::signal repaintGifs; + boost::signals2::signal layout; private: std::mutex windowMutex;