1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3 
4 /* ===============================================================
5  *
6  *                          LAYOUT
7  *
8  * ===============================================================*/
9 NK_API void
nk_layout_set_min_row_height(struct nk_context * ctx,float height)10 nk_layout_set_min_row_height(struct nk_context *ctx, float height)
11 {
12     struct nk_window *win;
13     struct nk_panel *layout;
14 
15     NK_ASSERT(ctx);
16     NK_ASSERT(ctx->current);
17     NK_ASSERT(ctx->current->layout);
18     if (!ctx || !ctx->current || !ctx->current->layout)
19         return;
20 
21     win = ctx->current;
22     layout = win->layout;
23     layout->row.min_height = height;
24 }
25 NK_API void
nk_layout_reset_min_row_height(struct nk_context * ctx)26 nk_layout_reset_min_row_height(struct nk_context *ctx)
27 {
28     struct nk_window *win;
29     struct nk_panel *layout;
30 
31     NK_ASSERT(ctx);
32     NK_ASSERT(ctx->current);
33     NK_ASSERT(ctx->current->layout);
34     if (!ctx || !ctx->current || !ctx->current->layout)
35         return;
36 
37     win = ctx->current;
38     layout = win->layout;
39     layout->row.min_height = ctx->style.font->height;
40     layout->row.min_height += ctx->style.text.padding.y*2;
41     layout->row.min_height += ctx->style.window.min_row_height_padding*2;
42 }
43 NK_LIB float
nk_layout_row_calculate_usable_space(const struct nk_style * style,enum nk_panel_type type,float total_space,int columns)44 nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,
45     float total_space, int columns)
46 {
47     float panel_spacing;
48     float panel_space;
49 
50     struct nk_vec2 spacing;
51 
52     NK_UNUSED(type);
53 
54     spacing = style->window.spacing;
55 
56     /* calculate the usable panel space */
57     panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;
58     panel_space  = total_space - panel_spacing;
59     return panel_space;
60 }
61 NK_LIB void
nk_panel_layout(const struct nk_context * ctx,struct nk_window * win,float height,int cols)62 nk_panel_layout(const struct nk_context *ctx, struct nk_window *win,
63     float height, int cols)
64 {
65     struct nk_panel *layout;
66     const struct nk_style *style;
67     struct nk_command_buffer *out;
68 
69     struct nk_vec2 item_spacing;
70     struct nk_color color;
71 
72     NK_ASSERT(ctx);
73     NK_ASSERT(ctx->current);
74     NK_ASSERT(ctx->current->layout);
75     if (!ctx || !ctx->current || !ctx->current->layout)
76         return;
77 
78     /* prefetch some configuration data */
79     layout = win->layout;
80     style = &ctx->style;
81     out = &win->buffer;
82     color = style->window.background;
83     item_spacing = style->window.spacing;
84 
85     /*  if one of these triggers you forgot to add an `if` condition around either
86         a window, group, popup, combobox or contextual menu `begin` and `end` block.
87         Example:
88             if (nk_begin(...) {...} nk_end(...); or
89             if (nk_group_begin(...) { nk_group_end(...);} */
90     NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));
91     NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));
92     NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));
93 
94     /* update the current row and set the current row layout */
95     layout->row.index = 0;
96     layout->at_y += layout->row.height;
97     layout->row.columns = cols;
98     if (height == 0.0f)
99         layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;
100     else layout->row.height = height + item_spacing.y;
101 
102     layout->row.item_offset = 0;
103     if (layout->flags & NK_WINDOW_DYNAMIC) {
104         /* draw background for dynamic panels */
105         struct nk_rect background;
106         background.x = win->bounds.x;
107         background.w = win->bounds.w;
108         background.y = layout->at_y - 1.0f;
109         background.h = layout->row.height + 1.0f;
110         nk_fill_rect(out, background, 0, color);
111     }
112 }
113 NK_LIB void
nk_row_layout(struct nk_context * ctx,enum nk_layout_format fmt,float height,int cols,int width)114 nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,
115     float height, int cols, int width)
116 {
117     /* update the current row and set the current row layout */
118     struct nk_window *win;
119     NK_ASSERT(ctx);
120     NK_ASSERT(ctx->current);
121     NK_ASSERT(ctx->current->layout);
122     if (!ctx || !ctx->current || !ctx->current->layout)
123         return;
124 
125     win = ctx->current;
126     nk_panel_layout(ctx, win, height, cols);
127     if (fmt == NK_DYNAMIC)
128         win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;
129     else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;
130 
131     win->layout->row.ratio = 0;
132     win->layout->row.filled = 0;
133     win->layout->row.item_offset = 0;
134     win->layout->row.item_width = (float)width;
135 }
136 NK_API float
nk_layout_ratio_from_pixel(struct nk_context * ctx,float pixel_width)137 nk_layout_ratio_from_pixel(struct nk_context *ctx, float pixel_width)
138 {
139     struct nk_window *win;
140     NK_ASSERT(ctx);
141     NK_ASSERT(pixel_width);
142     if (!ctx || !ctx->current || !ctx->current->layout) return 0;
143     win = ctx->current;
144     return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);
145 }
146 NK_API void
nk_layout_row_dynamic(struct nk_context * ctx,float height,int cols)147 nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)
148 {
149     nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);
150 }
151 NK_API void
nk_layout_row_static(struct nk_context * ctx,float height,int item_width,int cols)152 nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)
153 {
154     nk_row_layout(ctx, NK_STATIC, height, cols, item_width);
155 }
156 NK_API void
nk_layout_row_begin(struct nk_context * ctx,enum nk_layout_format fmt,float row_height,int cols)157 nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,
158     float row_height, int cols)
159 {
160     struct nk_window *win;
161     struct nk_panel *layout;
162 
163     NK_ASSERT(ctx);
164     NK_ASSERT(ctx->current);
165     NK_ASSERT(ctx->current->layout);
166     if (!ctx || !ctx->current || !ctx->current->layout)
167         return;
168 
169     win = ctx->current;
170     layout = win->layout;
171     nk_panel_layout(ctx, win, row_height, cols);
172     if (fmt == NK_DYNAMIC)
173         layout->row.type = NK_LAYOUT_DYNAMIC_ROW;
174     else layout->row.type = NK_LAYOUT_STATIC_ROW;
175 
176     layout->row.ratio = 0;
177     layout->row.filled = 0;
178     layout->row.item_width = 0;
179     layout->row.item_offset = 0;
180     layout->row.columns = cols;
181 }
182 NK_API void
nk_layout_row_push(struct nk_context * ctx,float ratio_or_width)183 nk_layout_row_push(struct nk_context *ctx, float ratio_or_width)
184 {
185     struct nk_window *win;
186     struct nk_panel *layout;
187 
188     NK_ASSERT(ctx);
189     NK_ASSERT(ctx->current);
190     NK_ASSERT(ctx->current->layout);
191     if (!ctx || !ctx->current || !ctx->current->layout)
192         return;
193 
194     win = ctx->current;
195     layout = win->layout;
196     NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
197     if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
198         return;
199 
200     if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {
201         float ratio = ratio_or_width;
202         if ((ratio + layout->row.filled) > 1.0f) return;
203         if (ratio > 0.0f)
204             layout->row.item_width = NK_SATURATE(ratio);
205         else layout->row.item_width = 1.0f - layout->row.filled;
206     } else layout->row.item_width = ratio_or_width;
207 }
208 NK_API void
nk_layout_row_end(struct nk_context * ctx)209 nk_layout_row_end(struct nk_context *ctx)
210 {
211     struct nk_window *win;
212     struct nk_panel *layout;
213 
214     NK_ASSERT(ctx);
215     NK_ASSERT(ctx->current);
216     NK_ASSERT(ctx->current->layout);
217     if (!ctx || !ctx->current || !ctx->current->layout)
218         return;
219 
220     win = ctx->current;
221     layout = win->layout;
222     NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);
223     if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)
224         return;
225     layout->row.item_width = 0;
226     layout->row.item_offset = 0;
227 }
228 NK_API void
nk_layout_row(struct nk_context * ctx,enum nk_layout_format fmt,float height,int cols,const float * ratio)229 nk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,
230     float height, int cols, const float *ratio)
231 {
232     int i;
233     int n_undef = 0;
234     struct nk_window *win;
235     struct nk_panel *layout;
236 
237     NK_ASSERT(ctx);
238     NK_ASSERT(ctx->current);
239     NK_ASSERT(ctx->current->layout);
240     if (!ctx || !ctx->current || !ctx->current->layout)
241         return;
242 
243     win = ctx->current;
244     layout = win->layout;
245     nk_panel_layout(ctx, win, height, cols);
246     if (fmt == NK_DYNAMIC) {
247         /* calculate width of undefined widget ratios */
248         float r = 0;
249         layout->row.ratio = ratio;
250         for (i = 0; i < cols; ++i) {
251             if (ratio[i] < 0.0f)
252                 n_undef++;
253             else r += ratio[i];
254         }
255         r = NK_SATURATE(1.0f - r);
256         layout->row.type = NK_LAYOUT_DYNAMIC;
257         layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;
258     } else {
259         layout->row.ratio = ratio;
260         layout->row.type = NK_LAYOUT_STATIC;
261         layout->row.item_width = 0;
262         layout->row.item_offset = 0;
263     }
264     layout->row.item_offset = 0;
265     layout->row.filled = 0;
266 }
267 NK_API void
nk_layout_row_template_begin(struct nk_context * ctx,float height)268 nk_layout_row_template_begin(struct nk_context *ctx, float height)
269 {
270     struct nk_window *win;
271     struct nk_panel *layout;
272 
273     NK_ASSERT(ctx);
274     NK_ASSERT(ctx->current);
275     NK_ASSERT(ctx->current->layout);
276     if (!ctx || !ctx->current || !ctx->current->layout)
277         return;
278 
279     win = ctx->current;
280     layout = win->layout;
281     nk_panel_layout(ctx, win, height, 1);
282     layout->row.type = NK_LAYOUT_TEMPLATE;
283     layout->row.columns = 0;
284     layout->row.ratio = 0;
285     layout->row.item_width = 0;
286     layout->row.item_height = 0;
287     layout->row.item_offset = 0;
288     layout->row.filled = 0;
289     layout->row.item.x = 0;
290     layout->row.item.y = 0;
291     layout->row.item.w = 0;
292     layout->row.item.h = 0;
293 }
294 NK_API void
nk_layout_row_template_push_dynamic(struct nk_context * ctx)295 nk_layout_row_template_push_dynamic(struct nk_context *ctx)
296 {
297     struct nk_window *win;
298     struct nk_panel *layout;
299 
300     NK_ASSERT(ctx);
301     NK_ASSERT(ctx->current);
302     NK_ASSERT(ctx->current->layout);
303     if (!ctx || !ctx->current || !ctx->current->layout)
304         return;
305 
306     win = ctx->current;
307     layout = win->layout;
308     NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
309     NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
310     if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
311     if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
312     layout->row.templates[layout->row.columns++] = -1.0f;
313 }
314 NK_API void
nk_layout_row_template_push_variable(struct nk_context * ctx,float min_width)315 nk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)
316 {
317     struct nk_window *win;
318     struct nk_panel *layout;
319 
320     NK_ASSERT(ctx);
321     NK_ASSERT(ctx->current);
322     NK_ASSERT(ctx->current->layout);
323     if (!ctx || !ctx->current || !ctx->current->layout)
324         return;
325 
326     win = ctx->current;
327     layout = win->layout;
328     NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
329     NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
330     if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
331     if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
332     layout->row.templates[layout->row.columns++] = -min_width;
333 }
334 NK_API void
nk_layout_row_template_push_static(struct nk_context * ctx,float width)335 nk_layout_row_template_push_static(struct nk_context *ctx, float width)
336 {
337     struct nk_window *win;
338     struct nk_panel *layout;
339 
340     NK_ASSERT(ctx);
341     NK_ASSERT(ctx->current);
342     NK_ASSERT(ctx->current->layout);
343     if (!ctx || !ctx->current || !ctx->current->layout)
344         return;
345 
346     win = ctx->current;
347     layout = win->layout;
348     NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
349     NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
350     if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
351     if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;
352     layout->row.templates[layout->row.columns++] = width;
353 }
354 NK_API void
nk_layout_row_template_end(struct nk_context * ctx)355 nk_layout_row_template_end(struct nk_context *ctx)
356 {
357     struct nk_window *win;
358     struct nk_panel *layout;
359 
360     int i = 0;
361     int variable_count = 0;
362     int min_variable_count = 0;
363     float min_fixed_width = 0.0f;
364     float total_fixed_width = 0.0f;
365     float max_variable_width = 0.0f;
366 
367     NK_ASSERT(ctx);
368     NK_ASSERT(ctx->current);
369     NK_ASSERT(ctx->current->layout);
370     if (!ctx || !ctx->current || !ctx->current->layout)
371         return;
372 
373     win = ctx->current;
374     layout = win->layout;
375     NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);
376     if (layout->row.type != NK_LAYOUT_TEMPLATE) return;
377     for (i = 0; i < layout->row.columns; ++i) {
378         float width = layout->row.templates[i];
379         if (width >= 0.0f) {
380             total_fixed_width += width;
381             min_fixed_width += width;
382         } else if (width < -1.0f) {
383             width = -width;
384             total_fixed_width += width;
385             max_variable_width = NK_MAX(max_variable_width, width);
386             variable_count++;
387         } else {
388             min_variable_count++;
389             variable_count++;
390         }
391     }
392     if (variable_count) {
393         float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
394                             layout->bounds.w, layout->row.columns);
395         float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;
396         int enough_space = var_width >= max_variable_width;
397         if (!enough_space)
398             var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;
399         for (i = 0; i < layout->row.columns; ++i) {
400             float *width = &layout->row.templates[i];
401             *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;
402         }
403     }
404 }
405 NK_API void
nk_layout_space_begin(struct nk_context * ctx,enum nk_layout_format fmt,float height,int widget_count)406 nk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,
407     float height, int widget_count)
408 {
409     struct nk_window *win;
410     struct nk_panel *layout;
411 
412     NK_ASSERT(ctx);
413     NK_ASSERT(ctx->current);
414     NK_ASSERT(ctx->current->layout);
415     if (!ctx || !ctx->current || !ctx->current->layout)
416         return;
417 
418     win = ctx->current;
419     layout = win->layout;
420     nk_panel_layout(ctx, win, height, widget_count);
421     if (fmt == NK_STATIC)
422         layout->row.type = NK_LAYOUT_STATIC_FREE;
423     else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;
424 
425     layout->row.ratio = 0;
426     layout->row.filled = 0;
427     layout->row.item_width = 0;
428     layout->row.item_offset = 0;
429 }
430 NK_API void
nk_layout_space_end(struct nk_context * ctx)431 nk_layout_space_end(struct nk_context *ctx)
432 {
433     struct nk_window *win;
434     struct nk_panel *layout;
435 
436     NK_ASSERT(ctx);
437     NK_ASSERT(ctx->current);
438     NK_ASSERT(ctx->current->layout);
439     if (!ctx || !ctx->current || !ctx->current->layout)
440         return;
441 
442     win = ctx->current;
443     layout = win->layout;
444     layout->row.item_width = 0;
445     layout->row.item_height = 0;
446     layout->row.item_offset = 0;
447     nk_zero(&layout->row.item, sizeof(layout->row.item));
448 }
449 NK_API void
nk_layout_space_push(struct nk_context * ctx,struct nk_rect rect)450 nk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)
451 {
452     struct nk_window *win;
453     struct nk_panel *layout;
454 
455     NK_ASSERT(ctx);
456     NK_ASSERT(ctx->current);
457     NK_ASSERT(ctx->current->layout);
458     if (!ctx || !ctx->current || !ctx->current->layout)
459         return;
460 
461     win = ctx->current;
462     layout = win->layout;
463     layout->row.item = rect;
464 }
465 NK_API struct nk_rect
nk_layout_space_bounds(struct nk_context * ctx)466 nk_layout_space_bounds(struct nk_context *ctx)
467 {
468     struct nk_rect ret;
469     struct nk_window *win;
470     struct nk_panel *layout;
471 
472     NK_ASSERT(ctx);
473     NK_ASSERT(ctx->current);
474     NK_ASSERT(ctx->current->layout);
475     win = ctx->current;
476     layout = win->layout;
477 
478     ret.x = layout->clip.x;
479     ret.y = layout->clip.y;
480     ret.w = layout->clip.w;
481     ret.h = layout->row.height;
482     return ret;
483 }
484 NK_API struct nk_rect
nk_layout_widget_bounds(struct nk_context * ctx)485 nk_layout_widget_bounds(struct nk_context *ctx)
486 {
487     struct nk_rect ret;
488     struct nk_window *win;
489     struct nk_panel *layout;
490 
491     NK_ASSERT(ctx);
492     NK_ASSERT(ctx->current);
493     NK_ASSERT(ctx->current->layout);
494     win = ctx->current;
495     layout = win->layout;
496 
497     ret.x = layout->at_x;
498     ret.y = layout->at_y;
499     ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);
500     ret.h = layout->row.height;
501     return ret;
502 }
503 NK_API struct nk_vec2
nk_layout_space_to_screen(struct nk_context * ctx,struct nk_vec2 ret)504 nk_layout_space_to_screen(struct nk_context *ctx, struct nk_vec2 ret)
505 {
506     struct nk_window *win;
507     struct nk_panel *layout;
508 
509     NK_ASSERT(ctx);
510     NK_ASSERT(ctx->current);
511     NK_ASSERT(ctx->current->layout);
512     win = ctx->current;
513     layout = win->layout;
514 
515     ret.x += layout->at_x - (float)*layout->offset_x;
516     ret.y += layout->at_y - (float)*layout->offset_y;
517     return ret;
518 }
519 NK_API struct nk_vec2
nk_layout_space_to_local(struct nk_context * ctx,struct nk_vec2 ret)520 nk_layout_space_to_local(struct nk_context *ctx, struct nk_vec2 ret)
521 {
522     struct nk_window *win;
523     struct nk_panel *layout;
524 
525     NK_ASSERT(ctx);
526     NK_ASSERT(ctx->current);
527     NK_ASSERT(ctx->current->layout);
528     win = ctx->current;
529     layout = win->layout;
530 
531     ret.x += -layout->at_x + (float)*layout->offset_x;
532     ret.y += -layout->at_y + (float)*layout->offset_y;
533     return ret;
534 }
535 NK_API struct nk_rect
nk_layout_space_rect_to_screen(struct nk_context * ctx,struct nk_rect ret)536 nk_layout_space_rect_to_screen(struct nk_context *ctx, struct nk_rect ret)
537 {
538     struct nk_window *win;
539     struct nk_panel *layout;
540 
541     NK_ASSERT(ctx);
542     NK_ASSERT(ctx->current);
543     NK_ASSERT(ctx->current->layout);
544     win = ctx->current;
545     layout = win->layout;
546 
547     ret.x += layout->at_x - (float)*layout->offset_x;
548     ret.y += layout->at_y - (float)*layout->offset_y;
549     return ret;
550 }
551 NK_API struct nk_rect
nk_layout_space_rect_to_local(struct nk_context * ctx,struct nk_rect ret)552 nk_layout_space_rect_to_local(struct nk_context *ctx, struct nk_rect ret)
553 {
554     struct nk_window *win;
555     struct nk_panel *layout;
556 
557     NK_ASSERT(ctx);
558     NK_ASSERT(ctx->current);
559     NK_ASSERT(ctx->current->layout);
560     win = ctx->current;
561     layout = win->layout;
562 
563     ret.x += -layout->at_x + (float)*layout->offset_x;
564     ret.y += -layout->at_y + (float)*layout->offset_y;
565     return ret;
566 }
567 NK_LIB void
nk_panel_alloc_row(const struct nk_context * ctx,struct nk_window * win)568 nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)
569 {
570     struct nk_panel *layout = win->layout;
571     struct nk_vec2 spacing = ctx->style.window.spacing;
572     const float row_height = layout->row.height - spacing.y;
573     nk_panel_layout(ctx, win, row_height, layout->row.columns);
574 }
575 NK_LIB void
nk_layout_widget_space(struct nk_rect * bounds,const struct nk_context * ctx,struct nk_window * win,int modify)576 nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,
577     struct nk_window *win, int modify)
578 {
579     struct nk_panel *layout;
580     const struct nk_style *style;
581 
582     struct nk_vec2 spacing;
583 
584     float item_offset = 0;
585     float item_width = 0;
586     float item_spacing = 0;
587     float panel_space = 0;
588 
589     NK_ASSERT(ctx);
590     NK_ASSERT(ctx->current);
591     NK_ASSERT(ctx->current->layout);
592     if (!ctx || !ctx->current || !ctx->current->layout)
593         return;
594 
595     win = ctx->current;
596     layout = win->layout;
597     style = &ctx->style;
598     NK_ASSERT(bounds);
599 
600     spacing = style->window.spacing;
601     panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,
602                                             layout->bounds.w, layout->row.columns);
603 
604     #define NK_FRAC(x) (x - (float)(int)x) /* will be used to remove fookin gaps */
605     /* calculate the width of one item inside the current layout space */
606     switch (layout->row.type) {
607     case NK_LAYOUT_DYNAMIC_FIXED: {
608         /* scaling fixed size widgets item width */
609         float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;
610         item_offset = (float)layout->row.index * w;
611         item_width = w + NK_FRAC(item_offset);
612         item_spacing = (float)layout->row.index * spacing.x;
613     } break;
614     case NK_LAYOUT_DYNAMIC_ROW: {
615         /* scaling single ratio widget width */
616         float w = layout->row.item_width * panel_space;
617         item_offset = layout->row.item_offset;
618         item_width = w + NK_FRAC(item_offset);
619         item_spacing = 0;
620 
621         if (modify) {
622             layout->row.item_offset += w + spacing.x;
623             layout->row.filled += layout->row.item_width;
624             layout->row.index = 0;
625         }
626     } break;
627     case NK_LAYOUT_DYNAMIC_FREE: {
628         /* panel width depended free widget placing */
629         bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);
630         bounds->x -= (float)*layout->offset_x;
631         bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);
632         bounds->y -= (float)*layout->offset_y;
633         bounds->w = layout->bounds.w  * layout->row.item.w + NK_FRAC(bounds->x);
634         bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y);
635         return;
636     }
637     case NK_LAYOUT_DYNAMIC: {
638         /* scaling arrays of panel width ratios for every widget */
639         float ratio, w;
640         NK_ASSERT(layout->row.ratio);
641         ratio = (layout->row.ratio[layout->row.index] < 0) ?
642             layout->row.item_width : layout->row.ratio[layout->row.index];
643 
644         w = (ratio * panel_space);
645         item_spacing = (float)layout->row.index * spacing.x;
646         item_offset = layout->row.item_offset;
647         item_width = w + NK_FRAC(item_offset);
648 
649         if (modify) {
650             layout->row.item_offset += w;
651             layout->row.filled += ratio;
652         }
653     } break;
654     case NK_LAYOUT_STATIC_FIXED: {
655         /* non-scaling fixed widgets item width */
656         item_width = layout->row.item_width;
657         item_offset = (float)layout->row.index * item_width;
658         item_spacing = (float)layout->row.index * spacing.x;
659     } break;
660     case NK_LAYOUT_STATIC_ROW: {
661         /* scaling single ratio widget width */
662         item_width = layout->row.item_width;
663         item_offset = layout->row.item_offset;
664         item_spacing = (float)layout->row.index * spacing.x;
665         if (modify) layout->row.item_offset += item_width;
666     } break;
667     case NK_LAYOUT_STATIC_FREE: {
668         /* free widget placing */
669         bounds->x = layout->at_x + layout->row.item.x;
670         bounds->w = layout->row.item.w;
671         if (((bounds->x + bounds->w) > layout->max_x) && modify)
672             layout->max_x = (bounds->x + bounds->w);
673         bounds->x -= (float)*layout->offset_x;
674         bounds->y = layout->at_y + layout->row.item.y;
675         bounds->y -= (float)*layout->offset_y;
676         bounds->h = layout->row.item.h;
677         return;
678     }
679     case NK_LAYOUT_STATIC: {
680         /* non-scaling array of panel pixel width for every widget */
681         item_spacing = (float)layout->row.index * spacing.x;
682         item_width = layout->row.ratio[layout->row.index];
683         item_offset = layout->row.item_offset;
684         if (modify) layout->row.item_offset += item_width;
685     } break;
686     case NK_LAYOUT_TEMPLATE: {
687         /* stretchy row layout with combined dynamic/static widget width*/
688         float w;
689         NK_ASSERT(layout->row.index < layout->row.columns);
690         NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);
691         w = layout->row.templates[layout->row.index];
692         item_offset = layout->row.item_offset;
693         item_width = w + NK_FRAC(item_offset);
694         item_spacing = (float)layout->row.index * spacing.x;
695         if (modify) layout->row.item_offset += w;
696     } break;
697     #undef NK_FRAC
698     default: NK_ASSERT(0); break;
699     };
700 
701     /* set the bounds of the newly allocated widget */
702     bounds->w = item_width;
703     bounds->h = layout->row.height - spacing.y;
704     bounds->y = layout->at_y - (float)*layout->offset_y;
705     bounds->x = layout->at_x + item_offset + item_spacing;
706     if (((bounds->x + bounds->w) > layout->max_x) && modify)
707         layout->max_x = bounds->x + bounds->w;
708     bounds->x -= (float)*layout->offset_x;
709 }
710 NK_LIB void
nk_panel_alloc_space(struct nk_rect * bounds,const struct nk_context * ctx)711 nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)
712 {
713     struct nk_window *win;
714     struct nk_panel *layout;
715 
716     NK_ASSERT(ctx);
717     NK_ASSERT(ctx->current);
718     NK_ASSERT(ctx->current->layout);
719     if (!ctx || !ctx->current || !ctx->current->layout)
720         return;
721 
722     /* check if the end of the row has been hit and begin new row if so */
723     win = ctx->current;
724     layout = win->layout;
725     if (layout->row.index >= layout->row.columns)
726         nk_panel_alloc_row(ctx, win);
727 
728     /* calculate widget position and size */
729     nk_layout_widget_space(bounds, ctx, win, nk_true);
730     layout->row.index++;
731 }
732 NK_LIB void
nk_layout_peek(struct nk_rect * bounds,struct nk_context * ctx)733 nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx)
734 {
735     float y;
736     int index;
737     struct nk_window *win;
738     struct nk_panel *layout;
739 
740     NK_ASSERT(ctx);
741     NK_ASSERT(ctx->current);
742     NK_ASSERT(ctx->current->layout);
743     if (!ctx || !ctx->current || !ctx->current->layout) {
744         *bounds = nk_rect(0,0,0,0);
745         return;
746     }
747 
748     win = ctx->current;
749     layout = win->layout;
750     y = layout->at_y;
751     index = layout->row.index;
752     if (layout->row.index >= layout->row.columns) {
753         layout->at_y += layout->row.height;
754         layout->row.index = 0;
755     }
756     nk_layout_widget_space(bounds, ctx, win, nk_false);
757     if (!layout->row.index) {
758         bounds->x -= layout->row.item_offset;
759     }
760     layout->at_y = y;
761     layout->row.index = index;
762 }
763 NK_API void
nk_spacer(struct nk_context * ctx)764 nk_spacer(struct nk_context *ctx )
765 {
766     struct nk_rect dummy_rect = { 0, 0, 0, 0 };
767     nk_panel_alloc_space( &dummy_rect, ctx );
768 }
769 
770