diff --git a/chatterino.pro b/chatterino.pro index bf3578cb0..6800fb8a2 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -194,7 +194,8 @@ SOURCES += \ src/widgets/helper/editablemodelview.cpp \ src/controllers/accounts/accountcontroller.cpp \ src/controllers/accounts/accountmodel.cpp \ - src/controllers/accounts/account.cpp + src/controllers/accounts/account.cpp \ + src/widgets/helper/splitoverlay.cpp HEADERS += \ src/precompiled_header.hpp \ @@ -336,7 +337,8 @@ HEADERS += \ src/controllers/accounts/accountcontroller.hpp \ src/controllers/accounts/accountmodel.hpp \ src/controllers/accounts/account.hpp \ - src/util/sharedptrelementless.hpp + src/util/sharedptrelementless.hpp \ + src/widgets/helper/splitoverlay.hpp RESOURCES += \ resources/resources.qrc diff --git a/resources/images/split/splitdown.png b/resources/images/split/splitdown.png new file mode 100644 index 000000000..3891ca398 Binary files /dev/null and b/resources/images/split/splitdown.png differ diff --git a/resources/images/split/splitleft.png b/resources/images/split/splitleft.png new file mode 100644 index 000000000..8d1cb0e19 Binary files /dev/null and b/resources/images/split/splitleft.png differ diff --git a/resources/images/split/splitmove.png b/resources/images/split/splitmove.png new file mode 100644 index 000000000..82bf5382b Binary files /dev/null and b/resources/images/split/splitmove.png differ diff --git a/resources/images/split/splitright.png b/resources/images/split/splitright.png new file mode 100644 index 000000000..173537331 Binary files /dev/null and b/resources/images/split/splitright.png differ diff --git a/resources/images/split/splitup.png b/resources/images/split/splitup.png new file mode 100644 index 000000000..a9cc0f30e Binary files /dev/null and b/resources/images/split/splitup.png differ diff --git a/resources/resources.qrc b/resources/resources.qrc index cb535c604..aa3b77573 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -46,6 +46,11 @@ images/about.svg images/moderatormode_disabled.png images/moderatormode_enabled.png + images/split/splitdown.png + images/split/splitleft.png + images/split/splitright.png + images/split/splitup.png + images/split/splitmove.png qt.conf diff --git a/src/singletons/resourcemanager.cpp b/src/singletons/resourcemanager.cpp index 274b8ee86..b989261c7 100644 --- a/src/singletons/resourcemanager.cpp +++ b/src/singletons/resourcemanager.cpp @@ -1,6 +1,7 @@ #include "resourcemanager.hpp" #include "util/urlfetch.hpp" +#include #include namespace chatterino { @@ -288,6 +289,11 @@ ResourceManager::ResourceManager() , buttonBan(lli(":/images/button_ban.png", 0.25)) , buttonTimeout(lli(":/images/button_timeout.png", 0.25)) { + this->split.left = QIcon(":/images/split/splitleft.png"); + this->split.right = QIcon(":/images/split/splitright.png"); + this->split.up = QIcon(":/images/split/splitup.png"); + this->split.down = QIcon(":/images/split/splitdown.png"); + this->split.move = QIcon(":/images/split/splitmove.png"); qDebug() << "init ResourceManager"; } diff --git a/src/singletons/resourcemanager.hpp b/src/singletons/resourcemanager.hpp index 17bb7f18a..2da506583 100644 --- a/src/singletons/resourcemanager.hpp +++ b/src/singletons/resourcemanager.hpp @@ -20,6 +20,14 @@ public: void initialize(); + struct { + QIcon left; + QIcon right; + QIcon up; + QIcon down; + QIcon move; + } split; + messages::Image *badgeStaff; messages::Image *badgeAdmin; messages::Image *badgeGlobalModerator; diff --git a/src/widgets/basewidget.cpp b/src/widgets/basewidget.cpp index 74b548286..4dcc1a6d3 100644 --- a/src/widgets/basewidget.cpp +++ b/src/widgets/basewidget.cpp @@ -111,7 +111,7 @@ void BaseWidget::childEvent(QChildEvent *event) void BaseWidget::showEvent(QShowEvent *) { - this->scaleChangedEvent(this->getScale()); + this->setScale(this->getScale()); this->themeRefreshEvent(); } diff --git a/src/widgets/helper/splitoverlay.cpp b/src/widgets/helper/splitoverlay.cpp new file mode 100644 index 000000000..45758b3af --- /dev/null +++ b/src/widgets/helper/splitoverlay.cpp @@ -0,0 +1,152 @@ +#include "splitoverlay.hpp" + +#include +#include +#include +#include +#include + +#include "application.hpp" +#include "singletons/resourcemanager.hpp" +#include "widgets/split.hpp" + +namespace chatterino { +namespace widgets { + +SplitOverlay::SplitOverlay(Split *parent) + : BaseWidget(parent) + , split(parent) +{ + QGridLayout *layout = new QGridLayout(this); + layout->setMargin(1); + layout->setSpacing(1); + + layout->setRowStretch(1, 1); + layout->setRowStretch(3, 1); + layout->setColumnStretch(1, 1); + layout->setColumnStretch(3, 1); + + QPushButton *move = new QPushButton(getApp()->resources->split.move, QString()); + QPushButton *left = new QPushButton(getApp()->resources->split.left, QString()); + QPushButton *right = new QPushButton(getApp()->resources->split.right, QString()); + QPushButton *up = new QPushButton(getApp()->resources->split.up, QString()); + QPushButton *down = new QPushButton(getApp()->resources->split.down, QString()); + + move->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + left->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + right->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + up->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + down->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + + move->setFlat(true); + left->setFlat(true); + right->setFlat(true); + up->setFlat(true); + down->setFlat(true); + + layout->addWidget(move, 2, 2); + layout->addWidget(left, 2, 0); + layout->addWidget(right, 2, 4); + layout->addWidget(up, 0, 2); + layout->addWidget(down, 4, 2); + + move->installEventFilter(new ButtonEventFilter(this, SplitMove)); + left->installEventFilter(new ButtonEventFilter(this, SplitLeft)); + right->installEventFilter(new ButtonEventFilter(this, SplitRight)); + up->installEventFilter(new ButtonEventFilter(this, SplitUp)); + down->installEventFilter(new ButtonEventFilter(this, SplitDown)); + + move->setFocusPolicy(Qt::NoFocus); + left->setFocusPolicy(Qt::NoFocus); + right->setFocusPolicy(Qt::NoFocus); + up->setFocusPolicy(Qt::NoFocus); + down->setFocusPolicy(Qt::NoFocus); + + move->setCursor(Qt::SizeAllCursor); + + this->managedConnect(this->scaleChanged, [=](float scale) { + int a = scale * 40; + QSize size(a, a); + + move->setIconSize(size); + left->setIconSize(size); + right->setIconSize(size); + up->setIconSize(size); + down->setIconSize(size); + }); +} + +void SplitOverlay::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.fillRect(this->rect(), QColor(0, 0, 0, 90)); + + QRect rect; + switch (this->hoveredElement) { + case SplitLeft: { + rect = QRect(0, 0, this->width() / 2, this->height()); + } break; + case SplitRight: { + rect = QRect(this->width() / 2, 0, this->width() / 2, this->height()); + } break; + case SplitUp: { + rect = QRect(0, 0, this->width(), this->height() / 2); + } break; + case SplitDown: { + rect = QRect(0, this->height() / 2, this->width(), this->height() / 2); + } break; + } + if (!rect.isNull()) { + painter.setPen(QColor(0, 148, 255, 0x70)); + painter.setBrush(QColor(0, 148, 255, 0x30)); + painter.drawRect(rect); + } +} + +SplitOverlay::ButtonEventFilter::ButtonEventFilter(SplitOverlay *_parent, HoveredElement _element) + : QObject(_parent) + , parent(_parent) + , hoveredElement(_element) +{ +} + +bool SplitOverlay::ButtonEventFilter::eventFilter(QObject *watched, QEvent *event) +{ + switch (event->type()) { + case QEvent::Enter: { + QGraphicsOpacityEffect *effect = + dynamic_cast(((QWidget *)watched)->graphicsEffect()); + + if (effect != nullptr) { + effect->setOpacity(1); + } + + this->parent->hoveredElement = this->hoveredElement; + this->parent->update(); + } break; + case QEvent::Leave: { + QGraphicsOpacityEffect *effect = + dynamic_cast(((QWidget *)watched)->graphicsEffect()); + + if (effect != nullptr) { + effect->setOpacity(0.7); + } + + this->parent->hoveredElement = HoveredElement::None; + this->parent->update(); + } break; + case QEvent::MouseButtonPress: { + if (this->hoveredElement == HoveredElement::SplitMove) { + QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::LeftButton) { + this->parent->split->drag(); + } + return true; + } + } break; + } + return QObject::eventFilter(watched, event); +} + +} // namespace widgets +} // namespace chatterino diff --git a/src/widgets/helper/splitoverlay.hpp b/src/widgets/helper/splitoverlay.hpp new file mode 100644 index 000000000..31b7a4b42 --- /dev/null +++ b/src/widgets/helper/splitoverlay.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "pajlada/signals/signalholder.hpp" +#include "widgets/basewidget.hpp" + +namespace chatterino { +namespace widgets { + +class Split; + +class SplitOverlay : public BaseWidget, pajlada::Signals::SignalHolder +{ +public: + explicit SplitOverlay(Split *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + enum HoveredElement { None, SplitMove, SplitLeft, SplitRight, SplitUp, SplitDown }; + HoveredElement hoveredElement = None; + Split *split; + + class ButtonEventFilter : public QObject + { + HoveredElement hoveredElement; + SplitOverlay *parent; + + public: + ButtonEventFilter(SplitOverlay *parent, HoveredElement hoveredElement); + + protected: + bool eventFilter(QObject *watched, QEvent *event) override; + }; + + friend class ButtonEventFilter; +}; + +} // namespace widgets +} // namespace chatterino diff --git a/src/widgets/split.cpp b/src/widgets/split.cpp index d4408191a..c186188c5 100644 --- a/src/widgets/split.cpp +++ b/src/widgets/split.cpp @@ -13,6 +13,7 @@ #include "widgets/helper/debugpopup.hpp" #include "widgets/helper/searchpopup.hpp" #include "widgets/helper/shortcut.hpp" +#include "widgets/helper/splitoverlay.hpp" #include "widgets/qualitypopup.hpp" #include "widgets/selectchanneldialog.hpp" #include "widgets/splitcontainer.hpp" @@ -38,6 +39,9 @@ using namespace chatterino::messages; namespace chatterino { namespace widgets { +pajlada::Signals::Signal Split::altPressedStatusChanged; +bool Split::altPressesStatus = false; + Split::Split(SplitContainer *parent) : Split((QWidget *)parent) { @@ -52,6 +56,7 @@ Split::Split(QWidget *parent) , header(this) , view(this) , input(this) + , overlay(new SplitOverlay(this)) { auto app = getApp(); @@ -119,8 +124,17 @@ Split::Split(QWidget *parent) this->managedConnections); this->header.updateModerationModeIcon(); + this->overlay->hide(); this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + this->managedConnect(altPressedStatusChanged, [this](bool status) { + if (status && this->isMouseOver) { + this->overlay->show(); + } else { + this->overlay->hide(); + } + }); } Split::~Split() @@ -287,15 +301,39 @@ void Split::keyReleaseEvent(QKeyEvent *event) this->handleModifiers(event, event->modifiers()); } +void Split::resizeEvent(QResizeEvent *event) +{ + BaseWidget::resizeEvent(event); + + this->overlay->setGeometry(this->rect()); +} + +void Split::enterEvent(QEvent *event) +{ + this->isMouseOver = true; + if (altPressesStatus) { + this->overlay->show(); + } +} + +void Split::leaveEvent(QEvent *event) +{ + this->isMouseOver = false; + this->overlay->hide(); +} + void Split::handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers) { if (modifiers == Qt::AltModifier) { - this->setCursor(Qt::SizeAllCursor); - event->accept(); - // } else if (modifiers == Qt::ControlModifier) { - // this->setCursor(Qt::SplitHCursor); - // event->accept(); + if (!altPressesStatus) { + altPressesStatus = true; + altPressedStatusChanged.invoke(true); + } } else { + if (altPressesStatus) { + altPressesStatus = false; + altPressedStatusChanged.invoke(false); + } this->setCursor(Qt::ArrowCursor); } } diff --git a/src/widgets/split.hpp b/src/widgets/split.hpp index dd6cbf56d..e184cefc9 100644 --- a/src/widgets/split.hpp +++ b/src/widgets/split.hpp @@ -21,6 +21,7 @@ namespace chatterino { namespace widgets { class SplitContainer; +class SplitOverlay; // Each ChatWidget consists of three sub-elements that handle their own part of the chat widget: // ChatWidgetHeader @@ -32,12 +33,15 @@ class SplitContainer; // - Responsible for rendering and handling user text input // // Each sub-element has a reference to the parent Chat Widget -class Split : public BaseWidget +class Split : public BaseWidget, pajlada::Signals::SignalHolder { friend class SplitInput; Q_OBJECT + static pajlada::Signals::Signal altPressedStatusChanged; + static bool altPressesStatus; + public: explicit Split(SplitContainer *parent); explicit Split(QWidget *parent); @@ -81,6 +85,9 @@ protected: void mousePressEvent(QMouseEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void keyReleaseEvent(QKeyEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; private: SplitContainer *container; @@ -90,11 +97,15 @@ private: SplitHeader header; ChannelView view; SplitInput input; + SplitOverlay *overlay; + double flexSizeX = 1; double flexSizeY = 1; bool moderationMode = false; + bool isMouseOver = false; + pajlada::Signals::Connection channelIDChangedConnection; pajlada::Signals::Connection usermodeChangedConnection; pajlada::Signals::Connection indirectChannelChangedConnection; diff --git a/src/widgets/window.cpp b/src/widgets/window.cpp index b2020ea23..ef667c50b 100644 --- a/src/widgets/window.cpp +++ b/src/widgets/window.cpp @@ -138,9 +138,9 @@ void Window::refreshWindowTitle(const QString &username) this->setWindowTitle(username + " - Chatterino for Twitch"); } -bool Window::event(QEvent *e) +bool Window::event(QEvent *event) { - switch (e->type()) { + switch (event->type()) { case QEvent::WindowActivate: break; @@ -156,7 +156,7 @@ bool Window::event(QEvent *e) } } break; }; - return BaseWindow::event(e); + return BaseWindow::event(event); } void Window::closeEvent(QCloseEvent *event)