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_slider.c
1#include "nuklear.h"
2#include "nuklear_internal.h"
3
4/* ===============================================================
5 *
6 * SLIDER
7 *
8 * ===============================================================*/
9NK_LIB float
10nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,
11 struct nk_rect *visual_cursor, struct nk_input *in,
12 struct nk_rect bounds, float slider_min, float slider_max, float slider_value,
13 float slider_step, float slider_steps)
14{
15 int left_mouse_down;
16 int left_mouse_click_in_cursor;
17
18 /* check if visual cursor is being dragged */
19 nk_widget_state_reset(state);
20 left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
21 left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,
22 NK_BUTTON_LEFT, *visual_cursor, nk_true);
23
24 if (left_mouse_down && left_mouse_click_in_cursor) {
25 float ratio = 0;
26 const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);
27 const float pxstep = bounds.w / slider_steps;
28
29 /* only update value if the next slider step is reached */
31 if (NK_ABS(d) >= pxstep) {
32 const float steps = (float)((int)(NK_ABS(d) / pxstep));
33 slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);
34 slider_value = NK_CLAMP(slider_min, slider_value, slider_max);
35 ratio = (slider_value - slider_min)/slider_step;
36 logical_cursor->x = bounds.x + (logical_cursor->w * ratio);
37 in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;
38 }
39 }
40
41 /* slider widget state */
42 if (nk_input_is_mouse_hovering_rect(in, bounds))
44 if (*state & NK_WIDGET_STATE_HOVER &&
45 !nk_input_is_mouse_prev_hovering_rect(in, bounds))
47 else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))
48 *state |= NK_WIDGET_STATE_LEFT;
49 return slider_value;
50}
51NK_LIB void
52nk_draw_slider(struct nk_command_buffer *out, nk_flags state,
53 const struct nk_style_slider *style, const struct nk_rect *bounds,
54 const struct nk_rect *visual_cursor, float min, float value, float max)
55{
56 struct nk_rect fill;
57 struct nk_rect bar;
58 const struct nk_style_item *background;
59
60 /* select correct slider images/colors */
61 struct nk_color bar_color;
62 const struct nk_style_item *cursor;
63
64 NK_UNUSED(min);
65 NK_UNUSED(max);
66 NK_UNUSED(value);
67
68 if (state & NK_WIDGET_STATE_ACTIVED) {
69 background = &style->active;
70 bar_color = style->bar_active;
71 cursor = &style->cursor_active;
72 } else if (state & NK_WIDGET_STATE_HOVER) {
73 background = &style->hover;
74 bar_color = style->bar_hover;
75 cursor = &style->cursor_hover;
76 } else {
77 background = &style->normal;
78 bar_color = style->bar_normal;
79 cursor = &style->cursor_normal;
80 }
81
82 /* calculate slider background bar */
83 bar.x = bounds->x;
84 bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;
85 bar.w = bounds->w;
86 bar.h = bounds->h/6;
87
88 /* filled background bar style */
89 fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;
90 fill.x = bar.x;
91 fill.y = bar.y;
92 fill.h = bar.h;
93
94 /* draw background */
95 switch(background->type) {
96 case NK_STYLE_ITEM_IMAGE:
97 nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
98 break;
99 case NK_STYLE_ITEM_NINE_SLICE:
100 nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
101 break;
102 case NK_STYLE_ITEM_COLOR:
103 nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
104 nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
105 break;
106 }
107
108 /* draw slider bar */
109 nk_fill_rect(out, bar, style->rounding, nk_rgb_factor(bar_color, style->color_factor));
110 nk_fill_rect(out, fill, style->rounding, nk_rgb_factor(style->bar_filled, style->color_factor));
111
112 /* draw cursor */
113 if (cursor->type == NK_STYLE_ITEM_IMAGE)
114 nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));
115 else
116 nk_fill_circle(out, *visual_cursor, nk_rgb_factor(cursor->data.color, style->color_factor));
117}
118NK_LIB float
119nk_do_slider(nk_flags *state,
120 struct nk_command_buffer *out, struct nk_rect bounds,
121 float min, float val, float max, float step,
122 const struct nk_style_slider *style, struct nk_input *in,
123 const struct nk_user_font *font)
124{
125 float slider_range;
126 float slider_min;
127 float slider_max;
128 float slider_value;
129 float slider_steps;
130 float cursor_offset;
131
132 struct nk_rect visual_cursor;
133 struct nk_rect logical_cursor;
134
135 NK_ASSERT(style);
136 NK_ASSERT(out);
137 if (!out || !style)
138 return 0;
139
140 /* remove padding from slider bounds */
141 bounds.x = bounds.x + style->padding.x;
142 bounds.y = bounds.y + style->padding.y;
143 bounds.h = NK_MAX(bounds.h, 2*style->padding.y);
144 bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);
145 bounds.w -= 2 * style->padding.x;
146 bounds.h -= 2 * style->padding.y;
147
148 /* optional buttons */
149 if (style->show_buttons) {
150 nk_flags ws;
151 struct nk_rect button;
152 button.y = bounds.y;
153 button.w = bounds.h;
154 button.h = bounds.h;
155
156 /* decrement button */
157 button.x = bounds.x;
158 if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,
159 &style->dec_button, in, font))
160 val -= step;
161
162 /* increment button */
163 button.x = (bounds.x + bounds.w) - button.w;
164 if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,
165 &style->inc_button, in, font))
166 val += step;
167
168 bounds.x = bounds.x + button.w + style->spacing.x;
169 bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);
170 }
171
172 /* remove one cursor size to support visual cursor */
173 bounds.x += style->cursor_size.x*0.5f;
174 bounds.w -= style->cursor_size.x;
175
176 /* make sure the provided values are correct */
177 slider_max = NK_MAX(min, max);
178 slider_min = NK_MIN(min, max);
179 slider_value = NK_CLAMP(slider_min, val, slider_max);
180 slider_range = slider_max - slider_min;
181 slider_steps = slider_range / step;
182 cursor_offset = (slider_value - slider_min) / step;
183
184 /* calculate cursor
185 Basically you have two cursors. One for visual representation and interaction
186 and one for updating the actual cursor value. */
187 logical_cursor.h = bounds.h;
188 logical_cursor.w = bounds.w / slider_steps;
189 logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);
190 logical_cursor.y = bounds.y;
191
192 visual_cursor.h = style->cursor_size.y;
193 visual_cursor.w = style->cursor_size.x;
194 visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;
195 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
196
197 slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,
198 in, bounds, slider_min, slider_max, slider_value, step, slider_steps);
199 visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;
200
201 /* draw slider */
202 if (style->draw_begin) style->draw_begin(out, style->userdata);
203 nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);
204 if (style->draw_end) style->draw_end(out, style->userdata);
205 return slider_value;
206}
207NK_API nk_bool
208nk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,
209 float value_step)
210{
211 struct nk_window *win;
212 struct nk_panel *layout;
213 struct nk_input *in;
214 const struct nk_style *style;
215
216 int ret = 0;
217 float old_value;
218 struct nk_rect bounds;
219 enum nk_widget_layout_states state;
220
221 NK_ASSERT(ctx);
222 NK_ASSERT(ctx->current);
223 NK_ASSERT(ctx->current->layout);
224 NK_ASSERT(value);
225 if (!ctx || !ctx->current || !ctx->current->layout || !value)
226 return ret;
227
228 win = ctx->current;
229 style = &ctx->style;
230 layout = win->layout;
231
232 state = nk_widget(&bounds, ctx);
233 if (!state) return ret;
234 in = (/*state == NK_WIDGET_ROM || */ state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
235
236 old_value = *value;
237 *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,
238 old_value, max_value, value_step, &style->slider, in, style->font);
239 return (old_value > *value || old_value < *value);
240}
241NK_API float
242nk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)
243{
244 nk_slider_float(ctx, min, &val, max, step); return val;
245}
246NK_API int
247nk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)
248{
249 float value = (float)val;
250 nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
251 return (int)value;
252}
253NK_API nk_bool
254nk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)
255{
256 int ret;
257 float value = (float)*val;
258 ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);
259 *val = (int)value;
260 return ret;
261}
262
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_fill_rect(struct nk_command_buffer *, struct nk_rect, float rounding, struct nk_color)
filled shades
@ NK_WIDGET_STATE_LEFT
!< widget is currently activated
Definition nuklear.h:3093
@ NK_WIDGET_STATE_ACTIVED
!< widget is being hovered
Definition nuklear.h:3092
@ NK_WIDGET_STATE_ENTERED
!< widget is neither active nor hovered
Definition nuklear.h:3090
@ NK_WIDGET_STATE_HOVER
!< widget has been hovered on the current frame
Definition nuklear.h:3091
@ NK_WIDGET_STATE_ACTIVE
!< widget is being hovered
Definition nuklear.h:3095
@ NK_WIDGET_STATE_HOVERED
!< widget is from this frame on not hovered anymore
Definition nuklear.h:3094
nk_widget_layout_states
Definition nuklear.h:3081
@ NK_WIDGET_DISABLED
The widget is manually disabled and acts like NK_WIDGET_ROM.
Definition nuklear.h:3085