Nuklear
This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.
nuklear_tree.c
1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3 
4 /* ===============================================================
5  *
6  * TREE
7  *
8  * ===============================================================*/
9 NK_INTERN int
10 nk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,
11  struct nk_image *img, const char *title, enum nk_collapse_states *state)
12 {
13  struct nk_window *win;
14  struct nk_panel *layout;
15  const struct nk_style *style;
16  struct nk_command_buffer *out;
17  const struct nk_input *in;
18  const struct nk_style_button *button;
19  enum nk_symbol_type symbol;
20  float row_height;
21 
22  struct nk_vec2 item_spacing;
23  struct nk_rect header = {0,0,0,0};
24  struct nk_rect sym = {0,0,0,0};
25  struct nk_text text;
26 
27  nk_flags ws = 0;
28  enum nk_widget_layout_states widget_state;
29 
30  NK_ASSERT(ctx);
31  NK_ASSERT(ctx->current);
32  NK_ASSERT(ctx->current->layout);
33  if (!ctx || !ctx->current || !ctx->current->layout)
34  return 0;
35 
36  /* cache some data */
37  win = ctx->current;
38  layout = win->layout;
39  out = &win->buffer;
40  style = &ctx->style;
41  item_spacing = style->window.spacing;
42 
43  /* calculate header bounds and draw background */
44  row_height = style->font->height + 2 * style->tab.padding.y;
45  nk_layout_set_min_row_height(ctx, row_height);
46  nk_layout_row_dynamic(ctx, row_height, 1);
48 
49  widget_state = nk_widget(&header, ctx);
50  if (type == NK_TREE_TAB) {
51  const struct nk_style_item *background = &style->tab.background;
52 
53  switch(background->type) {
54  case NK_STYLE_ITEM_IMAGE:
55  nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));
56  break;
57  case NK_STYLE_ITEM_NINE_SLICE:
58  nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));
59  break;
60  case NK_STYLE_ITEM_COLOR:
61  nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));
62  nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
63  style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));
64  break;
65  }
66  } else text.background = style->window.background;
67 
68  /* update node state */
69  in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
70  in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
71  if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))
72  *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;
73 
74  /* select correct button style */
75  if (*state == NK_MAXIMIZED) {
76  symbol = style->tab.sym_maximize;
77  if (type == NK_TREE_TAB)
78  button = &style->tab.tab_maximize_button;
79  else button = &style->tab.node_maximize_button;
80  } else {
81  symbol = style->tab.sym_minimize;
82  if (type == NK_TREE_TAB)
83  button = &style->tab.tab_minimize_button;
84  else button = &style->tab.node_minimize_button;
85  }
86 
87  {/* draw triangle button */
88  sym.w = sym.h = style->font->height;
89  sym.y = header.y + style->tab.padding.y;
90  sym.x = header.x + style->tab.padding.x;
91  nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,
92  button, 0, style->font);
93 
94  if (img) {
95  /* draw optional image icon */
96  sym.x = sym.x + sym.w + 4 * item_spacing.x;
97  nk_draw_image(&win->buffer, sym, img, nk_white);
98  sym.w = style->font->height + style->tab.spacing.x;}
99  }
100 
101  {/* draw label */
102  struct nk_rect label;
103  header.w = NK_MAX(header.w, sym.w + item_spacing.x);
104  label.x = sym.x + sym.w + item_spacing.x;
105  label.y = sym.y;
106  label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);
107  label.h = style->font->height;
108  text.text = nk_rgb_factor(style->tab.text, style->tab.color_factor);
109  text.padding = nk_vec2(0,0);
110  nk_widget_text(out, label, title, nk_strlen(title), &text,
111  NK_TEXT_LEFT, style->font);}
112 
113  /* increase x-axis cursor widget position pointer */
114  if (*state == NK_MAXIMIZED) {
115  layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
116  layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
117  layout->bounds.w -= (style->tab.indent + style->window.padding.x);
118  layout->row.tree_depth++;
119  return nk_true;
120  } else return nk_false;
121 }
122 NK_INTERN int
123 nk_tree_base(struct nk_context *ctx, enum nk_tree_type type,
124  struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
125  const char *hash, int len, int line)
126 {
127  struct nk_window *win = ctx->current;
128  int title_len = 0;
129  nk_hash tree_hash = 0;
130  nk_uint *state = 0;
131 
132  /* retrieve tree state from internal widget state tables */
133  if (!hash) {
134  title_len = (int)nk_strlen(title);
135  tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
136  } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
137  state = nk_find_value(win, tree_hash);
138  if (!state) {
139  state = nk_add_value(ctx, win, tree_hash, 0);
140  *state = initial_state;
141  }
142  return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);
143 }
144 NK_API nk_bool
145 nk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,
146  const char *title, enum nk_collapse_states *state)
147 {
148  return nk_tree_state_base(ctx, type, 0, title, state);
149 }
150 NK_API nk_bool
151 nk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,
152  struct nk_image img, const char *title, enum nk_collapse_states *state)
153 {
154  return nk_tree_state_base(ctx, type, &img, title, state);
155 }
156 NK_API void
158 {
159  struct nk_window *win = 0;
160  struct nk_panel *layout = 0;
161 
162  NK_ASSERT(ctx);
163  NK_ASSERT(ctx->current);
164  NK_ASSERT(ctx->current->layout);
165  if (!ctx || !ctx->current || !ctx->current->layout)
166  return;
167 
168  win = ctx->current;
169  layout = win->layout;
170  layout->at_x -= ctx->style.tab.indent + (float)*layout->offset_x;
171  layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;
172  NK_ASSERT(layout->row.tree_depth);
173  layout->row.tree_depth--;
174 }
175 NK_API nk_bool
176 nk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
177  const char *title, enum nk_collapse_states initial_state,
178  const char *hash, int len, int line)
179 {
180  return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);
181 }
182 NK_API nk_bool
183 nk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
184  struct nk_image img, const char *title, enum nk_collapse_states initial_state,
185  const char *hash, int len,int seed)
186 {
187  return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);
188 }
189 NK_API void
191 {
192  nk_tree_state_pop(ctx);
193 }
194 NK_INTERN int
195 nk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type,
196  struct nk_image *img, const char *title, int title_len,
197  enum nk_collapse_states *state, nk_bool *selected)
198 {
199  struct nk_window *win;
200  struct nk_panel *layout;
201  const struct nk_style *style;
202  struct nk_command_buffer *out;
203  const struct nk_input *in;
204  const struct nk_style_button *button;
205  enum nk_symbol_type symbol;
206  float row_height;
207  struct nk_vec2 padding;
208 
209  int text_len;
210  float text_width;
211 
212  struct nk_vec2 item_spacing;
213  struct nk_rect header = {0,0,0,0};
214  struct nk_rect sym = {0,0,0,0};
215 
216  nk_flags ws = 0;
217  enum nk_widget_layout_states widget_state;
218 
219  NK_ASSERT(ctx);
220  NK_ASSERT(ctx->current);
221  NK_ASSERT(ctx->current->layout);
222  if (!ctx || !ctx->current || !ctx->current->layout)
223  return 0;
224 
225  /* cache some data */
226  win = ctx->current;
227  layout = win->layout;
228  out = &win->buffer;
229  style = &ctx->style;
230  item_spacing = style->window.spacing;
231  padding = style->selectable.padding;
232 
233  /* calculate header bounds and draw background */
234  row_height = style->font->height + 2 * style->tab.padding.y;
235  nk_layout_set_min_row_height(ctx, row_height);
236  nk_layout_row_dynamic(ctx, row_height, 1);
238 
239  widget_state = nk_widget(&header, ctx);
240  if (type == NK_TREE_TAB) {
241  const struct nk_style_item *background = &style->tab.background;
242 
243  switch (background->type) {
244  case NK_STYLE_ITEM_IMAGE:
245  nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));
246  break;
247  case NK_STYLE_ITEM_NINE_SLICE:
248  nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));
249  break;
250  case NK_STYLE_ITEM_COLOR:
251  nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));
252  nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),
253  style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));
254 
255  break;
256  }
257  }
258 
259  in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;
260  in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;
261 
262  /* select correct button style */
263  if (*state == NK_MAXIMIZED) {
264  symbol = style->tab.sym_maximize;
265  if (type == NK_TREE_TAB)
266  button = &style->tab.tab_maximize_button;
267  else button = &style->tab.node_maximize_button;
268  } else {
269  symbol = style->tab.sym_minimize;
270  if (type == NK_TREE_TAB)
271  button = &style->tab.tab_minimize_button;
272  else button = &style->tab.node_minimize_button;
273  }
274  {/* draw triangle button */
275  sym.w = sym.h = style->font->height;
276  sym.y = header.y + style->tab.padding.y;
277  sym.x = header.x + style->tab.padding.x;
278  if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font))
279  *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;}
280 
281  /* draw label */
282  {nk_flags dummy = 0;
283  struct nk_rect label;
284  /* calculate size of the text and tooltip */
285  text_len = nk_strlen(title);
286  text_width = style->font->width(style->font->userdata, style->font->height, title, text_len);
287  text_width += (4 * padding.x);
288 
289  header.w = NK_MAX(header.w, sym.w + item_spacing.x);
290  label.x = sym.x + sym.w + item_spacing.x;
291  label.y = sym.y;
292  label.w = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width);
293  label.h = style->font->height;
294 
295  if (img) {
296  nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
297  selected, img, &style->selectable, in, style->font);
298  } else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,
299  selected, &style->selectable, in, style->font);
300  }
301  /* increase x-axis cursor widget position pointer */
302  if (*state == NK_MAXIMIZED) {
303  layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;
304  layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);
305  layout->bounds.w -= (style->tab.indent + style->window.padding.x);
306  layout->row.tree_depth++;
307  return nk_true;
308  } else return nk_false;
309 }
310 NK_INTERN int
311 nk_tree_element_base(struct nk_context *ctx, enum nk_tree_type type,
312  struct nk_image *img, const char *title, enum nk_collapse_states initial_state,
313  nk_bool *selected, const char *hash, int len, int line)
314 {
315  struct nk_window *win = ctx->current;
316  int title_len = 0;
317  nk_hash tree_hash = 0;
318  nk_uint *state = 0;
319 
320  /* retrieve tree state from internal widget state tables */
321  if (!hash) {
322  title_len = (int)nk_strlen(title);
323  tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);
324  } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);
325  state = nk_find_value(win, tree_hash);
326  if (!state) {
327  state = nk_add_value(ctx, win, tree_hash, 0);
328  *state = initial_state;
329  } return nk_tree_element_image_push_hashed_base(ctx, type, img, title,
330  nk_strlen(title), (enum nk_collapse_states*)state, selected);
331 }
332 NK_API nk_bool
333 nk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
334  const char *title, enum nk_collapse_states initial_state,
335  nk_bool *selected, const char *hash, int len, int seed)
336 {
337  return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed);
338 }
339 NK_API nk_bool
340 nk_tree_element_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,
341  struct nk_image img, const char *title, enum nk_collapse_states initial_state,
342  nk_bool *selected, const char *hash, int len,int seed)
343 {
344  return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed);
345 }
346 NK_API void
347 nk_tree_element_pop(struct nk_context *ctx)
348 {
349  nk_tree_state_pop(ctx);
350 }
351 
main API and documentation file
NK_API void nk_tree_pop(struct nk_context *)
Definition: nuklear_tree.c:190
@ NK_WINDOW_ROM
sets window widgets into a read only mode and does not allow input changes
Definition: nuklear.h:5492
NK_API void nk_draw_image(struct nk_command_buffer *, struct nk_rect, const struct nk_image *, struct nk_color)
misc
Definition: nuklear_draw.c:395
NK_API nk_bool nk_tree_image_push_hashed(struct nk_context *, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len, int seed)
Definition: nuklear_tree.c:183
NK_API void nk_fill_rect(struct nk_command_buffer *, struct nk_rect, float rounding, struct nk_color)
filled shades
Definition: nuklear_draw.c:152
NK_API nk_bool nk_tree_state_image_push(struct nk_context *, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state)
Definition: nuklear_tree.c:151
NK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
Sets current row layout to share horizontal space between @cols number of widgets evenly.
NK_API void nk_layout_reset_min_row_height(struct nk_context *)
Reset the currently used minimum row height back to font_height + text_padding + padding
NK_API nk_bool nk_tree_state_push(struct nk_context *, enum nk_tree_type, const char *title, enum nk_collapse_states *state)
Definition: nuklear_tree.c:145
NK_API nk_bool nk_tree_push_hashed(struct nk_context *, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len, int seed)
Definition: nuklear_tree.c:176
NK_API void nk_layout_set_min_row_height(struct nk_context *, float height)
Sets the currently used minimum row height.
NK_API void nk_tree_state_pop(struct nk_context *)
Definition: nuklear_tree.c:157
nk_widget_layout_states
Definition: nuklear.h:3081
@ NK_WIDGET_VALID
The widget is completely inside the window and can be updated and drawn.
Definition: nuklear.h:3083
nk_text_width_f width
!< max height of the font
Definition: nuklear.h:4009
float height
!< user provided font handle
Definition: nuklear.h:4008