nuklear_slider.c 9.3 KB

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