Chatterino
SplitContainer.hpp
Go to the documentation of this file.
1 #pragma once
2 
4 #include "widgets/BaseWidget.hpp"
5 
6 #include <QDragEnterEvent>
7 #include <QHBoxLayout>
8 #include <QRect>
9 #include <QVBoxLayout>
10 #include <QVector>
11 #include <QWidget>
12 
13 #include <algorithm>
14 #include <functional>
15 #include <pajlada/signals/signal.hpp>
16 #include <pajlada/signals/signalholder.hpp>
17 #include <unordered_map>
18 #include <vector>
19 
20 class QJsonObject;
21 
22 namespace chatterino {
23 
24 class Split;
25 class NotebookTab;
26 class Notebook;
27 
28 //
29 // Note: This class is a spaghetti container. There is a lot of spaghetti code
30 // inside but it doesn't expose any of it publicly.
31 //
32 
33 class SplitContainer final : public BaseWidget
34 {
35  Q_OBJECT
36 
37 public:
38  struct Node;
39 
40  // fourtf: !!! preserve the order of left, up, right and down
42 
43  struct Position final {
44  private:
45  Position() = default;
46  Position(Node *relativeNode, Direction direcion)
47  : relativeNode_(relativeNode)
48  , direction_(direcion)
49  {
50  }
51 
52  Node *relativeNode_;
53  Direction direction_;
54 
55  friend struct Node;
56  friend class SplitContainer;
57  };
58 
59 private:
60  struct DropRect final {
61  QRect rect;
62  Position position;
63 
64  DropRect(const QRect &_rect, const Position &_position)
65  : rect(_rect)
66  , position(_position)
67  {
68  }
69  };
70 
71  struct ResizeRect final {
72  QRect rect;
73  Node *node;
74  bool vertical;
75 
76  ResizeRect(const QRect &_rect, Node *_node, bool _vertical)
77  : rect(_rect)
78  , node(_node)
79  , vertical(_vertical)
80  {
81  }
82  };
83 
84 public:
85  struct Node final {
86  enum Type { EmptyRoot, _Split, VerticalContainer, HorizontalContainer };
87 
88  Type getType();
89  Split *getSplit();
90  Node *getParent();
91  qreal getHorizontalFlex();
92  qreal getVerticalFlex();
93  const std::vector<std::unique_ptr<Node>> &getChildren();
94 
95  private:
96  Node();
97  Node(Split *_split, Node *_parent);
98 
99  bool isOrContainsNode(Node *_node);
100  Node *findNodeContainingSplit(Split *_split);
101  void insertSplitRelative(Split *_split, Direction _direction);
102  void nestSplitIntoCollection(Split *_split, Direction _direction);
103  void insertNextToThis(Split *_split, Direction _direction);
104  void setSplit(Split *_split);
106  qreal getFlex(bool isVertical);
107  qreal getSize(bool isVertical);
108  qreal getChildrensTotalFlex(bool isVertical);
109  void layout(bool addSpacing, float _scale,
110  std::vector<DropRect> &dropRects_,
111  std::vector<ResizeRect> &resizeRects);
112 
113  static Type toContainerType(Direction _dir);
114 
115  Type type_;
116  Split *split_;
117  Node *preferedFocusTarget_;
118  Node *parent_;
119  QRectF geometry_;
120  qreal flexH_ = 1;
121  qreal flexV_ = 1;
122  std::vector<std::unique_ptr<Node>> children_;
123 
124  friend class SplitContainer;
125  };
126 
127 private:
128  class DropOverlay final : public QWidget
129  {
130  public:
131  DropOverlay(SplitContainer *_parent = nullptr);
132 
133  void setRects(std::vector<SplitContainer::DropRect> _rects);
134 
135  pajlada::Signals::NoArgSignal dragEnded;
136 
137  protected:
138  void paintEvent(QPaintEvent *event) override;
139  void dragEnterEvent(QDragEnterEvent *event) override;
140  void dragMoveEvent(QDragMoveEvent *event) override;
141  void dragLeaveEvent(QDragLeaveEvent *event) override;
142  void dropEvent(QDropEvent *event) override;
143 
144  private:
145  std::vector<DropRect> rects_;
146  QPoint mouseOverPoint_;
147  SplitContainer *parent_;
148  };
149 
150  class ResizeHandle final : public QWidget
151  {
152  public:
153  SplitContainer *parent;
154  Node *node;
155 
156  void setVertical(bool isVertical);
157  ResizeHandle(SplitContainer *_parent = nullptr);
158  void paintEvent(QPaintEvent *event) override;
159  void mousePressEvent(QMouseEvent *event) override;
160  void mouseReleaseEvent(QMouseEvent *event) override;
161  void mouseMoveEvent(QMouseEvent *event) override;
162  void mouseDoubleClickEvent(QMouseEvent *event) override;
163 
164  friend class SplitContainer;
165 
166  private:
167  void resetFlex();
168 
169  bool vertical_;
170  bool isMouseDown_ = false;
171  };
172 
173 public:
174  SplitContainer(Notebook *parent);
175 
176  Split *appendNewSplit(bool openChannelNameDialog);
177  void appendSplit(Split *split);
178  void insertSplit(Split *split, const Position &position);
179  void insertSplit(Split *split, Direction direction, Split *relativeTo);
180  void insertSplit(Split *split, Direction direction,
181  Node *relativeTo = nullptr);
182  Split *getSelectedSplit() const;
183  Position releaseSplit(Split *split);
184  Position deleteSplit(Split *split);
185 
186  void selectNextSplit(Direction direction);
187  void setSelected(Split *selected_);
188 
189  int getSplitCount();
190  const std::vector<Split *> getSplits() const;
191 
192  void refreshTab();
193 
194  NotebookTab *getTab() const;
195  Node *getBaseNode();
196 
197  void setTab(NotebookTab *tab_);
198  void hideResizeHandles();
199  void resetMouseStatus();
200 
201  static bool isDraggingSplit;
203 
204  void applyFromDescriptor(const NodeDescriptor &rootNode);
205 
206  void popup();
207 
208 protected:
209  void paintEvent(QPaintEvent *event) override;
210 
211  void focusInEvent(QFocusEvent *event) override;
212  void leaveEvent(QEvent *event) override;
213  void mouseMoveEvent(QMouseEvent *event) override;
214  void mouseReleaseEvent(QMouseEvent *event) override;
215 
216  void dragEnterEvent(QDragEnterEvent *event) override;
217 
218  void resizeEvent(QResizeEvent *event) override;
219 
220 private:
221  void applyFromDescriptorRecursively(const NodeDescriptor &rootNode,
222  Node *node);
223 
224  void layout();
225  void selectSplitRecursive(Node *node, Direction direction);
226  void focusSplitRecursive(Node *node);
227  void setPreferedTargetRecursive(Node *node);
228 
229  void addSplit(Split *split);
230 
231  Split *getTopRightSplit(Node &node);
232 
233  void refreshTabTitle();
234  void refreshTabLiveStatus();
235 
236  struct DropRegion {
237  QRect rect;
238  std::pair<int, int> position;
239 
240  DropRegion(QRect rect, std::pair<int, int> position)
241  {
242  this->rect = rect;
243  this->position = position;
244  }
245  };
246 
247  std::vector<DropRect> dropRects_;
248  std::vector<DropRegion> dropRegions_;
249  DropOverlay overlay_;
250  std::vector<std::unique_ptr<ResizeHandle>> resizeHandles_;
251  QPoint mouseOverPoint_;
252 
253  Node baseNode_;
254  Split *selected_{};
255  Split *topRight_{};
256  bool disableLayouting_{};
257 
258  NotebookTab *tab_;
259  std::vector<Split *> splits_;
260 
261  std::unordered_map<Split *, pajlada::Signals::SignalHolder>
262  connectionsPerSplit_;
263 
264  pajlada::Signals::SignalHolder signalHolder_;
265 
266  bool isDragging_ = false;
267 };
268 
269 } // namespace chatterino
Definition: SplitContainer.hpp:41
Node * getBaseNode()
Definition: SplitContainer.cpp:752
void appendSplit(Split *split)
Definition: SplitContainer.cpp:138
Definition: SplitContainer.hpp:43
Split * getSelectedSplit() const
Definition: SplitContainer.cpp:191
const std::vector< Split * > getSplits() const
Definition: SplitContainer.cpp:747
static Split * draggingSplit
Definition: SplitContainer.hpp:202
friend class SplitContainer
Definition: SplitContainer.hpp:56
Definition: SplitContainer.hpp:33
void hideResizeHandles()
Definition: SplitContainer.cpp:102
NotebookTab * getTab() const
Definition: SplitContainer.cpp:88
void selectNextSplit(Direction direction)
Definition: SplitContainer.cpp:356
void leaveEvent(QEvent *event) override
Definition: SplitContainer.cpp:716
Definition: Application.cpp:48
void mouseReleaseEvent(QMouseEvent *event) override
Definition: SplitContainer.cpp:570
Split * appendNewSplit(bool openChannelNameDialog)
Definition: SplitContainer.cpp:118
void popup()
Definition: SplitContainer.cpp:767
Direction
Definition: SplitContainer.hpp:41
std::variant< ContainerNodeDescriptor, SplitNodeDescriptor > NodeDescriptor
Definition: WindowDescriptors.hpp:58
Definition: SplitContainer.hpp:85
void paintEvent(QPaintEvent *event) override
Definition: SplitContainer.cpp:597
Definition: Split.hpp:36
Definition: SplitContainer.hpp:41
void focusInEvent(QFocusEvent *event) override
Definition: SplitContainer.cpp:722
Definition: NotebookTab.hpp:21
void mouseMoveEvent(QMouseEvent *event) override
Definition: SplitContainer.cpp:705
void refreshTab()
Definition: SplitContainer.cpp:736
Type
Definition: SplitContainer.hpp:86
friend struct Node
Definition: SplitContainer.hpp:55
Position deleteSplit(Split *split)
Definition: SplitContainer.cpp:344
Definition: SplitContainer.hpp:41
static bool isDraggingSplit
Definition: SplitContainer.hpp:201
void dragEnterEvent(QDragEnterEvent *event) override
Definition: SplitContainer.cpp:689
Definition: Notebook.hpp:22
void applyFromDescriptor(const NodeDescriptor &rootNode)
Definition: SplitContainer.cpp:757
void insertSplit(Split *split, const Position &position)
Definition: SplitContainer.cpp:143
Definition: SplitContainer.hpp:41
void setTab(NotebookTab *tab_)
Definition: SplitContainer.cpp:93
void resetMouseStatus()
Definition: SplitContainer.cpp:112
Definition: BaseWidget.hpp:14
void setSelected(Split *selected_)
Definition: SplitContainer.cpp:287
void resizeEvent(QResizeEvent *event) override
Definition: SplitContainer.cpp:563
int getSplitCount()
Definition: SplitContainer.cpp:742
Position releaseSplit(Split *split)
Definition: SplitContainer.cpp:315