From 27cd953c8caf3e35e1de8783d578a6c87b9b702d Mon Sep 17 00:00:00 2001 From: fourtf Date: Thu, 10 May 2018 23:58:07 +0200 Subject: [PATCH] improved splits --- src/widgets/helper/dropoverlay.cpp | 13 + src/widgets/helper/dropoverlay.hpp | 11 + src/widgets/helper/splitnode.cpp | 6 + src/widgets/helper/splitnode.hpp | 11 + src/widgets/helper/splitoverlay.cpp | 22 +- src/widgets/helper/splitoverlay.hpp | 9 + src/widgets/split.cpp | 57 ++-- src/widgets/split.hpp | 6 +- src/widgets/splitcontainer.cpp | 415 ++++++++-------------------- src/widgets/splitcontainer.hpp | 149 +++++++--- 10 files changed, 336 insertions(+), 363 deletions(-) create mode 100644 src/widgets/helper/dropoverlay.cpp create mode 100644 src/widgets/helper/dropoverlay.hpp create mode 100644 src/widgets/helper/splitnode.cpp create mode 100644 src/widgets/helper/splitnode.hpp diff --git a/src/widgets/helper/dropoverlay.cpp b/src/widgets/helper/dropoverlay.cpp new file mode 100644 index 000000000..f98160a5d --- /dev/null +++ b/src/widgets/helper/dropoverlay.cpp @@ -0,0 +1,13 @@ +//#include "dropoverlay.hpp" + +// namespace chatterino { +// namespace widgets { +// namespace helper { + +// DropOverlay::DropOverlay() +//{ +//} + +//} // namespace helper +//} // namespace widgets +//} // namespace chatterino diff --git a/src/widgets/helper/dropoverlay.hpp b/src/widgets/helper/dropoverlay.hpp new file mode 100644 index 000000000..7ae89104f --- /dev/null +++ b/src/widgets/helper/dropoverlay.hpp @@ -0,0 +1,11 @@ +//#pragma once + +//#include "widgets/helper/splitnode.hpp" + +// namespace chatterino { +// namespace widgets { +// namespace helper { + +//} // namespace helper +//} // namespace widgets +//} // namespace chatterino diff --git a/src/widgets/helper/splitnode.cpp b/src/widgets/helper/splitnode.cpp new file mode 100644 index 000000000..fac9a6739 --- /dev/null +++ b/src/widgets/helper/splitnode.cpp @@ -0,0 +1,6 @@ +#include "splitnode.hpp" + +SplitNode::SplitNode() +{ + +} diff --git a/src/widgets/helper/splitnode.hpp b/src/widgets/helper/splitnode.hpp new file mode 100644 index 000000000..dc57b0987 --- /dev/null +++ b/src/widgets/helper/splitnode.hpp @@ -0,0 +1,11 @@ +#ifndef SPLITNODE_HPP +#define SPLITNODE_HPP + + +class SplitNode +{ +public: + SplitNode(); +}; + +#endif // SPLITNODE_HPP \ No newline at end of file diff --git a/src/widgets/helper/splitoverlay.cpp b/src/widgets/helper/splitoverlay.cpp index fd6f23240..a43ac9567 100644 --- a/src/widgets/helper/splitoverlay.cpp +++ b/src/widgets/helper/splitoverlay.cpp @@ -19,6 +19,7 @@ SplitOverlay::SplitOverlay(Split *parent) , split(parent) { QGridLayout *layout = new QGridLayout(this); + this->_layout = layout; layout->setMargin(1); layout->setSpacing(1); @@ -28,10 +29,11 @@ SplitOverlay::SplitOverlay(Split *parent) 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()); + QPushButton *left = this->_left = new QPushButton(getApp()->resources->split.left, QString()); + QPushButton *right = this->_right = + new QPushButton(getApp()->resources->split.right, QString()); + QPushButton *up = this->_up = new QPushButton(getApp()->resources->split.up, QString()); + QPushButton *down = this->_down = new QPushButton(getApp()->resources->split.down, QString()); move->setGraphicsEffect(new QGraphicsOpacityEffect(this)); left->setGraphicsEffect(new QGraphicsOpacityEffect(this)); @@ -108,6 +110,18 @@ void SplitOverlay::paintEvent(QPaintEvent *event) } } +void SplitOverlay::resizeEvent(QResizeEvent *event) +{ + float scale = this->getScale(); + bool wideEnough = event->size().width() > 150 * scale; + bool highEnough = event->size().height() > 150 * scale; + + this->_left->setVisible(wideEnough); + this->_right->setVisible(wideEnough); + this->_up->setVisible(highEnough); + this->_down->setVisible(highEnough); +} + SplitOverlay::ButtonEventFilter::ButtonEventFilter(SplitOverlay *_parent, HoveredElement _element) : QObject(_parent) , parent(_parent) diff --git a/src/widgets/helper/splitoverlay.hpp b/src/widgets/helper/splitoverlay.hpp index de24dac6c..4877835ce 100644 --- a/src/widgets/helper/splitoverlay.hpp +++ b/src/widgets/helper/splitoverlay.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "pajlada/signals/signalholder.hpp" #include "widgets/basewidget.hpp" @@ -15,12 +18,18 @@ public: protected: void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private: // fourtf: !!! preserve the order of left, up, right and down enum HoveredElement { None, SplitMove, SplitLeft, SplitUp, SplitRight, SplitDown }; HoveredElement hoveredElement = None; Split *split; + QGridLayout *_layout; + QPushButton *_left; + QPushButton *_up; + QPushButton *_right; + QPushButton *_down; class ButtonEventFilter : public QObject { diff --git a/src/widgets/split.cpp b/src/widgets/split.cpp index 4d8681a05..1d1b9a5e2 100644 --- a/src/widgets/split.cpp +++ b/src/widgets/split.cpp @@ -39,8 +39,8 @@ using namespace chatterino::messages; namespace chatterino { namespace widgets { -pajlada::Signals::Signal Split::altPressedStatusChanged; -bool Split::altPressesStatus = false; +pajlada::Signals::Signal Split::modifierStatusChanged; +Qt::KeyboardModifiers Split::modifierStatus = Qt::NoModifier; Split::Split(SplitContainer *parent) : Split((QWidget *)parent) @@ -128,15 +128,14 @@ Split::Split(QWidget *parent) this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - this->managedConnect(altPressedStatusChanged, [this](bool status) { - // if (status && this->isMouseOver) { - // this->overlay->show(); - // } else { - // this->overlay->hide(); - // } + this->managedConnect(modifierStatusChanged, [this](Qt::KeyboardModifiers status) { + if ((status == Qt::AltModifier || status == (Qt::AltModifier | Qt::ControlModifier)) && + this->isMouseOver) { + this->overlay->show(); + } else { + this->overlay->hide(); + } }); - - this->setAcceptDrops(true); } Split::~Split() @@ -161,6 +160,11 @@ bool Split::isInContainer() const return this->container != nullptr; } +void Split::setContainer(SplitContainer *_container) +{ + this->container = _container; +} + IndirectChannel Split::getIndirectChannel() { return this->channel; @@ -299,7 +303,11 @@ void Split::resizeEvent(QResizeEvent *event) void Split::enterEvent(QEvent *event) { this->isMouseOver = true; - if (altPressesStatus) { + + auto a = modifierStatus; + + if (modifierStatus == Qt::AltModifier || + modifierStatus == (Qt::AltModifier | Qt::ControlModifier)) { this->overlay->show(); } } @@ -312,18 +320,23 @@ void Split::leaveEvent(QEvent *event) void Split::handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers) { - if (modifiers == Qt::AltModifier) { - if (!altPressesStatus) { - altPressesStatus = true; - altPressedStatusChanged.invoke(true); - } - } else { - if (altPressesStatus) { - altPressesStatus = false; - altPressedStatusChanged.invoke(false); - } - this->setCursor(Qt::ArrowCursor); + if (modifierStatus != modifiers) { + modifierStatus = modifiers; + modifierStatusChanged.invoke(modifiers); } + + // if (modifiers == Qt::AltModifier) { + // if (!modifierStatus) { + // modifierStatus = true; + // modifierStatusChanged.invoke(true); + // } + // } else { + // if (modifierStatus) { + // modifierStatus = false; + // modifierStatusChanged.invoke(false); + // } + // this->setCursor(Qt::ArrowCursor); + // } } void Split::dragEnterEvent(QDragEnterEvent *event) diff --git a/src/widgets/split.hpp b/src/widgets/split.hpp index 450623d0b..565844b38 100644 --- a/src/widgets/split.hpp +++ b/src/widgets/split.hpp @@ -69,8 +69,10 @@ public: bool isInContainer() const; - static pajlada::Signals::Signal altPressedStatusChanged; - static bool altPressesStatus; + void setContainer(SplitContainer *container); + + static pajlada::Signals::Signal modifierStatusChanged; + static Qt::KeyboardModifiers modifierStatus; protected: void paintEvent(QPaintEvent *event) override; diff --git a/src/widgets/splitcontainer.cpp b/src/widgets/splitcontainer.cpp index 0cf7f2c99..53395e45a 100644 --- a/src/widgets/splitcontainer.cpp +++ b/src/widgets/splitcontainer.cpp @@ -1,4 +1,5 @@ #include "widgets/splitcontainer.hpp" +#include "application.hpp" #include "common.hpp" #include "singletons/thememanager.hpp" #include "util/helpers.hpp" @@ -30,25 +31,29 @@ SplitContainer::SplitContainer(Notebook *parent, NotebookTab *_tab) : BaseWidget(parent) , tab(_tab) , dropPreview(this) + , mouseOverPoint(-10000, -10000) + , overlay(this) { this->tab->page = this; - // this->setLayout(&this->ui.parentLayout); - - // this->setHidden(true); - // this->setAcceptDrops(true); - - // this->ui.parentLayout.addSpacing(1); - // this->ui.parentLayout.addLayout(&this->ui.hbox); - // this->ui.parentLayout.setMargin(0); - - // this->ui.hbox.setSpacing(1); - // this->ui.hbox.setMargin(0); - this->refreshTabTitle(); - this->managedConnect(Split::altPressedStatusChanged, [this](auto) { this->layout(); }); + this->managedConnect(Split::modifierStatusChanged, [this](auto) { + // fourtf: maybe optimize + this->layout(); + }); + this->setCursor(Qt::PointingHandCursor); + this->setAcceptDrops(true); + + this->managedConnect(this->overlay.dragEnded, [this]() { + this->isDragging = false; + this->layout(); + }); + + this->overlay.hide(); + + this->setMouseTracking(true); this->setAcceptDrops(true); } @@ -91,6 +96,8 @@ void SplitContainer::insertSplit(Split *split, Direction direction, Split *relat void SplitContainer::insertSplit(Split *split, Direction direction, Node *relativeTo) { + split->setContainer(this); + if (relativeTo == nullptr) { if (this->baseNode.type == Node::EmptyRoot) { this->baseNode.setSplit(split); @@ -107,8 +114,11 @@ void SplitContainer::insertSplit(Split *split, Direction direction, Node *relati split->setParent(this); split->show(); + split->giveFocus(Qt::MouseFocusReason); this->splits.push_back(split); + // this->setAcceptDrops(false); + this->layout(); } @@ -121,6 +131,14 @@ SplitContainer::Position SplitContainer::releaseSplit(Split *split) split->setParent(nullptr); Position position = node->releaseSplit(); this->layout(); + if (splits.size() != 0) { + this->splits.front()->giveFocus(Qt::MouseFocusReason); + } + + // if (this->splits.empty()) { + // this->setAcceptDrops(true); + // } + return position; } @@ -137,11 +155,41 @@ void SplitContainer::layout() this->baseNode.geometry = this->rect(); std::vector _dropRects; - this->baseNode.layout(Split::altPressesStatus | this->isDragging, _dropRects); + this->baseNode.layout( + Split::modifierStatus == (Qt::AltModifier | Qt::ControlModifier) || this->isDragging, + this->getScale(), _dropRects); _dropRects.clear(); - this->baseNode.layout(Split::altPressesStatus | this->isDragging, _dropRects); + this->baseNode.layout( + Split::modifierStatus == (Qt::AltModifier | Qt::ControlModifier) || this->isDragging, + this->getScale(), _dropRects); - this->dropRects = std::move(_dropRects); + this->dropRects = _dropRects; + + for (Split *split : this->splits) { + const QRect &g = split->geometry(); + + Node *node = this->baseNode.findNodeContainingSplit(split); + + _dropRects.push_back(DropRect(QRect(g.left(), g.top(), g.width() / 4, g.height()), + Position(node, Direction::Left))); + _dropRects.push_back( + DropRect(QRect(g.left() + g.width() / 4 * 3, g.top(), g.width() / 4, g.height()), + Position(node, Direction::Right))); + + _dropRects.push_back(DropRect(QRect(g.left(), g.top(), g.width(), g.height() / 2), + Position(node, Direction::Above))); + _dropRects.push_back( + DropRect(QRect(g.left(), g.top() + g.height() / 2, g.width(), g.height() / 2), + Position(node, Direction::Below))); + } + + if (this->splits.empty()) { + QRect g = this->rect(); + _dropRects.push_back(DropRect(QRect(g.left(), g.top(), g.width(), g.height()), + Position(nullptr, Direction::Below))); + } + + this->overlay.setRects(std::move(_dropRects)); this->update(); } @@ -160,7 +208,7 @@ void SplitContainer::mouseReleaseEvent(QMouseEvent *event) // "Add Chat" was clicked this->appendNewSplit(true); - this->setCursor(QCursor(Qt::ArrowCursor)); + // this->setCursor(QCursor(Qt::ArrowCursor)); } else { auto it = std::find_if(this->dropRects.begin(), this->dropRects.end(), @@ -198,8 +246,16 @@ void SplitContainer::paintEvent(QPaintEvent *) } for (DropRect &dropRect : this->dropRects) { - painter.setPen("#774"); - painter.setBrush(QBrush("#553")); + QColor border = getApp()->themes->splits.dropPreviewBorder; + QColor background = getApp()->themes->splits.dropPreview; + + if (!dropRect.rect.contains(this->mouseOverPoint)) { + // border.setAlphaF(0.1); + background.setAlphaF(0.1); + } + + painter.setPen(border); + painter.setBrush(background); painter.drawRect(dropRect.rect.marginsRemoved(QMargins(2, 2, 2, 2))); } @@ -213,310 +269,57 @@ void SplitContainer::paintEvent(QPaintEvent *) void SplitContainer::dragEnterEvent(QDragEnterEvent *event) { - if (!event->mimeData()->hasFormat("chatterino/split")) - return; + // if (!event->mimeData()->hasFormat("chatterino/split")) + // return; - if (!SplitContainer::isDraggingSplit) { - return; - } + // if (!SplitContainer::isDraggingSplit) { + // return; + // } this->isDragging = true; this->layout(); - event->acceptProposedAction(); - - // this->dropRegions.clear(); - - // if (this->ui.hbox.count() == 0) { - // this->dropRegions.push_back(DropRegion(rect(), std::pair(-1, -1))); - // } else { - // for (int i = 0; i < this->ui.hbox.count() + 1; ++i) { - // this->dropRegions.push_back( - // DropRegion(QRect(((i * 4 - 1) * width() / this->ui.hbox.count()) / 4, 0, - // width() / this->ui.hbox.count() / 2 + 1, height() + 1), - // std::pair(i, -1))); - // } - - // for (int i = 0; i < this->ui.hbox.count(); ++i) { - // auto vbox = static_cast(this->ui.hbox.itemAt(i)); - - // for (int j = 0; j < vbox->count() + 1; ++j) { - // this->dropRegions.push_back(DropRegion( - // QRect(i * width() / this->ui.hbox.count(), - // ((j * 2 - 1) * height() / vbox->count()) / 2, - // width() / this->ui.hbox.count() + 1, height() / vbox->count() + 1), - - // std::pair(i, j))); - // } - // } + // if (this->splits.empty()) { + // event->acceptProposedAction(); // } - // setPreviewRect(event->pos()); - - // event->acceptProposedAction(); + this->overlay.setGeometry(this->rect()); + this->overlay.show(); + this->overlay.raise(); } void SplitContainer::dragMoveEvent(QDragMoveEvent *event) { - // setPreviewRect(event->pos()); + // if (this->splits.empty()) { + // event->acceptProposedAction(); + // } - for (auto &dropRect : this->dropRects) { - if (dropRect.rect.contains(event->pos())) { - event->acceptProposedAction(); - return; - } - } - event->setAccepted(false); + // for (auto &dropRect : this->dropRects) { + // if (dropRect.rect.contains(event->pos())) { + // event->acceptProposedAction(); + // return; + // } + // } + // event->setAccepted(false); } void SplitContainer::dragLeaveEvent(QDragLeaveEvent *event) { - this->isDragging = false; - this->layout(); - - // this->dropPreview.hide(); + // this->isDragging = false; + // this->layout(); } void SplitContainer::dropEvent(QDropEvent *event) { - // if (isDraggingSplit) { + // if (this->splits.empty()) { + // this->insertSplit(SplitContainer::draggingSplit, Direction::Above); // event->acceptProposedAction(); - - // SplitContainer::draggingSplit->setParent(this); - - // addToLayout(SplitContainer::draggingSplit, dropPosition); // } - // this->dropPreview.hide(); - - for (auto &dropRect : this->dropRects) { - if (dropRect.rect.contains(event->pos())) { - this->insertSplit(SplitContainer::draggingSplit, dropRect.position); - event->acceptProposedAction(); - break; - } - } - - this->isDragging = false; - this->layout(); + // this->isDragging = false; + // this->layout(); } -// void SplitContainer::updateFlexValues() -//{ -// for (int i = 0; i < this->ui.hbox.count(); i++) { -// QVBoxLayout *vbox = (QVBoxLayout *)ui.hbox.itemAt(i)->layout(); - -// if (vbox->count() != 0) { -// ui.hbox.setStretch(i, (int)(1000 * ((Split *)vbox->itemAt(0))->getFlexSizeX())); -// } -// } -//} - -// int SplitContainer::splitCount() const -//{ -// return this->splits.size(); -//} - -// std::pair SplitContainer::removeFromLayout(Split *widget) -//{ -// widget->getChannelView().tabHighlightRequested.disconnectAll(); - -// // remove reference to chat widget from chatWidgets vector -// auto it = std::find(std::begin(this->splits), std::end(this->splits), widget); -// if (it != std::end(this->splits)) { -// this->splits.erase(it); - -// this->refreshTitle(); -// } - -// Split *neighbouringSplit = nullptr; - -// // Position the split was found at -// int positionX = -1, positionY = -1; - -// bool removed = false; - -// QVBoxLayout *layoutToRemove = nullptr; - -// // Find widget in box, remove it, return its position -// for (int i = 0; i < this->ui.hbox.count(); ++i) { -// auto vbox = static_cast(this->ui.hbox.itemAt(i)); - -// auto vboxCount = vbox->count(); - -// for (int j = 0; j < vboxCount; ++j) { -// if (vbox->itemAt(j)->widget() != widget) { -// neighbouringSplit = dynamic_cast(vbox->itemAt(j)->widget()); - -// if (removed && neighbouringSplit != nullptr) { -// // The widget we searched for has been found, and we have a split to switch -// // focus to -// break; -// } - -// continue; -// } - -// removed = true; -// positionX = i; - -// // Remove split from box -// widget->setParent(nullptr); - -// if (vbox->count() == 0) { -// // The split was the last item remaining in the vbox -// // Remove the vbox once all iteration is done -// layoutToRemove = vbox; -// positionY = -1; -// break; -// } - -// // Don't break here yet, we want to keep iterating this vbox if possible to find the -// // closest still-alive neighbour that we can switch focus to -// positionY = j; - -// --j; -// --vboxCount; -// } - -// if (removed && neighbouringSplit != nullptr) { -// // The widget we searched for has been found, and we have a split to switch focus to -// break; -// } -// } - -// if (removed) { -// if (layoutToRemove != nullptr) { -// // The split we removed was the last split in its box. Remove the box -// // We delay the removing of the box so we can keep iterating over hbox safely -// this->ui.hbox.removeItem(layoutToRemove); -// delete layoutToRemove; -// } - -// if (neighbouringSplit != nullptr) { -// // We found a neighbour split we can switch focus to -// neighbouringSplit->giveFocus(Qt::MouseFocusReason); -// } -// } - -// return std::make_pair(positionX, positionY); -//} - -// void SplitContainer::addToLayout(Split *widget, std::pair position) -//{ -// this->splits.push_back(widget); -// widget->getChannelView().tabHighlightRequested.connect( -// [this](HighlightState state) { this->tab->setHighlightState(state); }); - -// this->refreshTitle(); - -// widget->giveFocus(Qt::MouseFocusReason); - -// // add vbox at the end -// if (position.first < 0 || position.first >= this->ui.hbox.count()) { -// auto vbox = new QVBoxLayout(); -// vbox->addWidget(widget); - -// this->ui.hbox.addLayout(vbox, 1); - -// this->refreshCurrentFocusCoordinates(); -// return; -// } - -// // insert vbox -// if (position.second == -1) { -// auto vbox = new QVBoxLayout(); -// vbox->addWidget(widget); - -// this->ui.hbox.insertLayout(position.first, vbox, 1); -// this->refreshCurrentFocusCoordinates(); -// return; -// } - -// // add to existing vbox -// auto vbox = static_cast(this->ui.hbox.itemAt(position.first)); - -// vbox->insertWidget(std::max(0, std::min(vbox->count(), position.second)), widget); - -// this->refreshCurrentFocusCoordinates(); -//} - -// const std::vector &SplitContainer::getSplits() const -//{ -// return this->splits; -//} - -// std::vector> SplitContainer::getColumns() const -//{ -// std::vector> columns; - -// for (int i = 0; i < this->ui.hbox.count(); i++) { -// std::vector cells; - -// QLayout *vbox = this->ui.hbox.itemAt(i)->layout(); -// for (int j = 0; j < vbox->count(); j++) { -// cells.push_back(dynamic_cast(vbox->itemAt(j)->widget())); -// } - -// columns.push_back(cells); -// } - -// return columns; -//} - -// void SplitContainer::refreshCurrentFocusCoordinates(bool alsoSetLastRequested) -//{ -// int setX = -1; -// int setY = -1; -// bool doBreak = false; -// for (int x = 0; x < this->ui.hbox.count(); ++x) { -// QLayoutItem *item = this->ui.hbox.itemAt(x); -// if (item->isEmpty()) { -// setX = x; -// break; -// } -// QVBoxLayout *vbox = static_cast(item->layout()); - -// for (int y = 0; y < vbox->count(); ++y) { -// QLayoutItem *innerItem = vbox->itemAt(y); - -// if (innerItem->isEmpty()) { -// setX = x; -// setY = y; -// doBreak = true; -// break; -// } - -// QWidget *w = innerItem->widget(); -// if (w) { -// Split *chatWidget = static_cast(w); -// if (chatWidget->hasFocus()) { -// setX = x; -// setY = y; -// doBreak = true; -// break; -// } -// } -// } - -// if (doBreak) { -// break; -// } -// } - -// if (setX != -1) { -// this->currentX = setX; - -// if (setY != -1) { -// this->currentY = setY; - -// if (alsoSetLastRequested) { -// this->lastRequestedY[setX] = setY; -// } -// } -// } -//} - // void SplitContainer::requestFocus(int requestedX, int requestedY) //{ // // XXX: Perhaps if we request an Y coordinate out of bounds, we shuold set all previously set @@ -561,7 +364,7 @@ void SplitContainer::dropEvent(QDropEvent *event) // } //} -// void SplitContainer::enterEvent(QEvent *) +// void SplitContainer::enterEvent(QEvent *event) //{ // if (this->ui.hbox.count() == 0) { // this->setCursor(QCursor(Qt::PointingHandCursor)); @@ -570,9 +373,17 @@ void SplitContainer::dropEvent(QDropEvent *event) // } //} -// void SplitContainer::leaveEvent(QEvent *) -//{ -//} +void SplitContainer::mouseMoveEvent(QMouseEvent *event) +{ + this->mouseOverPoint = event->pos(); + this->update(); +} + +void SplitContainer::leaveEvent(QEvent *event) +{ + this->mouseOverPoint = QPoint(-1000, -10000); + this->update(); +} // void SplitContainer::setPreviewRect(QPoint mousePos) //{ diff --git a/src/widgets/splitcontainer.hpp b/src/widgets/splitcontainer.hpp index 1ed3253e9..1fb3043af 100644 --- a/src/widgets/splitcontainer.hpp +++ b/src/widgets/splitcontainer.hpp @@ -16,8 +16,13 @@ #include #include +#include #include +// remove +#include "application.hpp" +#include "singletons/thememanager.hpp" + namespace chatterino { namespace widgets { @@ -285,7 +290,7 @@ public: } } - void layout(bool addSpacing, std::vector &dropRects) + void layout(bool addSpacing, float _scale, std::vector &dropRects) { switch (this->type) { case Node::_Split: { @@ -303,7 +308,8 @@ public: qreal childWidth = this->geometry.width(); if (addSpacing) { - qreal offset = this->geometry.width() * 0.1; + qreal offset = std::min(this->geometry.width() * 0.1, _scale * 24); + dropRects.emplace_back( QRect(childX, this->geometry.top(), offset, this->geometry.height()), Position(this, Direction::Left)); @@ -323,7 +329,7 @@ public: child->geometry = QRectF(childX, y, childWidth, child->geometry.height() * scaleFactor); - child->layout(addSpacing, dropRects); + child->layout(addSpacing, _scale, dropRects); y += child->geometry.height(); } } break; @@ -338,7 +344,7 @@ public: qreal childHeight = this->geometry.height(); if (addSpacing) { - qreal offset = this->geometry.height() * 0.1; + qreal offset = std::min(this->geometry.height() * 0.1, _scale * 24); dropRects.emplace_back( QRect(this->geometry.left(), childY, this->geometry.width(), offset), Position(this, Direction::Above)); @@ -347,8 +353,8 @@ public: this->geometry.width(), offset), Position(this, Direction::Below)); - childY += this->geometry.height() * 0.1; - childHeight -= this->geometry.height() * 0.2; + childY += offset; + childHeight -= offset * 2; } qreal scaleFactor = this->geometry.width() / totalWidth; @@ -358,7 +364,7 @@ public: child->geometry = QRectF(x, childY, child->geometry.width() * scaleFactor, childHeight); - child->layout(addSpacing, dropRects); + child->layout(addSpacing, _scale, dropRects); x += child->geometry.width(); } } break; @@ -374,6 +380,105 @@ public: friend class SplitContainer; }; + class DropOverlay : public QWidget + { + public: + DropOverlay(SplitContainer *_parent = nullptr) + : QWidget(_parent) + , parent(_parent) + , mouseOverPoint(-10000, -10000) + { + this->setMouseTracking(true); + this->setAcceptDrops(true); + } + + void setRects(std::vector _rects) + { + this->rects = std::move(_rects); + } + + pajlada::Signals::NoArgSignal dragEnded; + + protected: + void paintEvent(QPaintEvent *event) override + { + QPainter painter(this); + + // painter.fillRect(this->rect(), QColor("#334")); + + bool foundMover = false; + + for (DropRect &rect : this->rects) { + if (!foundMover && rect.rect.contains(this->mouseOverPoint)) { + painter.setBrush(getApp()->themes->splits.dropPreview); + painter.setPen(getApp()->themes->splits.dropPreviewBorder); + foundMover = true; + } else { + painter.setBrush(QColor(0, 0, 0, 0)); + painter.setPen(QColor(0, 0, 0, 0)); + // painter.setPen(getApp()->themes->splits.dropPreviewBorder); + } + + painter.drawRect(rect.rect); + } + } + + void mouseMoveEvent(QMouseEvent *event) + { + this->mouseOverPoint = event->pos(); + } + + void leaveEvent(QEvent *event) + { + this->mouseOverPoint = QPoint(-10000, -10000); + } + + void dragEnterEvent(QDragEnterEvent *event) + { + event->acceptProposedAction(); + } + + void dragMoveEvent(QDragMoveEvent *event) + { + event->acceptProposedAction(); + + this->mouseOverPoint = event->pos(); + this->update(); + } + + void dragLeaveEvent(QDragLeaveEvent *event) + { + this->mouseOverPoint = QPoint(-10000, -10000); + this->close(); + this->dragEnded.invoke(); + } + + void dropEvent(QDropEvent *event) + { + Position *position = nullptr; + for (DropRect &rect : this->rects) { + if (rect.rect.contains(this->mouseOverPoint)) { + position = &rect.position; + break; + } + } + + if (position != nullptr) { + this->parent->insertSplit(SplitContainer::draggingSplit, *position); + event->acceptProposedAction(); + } + + this->mouseOverPoint = QPoint(-10000, -10000); + this->close(); + this->dragEnded.invoke(); + } + + private: + std::vector rects; + QPoint mouseOverPoint; + SplitContainer *parent; + }; + SplitContainer(Notebook *parent, NotebookTab *_tab); void appendNewSplit(bool openChannelNameDialog); @@ -402,31 +507,6 @@ public: return &this->baseNode; } - // std::pair removeFromLayout(Split *widget); - // void addToLayout(Split *widget, std::pair position = std::pair(-1, - // -1)); - - // const std::vector &getSplits() const; - // std::vector> getColumns() const; - - // void addChat(bool openChannelNameDialog = false); - - // static std::pair dropPosition; - - // int currentX = 0; - // int currentY = 0; - // std::map lastRequestedY; - - // void refreshCurrentFocusCoordinates(bool alsoSetLastRequested = false); - // void requestFocus(int x, int y); - - // void updateFlexValues(); - // int splitCount() const; - - // void loadSplits(); - - // void save(); - static bool isDraggingSplit; static Split *draggingSplit; // static Position dragOriginalPosition; @@ -438,7 +518,8 @@ protected: // void showEvent(QShowEvent *event) override; // void enterEvent(QEvent *event) override; - // void leaveEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override; @@ -463,6 +544,8 @@ private: std::vector dropRects; std::vector dropRegions; NotebookPageDropPreview dropPreview; + DropOverlay overlay; + QPoint mouseOverPoint; void layout();