nuklear_property.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include "nuklear.h"
  2. #include "nuklear_internal.h"
  3. /* ===============================================================
  4. *
  5. * PROPERTY
  6. *
  7. * ===============================================================*/
  8. NK_LIB void
  9. nk_drag_behavior(nk_flags *state, const struct nk_input *in,
  10. struct nk_rect drag, struct nk_property_variant *variant,
  11. float inc_per_pixel)
  12. {
  13. int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;
  14. int left_mouse_click_in_cursor = in &&
  15. nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);
  16. nk_widget_state_reset(state);
  17. if (nk_input_is_mouse_hovering_rect(in, drag))
  18. *state = NK_WIDGET_STATE_HOVERED;
  19. if (left_mouse_down && left_mouse_click_in_cursor) {
  20. float delta, pixels;
  21. pixels = in->mouse.delta.x;
  22. delta = pixels * inc_per_pixel;
  23. switch (variant->kind) {
  24. default: break;
  25. case NK_PROPERTY_INT:
  26. variant->value.i = variant->value.i + (int)delta;
  27. variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
  28. break;
  29. case NK_PROPERTY_FLOAT:
  30. variant->value.f = variant->value.f + (float)delta;
  31. variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
  32. break;
  33. case NK_PROPERTY_DOUBLE:
  34. variant->value.d = variant->value.d + (double)delta;
  35. variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
  36. break;
  37. }
  38. *state = NK_WIDGET_STATE_ACTIVE;
  39. }
  40. if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))
  41. *state |= NK_WIDGET_STATE_ENTERED;
  42. else if (nk_input_is_mouse_prev_hovering_rect(in, drag))
  43. *state |= NK_WIDGET_STATE_LEFT;
  44. }
  45. NK_LIB void
  46. nk_property_behavior(nk_flags *ws, const struct nk_input *in,
  47. struct nk_rect property, struct nk_rect label, struct nk_rect edit,
  48. struct nk_rect empty, int *state, struct nk_property_variant *variant,
  49. float inc_per_pixel)
  50. {
  51. nk_widget_state_reset(ws);
  52. if (in && *state == NK_PROPERTY_DEFAULT) {
  53. if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))
  54. *state = NK_PROPERTY_EDIT;
  55. else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))
  56. *state = NK_PROPERTY_DRAG;
  57. else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))
  58. *state = NK_PROPERTY_DRAG;
  59. }
  60. if (*state == NK_PROPERTY_DRAG) {
  61. nk_drag_behavior(ws, in, property, variant, inc_per_pixel);
  62. if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;
  63. }
  64. }
  65. NK_LIB void
  66. nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,
  67. const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,
  68. const char *name, int len, const struct nk_user_font *font)
  69. {
  70. struct nk_text text;
  71. const struct nk_style_item *background;
  72. /* select correct background and text color */
  73. if (state & NK_WIDGET_STATE_ACTIVED) {
  74. background = &style->active;
  75. text.text = style->label_active;
  76. } else if (state & NK_WIDGET_STATE_HOVER) {
  77. background = &style->hover;
  78. text.text = style->label_hover;
  79. } else {
  80. background = &style->normal;
  81. text.text = style->label_normal;
  82. }
  83. text.text = nk_rgb_factor(text.text, style->color_factor);
  84. /* draw background */
  85. switch(background->type) {
  86. case NK_STYLE_ITEM_IMAGE:
  87. text.background = nk_rgba(0, 0, 0, 0);
  88. nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
  89. break;
  90. case NK_STYLE_ITEM_NINE_SLICE:
  91. text.background = nk_rgba(0, 0, 0, 0);
  92. nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
  93. break;
  94. case NK_STYLE_ITEM_COLOR:
  95. text.background = background->data.color;
  96. nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
  97. nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
  98. break;
  99. }
  100. /* draw label */
  101. text.padding = nk_vec2(0,0);
  102. if (name && name[0] != '#') {
  103. nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);
  104. }
  105. }
  106. NK_LIB void
  107. nk_do_property(nk_flags *ws,
  108. struct nk_command_buffer *out, struct nk_rect property,
  109. const char *name, struct nk_property_variant *variant,
  110. float inc_per_pixel, char *buffer, int *len,
  111. int *state, int *cursor, int *select_begin, int *select_end,
  112. const struct nk_style_property *style,
  113. enum nk_property_filter filter, struct nk_input *in,
  114. const struct nk_user_font *font, struct nk_text_edit *text_edit,
  115. enum nk_button_behavior behavior)
  116. {
  117. const nk_plugin_filter filters[] = {
  118. nk_filter_decimal,
  119. nk_filter_float
  120. };
  121. nk_bool active, old;
  122. int num_len = 0, name_len = 0;
  123. char string[NK_MAX_NUMBER_BUFFER];
  124. float size;
  125. char *dst = 0;
  126. int *length;
  127. struct nk_rect left;
  128. struct nk_rect right;
  129. struct nk_rect label;
  130. struct nk_rect edit;
  131. struct nk_rect empty;
  132. /* left decrement button */
  133. left.h = font->height/2;
  134. left.w = left.h;
  135. left.x = property.x + style->border + style->padding.x;
  136. left.y = property.y + style->border + property.h/2.0f - left.h/2;
  137. /* text label */
  138. if (name && name[0] != '#') {
  139. name_len = nk_strlen(name);
  140. }
  141. size = font->width(font->userdata, font->height, name, name_len);
  142. label.x = left.x + left.w + style->padding.x;
  143. label.w = (float)size + 2 * style->padding.x;
  144. label.y = property.y + style->border + style->padding.y;
  145. label.h = property.h - (2 * style->border + 2 * style->padding.y);
  146. /* right increment button */
  147. right.y = left.y;
  148. right.w = left.w;
  149. right.h = left.h;
  150. right.x = property.x + property.w - (right.w + style->padding.x);
  151. /* edit */
  152. if (*state == NK_PROPERTY_EDIT) {
  153. size = font->width(font->userdata, font->height, buffer, *len);
  154. size += style->edit.cursor_size;
  155. length = len;
  156. dst = buffer;
  157. } else {
  158. switch (variant->kind) {
  159. default: break;
  160. case NK_PROPERTY_INT:
  161. nk_itoa(string, variant->value.i);
  162. num_len = nk_strlen(string);
  163. break;
  164. case NK_PROPERTY_FLOAT:
  165. NK_DTOA(string, (double)variant->value.f);
  166. num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
  167. break;
  168. case NK_PROPERTY_DOUBLE:
  169. NK_DTOA(string, variant->value.d);
  170. num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);
  171. break;
  172. }
  173. size = font->width(font->userdata, font->height, string, num_len);
  174. dst = string;
  175. length = &num_len;
  176. }
  177. edit.w = (float)size + 2 * style->padding.x;
  178. edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));
  179. edit.x = right.x - (edit.w + style->padding.x);
  180. edit.y = property.y + style->border;
  181. edit.h = property.h - (2 * style->border);
  182. /* empty left space activator */
  183. empty.w = edit.x - (label.x + label.w);
  184. empty.x = label.x + label.w;
  185. empty.y = property.y;
  186. empty.h = property.h;
  187. /* update property */
  188. old = (*state == NK_PROPERTY_EDIT);
  189. nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);
  190. /* draw property */
  191. if (style->draw_begin) style->draw_begin(out, style->userdata);
  192. nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);
  193. if (style->draw_end) style->draw_end(out, style->userdata);
  194. /* execute right button */
  195. if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {
  196. switch (variant->kind) {
  197. default: break;
  198. case NK_PROPERTY_INT:
  199. variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;
  200. case NK_PROPERTY_FLOAT:
  201. variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;
  202. case NK_PROPERTY_DOUBLE:
  203. variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;
  204. }
  205. }
  206. /* execute left button */
  207. if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {
  208. switch (variant->kind) {
  209. default: break;
  210. case NK_PROPERTY_INT:
  211. variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;
  212. case NK_PROPERTY_FLOAT:
  213. variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;
  214. case NK_PROPERTY_DOUBLE:
  215. variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;
  216. }
  217. }
  218. if (old != NK_PROPERTY_EDIT && (*state == NK_PROPERTY_EDIT)) {
  219. /* property has been activated so setup buffer */
  220. NK_MEMCPY(buffer, dst, (nk_size)*length);
  221. *cursor = nk_utf_len(buffer, *length);
  222. *len = *length;
  223. length = len;
  224. dst = buffer;
  225. active = 0;
  226. } else active = (*state == NK_PROPERTY_EDIT);
  227. /* execute and run text edit field */
  228. nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);
  229. text_edit->active = (unsigned char)active;
  230. text_edit->string.len = *length;
  231. text_edit->cursor = NK_CLAMP(0, *cursor, *length);
  232. text_edit->select_start = NK_CLAMP(0,*select_begin, *length);
  233. text_edit->select_end = NK_CLAMP(0,*select_end, *length);
  234. text_edit->string.buffer.allocated = (nk_size)*length;
  235. text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;
  236. text_edit->string.buffer.memory.ptr = dst;
  237. text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;
  238. text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;
  239. nk_do_edit(ws, out, edit, (int)NK_EDIT_FIELD|(int)NK_EDIT_AUTO_SELECT,
  240. filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);
  241. *length = text_edit->string.len;
  242. *cursor = text_edit->cursor;
  243. *select_begin = text_edit->select_start;
  244. *select_end = text_edit->select_end;
  245. if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))
  246. text_edit->active = nk_false;
  247. if (active && !text_edit->active) {
  248. /* property is now not active so convert edit text to value*/
  249. *state = NK_PROPERTY_DEFAULT;
  250. buffer[*len] = '\0';
  251. switch (variant->kind) {
  252. default: break;
  253. case NK_PROPERTY_INT:
  254. variant->value.i = nk_strtoi(buffer, 0);
  255. variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);
  256. break;
  257. case NK_PROPERTY_FLOAT:
  258. nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
  259. variant->value.f = nk_strtof(buffer, 0);
  260. variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);
  261. break;
  262. case NK_PROPERTY_DOUBLE:
  263. nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);
  264. variant->value.d = nk_strtod(buffer, 0);
  265. variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);
  266. break;
  267. }
  268. }
  269. }
  270. NK_LIB struct nk_property_variant
  271. nk_property_variant_int(int value, int min_value, int max_value, int step)
  272. {
  273. struct nk_property_variant result;
  274. result.kind = NK_PROPERTY_INT;
  275. result.value.i = value;
  276. result.min_value.i = min_value;
  277. result.max_value.i = max_value;
  278. result.step.i = step;
  279. return result;
  280. }
  281. NK_LIB struct nk_property_variant
  282. nk_property_variant_float(float value, float min_value, float max_value, float step)
  283. {
  284. struct nk_property_variant result;
  285. result.kind = NK_PROPERTY_FLOAT;
  286. result.value.f = value;
  287. result.min_value.f = min_value;
  288. result.max_value.f = max_value;
  289. result.step.f = step;
  290. return result;
  291. }
  292. NK_LIB struct nk_property_variant
  293. nk_property_variant_double(double value, double min_value, double max_value,
  294. double step)
  295. {
  296. struct nk_property_variant result;
  297. result.kind = NK_PROPERTY_DOUBLE;
  298. result.value.d = value;
  299. result.min_value.d = min_value;
  300. result.max_value.d = max_value;
  301. result.step.d = step;
  302. return result;
  303. }
  304. NK_LIB void
  305. nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,
  306. float inc_per_pixel, const enum nk_property_filter filter)
  307. {
  308. struct nk_window *win;
  309. struct nk_panel *layout;
  310. struct nk_input *in;
  311. const struct nk_style *style;
  312. struct nk_rect bounds;
  313. enum nk_widget_layout_states s;
  314. int *state = 0;
  315. nk_hash hash = 0;
  316. char *buffer = 0;
  317. int *len = 0;
  318. int *cursor = 0;
  319. int *select_begin = 0;
  320. int *select_end = 0;
  321. int old_state;
  322. char dummy_buffer[NK_MAX_NUMBER_BUFFER];
  323. int dummy_state = NK_PROPERTY_DEFAULT;
  324. int dummy_length = 0;
  325. int dummy_cursor = 0;
  326. int dummy_select_begin = 0;
  327. int dummy_select_end = 0;
  328. NK_ASSERT(ctx);
  329. NK_ASSERT(ctx->current);
  330. NK_ASSERT(ctx->current->layout);
  331. if (!ctx || !ctx->current || !ctx->current->layout)
  332. return;
  333. win = ctx->current;
  334. layout = win->layout;
  335. style = &ctx->style;
  336. s = nk_widget(&bounds, ctx);
  337. if (!s) return;
  338. /* calculate hash from name */
  339. if (name[0] == '#') {
  340. hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);
  341. name++; /* special number hash */
  342. } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);
  343. /* check if property is currently hot item */
  344. if (win->property.active && hash == win->property.name) {
  345. buffer = win->property.buffer;
  346. len = &win->property.length;
  347. cursor = &win->property.cursor;
  348. state = &win->property.state;
  349. select_begin = &win->property.select_start;
  350. select_end = &win->property.select_end;
  351. } else {
  352. buffer = dummy_buffer;
  353. len = &dummy_length;
  354. cursor = &dummy_cursor;
  355. state = &dummy_state;
  356. select_begin = &dummy_select_begin;
  357. select_end = &dummy_select_end;
  358. }
  359. /* execute property widget */
  360. old_state = *state;
  361. ctx->text_edit.clip = ctx->clip;
  362. in = ((s == NK_WIDGET_ROM && !win->property.active) ||
  363. layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED) ? 0 : &ctx->input;
  364. nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,
  365. variant, inc_per_pixel, buffer, len, state, cursor, select_begin,
  366. select_end, &style->property, filter, in, style->font, &ctx->text_edit,
  367. ctx->button_behavior);
  368. if (in && *state != NK_PROPERTY_DEFAULT && !win->property.active) {
  369. /* current property is now hot */
  370. win->property.active = 1;
  371. NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);
  372. win->property.length = *len;
  373. win->property.cursor = *cursor;
  374. win->property.state = *state;
  375. win->property.name = hash;
  376. win->property.select_start = *select_begin;
  377. win->property.select_end = *select_end;
  378. if (*state == NK_PROPERTY_DRAG) {
  379. ctx->input.mouse.grab = nk_true;
  380. ctx->input.mouse.grabbed = nk_true;
  381. }
  382. }
  383. /* check if previously active property is now inactive */
  384. if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {
  385. if (old_state == NK_PROPERTY_DRAG) {
  386. ctx->input.mouse.grab = nk_false;
  387. ctx->input.mouse.grabbed = nk_false;
  388. ctx->input.mouse.ungrab = nk_true;
  389. }
  390. win->property.select_start = 0;
  391. win->property.select_end = 0;
  392. win->property.active = 0;
  393. }
  394. }
  395. NK_API void
  396. nk_property_int(struct nk_context *ctx, const char *name,
  397. int min, int *val, int max, int step, float inc_per_pixel)
  398. {
  399. struct nk_property_variant variant;
  400. NK_ASSERT(ctx);
  401. NK_ASSERT(name);
  402. NK_ASSERT(val);
  403. if (!ctx || !ctx->current || !name || !val) return;
  404. variant = nk_property_variant_int(*val, min, max, step);
  405. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
  406. *val = variant.value.i;
  407. }
  408. NK_API void
  409. nk_property_float(struct nk_context *ctx, const char *name,
  410. float min, float *val, float max, float step, float inc_per_pixel)
  411. {
  412. struct nk_property_variant variant;
  413. NK_ASSERT(ctx);
  414. NK_ASSERT(name);
  415. NK_ASSERT(val);
  416. if (!ctx || !ctx->current || !name || !val) return;
  417. variant = nk_property_variant_float(*val, min, max, step);
  418. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
  419. *val = variant.value.f;
  420. }
  421. NK_API void
  422. nk_property_double(struct nk_context *ctx, const char *name,
  423. double min, double *val, double max, double step, float inc_per_pixel)
  424. {
  425. struct nk_property_variant variant;
  426. NK_ASSERT(ctx);
  427. NK_ASSERT(name);
  428. NK_ASSERT(val);
  429. if (!ctx || !ctx->current || !name || !val) return;
  430. variant = nk_property_variant_double(*val, min, max, step);
  431. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
  432. *val = variant.value.d;
  433. }
  434. NK_API int
  435. nk_propertyi(struct nk_context *ctx, const char *name, int min, int val,
  436. int max, int step, float inc_per_pixel)
  437. {
  438. struct nk_property_variant variant;
  439. NK_ASSERT(ctx);
  440. NK_ASSERT(name);
  441. if (!ctx || !ctx->current || !name) return val;
  442. variant = nk_property_variant_int(val, min, max, step);
  443. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);
  444. val = variant.value.i;
  445. return val;
  446. }
  447. NK_API float
  448. nk_propertyf(struct nk_context *ctx, const char *name, float min,
  449. float val, float max, float step, float inc_per_pixel)
  450. {
  451. struct nk_property_variant variant;
  452. NK_ASSERT(ctx);
  453. NK_ASSERT(name);
  454. if (!ctx || !ctx->current || !name) return val;
  455. variant = nk_property_variant_float(val, min, max, step);
  456. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
  457. val = variant.value.f;
  458. return val;
  459. }
  460. NK_API double
  461. nk_propertyd(struct nk_context *ctx, const char *name, double min,
  462. double val, double max, double step, float inc_per_pixel)
  463. {
  464. struct nk_property_variant variant;
  465. NK_ASSERT(ctx);
  466. NK_ASSERT(name);
  467. if (!ctx || !ctx->current || !name) return val;
  468. variant = nk_property_variant_double(val, min, max, step);
  469. nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);
  470. val = variant.value.d;
  471. return val;
  472. }