5cells_init :: (tree_copy: []int, stat: *Statistics) {
6 row_count, col_count = dimensions(tree_copy.count);
7 create_cells(tree_copy, stat);
9 // Note: if we do hot reloading, we have to manage memory here!
10 this_allocation_is_not_a_leak(cells.data);
11}
13cells_fit_zoom :: () -> Camera2D {
14 width := col_count * CELL_WIDTH_HEIGHT;
15 height := row_count * CELL_WIDTH_HEIGHT;
17 center := Vector2.{ width / 2.0, height / 2.0 };
19 zoom_x := (SCREEN_WIDTH * 0.7) / width;
20 zoom_y := (SCREEN_HEIGHT * 0.7) / height;
21 fit_zoom := ifx zoom_x < zoom_y then zoom_x else zoom_y;
23 cam := camera;
24 cam.zoom = fit_zoom;
25 cam.offset = { SCREEN_WIDTH / 2.0, SCREEN_HEIGHT / 2.0 };
26 cam.target = center;
28 camera = cam;
29 return cam;
30}
32cells_draw_2d :: () {
33 assert(cells.count > 0, "Cell array empty");
35 first_cell := cells[0].rect;
36 last_cell := cells[cells.count-1].rect;
38 last_cell_in_first_row := cells[col_count].rect;
40 whole_cell: Rectangle; {
41 using whole_cell;
42 x = first_cell.x;
43 y = first_cell.y;
44 width = (last_cell_in_first_row.x + last_cell_in_first_row.width) - first_cell.x;
45 height = (last_cell.y + last_cell.width) - first_cell.y;
46 }
48 is_mouse_inside_any_cell := CheckCollisionPointRec(mouse_world, whole_cell);
50 for cells {
51 using it;
53 new_color := color;
55 inactive_color := color - { 0, 0, 0, 130 };
56 inactive_border := COLOR_CELLS_BORDER - { 0, 0, 0, 100 };
57 border_thickness := CELL_BORDER_THICK_NORMAL;
59 is_mouseover := CheckCollisionPointRec(mouse_world, rect);
61 if is_mouseover {
62 new_color += { 30, 30, 30, 0 };
63 border_thickness = CELL_BORDER_THICK_ACTIVE;
64 }
66 if is_mouse_inside_any_cell {
67 if is_mouseover {
68 DrawRectangleRec(rect, new_color);
69 DrawRectangleLinesEx(rect, border_thickness, COLOR_CELLS_BORDER_HIGHLIGHT);
70 } else {
71 DrawRectangleRec(rect, inactive_color);
72 DrawRectangleLinesEx(rect, border_thickness, inactive_border);
73 }
74 } else {
75 DrawRectangleRec(rect, new_color);
76 DrawRectangleLinesEx(rect, border_thickness, COLOR_CELLS_BORDER);
77 }
78 }
80 {
81 parent :: #code {
82 new_color := cell.color + COLOR_HIGHLIGHT0;
83 DrawRectangleRec(cell.rect, new_color);
84 }
86 child_left :: #code {
87 new_color := cell.color + COLOR_HIGHLIGHT0;
88 DrawRectangleRec(cell.rect, new_color);
89 }
91 child_right :: #code {
92 new_color := cell.color + COLOR_HIGHLIGHT0;
93 DrawRectangleRec(cell.rect, new_color);
94 }
96 draw_hover_cells(parent, child_left, child_right);
97 }
99 {
100 parent :: #code {
101 border_color := cell.color + COLOR_HIGHLIGHT2;
102 DrawRectangleLinesEx(
103 cell.rect,
104 CELL_BORDER_THICK_ACTIVE,
105 border_color
106 );
108 do_text(
109 "P",
110 { cell.rect.x, cell.rect.y },
111 CELL_INFO_FONT_SIZE,
112 .SOUTH_WEST,
113 border_color
114 );
115 }
117 child_left :: #code {
118 border_color := cell.color + COLOR_HIGHLIGHT2;
119 DrawRectangleLinesEx(
120 cell.rect,
121 CELL_BORDER_THICK_ACTIVE,
122 border_color
123 );
125 do_text(
126 "L",
127 { cell.rect.x, cell.rect.y },
128 CELL_INFO_FONT_SIZE,
129 .SOUTH_WEST,
130 border_color
131 );
132 }
134 child_right :: #code {
135 border_color := cell.color + COLOR_HIGHLIGHT2;
136 DrawRectangleLinesEx(
137 cell.rect,
138 CELL_BORDER_THICK_ACTIVE,
139 border_color
140 );
142 do_text(
143 "R",
144 { cell.rect.x, cell.rect.y },
145 CELL_INFO_FONT_SIZE,
146 .SOUTH_WEST,
147 border_color
148 );
149 }
151 draw_hover_cells(parent, child_left, child_right);
152 }
155 for cells {
156 using it;
158 do_text(label, { rect.x, rect.y }, 30, .CENTER, WHITE);
159 do_text(
160 tprint("%", it.index),
161 { rect.x, rect.y },
162 10,
163 .NORTH_WEST,
164 WHITE
165 );
166 }
167}
169cells_draw_screen :: (stats: *Statistics) {
170 gui_statistics(stats);
172 if !flag_has(.TOOLTIP) return;
174 for cells {
175 if !it.label continue;
176 if CheckCollisionPointRec(mouse_world, it.rect) {
177 text := tooltip_text(it_index, it.value);
178 tooltip(mouse_screen, text);
179 }
180 }
181}
184#scope_file
187cells: [..]Cell;
188row_count, col_count: int;
191CELL_INFO_FONT_SIZE :: 20;
192CELL_BORDER_THICK_NORMAL :: 1.0;
193CELL_BORDER_THICK_ACTIVE :: 2.0;
194CELL_WIDTH_HEIGHT :: 100.0;
195CELL_ASPECT_RATIO :float: #run 16.0 / 9.0;
196CELL_GAP :: 4.0;
199Cell :: struct {
200 index: int;
201 value: int;
202 rect: Rectangle;
203 label: string;
204 color: Color;
205}
207/** Overkill, but maybe we need it */
208Anchor :: enum {
209 CENTER;
210 NORTH;
211 EAST;
212 SOUTH;
213 WEST;
214 NORTH_EAST;
215 NORTH_WEST;
216 SOUTH_EAST;
217 SOUTH_WEST;
218}
221dimensions :: (length: int) -> (row: int, col: int) {
222 flen := cast(float, length);
223 row := ceil(sqrt(flen / CELL_ASPECT_RATIO));
224 col := ceil(flen / row);
225 return cast(int, row), cast(int, col);
226}
228cell_pos_from_index :: (index: int) -> Rectangle {
229 col := index % col_count;
230 row := index / col_count;
231 return .{
232 x = col * (CELL_WIDTH_HEIGHT + CELL_GAP),
233 y = row * (CELL_WIDTH_HEIGHT + CELL_GAP),
234 width = CELL_WIDTH_HEIGHT,
235 height = CELL_WIDTH_HEIGHT,
236 };
237}
239create_cells :: (tree: []int, stat: *Statistics) {
240 CELL_WITH_GAP :: #run CELL_WIDTH_HEIGHT + CELL_GAP;
242 rect: Rectangle;
243 rect.width = CELL_WIDTH_HEIGHT;
244 rect.height = CELL_WIDTH_HEIGHT;
245 rect.x = -CELL_WITH_GAP;
247 idx_col := col_count + 1;
249 for tree {
250 cell: Cell;
252 if idx_col {
253 rect.x += CELL_WITH_GAP;
254 idx_col -= 1;
255 } else {
256 rect.x = 0.0;
257 rect.y += CELL_WITH_GAP;
258 idx_col = col_count;
259 }
261 if it_index == 0 {
262 cell.label = "R";
263 cell.color = COLOR_NODE_ROOT;
264 stat.nodes += 1;
265 } else {
266 if it == {
267 case NODE_INTERNAL;
268 cell.label = "N";
269 cell.color = COLOR_NODE_INTERNAL;
270 stat.nodes += 1;
271 case NODE_EMPTY;
272 cell.color = COLOR_NODE_EMPTY;
273 stat.empty += 1;
274 case;
275 cell.label = tprint("%", it);
276 cell.color = COLOR_NODE_VALUE;
277 stat.children += 1;
278 }
279 }
281 cell.rect = rect;
282 cell.index = it_index;
283 cell.value = it;
284 array_add(*cells, cell);
285 }
286}
288draw_hover_cells :: (
289 $parent: Code,
290 $child_left: Code,
291 $child_right: Code,
292) {
293 for cells {
294 using it;
296 if CheckCollisionPointRec(mouse_world, rect) && label {
297 parent_idx := cast(int)floor((it_index - 1) / 2.0);
298 left_idx := 2 * it_index + 1;
299 right_idx := 2 * it_index + 2;
301 n := tree.count;
303 if it_index > 0 && cells[parent_idx].label {
304 cell := cells[parent_idx];
305 #insert,scope() parent;
306 }
307 if left_idx < n && cells[left_idx].label {
308 cell := cells[left_idx];
309 #insert,scope() child_left;
310 }
311 if right_idx < n && cells[right_idx].label {
312 cell := cells[right_idx];
313 #insert,scope() child_right;
314 }
315 }
317 }
318}
320do_text :: (text: string, pos: Vector2, size: s32, anchor: Anchor, color: Color) {
321 label_c := to_c_string(text);
322 tw := MeasureTextEx(GetFontDefault(), label_c, xx size, 1);
324 local_pos: Vector2;
325 PADDING :: Vector2.{ 6.0, 4.0 };
327 if anchor == {
328 case .CENTER;
329 local_pos.x = pos.x + (CELL_WIDTH_HEIGHT / 2.0) - (tw.x / 2.0);
330 local_pos.y = pos.y + (CELL_WIDTH_HEIGHT / 2.0) - (tw.y / 2.0);
331 case .NORTH;
332 local_pos = pos + { CELL_WIDTH_HEIGHT / 2.0 - (tw.x / 2.0), PADDING.y };
333 case .EAST;
334 local_pos = pos + {
335 CELL_WIDTH_HEIGHT - (tw.x + PADDING.x),
336 CELL_WIDTH_HEIGHT / 2.0 - (tw.y / 2.0)
337 };
338 case .SOUTH;
339 local_pos = pos + {
340 CELL_WIDTH_HEIGHT / 2.0 - (tw.x / 2.0),
341 (CELL_WIDTH_HEIGHT - PADDING.y - tw.y)
342 };
343 case .WEST;
344 local_pos = pos + {
345 PADDING.x,
346 CELL_WIDTH_HEIGHT / 2.0 - (tw.y / 2.0)
347 };
348 case .NORTH_EAST;
349 local_pos = pos + { CELL_WIDTH_HEIGHT - PADDING.x - tw.x, PADDING.y };
350 case .NORTH_WEST;
351 local_pos = pos + PADDING;
352 case .SOUTH_EAST;
353 local_pos = pos + {
354 CELL_WIDTH_HEIGHT - PADDING.x - tw.x,
355 CELL_WIDTH_HEIGHT - PADDING.y - tw.y
356 };
357 case .SOUTH_WEST;
358 local_pos = pos + {
359 PADDING.x,
360 CELL_WIDTH_HEIGHT - PADDING.y - tw.y
361 };
362 }
364 DrawText(
365 label_c,
366 xx local_pos.x,
367 xx local_pos.y,
368 size,
369 color
370 );
371}
index : binary-tree
---