Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
SplitTree.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include <phosphortiles_export.h>
7
8#include "AutotileConstants.h"
9
10#include <QJsonObject>
11#include <QRect>
12#include <QString>
13#include <QStringList>
14#include <QVector>
15
16#include <memory>
17
18namespace PhosphorTiles {
19
26struct PHOSPHORTILES_EXPORT SplitNode
27{
28 qreal splitRatio = AutotileDefaults::DefaultSplitRatio;
29 bool splitHorizontal = false;
30 std::unique_ptr<SplitNode> first;
31 std::unique_ptr<SplitNode> second;
32 SplitNode* parent = nullptr;
33 QString windowId;
34
35 bool isLeaf() const
36 {
37 return !first && !second;
38 }
39};
40
57class PHOSPHORTILES_EXPORT SplitTree
58{
59public:
66 enum class Edge {
67 Left,
68 Right,
69 Top,
70 Bottom
71 };
72
75
77 SplitTree(SplitTree&& other) noexcept;
78
80 SplitTree& operator=(SplitTree&& other) noexcept;
81
83
84 // Non-copyable (unique_ptr members)
85 SplitTree(const SplitTree&) = delete;
86 SplitTree& operator=(const SplitTree&) = delete;
87
88 // ═══════════════════════════════════════════════════════════════════════
89 // Queries
90 // ═══════════════════════════════════════════════════════════════════════
91
96 const SplitNode* root() const noexcept;
97 SplitNode* root() noexcept;
98
102 bool isEmpty() const noexcept;
103
107 int leafCount() const noexcept;
108
113 int treeHeight() const noexcept;
114
120 const SplitNode* leafForWindow(const QString& windowId) const;
121 SplitNode* leafForWindow(const QString& windowId);
122
127 QStringList leafOrder() const;
128
129 // ═══════════════════════════════════════════════════════════════════════
130 // Mutations
131 // ═══════════════════════════════════════════════════════════════════════
132
142 void insertAtFocused(const QString& windowId, const QString& focusedWindowId, qreal initialRatio = 0.0);
143
152 void insertAtEnd(const QString& windowId, qreal initialRatio = 0.0);
153
164 void insertAtPosition(const QString& windowId, int position, qreal initialRatio = 0.0);
165
170 void remove(const QString& windowId);
171
181 void swap(const QString& windowId1, const QString& windowId2);
182
201 bool swapLeaves(const QString& a, const QString& b);
202
208 void resizeSplit(const QString& windowId, qreal newRatio);
209
221 void resizeSplitNode(SplitNode* node, qreal newRatio);
222
240 const SplitNode* splitOwningEdge(const QString& windowId, Edge edge) const;
241 SplitNode* splitOwningEdge(const QString& windowId, Edge edge);
242
243 // ═══════════════════════════════════════════════════════════════════════
244 // Geometry
245 // ═══════════════════════════════════════════════════════════════════════
246
261 QVector<QRect> applyGeometry(const QRect& area, int innerGap) const;
262
272 bool rebuildFromOrder(const QStringList& tiledWindows,
273 qreal defaultSplitRatio = AutotileDefaults::DefaultSplitRatio);
274
275 // ═══════════════════════════════════════════════════════════════════════
276 // Serialization
277 // ═══════════════════════════════════════════════════════════════════════
278
282 QJsonObject toJson() const;
283
289 static std::unique_ptr<SplitTree> fromJson(const QJsonObject& json);
290
291private:
292 enum class InsertReady {
293 Proceed,
294 Done,
295 Rejected
296 };
300 static constexpr int MaxRuntimeTreeDepth = AutotileDefaults::MaxRuntimeTreeDepth;
301
302 InsertReady prepareInsert(const QString& windowId);
303
305 void insertAtEndRaw(const QString& windowId, qreal initialRatio);
306
308 void insertAtEndImpl(const QString& windowId, qreal initialRatio);
309
310 std::unique_ptr<SplitNode> m_root;
311
312 SplitNode* findLeaf(SplitNode* node, const QString& windowId, int depth = 0) const;
313 const SplitNode* findLeaf(const SplitNode* node, const QString& windowId, int depth = 0) const;
314 SplitNode* leafAtIndex(SplitNode* node, int targetIndex, int& currentIndex, int depth = 0) const;
315 const SplitNode* leafAtIndex(const SplitNode* node, int targetIndex, int& currentIndex, int depth = 0) const;
316 SplitNode* rightmostLeaf(SplitNode* node) const;
317 const SplitNode* rightmostLeaf(const SplitNode* node) const;
318 void collectLeafOrder(const SplitNode* node, QStringList& order, int depth = 0) const;
319 int countLeaves(const SplitNode* node, int depth = 0) const;
320 void applyGeometryRecursive(const SplitNode* node, const QRect& rect, int innerGap, QVector<QRect>& zones,
321 int depth = 0) const;
322
323 static int subtreeHeight(const SplitNode* node, int depth = 0);
324 static void splitLeaf(SplitNode* leaf, const QString& newId, qreal ratio);
325
326 static constexpr int MaxDeserializationDepth = AutotileDefaults::MaxRuntimeTreeDepth;
327 static constexpr int MaxDeserializationNodes = 1024;
328
329 static QJsonObject nodeToJson(const SplitNode* node, int depth = 0);
330 static std::unique_ptr<SplitNode> nodeFromJson(const QJsonObject& json, SplitNode* parent, int depth,
331 int& nodeCount, int& clampedRatios, QSet<QString>& seenIds);
332};
333
334} // namespace PhosphorTiles
Algorithm-layer constants for the autotile/tile primitives.
A binary split tree for interactive window tiling.
Definition SplitTree.h:58
SplitTree(SplitTree &&other) noexcept
Move constructor.
const SplitNode * root() const noexcept
Get the root node of the tree.
SplitTree & operator=(const SplitTree &)=delete
Edge
A geometric edge of a window's rectangle.
Definition SplitTree.h:66
SplitTree & operator=(SplitTree &&other) noexcept
Move assignment.
SplitTree()
Construct an empty tree (no root)
SplitTree(const SplitTree &)=delete
Definition AutotileEngine.h:46
A single node in the binary split tree.
Definition SplitTree.h:27
std::unique_ptr< SplitNode > second
Second child (right or bottom)
Definition SplitTree.h:31
bool isLeaf() const
Definition SplitTree.h:35
std::unique_ptr< SplitNode > first
First child (left or top)
Definition SplitTree.h:30
QString windowId
Non-empty only for leaf nodes.
Definition SplitTree.h:33