|
| 1 | +// Copyright (c) Epic Games Tools |
| 2 | +// Licensed under the MIT license (https://opensource.org/license/mit/) |
| 3 | + |
| 4 | +internal CFG_Node * |
| 5 | +cfg_window_from_cfg(CFG_Node *cfg) |
| 6 | +{ |
| 7 | + CFG_Node *result = &cfg_nil_node; |
| 8 | + for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent) |
| 9 | + { |
| 10 | + if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0)) |
| 11 | + { |
| 12 | + result = c; |
| 13 | + break; |
| 14 | + } |
| 15 | + } |
| 16 | + return result; |
| 17 | +} |
| 18 | + |
| 19 | +internal CFG_PanelTree |
| 20 | +cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root) |
| 21 | +{ |
| 22 | + Temp scratch = scratch_begin(&arena, 1); |
| 23 | + CFG_Node *wcfg = cfg_window_from_cfg(cfg_root); |
| 24 | + CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels")); |
| 25 | + CFG_PanelNode *dst_root = &cfg_nil_panel_node; |
| 26 | + CFG_PanelNode *dst_focused = &cfg_nil_panel_node; |
| 27 | + { |
| 28 | + Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y; |
| 29 | + CFG_NodeRec rec = {0}; |
| 30 | + CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node; |
| 31 | + for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next) |
| 32 | + { |
| 33 | + // rjf: build a panel node |
| 34 | + CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1); |
| 35 | + MemoryCopyStruct(dst, &cfg_nil_panel_node); |
| 36 | + dst->parent = dst_active_parent; |
| 37 | + if(dst_active_parent != &cfg_nil_panel_node) |
| 38 | + { |
| 39 | + DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev); |
| 40 | + dst_active_parent->child_count += 1; |
| 41 | + } |
| 42 | + if(dst_root == &cfg_nil_panel_node) |
| 43 | + { |
| 44 | + dst_root = dst; |
| 45 | + } |
| 46 | + |
| 47 | + // rjf: extract cfg info |
| 48 | + B32 panel_has_children = 0; |
| 49 | + dst->cfg = src; |
| 50 | + dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string)); |
| 51 | + dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min); |
| 52 | + dst->split_axis = active_split_axis; |
| 53 | + for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next) |
| 54 | + { |
| 55 | + MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string); |
| 56 | + if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) |
| 57 | + { |
| 58 | + panel_has_children = 1; |
| 59 | + } |
| 60 | + else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0)) |
| 61 | + { |
| 62 | + // NOTE(rjf): skip - this is a panel option. |
| 63 | + } |
| 64 | + else if(str8_match(src_child->string, str8_lit("selected"), 0)) |
| 65 | + { |
| 66 | + dst_focused = dst; |
| 67 | + } |
| 68 | + else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier) |
| 69 | + { |
| 70 | + cfg_node_ptr_list_push(arena, &dst->tabs, src_child); |
| 71 | + if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node) |
| 72 | + { |
| 73 | + dst->selected_tab = src_child; |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + // rjf: recurse |
| 79 | + rec = cfg_node_rec__depth_first(src_root, src); |
| 80 | + if(!panel_has_children) |
| 81 | + { |
| 82 | + MemoryZeroStruct(&rec); |
| 83 | + rec.next = &cfg_nil_node; |
| 84 | + for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1) |
| 85 | + { |
| 86 | + if(p->next != &cfg_nil_node) |
| 87 | + { |
| 88 | + rec.next = p->next; |
| 89 | + break; |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + if(rec.push_count > 0) |
| 94 | + { |
| 95 | + dst_active_parent = dst; |
| 96 | + active_split_axis = axis2_flip(active_split_axis); |
| 97 | + } |
| 98 | + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) |
| 99 | + { |
| 100 | + dst_active_parent = dst_active_parent->parent; |
| 101 | + active_split_axis = axis2_flip(active_split_axis); |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | + scratch_end(scratch); |
| 106 | + CFG_PanelTree tree = {dst_root, dst_focused}; |
| 107 | + return tree; |
| 108 | +} |
| 109 | + |
| 110 | +internal CFG_PanelNodeRec |
| 111 | +cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off) |
| 112 | +{ |
| 113 | + CFG_PanelNodeRec rec = {&cfg_nil_panel_node}; |
| 114 | + if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node) |
| 115 | + { |
| 116 | + rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off); |
| 117 | + rec.push_count += 1; |
| 118 | + } |
| 119 | + else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1) |
| 120 | + { |
| 121 | + if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node) |
| 122 | + { |
| 123 | + rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off); |
| 124 | + break; |
| 125 | + } |
| 126 | + } |
| 127 | + return rec; |
| 128 | +} |
| 129 | + |
| 130 | +internal CFG_PanelNode * |
| 131 | +cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg) |
| 132 | +{ |
| 133 | + CFG_PanelNode *result = &cfg_nil_panel_node; |
| 134 | + for(CFG_PanelNode *p = root; |
| 135 | + p != &cfg_nil_panel_node; |
| 136 | + p = cfg_panel_node_rec__depth_first_pre(root, p).next) |
| 137 | + { |
| 138 | + if(p->cfg == cfg) |
| 139 | + { |
| 140 | + result = p; |
| 141 | + break; |
| 142 | + } |
| 143 | + } |
| 144 | + return result; |
| 145 | +} |
| 146 | + |
| 147 | +internal Rng2F32 |
| 148 | +cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel) |
| 149 | +{ |
| 150 | + Rng2F32 rect = parent_rect; |
| 151 | + if(parent != &cfg_nil_panel_node) |
| 152 | + { |
| 153 | + Vec2F32 parent_rect_size = dim_2f32(parent_rect); |
| 154 | + Axis2 axis = parent->split_axis; |
| 155 | + rect.p1.v[axis] = rect.p0.v[axis]; |
| 156 | + for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next) |
| 157 | + { |
| 158 | + rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent; |
| 159 | + if(child == panel) |
| 160 | + { |
| 161 | + break; |
| 162 | + } |
| 163 | + rect.p0.v[axis] = rect.p1.v[axis]; |
| 164 | + } |
| 165 | + //rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; |
| 166 | + //rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; |
| 167 | + } |
| 168 | + rect.x0 = round_f32(rect.x0); |
| 169 | + rect.x1 = round_f32(rect.x1); |
| 170 | + rect.y0 = round_f32(rect.y0); |
| 171 | + rect.y1 = round_f32(rect.y1); |
| 172 | + return rect; |
| 173 | +} |
| 174 | + |
| 175 | +internal Rng2F32 |
| 176 | +cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel) |
| 177 | +{ |
| 178 | + Temp scratch = scratch_begin(0, 0); |
| 179 | + |
| 180 | + // rjf: count ancestors |
| 181 | + U64 ancestor_count = 0; |
| 182 | + for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent) |
| 183 | + { |
| 184 | + ancestor_count += 1; |
| 185 | + } |
| 186 | + |
| 187 | + // rjf: gather ancestors |
| 188 | + CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count); |
| 189 | + { |
| 190 | + U64 ancestor_idx = 0; |
| 191 | + for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent) |
| 192 | + { |
| 193 | + ancestors[ancestor_idx] = p; |
| 194 | + ancestor_idx += 1; |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + // rjf: go from highest ancestor => panel and calculate rect |
| 199 | + Rng2F32 parent_rect = root_rect; |
| 200 | + for(S64 ancestor_idx = (S64)ancestor_count-1; |
| 201 | + 0 <= ancestor_idx && ancestor_idx < ancestor_count; |
| 202 | + ancestor_idx -= 1) |
| 203 | + { |
| 204 | + CFG_PanelNode *ancestor = ancestors[ancestor_idx]; |
| 205 | + CFG_PanelNode *parent = ancestor->parent; |
| 206 | + if(parent != &cfg_nil_panel_node) |
| 207 | + { |
| 208 | + parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor); |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + // rjf: calculate final rect |
| 213 | + Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel); |
| 214 | + |
| 215 | + scratch_end(scratch); |
| 216 | + return rect; |
| 217 | +} |
0 commit comments