diff --git a/CHANGELOG.md b/CHANGELOG.md index 907a84ce5..8a2691d36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ - Bugfix: Fixed moderator-only topics being subscribed to for non-moderators. (#5056) - Bugfix: Fixed a bug where buttons would remain in a hovered state after leaving them. (#5077) - Bugfix: Fixed popup windows not persisting between restarts. (#5081) +- Bugfix: Fixed splits not retaining their focus after minimizing. (#5080) - Dev: Run miniaudio in a separate thread, and simplify it to not manage the device ourselves. There's a chance the simplification is a bad idea. (#4978) - Dev: Change clang-format from v14 to v16. (#4929) - Dev: Fixed UTF16 encoding of `modes` file for the installer. (#4791) @@ -103,6 +104,7 @@ - Dev: Added Tests for Windows and MacOS in CI. (#4970, #5032) - Dev: Move `clang-tidy` checker to its own CI job. (#4996) - Dev: Refactored the Image Uploader feature. (#4971) +- Dev: Refactored the SplitOverlay code. (#5082) - Dev: Fixed deadlock and use-after-free in tests. (#4981) - Dev: Moved all `.clang-format` files to the root directory. (#5037) - Dev: Load less message history upon reconnects. (#5001, #5018) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e649d312a..8919ebb7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -696,6 +696,7 @@ set(SOURCE_FILES widgets/splits/InputCompletionPopup.hpp widgets/splits/Split.cpp widgets/splits/Split.hpp + widgets/splits/SplitCommon.hpp widgets/splits/SplitContainer.cpp widgets/splits/SplitContainer.hpp widgets/splits/SplitHeader.cpp diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index 49889f7fc..038c45f8f 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -50,7 +50,6 @@ const QString WindowManager::WINDOW_LAYOUT_FILENAME( QStringLiteral("window-layout.json")); using SplitNode = SplitContainer::Node; -using SplitDirection = SplitContainer::Direction; void WindowManager::showSettingsDialog(QWidget *parent, SettingsDialogPreference preference) diff --git a/src/widgets/Notebook.cpp b/src/widgets/Notebook.cpp index 2aa02e722..c6e1c1713 100644 --- a/src/widgets/Notebook.cpp +++ b/src/widgets/Notebook.cpp @@ -1332,13 +1332,19 @@ SplitNotebook::SplitNotebook(Window *parent) }); } -void SplitNotebook::showEvent(QShowEvent *) +void SplitNotebook::showEvent(QShowEvent * /*event*/) { - if (auto page = this->getSelectedPage()) + if (auto *page = this->getSelectedPage()) { - if (auto split = page->findChild()) + auto *split = page->getSelectedSplit(); + if (!split) { - split->setFocus(Qt::FocusReason::OtherFocusReason); + split = page->findChild(); + } + + if (split) + { + split->setFocus(Qt::OtherFocusReason); } } } diff --git a/src/widgets/splits/Split.hpp b/src/widgets/splits/Split.hpp index f0cc3de85..644a892a9 100644 --- a/src/widgets/splits/Split.hpp +++ b/src/widgets/splits/Split.hpp @@ -4,6 +4,7 @@ #include "common/Channel.hpp" #include "common/NullablePtr.hpp" #include "widgets/BaseWidget.hpp" +#include "widgets/splits/SplitCommon.hpp" #include #include @@ -95,8 +96,7 @@ public: pajlada::Signals::Signal actionRequested; pajlada::Signals::Signal openSplitRequested; - // args: (SplitContainer::Direction dir, Split* parent) - pajlada::Signals::Signal insertSplitRequested; + pajlada::Signals::Signal insertSplitRequested; protected: void paintEvent(QPaintEvent *event) override; diff --git a/src/widgets/splits/SplitCommon.hpp b/src/widgets/splits/SplitCommon.hpp new file mode 100644 index 000000000..d77916311 --- /dev/null +++ b/src/widgets/splits/SplitCommon.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace chatterino { + +enum class SplitDirection { + Left, + Above, + Right, + Below, +}; + +} // namespace chatterino diff --git a/src/widgets/splits/SplitContainer.cpp b/src/widgets/splits/SplitContainer.cpp index 276ab6d2b..a5a1bb4b0 100644 --- a/src/widgets/splits/SplitContainer.cpp +++ b/src/widgets/splits/SplitContainer.cpp @@ -159,7 +159,7 @@ void SplitContainer::insertSplit(Split *split, InsertOptions &&options) } auto *relativeTo = options.relativeNode; - const auto direction = options.direction.value_or(Direction::Right); + const auto direction = options.direction.value_or(SplitDirection::Right); if (relativeTo == nullptr) { @@ -260,27 +260,26 @@ void SplitContainer::addSplit(Split *split) break; case Split::Action::SelectSplitLeft: - this->selectNextSplit(SplitContainer::Left); + this->selectNextSplit(SplitDirection::Left); break; case Split::Action::SelectSplitRight: - this->selectNextSplit(SplitContainer::Right); + this->selectNextSplit(SplitDirection::Right); break; case Split::Action::SelectSplitAbove: - this->selectNextSplit(SplitContainer::Above); + this->selectNextSplit(SplitDirection::Above); break; case Split::Action::SelectSplitBelow: - this->selectNextSplit(SplitContainer::Below); + this->selectNextSplit(SplitDirection::Below); break; } }); conns.managedConnect( - split->insertSplitRequested, [this](int dir, Split *parent) { - this->insertSplit(new Split(this), - { - .relativeSplit = parent, - .direction = static_cast(dir), - }); + split->insertSplitRequested, [this](SplitDirection dir, Split *parent) { + this->insertSplit(new Split(this), { + .relativeSplit = parent, + .direction = dir, + }); }); this->layout(); @@ -355,7 +354,7 @@ SplitContainer::Position SplitContainer::deleteSplit(Split *split) return releaseSplit(split); } -void SplitContainer::selectNextSplit(Direction direction) +void SplitContainer::selectNextSplit(SplitDirection direction) { assertInGuiThread(); @@ -365,7 +364,7 @@ void SplitContainer::selectNextSplit(Direction direction) } } -void SplitContainer::selectSplitRecursive(Node *node, Direction direction) +void SplitContainer::selectSplitRecursive(Node *node, SplitDirection direction) { if (node->parent_ != nullptr) { @@ -379,7 +378,8 @@ void SplitContainer::selectSplitRecursive(Node *node, Direction direction) }); assert(it != siblings.end()); - if (direction == Direction::Left || direction == Direction::Above) + if (direction == SplitDirection::Left || + direction == SplitDirection::Above) { if (it == siblings.begin()) { @@ -507,20 +507,20 @@ void SplitContainer::layout() // left dropRects.emplace_back( QRect(g.left(), g.top(), g.width() / 3, g.height()), - Position(node, Direction::Left)); + Position(node, SplitDirection::Left)); // right dropRects.emplace_back(QRect(g.right() - g.width() / 3, g.top(), g.width() / 3, g.height()), - Position(node, Direction::Right)); + Position(node, SplitDirection::Right)); // top dropRects.emplace_back( QRect(g.left(), g.top(), g.width(), g.height() / 2), - Position(node, Direction::Above)); + Position(node, SplitDirection::Above)); // bottom dropRects.emplace_back(QRect(g.left(), g.bottom() - g.height() / 2, g.width(), g.height() / 2), - Position(node, Direction::Below)); + Position(node, SplitDirection::Below)); } if (this->splits_.empty()) @@ -528,7 +528,7 @@ void SplitContainer::layout() QRect g = this->rect(); dropRects.emplace_back( QRect(g.left(), g.top(), g.width() - 1, g.height() - 1), - Position(nullptr, Direction::Below)); + Position(nullptr, SplitDirection::Below)); } this->overlay_.setRects(std::move(dropRects)); @@ -1027,7 +1027,7 @@ SplitContainer::Node *SplitContainer::Node::findNodeContainingSplit( } void SplitContainer::Node::insertSplitRelative(Split *_split, - Direction _direction) + SplitDirection _direction) { if (this->parent_ == nullptr) { @@ -1066,7 +1066,7 @@ void SplitContainer::Node::insertSplitRelative(Split *_split, } void SplitContainer::Node::nestSplitIntoCollection(Split *_split, - Direction _direction) + SplitDirection _direction) { if (toContainerType(_direction) == this->type_) { @@ -1095,7 +1095,8 @@ void SplitContainer::Node::nestSplitIntoCollection(Split *_split, } } -void SplitContainer::Node::insertNextToThis(Split *_split, Direction _direction) +void SplitContainer::Node::insertNextToThis(Split *_split, + SplitDirection _direction) { auto &siblings = this->parent_->children_; @@ -1115,7 +1116,8 @@ void SplitContainer::Node::insertNextToThis(Split *_split, Direction _direction) }); assert(it != siblings.end()); - if (_direction == Direction::Right || _direction == Direction::Below) + if (_direction == SplitDirection::Right || + _direction == SplitDirection::Below) { it++; } @@ -1145,7 +1147,7 @@ SplitContainer::Position SplitContainer::Node::releaseSplit() Position pos; pos.relativeNode_ = nullptr; - pos.direction_ = Direction::Right; + pos.direction_ = SplitDirection::Right; return pos; } @@ -1163,13 +1165,15 @@ SplitContainer::Position SplitContainer::Node::releaseSplit() position.relativeNode_ = this->parent_; if (this->parent_->type_ == Type::VerticalContainer) { - position.direction_ = - siblings.begin() == it ? Direction::Above : Direction::Below; + position.direction_ = siblings.begin() == it + ? SplitDirection::Above + : SplitDirection::Below; } else { - position.direction_ = - siblings.begin() == it ? Direction::Left : Direction::Right; + position.direction_ = siblings.begin() == it + ? SplitDirection::Left + : SplitDirection::Right; } auto *parent = this->parent_; @@ -1191,8 +1195,8 @@ SplitContainer::Position SplitContainer::Node::releaseSplit() { position.direction_ = this->parent_->type_ == Type::VerticalContainer - ? Direction::Below - : Direction::Right; + ? SplitDirection::Below + : SplitDirection::Right; siblings.erase(it); position.relativeNode_ = siblings.back().get(); } @@ -1201,8 +1205,8 @@ SplitContainer::Position SplitContainer::Node::releaseSplit() position.relativeNode_ = (it + 1)->get(); position.direction_ = this->parent_->type_ == Type::VerticalContainer - ? Direction::Above - : Direction::Left; + ? SplitDirection::Above + : SplitDirection::Left; siblings.erase(it); } } @@ -1282,8 +1286,8 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale, isVertical ? offset : this->geometry_.width(), isVertical ? this->geometry_.height() : offset) .toRect(), - Position(this, - isVertical ? Direction::Left : Direction::Above)); + Position(this, isVertical ? SplitDirection::Left + : SplitDirection::Above)); // droprect right / below if (isVertical) @@ -1293,7 +1297,7 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale, this->geometry_.top(), offset, this->geometry_.height()) .toRect(), - Position(this, Direction::Right)); + Position(this, SplitDirection::Right)); } else { @@ -1302,7 +1306,7 @@ void SplitContainer::Node::layout(bool addSpacing, float _scale, this->geometry_.bottom() - offset, this->geometry_.width(), offset) .toRect(), - Position(this, Direction::Below)); + Position(this, SplitDirection::Below)); } // shrink childRect @@ -1391,9 +1395,10 @@ void SplitContainer::Node::clamp() this->flexV_ = std::max(0.0, this->flexV_); } -SplitContainer::Node::Type SplitContainer::Node::toContainerType(Direction _dir) +SplitContainer::Node::Type SplitContainer::Node::toContainerType( + SplitDirection _dir) { - return _dir == Direction::Left || _dir == Direction::Right + return _dir == SplitDirection::Left || _dir == SplitDirection::Right ? Type::HorizontalContainer : Type::VerticalContainer; } diff --git a/src/widgets/splits/SplitContainer.hpp b/src/widgets/splits/SplitContainer.hpp index e7472af02..9022085da 100644 --- a/src/widgets/splits/SplitContainer.hpp +++ b/src/widgets/splits/SplitContainer.hpp @@ -2,6 +2,7 @@ #include "common/WindowDescriptors.hpp" #include "widgets/BaseWidget.hpp" +#include "widgets/splits/SplitCommon.hpp" #include #include @@ -35,21 +36,17 @@ class SplitContainer final : public BaseWidget public: struct Node; - // fourtf: !!! preserve the order of left, up, right and down - // It's important to preserve since we cast from an int to this enum, so 0 = left, 1 = above etc - enum Direction { Left, Above, Right, Below }; - struct Position final { private: Position() = default; - Position(Node *relativeNode, Direction direcion) + Position(Node *relativeNode, SplitDirection direction) : relativeNode_(relativeNode) - , direction_(direcion) + , direction_(direction) { } Node *relativeNode_{nullptr}; - Direction direction_{Direction::Right}; + SplitDirection direction_{SplitDirection::Right}; friend struct Node; friend class SplitContainer; @@ -102,9 +99,9 @@ public: bool isOrContainsNode(Node *_node); Node *findNodeContainingSplit(Split *_split); - void insertSplitRelative(Split *_split, Direction _direction); - void nestSplitIntoCollection(Split *_split, Direction _direction); - void insertNextToThis(Split *_split, Direction _direction); + void insertSplitRelative(Split *_split, SplitDirection _direction); + void nestSplitIntoCollection(Split *_split, SplitDirection _direction); + void insertNextToThis(Split *_split, SplitDirection _direction); void setSplit(Split *_split); Position releaseSplit(); qreal getFlex(bool isVertical); @@ -117,7 +114,7 @@ public: // Clamps the flex values ensuring they're never below 0 void clamp(); - static Type toContainerType(Direction _dir); + static Type toContainerType(SplitDirection _dir); Type type_; Split *split_; @@ -190,7 +187,7 @@ public: Split *relativeSplit{nullptr}; Node *relativeNode{nullptr}; - std::optional direction{}; + std::optional direction{}; }; // Insert split into the base node of this container @@ -209,7 +206,7 @@ public: Position releaseSplit(Split *split); Position deleteSplit(Split *split); - void selectNextSplit(Direction direction); + void selectNextSplit(SplitDirection direction); void setSelected(Split *split); std::vector getSplits() const; @@ -244,7 +241,7 @@ private: Node *baseNode); void layout(); - void selectSplitRecursive(Node *node, Direction direction); + void selectSplitRecursive(Node *node, SplitDirection direction); void focusSplitRecursive(Node *node); void setPreferedTargetRecursive(Node *node); diff --git a/src/widgets/splits/SplitOverlay.cpp b/src/widgets/splits/SplitOverlay.cpp index 3ddf02200..a3fc538c4 100644 --- a/src/widgets/splits/SplitOverlay.cpp +++ b/src/widgets/splits/SplitOverlay.cpp @@ -14,14 +14,117 @@ #include #include +namespace { + +using namespace chatterino; + +class ButtonEventFilter : public QObject +{ + SplitOverlay *parent; + SplitOverlayButton buttonType; + +public: + ButtonEventFilter(SplitOverlay *_parent, SplitOverlayButton _buttonType); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; +}; + +ButtonEventFilter::ButtonEventFilter(SplitOverlay *_parent, + SplitOverlayButton _buttonType) + : QObject(_parent) + , parent(_parent) + , buttonType(_buttonType) +{ +} + +bool ButtonEventFilter::eventFilter(QObject *watched, QEvent *event) +{ + switch (event->type()) + { + case QEvent::Enter: { + auto *effect = dynamic_cast( + ((QWidget *)watched)->graphicsEffect()); + + if (effect != nullptr) + { + effect->setOpacity(0.99); + } + + this->parent->setHoveredButton(this->buttonType); + } + break; + + case QEvent::Leave: { + auto *effect = dynamic_cast( + ((QWidget *)watched)->graphicsEffect()); + + if (effect != nullptr) + { + effect->setOpacity(0.7); + } + + this->parent->setHoveredButton({}); + } + break; + + case QEvent::MouseButtonPress: { + if (this->buttonType == SplitOverlayButton::Move) + { + auto *mouseEvent = dynamic_cast(event); + assert(mouseEvent != nullptr); + if (mouseEvent->button() == Qt::LeftButton) + { + this->parent->dragPressed(); + } + return true; + } + } + break; + + case QEvent::MouseButtonRelease: { + switch (this->buttonType) + { + case SplitOverlayButton::Move: + break; + + case SplitOverlayButton::Left: { + this->parent->createSplitPressed(SplitDirection::Left); + } + break; + + case SplitOverlayButton::Up: { + this->parent->createSplitPressed(SplitDirection::Above); + } + break; + + case SplitOverlayButton::Right: { + this->parent->createSplitPressed(SplitDirection::Right); + } + break; + + case SplitOverlayButton::Down: { + this->parent->createSplitPressed(SplitDirection::Below); + } + break; + } + } + break; + + default:; + } + return QObject::eventFilter(watched, event); +} + +} // namespace + namespace chatterino { SplitOverlay::SplitOverlay(Split *parent) : BaseWidget(parent) , split_(parent) { - QGridLayout *layout = new QGridLayout(this); - this->layout_ = layout; + auto *layout = new QGridLayout(this); layout->setContentsMargins(1, 1, 1, 1); layout->setSpacing(1); @@ -30,69 +133,93 @@ SplitOverlay::SplitOverlay(Split *parent) layout->setColumnStretch(1, 1); layout->setColumnStretch(3, 1); - auto *move = new QPushButton(getResources().split.move, QString()); - auto *left = this->left_ = - new QPushButton(getResources().split.left, QString()); - auto *right = this->right_ = - new QPushButton(getResources().split.right, QString()); - auto *up = this->up_ = new QPushButton(getResources().split.up, QString()); - auto *down = this->down_ = - new QPushButton(getResources().split.down, QString()); + this->move_ = new QPushButton(getResources().split.move, {}); + this->left_ = new QPushButton(getResources().split.left, {}); + this->right_ = new QPushButton(getResources().split.right, {}); + this->up_ = new QPushButton(getResources().split.up, {}); + this->down_ = new QPushButton(getResources().split.down, {}); - 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)); + this->move_->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + this->left_->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + this->right_->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + this->up_->setGraphicsEffect(new QGraphicsOpacityEffect(this)); + this->down_->setGraphicsEffect(new QGraphicsOpacityEffect(this)); - move->setFlat(true); - left->setFlat(true); - right->setFlat(true); - up->setFlat(true); - down->setFlat(true); + this->move_->setFlat(true); + this->left_->setFlat(true); + this->right_->setFlat(true); + this->up_->setFlat(true); + this->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); + layout->addWidget(this->move_, 2, 2); + layout->addWidget(this->left_, 2, 0); + layout->addWidget(this->right_, 2, 4); + layout->addWidget(this->up_, 0, 2); + layout->addWidget(this->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)); + this->move_->installEventFilter( + new ButtonEventFilter(this, SplitOverlayButton::Move)); + this->left_->installEventFilter( + new ButtonEventFilter(this, SplitOverlayButton::Left)); + this->right_->installEventFilter( + new ButtonEventFilter(this, SplitOverlayButton::Right)); + this->up_->installEventFilter( + new ButtonEventFilter(this, SplitOverlayButton::Up)); + this->down_->installEventFilter( + new ButtonEventFilter(this, SplitOverlayButton::Down)); - move->setFocusPolicy(Qt::NoFocus); - left->setFocusPolicy(Qt::NoFocus); - right->setFocusPolicy(Qt::NoFocus); - up->setFocusPolicy(Qt::NoFocus); - down->setFocusPolicy(Qt::NoFocus); + this->move_->setFocusPolicy(Qt::NoFocus); + this->left_->setFocusPolicy(Qt::NoFocus); + this->right_->setFocusPolicy(Qt::NoFocus); + this->up_->setFocusPolicy(Qt::NoFocus); + this->down_->setFocusPolicy(Qt::NoFocus); - move->setCursor(Qt::SizeAllCursor); - left->setCursor(Qt::PointingHandCursor); - right->setCursor(Qt::PointingHandCursor); - up->setCursor(Qt::PointingHandCursor); - down->setCursor(Qt::PointingHandCursor); - - this->signalHolder_.managedConnect(this->scaleChanged, [=](float _scale) { - int a = int(_scale * 30); - QSize size(a, a); - - move->setIconSize(size); - left->setIconSize(size); - right->setIconSize(size); - up->setIconSize(size); - down->setIconSize(size); - }); + this->move_->setCursor(Qt::SizeAllCursor); + this->left_->setCursor(Qt::PointingHandCursor); + this->right_->setCursor(Qt::PointingHandCursor); + this->up_->setCursor(Qt::PointingHandCursor); + this->down_->setCursor(Qt::PointingHandCursor); this->setMouseTracking(true); this->setCursor(Qt::ArrowCursor); } -void SplitOverlay::paintEvent(QPaintEvent *) +void SplitOverlay::setHoveredButton( + std::optional hoveredButton) { + this->hoveredButton_ = hoveredButton; + this->update(); +} + +void SplitOverlay::dragPressed() +{ + this->split_->drag(); +} + +void SplitOverlay::createSplitPressed(SplitDirection direction) +{ + this->split_->insertSplitRequested.invoke(direction, this->split_); + this->hide(); +} + +void SplitOverlay::scaleChangedEvent(float newScale) +{ + int a = int(newScale * 30); + QSize size(a, a); + + this->move_->setIconSize(size); + this->left_->setIconSize(size); + this->right_->setIconSize(size); + this->up_->setIconSize(size); + this->down_->setIconSize(size); + BaseWidget::scaleChangedEvent(newScale); +} + +void SplitOverlay::paintEvent(QPaintEvent *event) +{ + (void)event; + QPainter painter(this); if (this->theme->isLightTheme()) { @@ -103,26 +230,32 @@ void SplitOverlay::paintEvent(QPaintEvent *) painter.fillRect(this->rect(), QColor(0, 0, 0, 150)); } - QRect rect; - switch (this->hoveredElement_) + if (!this->hoveredButton_.has_value()) { - case SplitLeft: { + return; + } + + QRect rect; + auto hoveredButton = this->hoveredButton_.value(); + switch (hoveredButton) + { + case SplitOverlayButton::Left: { rect = QRect(0, 0, this->width() / 2, this->height()); } break; - case SplitRight: { + case SplitOverlayButton::Right: { rect = QRect(this->width() / 2, 0, this->width() / 2, this->height()); } break; - case SplitUp: { + case SplitOverlayButton::Up: { rect = QRect(0, 0, this->width(), this->height() / 2); } break; - case SplitDown: { + case SplitOverlayButton::Down: { rect = QRect(0, this->height() / 2, this->width(), this->height() / 2); } @@ -131,11 +264,10 @@ void SplitOverlay::paintEvent(QPaintEvent *) default:; } - rect.setRight(rect.right() - 1); - rect.setBottom(rect.bottom() - 1); - if (!rect.isNull()) { + rect.setRight(rect.right() - 1); + rect.setBottom(rect.bottom() - 1); painter.setPen(getApp()->themes->splits.dropPreviewBorder); painter.setBrush(getApp()->themes->splits.dropPreview); painter.drawRect(rect); @@ -144,9 +276,12 @@ void SplitOverlay::paintEvent(QPaintEvent *) void SplitOverlay::resizeEvent(QResizeEvent *event) { - float _scale = this->scale(); - bool wideEnough = event->size().width() > 150 * _scale; - bool highEnough = event->size().height() > 150 * _scale; + const auto currentScale = this->scale(); + const auto minimumWidth = 150.F * currentScale; + const auto minimumHeight = 150.F * currentScale; + + const auto wideEnough = event->size().width() > minimumWidth; + const auto highEnough = event->size().height() > minimumHeight; this->left_->setVisible(wideEnough); this->right_->setVisible(wideEnough); @@ -164,75 +299,4 @@ void SplitOverlay::mouseMoveEvent(QMouseEvent *event) // } } -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(0.99); - } - - 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; - case QEvent::MouseButtonRelease: { - if (this->hoveredElement != HoveredElement::SplitMove) - { - auto dir = SplitContainer::Direction( - this->hoveredElement + SplitContainer::Left - SplitLeft); - - this->parent->split_->insertSplitRequested.invoke( - static_cast(dir), this->parent->split_); - - this->parent->hide(); - } - } - break; - default:; - } - return QObject::eventFilter(watched, event); -} - } // namespace chatterino diff --git a/src/widgets/splits/SplitOverlay.hpp b/src/widgets/splits/SplitOverlay.hpp index caaf07654..6e8f76295 100644 --- a/src/widgets/splits/SplitOverlay.hpp +++ b/src/widgets/splits/SplitOverlay.hpp @@ -1,60 +1,53 @@ #pragma once #include "widgets/BaseWidget.hpp" +#include "widgets/splits/SplitCommon.hpp" -#include -#include #include +#include + namespace chatterino { class Split; +/// Type of button in the split overlay (the overlay that appears when holding down ctrl+alt) +enum class SplitOverlayButton { + Move, + Left, + Up, + Right, + Down, +}; + class SplitOverlay : public BaseWidget { public: - explicit SplitOverlay(Split *parent = nullptr); + explicit SplitOverlay(Split *parent); + + // Called from the Split Overlay's button when it gets hovered over + void setHoveredButton(std::optional hoveredButton); + + // Called from the Split Overlay's button when the move button is pressed + void dragPressed(); + + // Called from the Split Overlay's button when one of the direction buttons are pressed + void createSplitPressed(SplitDirection direction); protected: - // bool event(QEvent *event) override; + void scaleChangedEvent(float newScale) override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; private: - // fourtf: !!! preserve the order of left, up, right and down - enum HoveredElement { - None, - SplitMove, - SplitLeft, - SplitUp, - SplitRight, - SplitDown - }; - - class ButtonEventFilter : public QObject - { - SplitOverlay *parent; - HoveredElement hoveredElement; - - public: - ButtonEventFilter(SplitOverlay *parent, HoveredElement hoveredElement); - - protected: - bool eventFilter(QObject *watched, QEvent *event) override; - }; - - HoveredElement hoveredElement_ = None; + std::optional hoveredButton_{}; Split *split_; - QGridLayout *layout_; + QPushButton *move_; QPushButton *left_; QPushButton *up_; QPushButton *right_; QPushButton *down_; - - pajlada::Signals::SignalHolder signalHolder_; - - friend class ButtonEventFilter; }; } // namespace chatterino