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.
 
Loading...
Searching...
No Matches
nuklear_chart.c
1#include "nuklear.h"
2#include "nuklear_internal.h"
3
4/* ==============================================================
5 *
6 * CHART
7 *
8 * ===============================================================*/
9NK_API nk_bool
10nk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,
11 struct nk_color color, struct nk_color highlight,
12 int count, float min_value, float max_value)
13{
14 struct nk_window *win;
15 struct nk_chart *chart;
16 const struct nk_style *config;
17 const struct nk_style_chart *style;
18
19 const struct nk_style_item *background;
20 struct nk_rect bounds = {0, 0, 0, 0};
21
22 NK_ASSERT(ctx);
23 NK_ASSERT(ctx->current);
24 NK_ASSERT(ctx->current->layout);
25
26 if (!ctx || !ctx->current || !ctx->current->layout) return 0;
27 if (!nk_widget(&bounds, ctx)) {
28 chart = &ctx->current->layout->chart;
29 nk_zero(chart, sizeof(*chart));
30 return 0;
31 }
32
33 win = ctx->current;
34 config = &ctx->style;
35 chart = &win->layout->chart;
36 style = &config->chart;
37
38 /* setup basic generic chart */
39 nk_zero(chart, sizeof(*chart));
40 chart->x = bounds.x + style->padding.x;
41 chart->y = bounds.y + style->padding.y;
42 chart->w = bounds.w - 2 * style->padding.x;
43 chart->h = bounds.h - 2 * style->padding.y;
44 chart->w = NK_MAX(chart->w, 2 * style->padding.x);
45 chart->h = NK_MAX(chart->h, 2 * style->padding.y);
46
47 /* add first slot into chart */
48 {struct nk_chart_slot *slot = &chart->slots[chart->slot++];
49 slot->type = type;
50 slot->count = count;
51 slot->color = nk_rgb_factor(color, style->color_factor);
52 slot->highlight = highlight;
53 slot->min = NK_MIN(min_value, max_value);
54 slot->max = NK_MAX(min_value, max_value);
55 slot->range = slot->max - slot->min;
56 slot->show_markers = style->show_markers;}
57
58 /* draw chart background */
59 background = &style->background;
60
61 switch(background->type) {
62 case NK_STYLE_ITEM_IMAGE:
63 nk_draw_image(&win->buffer, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
64 break;
65 case NK_STYLE_ITEM_NINE_SLICE:
66 nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
67 break;
68 case NK_STYLE_ITEM_COLOR:
69 nk_fill_rect(&win->buffer, bounds, style->rounding, nk_rgb_factor(style->border_color, style->color_factor));
70 nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),
71 style->rounding, nk_rgb_factor(style->background.data.color, style->color_factor));
72 break;
73 }
74 return 1;
75}
76NK_API nk_bool
77nk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,
78 int count, float min_value, float max_value)
79{
80 return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,
81 ctx->style.chart.selected_color, count, min_value, max_value);
82}
83NK_API void
84nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,
85 struct nk_color color, struct nk_color highlight,
86 int count, float min_value, float max_value)
87{
88 const struct nk_style_chart* style;
89
90 NK_ASSERT(ctx);
91 NK_ASSERT(ctx->current);
92 NK_ASSERT(ctx->current->layout);
93 NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);
94 if (!ctx || !ctx->current || !ctx->current->layout) return;
95 if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;
96
97 style = &ctx->style.chart;
98
99 /* add another slot into the graph */
100 {struct nk_chart *chart = &ctx->current->layout->chart;
101 struct nk_chart_slot *slot = &chart->slots[chart->slot++];
102 slot->type = type;
103 slot->count = count;
104 slot->color = nk_rgb_factor(color, style->color_factor);
105 slot->highlight = highlight;
106 slot->min = NK_MIN(min_value, max_value);
107 slot->max = NK_MAX(min_value, max_value);
108 slot->range = slot->max - slot->min;
109 slot->show_markers = style->show_markers;}
110}
111NK_API void
112nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,
113 int count, float min_value, float max_value)
114{
115 nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,
116 ctx->style.chart.selected_color, count, min_value, max_value);
117}
118NK_INTERN nk_flags
119nk_chart_push_line(struct nk_context *ctx, struct nk_window *win,
120 struct nk_chart *g, float value, int slot)
121{
122 struct nk_panel *layout = win->layout;
123 const struct nk_input *i = ctx->current->widgets_disabled ? 0 : &ctx->input;
124 struct nk_command_buffer *out = &win->buffer;
125
126 nk_flags ret = 0;
127 struct nk_vec2 cur;
128 struct nk_rect bounds;
129 struct nk_color color;
130 float step;
131 float range;
132 float ratio;
133
134 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
135 step = g->w / (float)g->slots[slot].count;
136 range = g->slots[slot].max - g->slots[slot].min;
137 ratio = (value - g->slots[slot].min) / range;
138
139 if (g->slots[slot].index == 0) {
140 /* first data point does not have a connection */
141 g->slots[slot].last.x = g->x;
142 g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;
143
144 bounds.x = g->slots[slot].last.x - 2;
145 bounds.y = g->slots[slot].last.y - 2;
146 bounds.w = bounds.h = 4;
147
148 color = g->slots[slot].color;
149 if (!(layout->flags & NK_WINDOW_ROM) && i &&
150 NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){
151 ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;
152 ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&
153 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
154 color = g->slots[slot].highlight;
155 }
156 if (g->slots[slot].show_markers) {
157 nk_fill_rect(out, bounds, 0, color);
158 }
159 g->slots[slot].index += 1;
160 return ret;
161 }
162
163 /* draw a line between the last data point and the new one */
164 color = g->slots[slot].color;
165 cur.x = g->x + (float)(step * (float)g->slots[slot].index);
166 cur.y = (g->y + g->h) - (ratio * (float)g->h);
167 nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);
168
169 bounds.x = cur.x - 3;
170 bounds.y = cur.y - 3;
171 bounds.w = bounds.h = 6;
172
173 /* user selection of current data point */
174 if (!(layout->flags & NK_WINDOW_ROM)) {
175 if (nk_input_is_mouse_hovering_rect(i, bounds)) {
176 ret = NK_CHART_HOVERING;
177 ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&
178 i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
179 color = g->slots[slot].highlight;
180 }
181 }
182 if (g->slots[slot].show_markers) {
183 nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);
184 }
185
186 /* save current data point position */
187 g->slots[slot].last.x = cur.x;
188 g->slots[slot].last.y = cur.y;
189 g->slots[slot].index += 1;
190 return ret;
191}
192NK_INTERN nk_flags
193nk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,
194 struct nk_chart *chart, float value, int slot)
195{
196 struct nk_command_buffer *out = &win->buffer;
197 const struct nk_input *in = ctx->current->widgets_disabled ? 0 : &ctx->input;
198 struct nk_panel *layout = win->layout;
199
200 float ratio;
201 nk_flags ret = 0;
202 struct nk_color color;
203 struct nk_rect item = {0,0,0,0};
204
205 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
206 if (chart->slots[slot].index >= chart->slots[slot].count)
207 return nk_false;
208 if (chart->slots[slot].count) {
209 float padding = (float)(chart->slots[slot].count-1);
210 item.w = (chart->w - padding) / (float)(chart->slots[slot].count);
211 }
212
213 /* calculate bounds of current bar chart entry */
214 color = chart->slots[slot].color;;
215 item.h = chart->h * NK_ABS((value/chart->slots[slot].range));
216 if (value >= 0) {
217 ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);
218 item.y = (chart->y + chart->h) - chart->h * ratio;
219 } else {
220 ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;
221 item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;
222 }
223 item.x = chart->x + ((float)chart->slots[slot].index * item.w);
224 item.x = item.x + ((float)chart->slots[slot].index);
225
226 /* user chart bar selection */
227 if (!(layout->flags & NK_WINDOW_ROM) && in &&
228 NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {
229 ret = NK_CHART_HOVERING;
230 ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&
231 in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;
232 color = chart->slots[slot].highlight;
233 }
234 nk_fill_rect(out, item, 0, color);
235 chart->slots[slot].index += 1;
236 return ret;
237}
238NK_API nk_flags
239nk_chart_push_slot(struct nk_context *ctx, float value, int slot)
240{
241 nk_flags flags;
242 struct nk_window *win;
243
244 NK_ASSERT(ctx);
245 NK_ASSERT(ctx->current);
246 NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);
247 NK_ASSERT(slot < ctx->current->layout->chart.slot);
248 if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;
249 if (slot >= ctx->current->layout->chart.slot) return nk_false;
250
251 win = ctx->current;
252 if (win->layout->chart.slot < slot) return nk_false;
253 switch (win->layout->chart.slots[slot].type) {
254 case NK_CHART_LINES:
255 flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;
256 case NK_CHART_COLUMN:
257 flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;
258 default:
259 case NK_CHART_MAX:
260 flags = 0;
261 }
262 return flags;
263}
264NK_API nk_flags
265nk_chart_push(struct nk_context *ctx, float value)
266{
267 return nk_chart_push_slot(ctx, value, 0);
268}
269NK_API void
270nk_chart_end(struct nk_context *ctx)
271{
272 struct nk_window *win;
273 struct nk_chart *chart;
274
275 NK_ASSERT(ctx);
276 NK_ASSERT(ctx->current);
277 if (!ctx || !ctx->current)
278 return;
279
280 win = ctx->current;
281 chart = &win->layout->chart;
282 NK_MEMSET(chart, 0, sizeof(*chart));
283 return;
284}
285NK_API void
286nk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,
287 int count, int offset)
288{
289 int i = 0;
290 float min_value;
291 float max_value;
292
293 NK_ASSERT(ctx);
294 NK_ASSERT(values);
295 if (!ctx || !values || !count) return;
296
297 min_value = values[offset];
298 max_value = values[offset];
299 for (i = 0; i < count; ++i) {
300 min_value = NK_MIN(values[i + offset], min_value);
301 max_value = NK_MAX(values[i + offset], max_value);
302 }
303
304 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
305 for (i = 0; i < count; ++i)
306 nk_chart_push(ctx, values[i + offset]);
307 nk_chart_end(ctx);
308 }
309}
310NK_API void
311nk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,
312 float(*value_getter)(void* user, int index), int count, int offset)
313{
314 int i = 0;
315 float min_value;
316 float max_value;
317
318 NK_ASSERT(ctx);
319 NK_ASSERT(value_getter);
320 if (!ctx || !value_getter || !count) return;
321
322 max_value = min_value = value_getter(userdata, offset);
323 for (i = 0; i < count; ++i) {
324 float value = value_getter(userdata, i + offset);
325 min_value = NK_MIN(value, min_value);
326 max_value = NK_MAX(value, max_value);
327 }
328
329 if (nk_chart_begin(ctx, type, count, min_value, max_value)) {
330 for (i = 0; i < count; ++i)
331 nk_chart_push(ctx, value_getter(userdata, i + offset));
332 nk_chart_end(ctx);
333 }
334}
335
main API and documentation file
@ 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
NK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color)
shape outlines
NK_API void nk_fill_rect(struct nk_command_buffer *, struct nk_rect, float rounding, struct nk_color)
filled shades