Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_gui_tree_order.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
29
30#define ALLEGRO_UNSTABLE 1
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include "nilorea/n_common.h"
37#include "nilorea/n_gui.h"
38#include "nilorea/n_log.h"
39
40static int failures = 0;
41
42static void expect_true(const char* label, int cond) {
43 if (!cond) {
44 n_log(LOG_ERR, "%s: condition false", label);
45 failures++;
46 }
47}
48
49/* What the tree is showing, top to bottom, as labels. The listbox holds the
50 drawn text with its indent and its marker, so the node behind each row is
51 read through visible_map instead. */
52static void visible_labels(N_GUI_TREE* tree, const char** out, int max, int* count) {
53 int i = 0;
54 *count = 0;
55 for (i = 0; i < tree->nb_visible && i < max; i++)
56 out[(*count)++] = tree->nodes[tree->visible_map[i]].label;
57}
58
59static void expect_order(N_GUI_TREE* tree, const char* const* want, int n) {
60 const char* got[32];
61 int count = 0, i = 0;
62
63 visible_labels(tree, got, 32, &count);
64 if (count != n) {
65 n_log(LOG_ERR, "expected %d rows, got %d", n, count);
66 failures++;
67 for (i = 0; i < count; i++)
68 n_log(LOG_ERR, " row %d: %s", i, got[i]);
69 return;
70 }
71 for (i = 0; i < n; i++) {
72 if (strcmp(got[i], want[i]) != 0) {
73 n_log(LOG_ERR, "row %d: expected %s, got %s", i, want[i], got[i]);
74 failures++;
75 }
76 }
77}
78
79int main(int argc, char** argv) {
80 (void)argc;
81 (void)argv;
83
84 if (!al_init() || !al_init_font_addon()) {
85 n_log(LOG_ERR, "allegro init failed");
86 return 1;
87 }
88 ALLEGRO_FONT* font = al_create_builtin_font();
89 if (!font) {
90 n_log(LOG_ERR, "al_create_builtin_font failed");
91 return 1;
92 }
94 if (!gui) {
95 n_log(LOG_ERR, "n_gui_new_ctx failed");
96 al_destroy_font(font);
97 return 1;
98 }
99 n_gui_set_display_size(gui, 400.0f, 300.0f);
100
101 {
102 int win = n_gui_add_window(gui, "Panel", 0.0f, 0.0f, 300.0f, 260.0f);
103 N_GUI_TREE* tree = n_gui_tree_create(gui, win, 0.0f, 0.0f, 200.0f, 240.0f, NULL, NULL);
104 int home = -1, data = -1, music = -1, prog = -1, root = -1;
105
106 expect_true("tree created", tree != NULL);
107 if (!tree)
108 return 1;
109
110 /* Two roots and their children, added breadth first, which is what a
111 directory listing hands you: one readdir gives every child of one
112 folder and nothing below them. */
113 home = n_gui_tree_add_node(tree, "home", -1, NULL);
114 data = n_gui_tree_add_node(tree, "data", home, NULL);
115 music = n_gui_tree_add_node(tree, "music", home, NULL);
116 root = n_gui_tree_add_node(tree, "tmp", -1, NULL);
117 expect_true("nodes added", tree->nb_nodes == 4 && root == 3);
118
119 n_gui_tree_toggle_expand(tree, home);
120 expect_true("a child knows its depth", tree->nodes[music].depth == 1);
121 {
122 static const char* const want[] = {"home", "data", "music", "tmp"};
123 expect_order(tree, want, 4);
124 }
125
126 /* And now the case this file exists for: the folder is opened, so its
127 own children are read and added. They go on the end of the node
128 array, a long way after their parent, and they still have to be
129 drawn directly under it. */
130 prog = n_gui_tree_add_node(tree, "prog", data, NULL);
131 n_gui_tree_add_node(tree, "photos", data, NULL);
132 n_gui_tree_toggle_expand(tree, data);
133 {
134 static const char* const want[] = {"home", "data", "prog", "photos", "music",
135 "tmp"};
136 expect_order(tree, want, 6);
137 }
138
139 /* Two levels of it, because the bug this catches put every lazily
140 read level at the bottom in the order it was read, which looks
141 almost right until a second level is opened. */
142 n_gui_tree_add_node(tree, "afterapro", prog, NULL);
143 n_gui_tree_toggle_expand(tree, prog);
144 {
145 static const char* const want[] = {"home", "data", "prog", "afterapro",
146 "photos", "music", "tmp"};
147 expect_order(tree, want, 7);
148 }
149
150 /* A child of the second root, added last of all, belongs to it and
151 not to the first one. */
152 n_gui_tree_add_node(tree, "cache", root, NULL);
153 n_gui_tree_toggle_expand(tree, root);
154 {
155 static const char* const want[] = {"home", "data", "prog", "afterapro",
156 "photos", "music", "tmp", "cache"};
157 expect_order(tree, want, 8);
158 }
159
160 /* Folding a branch hides everything under it, however far down the
161 node array those children happen to live. */
162 n_gui_tree_toggle_expand(tree, data);
163 {
164 static const char* const want[] = {"home", "data", "music", "tmp", "cache"};
165 expect_order(tree, want, 5);
166 }
167
168 /* And the row the selection is on follows the node, not its index:
169 selecting the second root and asking which row it is on has to
170 answer the row it is drawn at. */
171 n_gui_tree_set_selection(tree, root);
172 expect_true("selection kept", n_gui_tree_get_selection(tree) == root);
173 expect_true("selection is on the row it is drawn at",
175 root);
176
177 n_gui_tree_free(&tree);
178 }
179
181 al_destroy_font(font);
182
183 if (failures)
184 printf("ex_gui_tree_order: FAILED, %d check(s)\n", failures);
185 else
186 printf("ex_gui_tree_order: ok\n");
187 return failures ? 1 : 0;
188}
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
static void expect_true(const char *label, int cond)
Definition ex_atlas.c:53
static N_GUI_CTX * gui
static void expect_order(N_GUI_TREE *tree, const char *const *want, int n)
static void visible_labels(N_GUI_TREE *tree, const char **out, int max, int *count)
FONT * font
the default 8x8 font, valid after allegro_init()
N_GUI_TREE_NODE nodes[2048]
node storage
Definition n_gui.h:3497
int listbox_id
listbox widget ID
Definition n_gui.h:3495
char label[128]
display text
Definition n_gui.h:3468
int visible_map[2048]
visible row to node index
Definition n_gui.h:3499
int nb_nodes
number of nodes
Definition n_gui.h:3498
int nb_visible
number of visible rows
Definition n_gui.h:3500
int depth
depth in tree (0 = root)
Definition n_gui.h:3471
void n_gui_set_display_size(N_GUI_CTX *ctx, float w, float h)
set the display (viewport) size so global scrollbars can be computed.
Definition n_gui.c:12348
int n_gui_listbox_get_selected(N_GUI_CTX *ctx, int widget_id)
get the index of the first selected item in a listbox
Definition n_gui.c:4455
void n_gui_tree_set_selection(N_GUI_TREE *tree, int node_index)
programmatically select a node; ancestors are expanded so the node is visible, and the listbox scroll...
Definition n_gui.c:17764
void n_gui_tree_free(N_GUI_TREE **tree)
free a tree view (does not destroy the N_GUI listbox)
Definition n_gui.c:17881
int n_gui_tree_get_selection(N_GUI_TREE *tree)
get the index of the currently selected node, or -1 when nothing is selected or the selection points ...
Definition n_gui.c:17757
int n_gui_add_window(N_GUI_CTX *ctx, const char *title, float x, float y, float w, float h)
Add a new pseudo-window to the context.
Definition n_gui.c:1277
N_GUI_CTX * n_gui_new_ctx(ALLEGRO_FONT *default_font)
Create a new GUI context.
Definition n_gui.c:1103
N_GUI_TREE * n_gui_tree_create(N_GUI_CTX *ctx, int window_id, float x, float y, float w, float h, void(*on_select)(int, void *), void *user_data)
create a tree view in an existing window
Definition n_gui.c:17598
void n_gui_tree_toggle_expand(N_GUI_TREE *tree, int node_index)
toggle expand/collapse of a node.
Definition n_gui.c:17819
void n_gui_destroy_ctx(N_GUI_CTX **ctx)
Destroy a GUI context and all its windows/widgets.
Definition n_gui.c:1209
int n_gui_tree_add_node(N_GUI_TREE *tree, const char *label, int parent_index, void *user_data)
add a node to the tree
Definition n_gui.c:17665
The top-level GUI context that holds all windows.
Definition n_gui.h:1669
tree view built from an N_GUI listbox
Definition n_gui.h:3493
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
Common headers and low-level functions & define.
GUI system: buttons, sliders, text areas, checkboxes, scrollbars, dropdown menus, windows.
Generic log system.