5#include <unordered_set>
11namespace layout_designer {
24 return g_next_dock_node_id.fetch_add(1, std::memory_order_relaxed);
32 DockNodeId expected = g_next_dock_node_id.load(std::memory_order_relaxed);
33 while (expected <=
id) {
34 if (g_next_dock_node_id.compare_exchange_weak(expected,
id + 1,
35 std::memory_order_relaxed)) {
45 auto node = std::make_unique<DockNode>();
48 node->panels = std::move(
panels);
49 node->active_tab_index = 0;
54 std::unique_ptr<DockNode> a,
55 std::unique_ptr<DockNode> b) {
56 auto node = std::make_unique<DockNode>();
59 node->split_direction = dir;
60 node->split_ratio = ratio;
61 node->child_a = std::move(a);
62 node->child_b = std::move(b);
67 auto copy = std::make_unique<DockNode>();
78 copy->child_a =
child_a->Clone();
80 copy->child_b =
child_b->Clone();
85 std::unique_ptr<DockNode> new_child,
86 bool new_child_first) {
87 auto saved_panels = std::move(
panels);
96 auto existing_leaf =
MakeLeaf(std::move(saved_panels));
97 existing_leaf->active_tab_index = saved_tab;
99 if (new_child_first) {
100 child_a = std::move(new_child);
101 child_b = std::move(existing_leaf);
103 child_a = std::move(existing_leaf);
104 child_b = std::move(new_child);
116 *
this = std::move(*surviving);
122 for (
const auto& p :
panels) {
123 if (p.panel_id == panel_id)
129 if (
const auto* hit =
child_a->FindPanel(panel_id))
133 if (
const auto* hit =
child_b->FindPanel(panel_id))
142 : name(std::move(n)), root(
DockNode::MakeLeaf({})) {}
157 std::unordered_set<std::string>* seen_panel_ids,
158 std::unordered_set<DockNodeId>* seen_node_ids,
159 std::string* error) {
167 *error =
"node has invalid id (kInvalidDockNodeId)";
170 if (!seen_node_ids->insert(node.
id).second) {
172 *error =
"duplicate node id: " + std::to_string(node.
id);
177 const int n =
static_cast<int>(node.
panels.size());
181 *error =
"empty leaf has non-zero active_tab_index";
186 *error =
"active_tab_index out of range";
189 for (
const auto& p : node.
panels) {
190 if (p.panel_id.empty()) {
192 *error =
"panel has empty panel_id";
195 auto inserted = seen_panel_ids->insert(p.panel_id);
196 if (!inserted.second) {
198 *error =
"panel id '" + p.panel_id +
"' appears twice";
208 *error =
"split node has null child";
213 *error =
"split_ratio out of range [0.05, 0.95]";
225 *error =
"tree has null root";
228 std::unordered_set<std::string> seen_panel_ids;
229 std::unordered_set<DockNodeId> seen_node_ids;
230 return ValidateNode(*
root, &seen_panel_ids, &seen_node_ids, error);
254 return FindNodeInSubtree(
root.get(),
id);
bool ValidateNode(const DockNode &node, std::unordered_set< std::string > *seen_panel_ids, std::unordered_set< DockNodeId > *seen_node_ids, std::string *error)
const DockNode * FindNodeInSubtree(const DockNode *node, DockNodeId id)
std::atomic< DockNodeId > g_next_dock_node_id
DockNodeId AllocateDockNodeId()
void ObserveDockNodeId(DockNodeId id)
DockTree MakeEmptyTree(std::string name)
constexpr DockNodeId kInvalidDockNodeId
Represents a dock node in the layout tree.
const PanelEntry * FindPanel(const std::string &panel_id) const
static std::unique_ptr< DockNode > MakeLeaf(std::vector< PanelEntry > panels)
bool PromoteSingleChild()
std::unique_ptr< DockNode > child_a
std::unique_ptr< DockNode > child_b
static std::unique_ptr< DockNode > MakeSplit(SplitDirection dir, float ratio, std::unique_ptr< DockNode > a, std::unique_ptr< DockNode > b)
SplitDirection split_direction
std::unique_ptr< DockNode > Clone() const
std::vector< PanelEntry > panels
void SplitInPlace(SplitDirection dir, float ratio, std::unique_ptr< DockNode > new_child, bool new_child_first)
std::unique_ptr< DockNode > root
std::uint64_t schema_version
bool Validate(std::string *error) const
const DockNode * FindNode(DockNodeId id) const