mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
added basic new layout
This commit is contained in:
parent
64160e60af
commit
c1a3764f44
12 changed files with 1101 additions and 583 deletions
|
@ -209,7 +209,7 @@ void WindowManager::initialize()
|
|||
QJsonObject split_obj = split_val.toObject();
|
||||
split->setChannel(this->decodeChannel(split_obj));
|
||||
|
||||
tab->addToLayout(split, std::make_pair(colNr, 10000000));
|
||||
// tab->addToLayout(split, std::make_pair(colNr, 10000000));
|
||||
}
|
||||
colNr++;
|
||||
}
|
||||
|
@ -271,20 +271,20 @@ void WindowManager::save()
|
|||
|
||||
// splits
|
||||
QJsonArray columns_arr;
|
||||
std::vector<std::vector<widgets::Split *>> columns = tab->getColumns();
|
||||
// std::vector<std::vector<widgets::Split *>> columns = tab->getColumns();
|
||||
|
||||
for (std::vector<widgets::Split *> &cells : columns) {
|
||||
QJsonArray cells_arr;
|
||||
// for (std::vector<widgets::Split *> &cells : columns) {
|
||||
// QJsonArray cells_arr;
|
||||
|
||||
for (widgets::Split *cell : cells) {
|
||||
QJsonObject cell_obj;
|
||||
// for (widgets::Split *cell : cells) {
|
||||
// QJsonObject cell_obj;
|
||||
|
||||
this->encodeChannel(cell->getIndirectChannel(), cell_obj);
|
||||
// this->encodeChannel(cell->getIndirectChannel(), cell_obj);
|
||||
|
||||
cells_arr.append(cell_obj);
|
||||
}
|
||||
columns_arr.append(cells_arr);
|
||||
}
|
||||
// cells_arr.append(cell_obj);
|
||||
// }
|
||||
// columns_arr.append(cells_arr);
|
||||
// }
|
||||
|
||||
tab_obj.insert("splits", columns_arr);
|
||||
tabs_arr.append(tab_obj);
|
||||
|
|
|
@ -139,10 +139,10 @@ void NotebookButton::dropEvent(QDropEvent *event)
|
|||
Notebook *notebook = dynamic_cast<Notebook *>(this->parentWidget());
|
||||
|
||||
if (notebook != nuuls) {
|
||||
SplitContainer *tab = notebook->addNewPage();
|
||||
SplitContainer *page = notebook->addNewPage();
|
||||
|
||||
SplitContainer::draggingSplit->setParent(tab);
|
||||
tab->addToLayout(SplitContainer::draggingSplit);
|
||||
SplitContainer::draggingSplit->setParent(page);
|
||||
page->appendSplit(SplitContainer::draggingSplit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ NotebookTab::NotebookTab(Notebook *_notebook)
|
|||
QString newTitle = d.getText();
|
||||
if (newTitle.isEmpty()) {
|
||||
this->useDefaultTitle = true;
|
||||
this->page->refreshTitle();
|
||||
this->page->refreshTabTitle();
|
||||
} else {
|
||||
this->useDefaultTitle = false;
|
||||
this->setTitle(newTitle);
|
||||
|
|
|
@ -241,13 +241,13 @@ void SplitHeader::mouseMoveEvent(QMouseEvent *event)
|
|||
tooltipWidget->show();
|
||||
}
|
||||
|
||||
if (this->dragging) {
|
||||
if (std::abs(this->dragStart.x() - event->pos().x()) > 12 ||
|
||||
std::abs(this->dragStart.y() - event->pos().y()) > 12) {
|
||||
this->split->drag();
|
||||
this->dragging = false;
|
||||
}
|
||||
}
|
||||
// if (this->dragging) {
|
||||
// if (std::abs(this->dragStart.x() - event->pos().x()) > 12 ||
|
||||
// std::abs(this->dragStart.y() - event->pos().y()) > 12) {
|
||||
// this->split->drag();
|
||||
// this->dragging = false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void SplitHeader::leaveEvent(QEvent *event)
|
||||
|
|
|
@ -163,15 +163,16 @@ void SplitInput::installKeyPressedEvent()
|
|||
return;
|
||||
}
|
||||
if (event->modifiers() == Qt::AltModifier) {
|
||||
SplitContainer *page =
|
||||
static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
// SplitContainer *page =
|
||||
// static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
|
||||
int reqX = page->currentX;
|
||||
int reqY = page->lastRequestedY[reqX] - 1;
|
||||
// page->requestFocus();
|
||||
// int reqX = page->currentX;
|
||||
// int reqY = page->lastRequestedY[reqX] - 1;
|
||||
|
||||
qDebug() << "Alt+Down to" << reqX << "/" << reqY;
|
||||
// qDebug() << "Alt+Down to" << reqX << "/" << reqY;
|
||||
|
||||
page->requestFocus(reqX, reqY);
|
||||
// page->requestFocus(reqX, reqY);
|
||||
} else {
|
||||
if (this->prevMsg.size() && this->prevIndex) {
|
||||
if (this->prevIndex == (this->prevMsg.size())) {
|
||||
|
@ -191,15 +192,15 @@ void SplitInput::installKeyPressedEvent()
|
|||
return;
|
||||
}
|
||||
if (event->modifiers() == Qt::AltModifier) {
|
||||
SplitContainer *page =
|
||||
static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
// SplitContainer *page =
|
||||
// static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
|
||||
int reqX = page->currentX;
|
||||
int reqY = page->lastRequestedY[reqX] + 1;
|
||||
// int reqX = page->currentX;
|
||||
// int reqY = page->lastRequestedY[reqX] + 1;
|
||||
|
||||
qDebug() << "Alt+Down to" << reqX << "/" << reqY;
|
||||
// qDebug() << "Alt+Down to" << reqX << "/" << reqY;
|
||||
|
||||
page->requestFocus(reqX, reqY);
|
||||
// page->requestFocus(reqX, reqY);
|
||||
} else {
|
||||
if (this->prevIndex != (this->prevMsg.size() - 1) &&
|
||||
this->prevIndex != this->prevMsg.size()) {
|
||||
|
@ -216,27 +217,27 @@ void SplitInput::installKeyPressedEvent()
|
|||
}
|
||||
} else if (event->key() == Qt::Key_Left) {
|
||||
if (event->modifiers() == Qt::AltModifier) {
|
||||
SplitContainer *page =
|
||||
static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
// SplitContainer *page =
|
||||
// static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
|
||||
int reqX = page->currentX - 1;
|
||||
int reqY = page->lastRequestedY[reqX];
|
||||
// int reqX = page->currentX - 1;
|
||||
// int reqY = page->lastRequestedY[reqX];
|
||||
|
||||
qDebug() << "Alt+Left to" << reqX << "/" << reqY;
|
||||
// qDebug() << "Alt+Left to" << reqX << "/" << reqY;
|
||||
|
||||
page->requestFocus(reqX, reqY);
|
||||
// page->requestFocus(reqX, reqY);
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Right) {
|
||||
if (event->modifiers() == Qt::AltModifier) {
|
||||
SplitContainer *page =
|
||||
static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
// SplitContainer *page =
|
||||
// static_cast<SplitContainer *>(this->chatWidget->parentWidget());
|
||||
|
||||
int reqX = page->currentX + 1;
|
||||
int reqY = page->lastRequestedY[reqX];
|
||||
// int reqX = page->currentX + 1;
|
||||
// int reqY = page->lastRequestedY[reqX];
|
||||
|
||||
qDebug() << "Alt+Right to" << reqX << "/" << reqY;
|
||||
// qDebug() << "Alt+Right to" << reqX << "/" << reqY;
|
||||
|
||||
page->requestFocus(reqX, reqY);
|
||||
// page->requestFocus(reqX, reqY);
|
||||
}
|
||||
} else if (event->key() == Qt::Key_Tab) {
|
||||
if (event->modifiers() == Qt::ControlModifier) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "application.hpp"
|
||||
#include "singletons/resourcemanager.hpp"
|
||||
#include "widgets/split.hpp"
|
||||
#include "widgets/splitcontainer.hpp"
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
@ -146,6 +147,17 @@ bool SplitOverlay::ButtonEventFilter::eventFilter(QObject *watched, QEvent *even
|
|||
this->parent->split->drag();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
SplitContainer *container = this->parent->split->getContainer();
|
||||
|
||||
if (container != nullptr) {
|
||||
auto *_split = new Split(container);
|
||||
container->insertSplit(
|
||||
_split,
|
||||
(SplitContainer::Direction)(this->hoveredElement + SplitContainer::Left -
|
||||
SplitLeft),
|
||||
this->parent->split);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ protected:
|
|||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
enum HoveredElement { None, SplitMove, SplitLeft, SplitRight, SplitUp, SplitDown };
|
||||
// fourtf: !!! preserve the order of left, up, right and down
|
||||
enum HoveredElement { None, SplitMove, SplitLeft, SplitUp, SplitRight, SplitDown };
|
||||
HoveredElement hoveredElement = None;
|
||||
Split *split;
|
||||
|
||||
|
|
|
@ -391,13 +391,13 @@ Notebook::Notebook(Window *parent, bool _showButtons)
|
|||
|
||||
// Window-wide hotkeys
|
||||
// CTRL+T: Create new split in selected notebook page
|
||||
CreateWindowShortcut(this, "CTRL+T", [this]() {
|
||||
if (this->selectedPage == nullptr) {
|
||||
return;
|
||||
}
|
||||
// CreateWindowShortcut(this, "CTRL+T", [this]() {
|
||||
// if (this->selectedPage == nullptr) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
this->selectedPage->addChat(true);
|
||||
});
|
||||
// this->selectedPage->addChat(true);
|
||||
// });
|
||||
}
|
||||
|
||||
SplitContainer *Notebook::addNewPage(bool select)
|
||||
|
@ -420,7 +420,7 @@ SplitContainer *Notebook::addNewPage(bool select)
|
|||
|
||||
void Notebook::removePage(SplitContainer *page)
|
||||
{
|
||||
if (page->splitCount() > 0 && closeConfirmDialog.exec() != QMessageBox::Yes) {
|
||||
if (page->getSplitCount() > 0 && closeConfirmDialog.exec() != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -484,7 +484,8 @@ void Notebook::select(SplitContainer *page)
|
|||
if (this->selectedPage != nullptr) {
|
||||
this->selectedPage->setHidden(true);
|
||||
this->selectedPage->getTab()->setSelected(false);
|
||||
for (auto split : this->selectedPage->getSplits()) {
|
||||
|
||||
for (Split *split : this->selectedPage->getSplits()) {
|
||||
split->updateLastReadMessage();
|
||||
}
|
||||
}
|
||||
|
@ -663,8 +664,7 @@ void Notebook::settingsButtonClicked()
|
|||
void Notebook::usersButtonClicked()
|
||||
{
|
||||
auto app = getApp();
|
||||
app->windows->showAccountSelectPopup(
|
||||
this->mapToGlobal(this->userButton.rect().bottomRight()));
|
||||
app->windows->showAccountSelectPopup(this->mapToGlobal(this->userButton.rect().bottomRight()));
|
||||
}
|
||||
|
||||
void Notebook::addPageButtonClicked()
|
||||
|
|
|
@ -135,6 +135,8 @@ Split::Split(QWidget *parent)
|
|||
// this->overlay->hide();
|
||||
// }
|
||||
});
|
||||
|
||||
this->setAcceptDrops(true);
|
||||
}
|
||||
|
||||
Split::~Split()
|
||||
|
@ -144,6 +146,16 @@ Split::~Split()
|
|||
this->indirectChannelChangedConnection.disconnect();
|
||||
}
|
||||
|
||||
ChannelView &Split::getChannelView()
|
||||
{
|
||||
return this->view;
|
||||
}
|
||||
|
||||
SplitContainer *Split::getContainer()
|
||||
{
|
||||
return this->container;
|
||||
}
|
||||
|
||||
bool Split::isInContainer() const
|
||||
{
|
||||
return this->container != nullptr;
|
||||
|
@ -185,30 +197,6 @@ void Split::setChannel(IndirectChannel newChannel)
|
|||
this->channelChanged.invoke();
|
||||
}
|
||||
|
||||
void Split::setFlexSizeX(double x)
|
||||
{
|
||||
// this->flexSizeX = x;
|
||||
// this->parentPage->updateFlexValues();
|
||||
}
|
||||
|
||||
double Split::getFlexSizeX()
|
||||
{
|
||||
// return this->flexSizeX;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Split::setFlexSizeY(double y)
|
||||
{
|
||||
// this->flexSizeY = y;
|
||||
// this->parentPage.updateFlexValues();
|
||||
}
|
||||
|
||||
double Split::getFlexSizeY()
|
||||
{
|
||||
// return this->flexSizeY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Split::setModerationMode(bool value)
|
||||
{
|
||||
if (value != this->moderationMode) {
|
||||
|
@ -236,7 +224,7 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
|||
if (dialog->hasSeletedChannel()) {
|
||||
this->setChannel(dialog->getSelectedChannel());
|
||||
if (this->isInContainer()) {
|
||||
this->container->refreshTitle();
|
||||
this->container->refreshTabTitle();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,9 +272,9 @@ void Split::mouseMoveEvent(QMouseEvent *event)
|
|||
|
||||
void Split::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->buttons() == Qt::LeftButton && event->modifiers() & Qt::AltModifier) {
|
||||
this->drag();
|
||||
}
|
||||
// if (event->buttons() == Qt::LeftButton && event->modifiers() & Qt::AltModifier) {
|
||||
// this->drag();
|
||||
// }
|
||||
}
|
||||
|
||||
void Split::keyPressEvent(QKeyEvent *event)
|
||||
|
@ -338,19 +326,40 @@ void Split::handleModifiers(QEvent *event, Qt::KeyboardModifiers modifiers)
|
|||
}
|
||||
}
|
||||
|
||||
void Split::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
event->acceptProposedAction();
|
||||
this->isDragging = true;
|
||||
QTimer::singleShot(1, [this] { this->overlay->show(); });
|
||||
}
|
||||
|
||||
void Split::dragLeaveEvent(QDragLeaveEvent *event)
|
||||
{
|
||||
this->overlay->hide();
|
||||
this->isDragging = false;
|
||||
}
|
||||
|
||||
void Split::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void Split::dropEvent(QDropEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
/// Slots
|
||||
void Split::doAddSplit()
|
||||
{
|
||||
if (this->container) {
|
||||
this->container->addChat(true);
|
||||
this->container->appendNewSplit(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Split::doCloseSplit()
|
||||
{
|
||||
if (this->container) {
|
||||
this->container->removeFromLayout(this);
|
||||
deleteLater();
|
||||
this->container->deleteSplit(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,7 +382,7 @@ void Split::doPopup()
|
|||
new Split(static_cast<SplitContainer *>(window.getNotebook().getOrAddSelectedPage()));
|
||||
|
||||
split->setChannel(this->getIndirectChannel());
|
||||
window.getNotebook().getOrAddSelectedPage()->addToLayout(split);
|
||||
window.getNotebook().getOrAddSelectedPage()->appendSplit(split);
|
||||
|
||||
window.show();
|
||||
}
|
||||
|
@ -536,26 +545,6 @@ static Iter select_randomly(Iter start, Iter end)
|
|||
return select_randomly(start, end, gen);
|
||||
}
|
||||
|
||||
void Split::doIncFlexX()
|
||||
{
|
||||
this->setFlexSizeX(this->getFlexSizeX() * 1.2);
|
||||
}
|
||||
|
||||
void Split::doDecFlexX()
|
||||
{
|
||||
this->setFlexSizeX(this->getFlexSizeX() * (1 / 1.2));
|
||||
}
|
||||
|
||||
void Split::doIncFlexY()
|
||||
{
|
||||
this->setFlexSizeY(this->getFlexSizeY() * 1.2);
|
||||
}
|
||||
|
||||
void Split::doDecFlexY()
|
||||
{
|
||||
this->setFlexSizeY(this->getFlexSizeY() * (1 / 1.2));
|
||||
}
|
||||
|
||||
void Split::drag()
|
||||
{
|
||||
auto container = dynamic_cast<SplitContainer *>(this->parentWidget());
|
||||
|
@ -564,7 +553,7 @@ void Split::drag()
|
|||
SplitContainer::isDraggingSplit = true;
|
||||
SplitContainer::draggingSplit = this;
|
||||
|
||||
auto originalLocation = container->removeFromLayout(this);
|
||||
auto originalLocation = container->releaseSplit(this);
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
|
@ -576,7 +565,8 @@ void Split::drag()
|
|||
Qt::DropAction dropAction = drag->exec(Qt::MoveAction);
|
||||
|
||||
if (dropAction == Qt::IgnoreAction) {
|
||||
container->addToLayout(this, originalLocation);
|
||||
container->insertSplit(this,
|
||||
originalLocation); // SplitContainer::dragOriginalPosition);
|
||||
}
|
||||
|
||||
SplitContainer::isDraggingSplit = false;
|
||||
|
|
|
@ -39,9 +39,6 @@ class Split : public BaseWidget, pajlada::Signals::SignalHolder
|
|||
|
||||
Q_OBJECT
|
||||
|
||||
static pajlada::Signals::Signal<bool> altPressedStatusChanged;
|
||||
static bool altPressesStatus;
|
||||
|
||||
public:
|
||||
explicit Split(SplitContainer *parent);
|
||||
explicit Split(QWidget *parent);
|
||||
|
@ -50,20 +47,13 @@ public:
|
|||
|
||||
pajlada::Signals::NoArgSignal channelChanged;
|
||||
|
||||
ChannelView &getChannelView()
|
||||
{
|
||||
return this->view;
|
||||
}
|
||||
ChannelView &getChannelView();
|
||||
SplitContainer *getContainer();
|
||||
|
||||
IndirectChannel getIndirectChannel();
|
||||
ChannelPtr getChannel();
|
||||
void setChannel(IndirectChannel newChannel);
|
||||
|
||||
void setFlexSizeX(double x);
|
||||
double getFlexSizeX();
|
||||
void setFlexSizeY(double y);
|
||||
double getFlexSizeY();
|
||||
|
||||
void setModerationMode(bool value);
|
||||
bool getModerationMode() const;
|
||||
|
||||
|
@ -79,6 +69,9 @@ public:
|
|||
|
||||
bool isInContainer() const;
|
||||
|
||||
static pajlada::Signals::Signal<bool> altPressedStatusChanged;
|
||||
static bool altPressesStatus;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
@ -89,6 +82,11 @@ protected:
|
|||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
private:
|
||||
SplitContainer *container;
|
||||
IndirectChannel channel;
|
||||
|
@ -99,12 +97,10 @@ private:
|
|||
SplitInput input;
|
||||
SplitOverlay *overlay;
|
||||
|
||||
double flexSizeX = 1;
|
||||
double flexSizeY = 1;
|
||||
|
||||
bool moderationMode = false;
|
||||
|
||||
bool isMouseOver = false;
|
||||
bool isDragging = false;
|
||||
|
||||
pajlada::Signals::Connection channelIDChangedConnection;
|
||||
pajlada::Signals::Connection usermodeChangedConnection;
|
||||
|
@ -151,11 +147,6 @@ public slots:
|
|||
|
||||
// Open viewer list of the channel
|
||||
void doOpenViewerList();
|
||||
|
||||
void doIncFlexX();
|
||||
void doDecFlexX();
|
||||
void doIncFlexY();
|
||||
void doDecFlexY();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,47 +12,433 @@
|
|||
#include <QVector>
|
||||
#include <QWidget>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <pajlada/signals/signalholder.hpp>
|
||||
|
||||
namespace chatterino {
|
||||
namespace widgets {
|
||||
|
||||
class SplitContainer : public BaseWidget
|
||||
class SplitContainer : public BaseWidget, pajlada::Signals::SignalHolder
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// fourtf: !!! preserve the order of left, up, right and down
|
||||
enum Direction { Left, Above, Right, Below };
|
||||
|
||||
struct Node;
|
||||
|
||||
struct Position {
|
||||
private:
|
||||
Position() = default;
|
||||
Position(Node *_relativeNode, Direction _direcion)
|
||||
: relativeNode(_relativeNode)
|
||||
, direction(_direcion)
|
||||
{
|
||||
}
|
||||
|
||||
Node *relativeNode;
|
||||
Direction direction;
|
||||
|
||||
friend struct Node;
|
||||
friend class SplitContainer;
|
||||
};
|
||||
|
||||
struct DropRect {
|
||||
QRect rect;
|
||||
Position position;
|
||||
|
||||
DropRect(const QRect &_rect, const Position &_position)
|
||||
: rect(_rect)
|
||||
, position(_position)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Node final {
|
||||
enum Type { EmptyRoot, _Split, VerticalContainer, HorizontalContainer };
|
||||
|
||||
Type getType()
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
Split *getSplit()
|
||||
{
|
||||
return this->split;
|
||||
}
|
||||
const std::vector<std::unique_ptr<Node>> &getChildren()
|
||||
{
|
||||
return this->children;
|
||||
}
|
||||
|
||||
private:
|
||||
Type type;
|
||||
Split *split;
|
||||
Node *parent;
|
||||
QRectF geometry;
|
||||
std::vector<std::unique_ptr<Node>> children;
|
||||
|
||||
Node()
|
||||
: type(Type::EmptyRoot)
|
||||
, split(nullptr)
|
||||
, parent(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Node(Split *_split, Node *_parent)
|
||||
: type(Type::_Split)
|
||||
, split(_split)
|
||||
, parent(_parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool isOrContainsNode(Node *_node)
|
||||
{
|
||||
if (this == _node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return std::any_of(
|
||||
this->children.begin(), this->children.end(),
|
||||
[_node](std::unique_ptr<Node> &n) { return n->isOrContainsNode(_node); });
|
||||
}
|
||||
|
||||
Node *findNodeContainingSplit(Split *_split)
|
||||
{
|
||||
if (this->type == Type::_Split && this->split == _split) {
|
||||
return this;
|
||||
}
|
||||
|
||||
for (std::unique_ptr<Node> &node : this->children) {
|
||||
Node *a = node->findNodeContainingSplit(_split);
|
||||
|
||||
if (a != nullptr) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void insertSplitRelative(Split *_split, Direction _direction)
|
||||
{
|
||||
if (this->parent == nullptr) {
|
||||
switch (this->type) {
|
||||
case Node::EmptyRoot: {
|
||||
this->setSplit(_split);
|
||||
} break;
|
||||
case Node::_Split: {
|
||||
this->nestSplitIntoCollection(_split, _direction);
|
||||
} break;
|
||||
case Node::HorizontalContainer: {
|
||||
if (toContainerType(_direction) == Node::HorizontalContainer) {
|
||||
assert(false);
|
||||
} else {
|
||||
this->nestSplitIntoCollection(_split, _direction);
|
||||
}
|
||||
} break;
|
||||
case Node::VerticalContainer: {
|
||||
if (toContainerType(_direction) == Node::VerticalContainer) {
|
||||
assert(false);
|
||||
} else {
|
||||
this->nestSplitIntoCollection(_split, _direction);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// parent != nullptr
|
||||
if (parent->type == toContainerType(_direction)) {
|
||||
// hell yeah we'll just insert it next to outselves
|
||||
this->_insertNextToThis(_split, _direction);
|
||||
} else {
|
||||
this->nestSplitIntoCollection(_split, _direction);
|
||||
}
|
||||
}
|
||||
|
||||
void nestSplitIntoCollection(Split *_split, Direction _direction)
|
||||
{
|
||||
// we'll need to nest outselves
|
||||
// move all our data into a new node
|
||||
Node *clone = new Node();
|
||||
clone->type = this->type;
|
||||
clone->children = std::move(this->children);
|
||||
for (std::unique_ptr<Node> &node : clone->children) {
|
||||
node->parent = clone;
|
||||
}
|
||||
clone->split = this->split;
|
||||
clone->parent = this;
|
||||
|
||||
// add the node to our children and change our type
|
||||
this->children.push_back(std::unique_ptr<Node>(clone));
|
||||
this->type = toContainerType(_direction);
|
||||
this->split = nullptr;
|
||||
|
||||
clone->_insertNextToThis(_split, _direction);
|
||||
}
|
||||
|
||||
void _insertNextToThis(Split *_split, Direction _direction)
|
||||
{
|
||||
auto &siblings = this->parent->children;
|
||||
|
||||
qreal size =
|
||||
// std::accumulate(this->parent->children.begin(),
|
||||
// this->parent->children.end(), 0,
|
||||
// [_direction](qreal val, Node *node) {
|
||||
// if (toContainerType(_direction) ==
|
||||
// Type::VerticalContainer) {
|
||||
// return val + node->geometry.height();
|
||||
// } else {
|
||||
// return val + node->geometry.width();
|
||||
// }
|
||||
// });
|
||||
|
||||
this->parent->geometry.width() / siblings.size();
|
||||
|
||||
if (siblings.size() == 1) {
|
||||
this->geometry = QRect(0, 0, size, size);
|
||||
}
|
||||
|
||||
auto it = std::find_if(siblings.begin(), siblings.end(),
|
||||
[this](auto &node) { return this == node.get(); });
|
||||
|
||||
assert(it != siblings.end());
|
||||
if (_direction == Direction::Right || _direction == Direction::Below) {
|
||||
it++;
|
||||
}
|
||||
|
||||
Node *node = new Node(_split, this->parent);
|
||||
node->geometry = QRectF(0, 0, size, size);
|
||||
siblings.insert(it, std::unique_ptr<Node>(node));
|
||||
}
|
||||
|
||||
void setSplit(Split *_split)
|
||||
{
|
||||
assert(this->split == nullptr);
|
||||
assert(this->children.size() == 0);
|
||||
|
||||
this->split = _split;
|
||||
this->type = Type::_Split;
|
||||
}
|
||||
|
||||
Position releaseSplit()
|
||||
{
|
||||
assert(this->type == Type::_Split);
|
||||
|
||||
if (parent == nullptr) {
|
||||
this->type = Type::EmptyRoot;
|
||||
this->split = nullptr;
|
||||
|
||||
Position pos;
|
||||
pos.relativeNode = nullptr;
|
||||
pos.direction = Direction::Right;
|
||||
return pos;
|
||||
} else {
|
||||
auto &siblings = this->parent->children;
|
||||
|
||||
auto it = std::find_if(begin(siblings), end(siblings),
|
||||
[this](auto &node) { return this == node.get(); });
|
||||
assert(it != siblings.end());
|
||||
|
||||
Position position;
|
||||
if (siblings.size() == 2) {
|
||||
// delete this and move split to parent
|
||||
position.relativeNode = this->parent;
|
||||
if (this->parent->type == Type::VerticalContainer) {
|
||||
position.direction =
|
||||
siblings.begin() == it ? Direction::Above : Direction::Below;
|
||||
} else {
|
||||
position.direction =
|
||||
siblings.begin() == it ? Direction::Left : Direction::Right;
|
||||
}
|
||||
|
||||
Node *_parent = this->parent;
|
||||
siblings.erase(it);
|
||||
std::unique_ptr<Node> &sibling = siblings.front();
|
||||
_parent->type = sibling->type;
|
||||
_parent->split = sibling->split;
|
||||
std::vector<std::unique_ptr<Node>> nodes = std::move(sibling->children);
|
||||
for (auto &node : nodes) {
|
||||
node->parent = _parent;
|
||||
}
|
||||
_parent->children = std::move(nodes);
|
||||
} else {
|
||||
if (this == siblings.back().get()) {
|
||||
position.direction = this->parent->type == Type::VerticalContainer
|
||||
? Direction::Below
|
||||
: Direction::Right;
|
||||
siblings.erase(it);
|
||||
position.relativeNode = siblings.back().get();
|
||||
} else {
|
||||
position.relativeNode = (it + 1)->get();
|
||||
position.direction = this->parent->type == Type::VerticalContainer
|
||||
? Direction::Above
|
||||
: Direction::Left;
|
||||
siblings.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
void layout(bool addSpacing, std::vector<DropRect> &dropRects)
|
||||
{
|
||||
switch (this->type) {
|
||||
case Node::_Split: {
|
||||
QRect rect = this->geometry.toRect();
|
||||
this->split->setGeometry(rect.marginsRemoved(QMargins(1, 1, 1, 1)));
|
||||
} break;
|
||||
case Node::VerticalContainer: {
|
||||
qreal totalHeight =
|
||||
std::accumulate(this->children.begin(), this->children.end(), 0,
|
||||
[](qreal val, std::unique_ptr<Node> &node) {
|
||||
return val + node->geometry.height();
|
||||
});
|
||||
|
||||
qreal childX = this->geometry.left();
|
||||
qreal childWidth = this->geometry.width();
|
||||
|
||||
if (addSpacing) {
|
||||
qreal offset = this->geometry.width() * 0.1;
|
||||
dropRects.emplace_back(
|
||||
QRect(childX, this->geometry.top(), offset, this->geometry.height()),
|
||||
Position(this, Direction::Left));
|
||||
dropRects.emplace_back(
|
||||
QRect(childX + this->geometry.width() - offset, this->geometry.top(),
|
||||
offset, this->geometry.height()),
|
||||
Position(this, Direction::Right));
|
||||
|
||||
childX += offset;
|
||||
childWidth -= offset * 2;
|
||||
}
|
||||
|
||||
qreal scaleFactor = this->geometry.height() / totalHeight;
|
||||
|
||||
qreal y = this->geometry.top();
|
||||
for (std::unique_ptr<Node> &child : this->children) {
|
||||
child->geometry =
|
||||
QRectF(childX, y, childWidth, child->geometry.height() * scaleFactor);
|
||||
|
||||
child->layout(addSpacing, dropRects);
|
||||
y += child->geometry.height();
|
||||
}
|
||||
} break;
|
||||
case Node::HorizontalContainer: {
|
||||
qreal totalWidth =
|
||||
std::accumulate(this->children.begin(), this->children.end(), 0,
|
||||
[](qreal val, std::unique_ptr<Node> &node) {
|
||||
return val + node->geometry.width();
|
||||
});
|
||||
|
||||
qreal childY = this->geometry.top();
|
||||
qreal childHeight = this->geometry.height();
|
||||
|
||||
if (addSpacing) {
|
||||
qreal offset = this->geometry.height() * 0.1;
|
||||
dropRects.emplace_back(
|
||||
QRect(this->geometry.left(), childY, this->geometry.width(), offset),
|
||||
Position(this, Direction::Above));
|
||||
dropRects.emplace_back(
|
||||
QRect(this->geometry.left(), childY + this->geometry.height() - offset,
|
||||
this->geometry.width(), offset),
|
||||
Position(this, Direction::Below));
|
||||
|
||||
childY += this->geometry.height() * 0.1;
|
||||
childHeight -= this->geometry.height() * 0.2;
|
||||
}
|
||||
|
||||
qreal scaleFactor = this->geometry.width() / totalWidth;
|
||||
|
||||
qreal x = this->geometry.left();
|
||||
for (std::unique_ptr<Node> &child : this->children) {
|
||||
child->geometry =
|
||||
QRectF(x, childY, child->geometry.width() * scaleFactor, childHeight);
|
||||
|
||||
child->layout(addSpacing, dropRects);
|
||||
x += child->geometry.width();
|
||||
}
|
||||
} break;
|
||||
};
|
||||
}
|
||||
|
||||
static Type toContainerType(Direction _dir)
|
||||
{
|
||||
return _dir == Direction::Left || _dir == Direction::Right ? Type::HorizontalContainer
|
||||
: Type::VerticalContainer;
|
||||
}
|
||||
|
||||
friend class SplitContainer;
|
||||
};
|
||||
|
||||
SplitContainer(Notebook *parent, NotebookTab *_tab);
|
||||
|
||||
std::pair<int, int> removeFromLayout(Split *widget);
|
||||
void addToLayout(Split *widget, std::pair<int, int> position = std::pair<int, int>(-1, -1));
|
||||
void appendNewSplit(bool openChannelNameDialog);
|
||||
void appendSplit(Split *split);
|
||||
void insertSplit(Split *split, const Position &position);
|
||||
void insertSplit(Split *split, Direction direction, Split *relativeTo);
|
||||
void insertSplit(Split *split, Direction direction, Node *relativeTo = nullptr);
|
||||
Position releaseSplit(Split *split);
|
||||
Position deleteSplit(Split *split);
|
||||
|
||||
int getSplitCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::vector<Split *> getSplits() const
|
||||
{
|
||||
return this->splits;
|
||||
}
|
||||
|
||||
void refreshTabTitle();
|
||||
|
||||
const std::vector<Split *> &getSplits() const;
|
||||
std::vector<std::vector<Split *>> getColumns() const;
|
||||
NotebookTab *getTab() const;
|
||||
const Node *getBaseNode()
|
||||
{
|
||||
return &this->baseNode;
|
||||
}
|
||||
|
||||
void addChat(bool openChannelNameDialog = false);
|
||||
// std::pair<int, int> removeFromLayout(Split *widget);
|
||||
// void addToLayout(Split *widget, std::pair<int, int> position = std::pair<int, int>(-1,
|
||||
// -1));
|
||||
|
||||
// const std::vector<Split *> &getSplits() const;
|
||||
// std::vector<std::vector<Split *>> getColumns() const;
|
||||
|
||||
// void addChat(bool openChannelNameDialog = false);
|
||||
|
||||
// static std::pair<int, int> dropPosition;
|
||||
|
||||
// int currentX = 0;
|
||||
// int currentY = 0;
|
||||
// std::map<int, int> 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 std::pair<int, int> dropPosition;
|
||||
|
||||
int currentX = 0;
|
||||
int currentY = 0;
|
||||
std::map<int, int> lastRequestedY;
|
||||
|
||||
void refreshCurrentFocusCoordinates(bool alsoSetLastRequested = false);
|
||||
void requestFocus(int x, int y);
|
||||
|
||||
void updateFlexValues();
|
||||
int splitCount() const;
|
||||
// static Position dragOriginalPosition;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
// bool eventFilter(QObject *object, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
// void showEvent(QShowEvent *event) override;
|
||||
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
// void enterEvent(QEvent *event) override;
|
||||
// void leaveEvent(QEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
|
@ -60,6 +446,8 @@ protected:
|
|||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
struct DropRegion {
|
||||
QRect rect;
|
||||
|
@ -72,31 +460,32 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
NotebookTab *tab;
|
||||
|
||||
struct {
|
||||
QVBoxLayout parentLayout;
|
||||
|
||||
QHBoxLayout hbox;
|
||||
} ui;
|
||||
|
||||
std::vector<Split *> splits;
|
||||
std::vector<DropRect> dropRects;
|
||||
std::vector<DropRegion> dropRegions;
|
||||
|
||||
NotebookPageDropPreview dropPreview;
|
||||
|
||||
void setPreviewRect(QPoint mousePos);
|
||||
void layout();
|
||||
|
||||
std::pair<int, int> getChatPosition(const Split *chatWidget);
|
||||
Node baseNode;
|
||||
|
||||
Split *createChatWidget();
|
||||
NotebookTab *tab;
|
||||
std::vector<Split *> splits;
|
||||
|
||||
public:
|
||||
void refreshTitle();
|
||||
bool isDragging = false;
|
||||
|
||||
void loadSplits();
|
||||
// struct {
|
||||
// QVBoxLayout parentLayout;
|
||||
|
||||
void save();
|
||||
// QHBoxLayout hbox;
|
||||
// } ui;
|
||||
|
||||
// std::vector<Split *> splits;
|
||||
|
||||
// void setPreviewRect(QPoint mousePos);
|
||||
|
||||
// std::pair<int, int> getChatPosition(const Split *chatWidget);
|
||||
|
||||
// Split *createChatWidget();
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
|
Loading…
Reference in a new issue