yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dock_tree.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_LAYOUT_LAYOUT_DESIGNER_DOCK_TREE_H_
2#define YAZE_APP_EDITOR_LAYOUT_LAYOUT_DESIGNER_DOCK_TREE_H_
3
4#include <cstdint>
5#include <memory>
6#include <string>
7#include <vector>
8
9namespace yaze {
10namespace editor {
11namespace layout_designer {
12
13// Stable per-node identity. Allocated at factory time from a process-wide
14// monotonic counter so ids are unique across all live DockTrees in a
15// session. Survives Clone, JSON round-trip, and structural mutations,
16// which is what lets the Layout Designer hold selection by id rather than
17// raw `DockNode*`.
18//
19// Reserve 0 as the "invalid / unset" sentinel — every real node has id
20// >= 1.
21using DockNodeId = std::uint64_t;
22inline constexpr DockNodeId kInvalidDockNodeId = 0;
23
24namespace internal {
25
26// Returns a fresh, never-before-used DockNodeId. Thread-safe.
28
29// Bump the internal counter so subsequent AllocateDockNodeId() calls
30// return values strictly greater than `id`. Called by the JSON parser
31// for every parsed id so newly-allocated nodes don't collide with
32// loaded ones. No-op when `id` is kInvalidDockNodeId or already below
33// the current counter.
35
36} // namespace internal
37
38// Dock split direction. Independent of ImGuiDir so the data model and its
39// JSON representation don't require imgui.h; LayoutManager converts at the
40// DockBuilder boundary.
41enum class SplitDirection : std::uint8_t {
42 kLeft,
43 kRight,
44 kUp,
45 kDown,
46};
47
48// A single panel referenced by the tree. `panel_id` is the stable id
49// registered via REGISTER_PANEL (e.g. "dungeon.room_selector");
50// `display_name` + `icon` are cached at capture/authoring time so the
51// designer can render the palette/canvas without consulting the live
52// panel registry.
53struct PanelEntry {
54 std::string panel_id;
55 std::string display_name;
56 std::string icon;
57};
58
59// A node in the dock tree. Either a leaf (a tab group of panels) or a
60// split (direction + ratio + two children).
61struct DockNode {
62 enum class Type : std::uint8_t { kLeaf, kSplit };
63
64 // Stable id, allocated at factory time. Default-constructed DockNodes
65 // (e.g. via `DockNode n;`) have id == kInvalidDockNodeId; the factories
66 // (`MakeLeaf` / `MakeSplit`) and `Clone()` set it to a real value.
68
70
71 // kLeaf fields.
72 std::vector<PanelEntry> panels;
74
75 // kSplit fields.
77 float split_ratio = 0.5f;
78 std::unique_ptr<DockNode> child_a; // left / top
79 std::unique_ptr<DockNode> child_b; // right / bottom
80
81 DockNode() = default;
82
83 // Factories (clearer than member-by-member init in callers/tests).
84 static std::unique_ptr<DockNode> MakeLeaf(std::vector<PanelEntry> panels);
85 static std::unique_ptr<DockNode> MakeSplit(SplitDirection dir, float ratio,
86 std::unique_ptr<DockNode> a,
87 std::unique_ptr<DockNode> b);
88
89 // Deep copy.
90 std::unique_ptr<DockNode> Clone() const;
91
92 // Turn this leaf into a split. Current panels + active_tab_index migrate
93 // to the opposite side; `new_child` occupies the other side.
94 // `new_child_first == true` puts it at child_a (left/top). Must be called
95 // on a leaf.
96 void SplitInPlace(SplitDirection dir, float ratio,
97 std::unique_ptr<DockNode> new_child, bool new_child_first);
98
99 // If this is a split with exactly one non-null child, replace self with
100 // that child's contents and return true. No-op otherwise.
101 bool PromoteSingleChild();
102
103 // Depth-first search for a panel by id. Returns nullptr when absent.
104 const PanelEntry* FindPanel(const std::string& panel_id) const;
105};
106
107// A named dock tree ready to be serialized and re-applied.
108struct DockTree {
109 std::string name;
110 std::string description;
111 // schema_version 2 added stable per-node `DockNodeId`. v1 JSON (no
112 // ids) still parses — the loader allocates fresh ids for nodes that
113 // lack them.
114 std::uint64_t schema_version = 2;
115 std::unique_ptr<DockNode> root; // Always non-null after construction.
116
117 DockTree();
118 explicit DockTree(std::string name);
119
120 DockTree Clone() const;
121
122 // Validate structural invariants. On first failure writes a human-
123 // readable message into `*error` (if non-null) and returns false.
124 //
125 // Checks:
126 // - root is non-null
127 // - every kSplit node has non-null child_a and child_b
128 // - every kSplit's split_ratio is in [0.05, 0.95]
129 // - every kLeaf's active_tab_index is 0 (for empty leaves) or in
130 // [0, panels.size())
131 // - every PanelEntry.panel_id is non-empty and unique across the tree
132 bool Validate(std::string* error) const;
133
134 // Linear DFS lookup by stable id. Returns nullptr when `id` is
135 // kInvalidDockNodeId or not present in this tree. The non-const
136 // overload returns a mutable pointer for callers that need to write
137 // back (e.g. the split-boundary drag path on the active node).
138 const DockNode* FindNode(DockNodeId id) const;
140};
141
142// Returns an empty single-leaf tree. Equivalent to `DockTree(name)` but
143// reads cleanly at call sites that want "a blank canvas".
144DockTree MakeEmptyTree(std::string name = "Untitled");
145
146} // namespace layout_designer
147} // namespace editor
148} // namespace yaze
149
150#endif // YAZE_APP_EDITOR_LAYOUT_LAYOUT_DESIGNER_DOCK_TREE_H_
DockTree MakeEmptyTree(std::string name)
Definition dock_tree.cc:262
constexpr DockNodeId kInvalidDockNodeId
Definition dock_tree.h:22
Represents a dock node in the layout tree.
Definition dock_tree.h:61
const PanelEntry * FindPanel(const std::string &panel_id) const
Definition dock_tree.cc:120
static std::unique_ptr< DockNode > MakeLeaf(std::vector< PanelEntry > panels)
Definition dock_tree.cc:44
std::unique_ptr< DockNode > child_a
Definition dock_tree.h:78
std::unique_ptr< DockNode > child_b
Definition dock_tree.h:79
static std::unique_ptr< DockNode > MakeSplit(SplitDirection dir, float ratio, std::unique_ptr< DockNode > a, std::unique_ptr< DockNode > b)
Definition dock_tree.cc:53
std::unique_ptr< DockNode > Clone() const
Definition dock_tree.cc:66
std::vector< PanelEntry > panels
Definition dock_tree.h:72
void SplitInPlace(SplitDirection dir, float ratio, std::unique_ptr< DockNode > new_child, bool new_child_first)
Definition dock_tree.cc:84
std::unique_ptr< DockNode > root
Definition dock_tree.h:115
bool Validate(std::string *error) const
Definition dock_tree.cc:222
const DockNode * FindNode(DockNodeId id) const
Definition dock_tree.cc:251