mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
248 lines
6.5 KiB
C++
248 lines
6.5 KiB
C++
#pragma once
|
|
|
|
#include "widgets/basewidget.hpp"
|
|
#include "widgets/helper/droppreview.hpp"
|
|
#include "widgets/helper/notebooktab.hpp"
|
|
#include "widgets/split.hpp"
|
|
|
|
#include <QDragEnterEvent>
|
|
#include <QHBoxLayout>
|
|
#include <QRect>
|
|
#include <QVBoxLayout>
|
|
#include <QVector>
|
|
#include <QWidget>
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
#include <pajlada/signals/signal.hpp>
|
|
#include <pajlada/signals/signalholder.hpp>
|
|
|
|
class QJsonObject;
|
|
|
|
namespace chatterino {
|
|
namespace widgets {
|
|
|
|
//
|
|
// Note: This class is a spaghetti container. There is a lot of spaghetti code inside but it doesn't
|
|
// expose any of it publicly.
|
|
//
|
|
|
|
class SplitContainer : public BaseWidget, pajlada::Signals::SignalHolder
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
struct Node;
|
|
|
|
// fourtf: !!! preserve the order of left, up, right and down
|
|
enum Direction { Left, Above, Right, Below };
|
|
|
|
struct Position final {
|
|
private:
|
|
Position() = default;
|
|
Position(Node *_relativeNode, Direction _direcion)
|
|
: relativeNode(_relativeNode)
|
|
, direction(_direcion)
|
|
{
|
|
}
|
|
|
|
Node *relativeNode;
|
|
Direction direction;
|
|
|
|
friend struct Node;
|
|
friend class SplitContainer;
|
|
};
|
|
|
|
private:
|
|
struct DropRect final {
|
|
QRect rect;
|
|
Position position;
|
|
|
|
DropRect(const QRect &_rect, const Position &_position)
|
|
: rect(_rect)
|
|
, position(_position)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct ResizeRect final {
|
|
QRect rect;
|
|
Node *node;
|
|
bool vertical;
|
|
|
|
ResizeRect(const QRect &_rect, Node *_node, bool _vertical)
|
|
: rect(_rect)
|
|
, node(_node)
|
|
, vertical(_vertical)
|
|
{
|
|
}
|
|
};
|
|
|
|
public:
|
|
struct Node final {
|
|
enum Type { EmptyRoot, _Split, VerticalContainer, HorizontalContainer };
|
|
|
|
Type getType();
|
|
Split *getSplit();
|
|
Node *getParent();
|
|
qreal getHorizontalFlex();
|
|
qreal getVerticalFlex();
|
|
const std::vector<std::unique_ptr<Node>> &getChildren();
|
|
|
|
private:
|
|
Type type;
|
|
Split *split;
|
|
Node *preferedFocusTarget;
|
|
Node *parent;
|
|
QRectF geometry;
|
|
qreal flexH = 1;
|
|
qreal flexV = 1;
|
|
std::vector<std::unique_ptr<Node>> children;
|
|
|
|
Node();
|
|
Node(Split *_split, Node *_parent);
|
|
|
|
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 setSplit(Split *_split);
|
|
Position releaseSplit();
|
|
qreal getFlex(bool isVertical);
|
|
qreal getSize(bool isVertical);
|
|
qreal getChildrensTotalFlex(bool isVertical);
|
|
void layout(bool addSpacing, float _scale, std::vector<DropRect> &dropRects,
|
|
std::vector<ResizeRect> &resizeRects);
|
|
|
|
static Type toContainerType(Direction _dir);
|
|
|
|
friend class SplitContainer;
|
|
};
|
|
|
|
private:
|
|
class DropOverlay final : public QWidget
|
|
{
|
|
public:
|
|
DropOverlay(SplitContainer *_parent = nullptr);
|
|
|
|
void setRects(std::vector<SplitContainer::DropRect> _rects);
|
|
|
|
pajlada::Signals::NoArgSignal dragEnded;
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *event) override;
|
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
|
void dragMoveEvent(QDragMoveEvent *event) override;
|
|
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
|
void dropEvent(QDropEvent *event) override;
|
|
|
|
private:
|
|
std::vector<DropRect> rects;
|
|
QPoint mouseOverPoint;
|
|
SplitContainer *parent;
|
|
};
|
|
|
|
class ResizeHandle final : public QWidget
|
|
{
|
|
public:
|
|
SplitContainer *parent;
|
|
Node *node;
|
|
|
|
void setVertical(bool isVertical);
|
|
ResizeHandle(SplitContainer *_parent = nullptr);
|
|
void paintEvent(QPaintEvent *event) override;
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
|
|
friend class SplitContainer;
|
|
|
|
private:
|
|
bool vertical;
|
|
bool isMouseDown = false;
|
|
};
|
|
|
|
public:
|
|
SplitContainer(Notebook *parent);
|
|
|
|
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);
|
|
|
|
void selectNextSplit(Direction direction);
|
|
|
|
void decodeFromJson(QJsonObject &obj);
|
|
|
|
int getSplitCount();
|
|
const std::vector<Split *> getSplits() const;
|
|
void refreshTabTitle();
|
|
NotebookTab *getTab() const;
|
|
Node *getBaseNode();
|
|
|
|
void setTab(NotebookTab *tab);
|
|
void hideResizeHandles();
|
|
void resetMouseStatus();
|
|
|
|
static bool isDraggingSplit;
|
|
static Split *draggingSplit;
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
void focusInEvent(QFocusEvent *event) override;
|
|
void leaveEvent(QEvent *event) override;
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
|
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
|
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
|
|
private:
|
|
struct DropRegion {
|
|
QRect rect;
|
|
std::pair<int, int> position;
|
|
|
|
DropRegion(QRect rect, std::pair<int, int> position)
|
|
{
|
|
this->rect = rect;
|
|
this->position = position;
|
|
}
|
|
};
|
|
|
|
void addSplit(Split *split);
|
|
|
|
std::vector<DropRect> dropRects;
|
|
std::vector<DropRegion> dropRegions;
|
|
NotebookPageDropPreview dropPreview;
|
|
DropOverlay overlay;
|
|
std::vector<std::unique_ptr<ResizeHandle>> resizeHandles;
|
|
QPoint mouseOverPoint;
|
|
|
|
void layout();
|
|
|
|
Node baseNode;
|
|
Split *selected;
|
|
void setSelected(Split *selected);
|
|
void selectSplitRecursive(Node *node, Direction direction);
|
|
void focusSplitRecursive(Node *node, Direction direction);
|
|
void setPreferedTargetRecursive(Node *node);
|
|
|
|
NotebookTab *tab;
|
|
std::vector<Split *> splits;
|
|
|
|
bool isDragging = false;
|
|
|
|
void decodeNodeRecusively(QJsonObject &obj, Node *node);
|
|
};
|
|
|
|
} // namespace widgets
|
|
} // namespace chatterino
|