2017-06-07 10:09:24 +02:00
|
|
|
#pragma once
|
2016-12-29 17:31:07 +01:00
|
|
|
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "widgets/BaseWidget.hpp"
|
2016-12-30 12:20:26 +01:00
|
|
|
|
2017-01-18 04:52:47 +01:00
|
|
|
#include <QDragEnterEvent>
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <QRect>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
#include <QVector>
|
|
|
|
#include <QWidget>
|
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
2018-05-10 23:58:07 +02:00
|
|
|
#include <pajlada/signals/signal.hpp>
|
2018-05-10 19:50:31 +02:00
|
|
|
#include <pajlada/signals/signalholder.hpp>
|
2018-08-11 22:23:06 +02:00
|
|
|
#include <vector>
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
class QJsonObject;
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2017-01-18 21:30:23 +01:00
|
|
|
namespace chatterino {
|
|
|
|
|
2018-08-11 22:23:06 +02:00
|
|
|
class Split;
|
|
|
|
class NotebookTab;
|
|
|
|
class Notebook;
|
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
//
|
2018-08-06 21:17:03 +02:00
|
|
|
// Note: This class is a spaghetti container. There is a lot of spaghetti code
|
|
|
|
// inside but it doesn't expose any of it publicly.
|
2018-05-16 14:55:45 +02:00
|
|
|
//
|
|
|
|
|
2018-08-11 22:23:06 +02:00
|
|
|
class SplitContainer final : public BaseWidget, pajlada::Signals::SignalHolder
|
2016-12-29 17:31:07 +01:00
|
|
|
{
|
2017-01-11 18:52:09 +01:00
|
|
|
Q_OBJECT
|
2016-12-29 17:31:07 +01:00
|
|
|
|
2018-05-16 17:47:58 +02:00
|
|
|
public:
|
2018-05-16 14:55:45 +02:00
|
|
|
struct Node;
|
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
// fourtf: !!! preserve the order of left, up, right and down
|
|
|
|
enum Direction { Left, Above, Right, Below };
|
|
|
|
|
2018-05-24 17:13:46 +02:00
|
|
|
struct Position final {
|
2018-05-10 19:50:31 +02:00
|
|
|
private:
|
|
|
|
Position() = default;
|
2018-07-06 19:23:47 +02:00
|
|
|
Position(Node *relativeNode, Direction direcion)
|
|
|
|
: relativeNode_(relativeNode)
|
|
|
|
, direction_(direcion)
|
2018-05-10 19:50:31 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
Node *relativeNode_;
|
|
|
|
Direction direction_;
|
2018-05-10 19:50:31 +02:00
|
|
|
|
|
|
|
friend struct Node;
|
|
|
|
friend class SplitContainer;
|
|
|
|
};
|
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
private:
|
2018-05-24 17:13:46 +02:00
|
|
|
struct DropRect final {
|
2018-05-10 19:50:31 +02:00
|
|
|
QRect rect;
|
|
|
|
Position position;
|
|
|
|
|
|
|
|
DropRect(const QRect &_rect, const Position &_position)
|
|
|
|
: rect(_rect)
|
|
|
|
, position(_position)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-24 17:13:46 +02:00
|
|
|
struct ResizeRect final {
|
2018-05-16 14:55:45 +02:00
|
|
|
QRect rect;
|
|
|
|
Node *node;
|
|
|
|
bool vertical;
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
ResizeRect(const QRect &_rect, Node *_node, bool _vertical)
|
|
|
|
: rect(_rect)
|
|
|
|
, node(_node)
|
|
|
|
, vertical(_vertical)
|
2018-05-10 19:50:31 +02:00
|
|
|
{
|
|
|
|
}
|
2018-05-16 14:55:45 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
2018-05-10 19:50:31 +02:00
|
|
|
|
|
|
|
private:
|
2018-05-16 14:55:45 +02:00
|
|
|
Node();
|
|
|
|
Node(Split *_split, Node *_parent);
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
bool isOrContainsNode(Node *_node);
|
|
|
|
Node *findNodeContainingSplit(Split *_split);
|
|
|
|
void insertSplitRelative(Split *_split, Direction _direction);
|
|
|
|
void nestSplitIntoCollection(Split *_split, Direction _direction);
|
2018-07-06 19:23:47 +02:00
|
|
|
void insertNextToThis(Split *_split, Direction _direction);
|
2018-05-16 14:55:45 +02:00
|
|
|
void setSplit(Split *_split);
|
|
|
|
Position releaseSplit();
|
|
|
|
qreal getFlex(bool isVertical);
|
|
|
|
qreal getSize(bool isVertical);
|
|
|
|
qreal getChildrensTotalFlex(bool isVertical);
|
2018-08-06 21:17:03 +02:00
|
|
|
void layout(bool addSpacing, float _scale,
|
|
|
|
std::vector<DropRect> &dropRects_,
|
2018-05-16 14:55:45 +02:00
|
|
|
std::vector<ResizeRect> &resizeRects);
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
static Type toContainerType(Direction _dir);
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
Type type_;
|
|
|
|
Split *split_;
|
|
|
|
Node *preferedFocusTarget_;
|
|
|
|
Node *parent_;
|
|
|
|
QRectF geometry_;
|
|
|
|
qreal flexH_ = 1;
|
|
|
|
qreal flexV_ = 1;
|
|
|
|
std::vector<std::unique_ptr<Node>> children_;
|
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
friend class SplitContainer;
|
|
|
|
};
|
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
private:
|
2018-05-24 17:13:46 +02:00
|
|
|
class DropOverlay final : public QWidget
|
2018-05-10 23:58:07 +02:00
|
|
|
{
|
|
|
|
public:
|
2018-05-16 14:55:45 +02:00
|
|
|
DropOverlay(SplitContainer *_parent = nullptr);
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
void setRects(std::vector<SplitContainer::DropRect> _rects);
|
2018-05-10 23:58:07 +02:00
|
|
|
|
|
|
|
pajlada::Signals::NoArgSignal dragEnded;
|
|
|
|
|
|
|
|
protected:
|
2018-05-16 14:55:45 +02:00
|
|
|
void paintEvent(QPaintEvent *event) override;
|
2018-05-24 17:13:46 +02:00
|
|
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
|
|
|
void dragMoveEvent(QDragMoveEvent *event) override;
|
|
|
|
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
|
|
|
void dropEvent(QDropEvent *event) override;
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
private:
|
2018-07-06 19:23:47 +02:00
|
|
|
std::vector<DropRect> rects_;
|
|
|
|
QPoint mouseOverPoint_;
|
|
|
|
SplitContainer *parent_;
|
2018-05-16 14:55:45 +02:00
|
|
|
};
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2018-05-24 17:13:46 +02:00
|
|
|
class ResizeHandle final : public QWidget
|
2018-05-16 14:55:45 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
SplitContainer *parent;
|
|
|
|
Node *node;
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
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;
|
2018-07-04 19:52:11 +02:00
|
|
|
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
2018-05-10 23:58:07 +02:00
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
friend class SplitContainer;
|
2018-05-10 23:58:07 +02:00
|
|
|
|
|
|
|
private:
|
2018-08-07 23:46:00 +02:00
|
|
|
void resetFlex();
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
bool vertical_;
|
|
|
|
bool isMouseDown_ = false;
|
2018-05-10 23:58:07 +02:00
|
|
|
};
|
|
|
|
|
2018-05-16 14:55:45 +02:00
|
|
|
public:
|
2018-05-23 11:59:37 +02:00
|
|
|
SplitContainer(Notebook *parent);
|
2017-06-26 16:41:20 +02:00
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
void appendNewSplit(bool openChannelNameDialog);
|
|
|
|
void appendSplit(Split *split);
|
|
|
|
void insertSplit(Split *split, const Position &position);
|
|
|
|
void insertSplit(Split *split, Direction direction, Split *relativeTo);
|
2018-08-06 21:17:03 +02:00
|
|
|
void insertSplit(Split *split, Direction direction,
|
|
|
|
Node *relativeTo = nullptr);
|
2018-05-10 19:50:31 +02:00
|
|
|
Position releaseSplit(Split *split);
|
|
|
|
Position deleteSplit(Split *split);
|
|
|
|
|
2018-05-25 14:57:17 +02:00
|
|
|
void selectNextSplit(Direction direction);
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-25 14:57:17 +02:00
|
|
|
void decodeFromJson(QJsonObject &obj);
|
2018-05-10 19:50:31 +02:00
|
|
|
|
2018-05-25 14:57:17 +02:00
|
|
|
int getSplitCount();
|
|
|
|
const std::vector<Split *> getSplits() const;
|
2018-05-10 19:50:31 +02:00
|
|
|
void refreshTabTitle();
|
2018-05-23 11:59:37 +02:00
|
|
|
NotebookTab *getTab() const;
|
2018-05-25 14:57:17 +02:00
|
|
|
Node *getBaseNode();
|
2017-01-16 03:15:07 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
void setTab(NotebookTab *tab_);
|
2018-05-25 16:11:03 +02:00
|
|
|
void hideResizeHandles();
|
2018-06-01 14:46:41 +02:00
|
|
|
void resetMouseStatus();
|
2018-05-23 04:22:17 +02:00
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
static bool isDraggingSplit;
|
|
|
|
static Split *draggingSplit;
|
2017-11-12 17:21:50 +01:00
|
|
|
|
2016-12-30 18:00:25 +01:00
|
|
|
protected:
|
2018-04-07 12:53:10 +02:00
|
|
|
void paintEvent(QPaintEvent *event) override;
|
2017-01-01 02:30:42 +01:00
|
|
|
|
2018-05-31 16:02:20 +02:00
|
|
|
void focusInEvent(QFocusEvent *event) override;
|
2018-05-10 23:58:07 +02:00
|
|
|
void leaveEvent(QEvent *event) override;
|
|
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
2018-04-07 12:53:10 +02:00
|
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
2017-01-01 13:07:36 +01:00
|
|
|
|
2018-04-07 12:53:10 +02:00
|
|
|
void dragEnterEvent(QDragEnterEvent *event) override;
|
2017-01-01 02:30:42 +01:00
|
|
|
|
2018-05-10 19:50:31 +02:00
|
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
|
|
|
2017-04-12 17:46:44 +02:00
|
|
|
private:
|
2018-07-06 19:23:47 +02:00
|
|
|
void layout();
|
|
|
|
void setSelected(Split *selected_);
|
|
|
|
void selectSplitRecursive(Node *node, Direction direction);
|
|
|
|
void focusSplitRecursive(Node *node, Direction direction);
|
|
|
|
void setPreferedTargetRecursive(Node *node);
|
|
|
|
|
|
|
|
void addSplit(Split *split);
|
|
|
|
|
|
|
|
void decodeNodeRecusively(QJsonObject &obj, Node *node);
|
2018-09-04 21:39:54 +02:00
|
|
|
Split *getTopRightSplit(Node &node);
|
2018-07-06 19:23:47 +02:00
|
|
|
|
2017-01-11 18:52:09 +01:00
|
|
|
struct DropRegion {
|
2017-01-01 02:30:42 +01:00
|
|
|
QRect rect;
|
|
|
|
std::pair<int, int> position;
|
|
|
|
|
|
|
|
DropRegion(QRect rect, std::pair<int, int> position)
|
|
|
|
{
|
|
|
|
this->rect = rect;
|
|
|
|
this->position = position;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
std::vector<DropRect> dropRects_;
|
|
|
|
std::vector<DropRegion> dropRegions_;
|
|
|
|
DropOverlay overlay_;
|
|
|
|
std::vector<std::unique_ptr<ResizeHandle>> resizeHandles_;
|
|
|
|
QPoint mouseOverPoint_;
|
2018-05-24 17:13:46 +02:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
Node baseNode_;
|
|
|
|
Split *selected_;
|
2018-09-04 21:39:54 +02:00
|
|
|
Split *topRight_{};
|
2017-01-16 03:15:07 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
NotebookTab *tab_;
|
|
|
|
std::vector<Split *> splits_;
|
2017-01-01 02:30:42 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
bool isDragging_ = false;
|
2016-12-29 17:31:07 +01:00
|
|
|
};
|
2017-01-28 22:35:23 +01:00
|
|
|
|
2017-04-14 17:52:22 +02:00
|
|
|
} // namespace chatterino
|