1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3 
4 /* ===============================================================
5  *
6  *                              TOGGLE
7  *
8  * ===============================================================*/
9 NK_LIB int
nk_toggle_behavior(const struct nk_input * in,struct nk_rect select,nk_flags * state,int active)10 nk_toggle_behavior(const struct nk_input *in, struct nk_rect select,
11     nk_flags *state, int active)
12 {
13     nk_widget_state_reset(state);
14     if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {
15         *state = NK_WIDGET_STATE_ACTIVE;
16         active = !active;
17     }
18     if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))
19         *state |= NK_WIDGET_STATE_ENTERED;
20     else if (nk_input_is_mouse_prev_hovering_rect(in, select))
21         *state |= NK_WIDGET_STATE_LEFT;
22     return active;
23 }
24 NK_LIB void
nk_draw_checkbox(struct nk_command_buffer * out,nk_flags state,const struct nk_style_toggle * style,int active,const struct nk_rect * label,const struct nk_rect * selector,const struct nk_rect * cursors,const char * string,int len,const struct nk_user_font * font)25 nk_draw_checkbox(struct nk_command_buffer *out,
26     nk_flags state, const struct nk_style_toggle *style, int active,
27     const struct nk_rect *label, const struct nk_rect *selector,
28     const struct nk_rect *cursors, const char *string, int len,
29     const struct nk_user_font *font)
30 {
31     const struct nk_style_item *background;
32     const struct nk_style_item *cursor;
33     struct nk_text text;
34 
35     /* select correct colors/images */
36     if (state & NK_WIDGET_STATE_HOVER) {
37         background = &style->hover;
38         cursor = &style->cursor_hover;
39         text.text = style->text_hover;
40     } else if (state & NK_WIDGET_STATE_ACTIVED) {
41         background = &style->hover;
42         cursor = &style->cursor_hover;
43         text.text = style->text_active;
44     } else {
45         background = &style->normal;
46         cursor = &style->cursor_normal;
47         text.text = style->text_normal;
48     }
49 
50     /* draw background and cursor */
51     if (background->type == NK_STYLE_ITEM_COLOR) {
52         nk_fill_rect(out, *selector, 0, style->border_color);
53         nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, background->data.color);
54     } else nk_draw_image(out, *selector, &background->data.image, nk_white);
55     if (active) {
56         if (cursor->type == NK_STYLE_ITEM_IMAGE)
57             nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
58         else nk_fill_rect(out, *cursors, 0, cursor->data.color);
59     }
60 
61     text.padding.x = 0;
62     text.padding.y = 0;
63     text.background = style->text_background;
64     nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
65 }
66 NK_LIB void
nk_draw_option(struct nk_command_buffer * out,nk_flags state,const struct nk_style_toggle * style,int active,const struct nk_rect * label,const struct nk_rect * selector,const struct nk_rect * cursors,const char * string,int len,const struct nk_user_font * font)67 nk_draw_option(struct nk_command_buffer *out,
68     nk_flags state, const struct nk_style_toggle *style, int active,
69     const struct nk_rect *label, const struct nk_rect *selector,
70     const struct nk_rect *cursors, const char *string, int len,
71     const struct nk_user_font *font)
72 {
73     const struct nk_style_item *background;
74     const struct nk_style_item *cursor;
75     struct nk_text text;
76 
77     /* select correct colors/images */
78     if (state & NK_WIDGET_STATE_HOVER) {
79         background = &style->hover;
80         cursor = &style->cursor_hover;
81         text.text = style->text_hover;
82     } else if (state & NK_WIDGET_STATE_ACTIVED) {
83         background = &style->hover;
84         cursor = &style->cursor_hover;
85         text.text = style->text_active;
86     } else {
87         background = &style->normal;
88         cursor = &style->cursor_normal;
89         text.text = style->text_normal;
90     }
91 
92     /* draw background and cursor */
93     if (background->type == NK_STYLE_ITEM_COLOR) {
94         nk_fill_circle(out, *selector, style->border_color);
95         nk_fill_circle(out, nk_shrink_rect(*selector, style->border), background->data.color);
96     } else nk_draw_image(out, *selector, &background->data.image, nk_white);
97     if (active) {
98         if (cursor->type == NK_STYLE_ITEM_IMAGE)
99             nk_draw_image(out, *cursors, &cursor->data.image, nk_white);
100         else nk_fill_circle(out, *cursors, cursor->data.color);
101     }
102 
103     text.padding.x = 0;
104     text.padding.y = 0;
105     text.background = style->text_background;
106     nk_widget_text(out, *label, string, len, &text, NK_TEXT_LEFT, font);
107 }
108 NK_LIB int
nk_do_toggle(nk_flags * state,struct nk_command_buffer * out,struct nk_rect r,int * active,const char * str,int len,enum nk_toggle_type type,const struct nk_style_toggle * style,const struct nk_input * in,const struct nk_user_font * font)109 nk_do_toggle(nk_flags *state,
110     struct nk_command_buffer *out, struct nk_rect r,
111     int *active, const char *str, int len, enum nk_toggle_type type,
112     const struct nk_style_toggle *style, const struct nk_input *in,
113     const struct nk_user_font *font)
114 {
115     int was_active;
116     struct nk_rect bounds;
117     struct nk_rect select;
118     struct nk_rect cursor;
119     struct nk_rect label;
120 
121     NK_ASSERT(style);
122     NK_ASSERT(out);
123     NK_ASSERT(font);
124     if (!out || !style || !font || !active)
125         return 0;
126 
127     r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);
128     r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);
129 
130     /* add additional touch padding for touch screen devices */
131     bounds.x = r.x - style->touch_padding.x;
132     bounds.y = r.y - style->touch_padding.y;
133     bounds.w = r.w + 2 * style->touch_padding.x;
134     bounds.h = r.h + 2 * style->touch_padding.y;
135 
136     /* calculate the selector space */
137     select.w = font->height;
138     select.h = select.w;
139     select.y = r.y + r.h/2.0f - select.h/2.0f;
140     select.x = r.x;
141 
142     /* calculate the bounds of the cursor inside the selector */
143     cursor.x = select.x + style->padding.x + style->border;
144     cursor.y = select.y + style->padding.y + style->border;
145     cursor.w = select.w - (2 * style->padding.x + 2 * style->border);
146     cursor.h = select.h - (2 * style->padding.y + 2 * style->border);
147 
148     /* label behind the selector */
149     label.x = select.x + select.w + style->spacing;
150     label.y = select.y;
151     label.w = NK_MAX(r.x + r.w, label.x) - label.x;
152     label.h = select.w;
153 
154     /* update selector */
155     was_active = *active;
156     *active = nk_toggle_behavior(in, bounds, state, *active);
157 
158     /* draw selector */
159     if (style->draw_begin)
160         style->draw_begin(out, style->userdata);
161     if (type == NK_TOGGLE_CHECK) {
162         nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font);
163     } else {
164         nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font);
165     }
166     if (style->draw_end)
167         style->draw_end(out, style->userdata);
168     return (was_active != *active);
169 }
170 /*----------------------------------------------------------------
171  *
172  *                          CHECKBOX
173  *
174  * --------------------------------------------------------------*/
175 NK_API int
nk_check_text(struct nk_context * ctx,const char * text,int len,int active)176 nk_check_text(struct nk_context *ctx, const char *text, int len, int active)
177 {
178     struct nk_window *win;
179     struct nk_panel *layout;
180     const struct nk_input *in;
181     const struct nk_style *style;
182 
183     struct nk_rect bounds;
184     enum nk_widget_layout_states state;
185 
186     NK_ASSERT(ctx);
187     NK_ASSERT(ctx->current);
188     NK_ASSERT(ctx->current->layout);
189     if (!ctx || !ctx->current || !ctx->current->layout)
190         return active;
191 
192     win = ctx->current;
193     style = &ctx->style;
194     layout = win->layout;
195 
196     state = nk_widget(&bounds, ctx);
197     if (!state) return active;
198     in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
199     nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,
200         text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font);
201     return active;
202 }
203 NK_API unsigned int
nk_check_flags_text(struct nk_context * ctx,const char * text,int len,unsigned int flags,unsigned int value)204 nk_check_flags_text(struct nk_context *ctx, const char *text, int len,
205     unsigned int flags, unsigned int value)
206 {
207     int old_active;
208     NK_ASSERT(ctx);
209     NK_ASSERT(text);
210     if (!ctx || !text) return flags;
211     old_active = (int)((flags & value) & value);
212     if (nk_check_text(ctx, text, len, old_active))
213         flags |= value;
214     else flags &= ~value;
215     return flags;
216 }
217 NK_API int
nk_checkbox_text(struct nk_context * ctx,const char * text,int len,int * active)218 nk_checkbox_text(struct nk_context *ctx, const char *text, int len, int *active)
219 {
220     int old_val;
221     NK_ASSERT(ctx);
222     NK_ASSERT(text);
223     NK_ASSERT(active);
224     if (!ctx || !text || !active) return 0;
225     old_val = *active;
226     *active = nk_check_text(ctx, text, len, *active);
227     return old_val != *active;
228 }
229 NK_API int
nk_checkbox_flags_text(struct nk_context * ctx,const char * text,int len,unsigned int * flags,unsigned int value)230 nk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,
231     unsigned int *flags, unsigned int value)
232 {
233     int active;
234     NK_ASSERT(ctx);
235     NK_ASSERT(text);
236     NK_ASSERT(flags);
237     if (!ctx || !text || !flags) return 0;
238 
239     active = (int)((*flags & value) & value);
240     if (nk_checkbox_text(ctx, text, len, &active)) {
241         if (active) *flags |= value;
242         else *flags &= ~value;
243         return 1;
244     }
245     return 0;
246 }
nk_check_label(struct nk_context * ctx,const char * label,int active)247 NK_API int nk_check_label(struct nk_context *ctx, const char *label, int active)
248 {
249     return nk_check_text(ctx, label, nk_strlen(label), active);
250 }
nk_check_flags_label(struct nk_context * ctx,const char * label,unsigned int flags,unsigned int value)251 NK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,
252     unsigned int flags, unsigned int value)
253 {
254     return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);
255 }
nk_checkbox_label(struct nk_context * ctx,const char * label,int * active)256 NK_API int nk_checkbox_label(struct nk_context *ctx, const char *label, int *active)
257 {
258     return nk_checkbox_text(ctx, label, nk_strlen(label), active);
259 }
nk_checkbox_flags_label(struct nk_context * ctx,const char * label,unsigned int * flags,unsigned int value)260 NK_API int nk_checkbox_flags_label(struct nk_context *ctx, const char *label,
261     unsigned int *flags, unsigned int value)
262 {
263     return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);
264 }
265 /*----------------------------------------------------------------
266  *
267  *                          OPTION
268  *
269  * --------------------------------------------------------------*/
270 NK_API int
nk_option_text(struct nk_context * ctx,const char * text,int len,int is_active)271 nk_option_text(struct nk_context *ctx, const char *text, int len, int is_active)
272 {
273     struct nk_window *win;
274     struct nk_panel *layout;
275     const struct nk_input *in;
276     const struct nk_style *style;
277 
278     struct nk_rect bounds;
279     enum nk_widget_layout_states state;
280 
281     NK_ASSERT(ctx);
282     NK_ASSERT(ctx->current);
283     NK_ASSERT(ctx->current->layout);
284     if (!ctx || !ctx->current || !ctx->current->layout)
285         return is_active;
286 
287     win = ctx->current;
288     style = &ctx->style;
289     layout = win->layout;
290 
291     state = nk_widget(&bounds, ctx);
292     if (!state) return (int)state;
293     in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
294     nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,
295         text, len, NK_TOGGLE_OPTION, &style->option, in, style->font);
296     return is_active;
297 }
298 NK_API int
nk_radio_text(struct nk_context * ctx,const char * text,int len,int * active)299 nk_radio_text(struct nk_context *ctx, const char *text, int len, int *active)
300 {
301     int old_value;
302     NK_ASSERT(ctx);
303     NK_ASSERT(text);
304     NK_ASSERT(active);
305     if (!ctx || !text || !active) return 0;
306     old_value = *active;
307     *active = nk_option_text(ctx, text, len, old_value);
308     return old_value != *active;
309 }
310 NK_API int
nk_option_label(struct nk_context * ctx,const char * label,int active)311 nk_option_label(struct nk_context *ctx, const char *label, int active)
312 {
313     return nk_option_text(ctx, label, nk_strlen(label), active);
314 }
315 NK_API int
nk_radio_label(struct nk_context * ctx,const char * label,int * active)316 nk_radio_label(struct nk_context *ctx, const char *label, int *active)
317 {
318     return nk_radio_text(ctx, label, nk_strlen(label), active);
319 }
320 
321