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_edit.c
1#include "nuklear.h"
2#include "nuklear_internal.h"
3
4/* ===============================================================
5 *
6 * FILTER
7 *
8 * ===============================================================*/
9NK_API nk_bool
10nk_filter_default(const struct nk_text_edit *box, nk_rune unicode)
11{
12 NK_UNUSED(unicode);
13 NK_UNUSED(box);
14 return nk_true;
15}
16NK_API nk_bool
17nk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)
18{
19 NK_UNUSED(box);
20 if (unicode > 128) return nk_false;
21 else return nk_true;
22}
23NK_API nk_bool
24nk_filter_float(const struct nk_text_edit *box, nk_rune unicode)
25{
26 NK_UNUSED(box);
27 if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
28 return nk_false;
29 else return nk_true;
30}
31NK_API nk_bool
32nk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)
33{
34 NK_UNUSED(box);
35 if ((unicode < '0' || unicode > '9') && unicode != '-')
36 return nk_false;
37 else return nk_true;
38}
39NK_API nk_bool
40nk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)
41{
42 NK_UNUSED(box);
43 if ((unicode < '0' || unicode > '9') &&
44 (unicode < 'a' || unicode > 'f') &&
45 (unicode < 'A' || unicode > 'F'))
46 return nk_false;
47 else return nk_true;
48}
49NK_API nk_bool
50nk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)
51{
52 NK_UNUSED(box);
53 if (unicode < '0' || unicode > '7')
54 return nk_false;
55 else return nk_true;
56}
57NK_API nk_bool
58nk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)
59{
60 NK_UNUSED(box);
61 if (unicode != '0' && unicode != '1')
62 return nk_false;
63 else return nk_true;
64}
65
66/* ===============================================================
67 *
68 * EDIT
69 *
70 * ===============================================================*/
71NK_LIB void
72nk_edit_draw_text(struct nk_command_buffer *out,
73 const struct nk_style_edit *style, float pos_x, float pos_y,
74 float x_offset, const char *text, int byte_len, float row_height,
75 const struct nk_user_font *font, struct nk_color background,
76 struct nk_color foreground, nk_bool is_selected)
77{
78 NK_ASSERT(out);
79 NK_ASSERT(font);
80 NK_ASSERT(style);
81 if (!text || !byte_len || !out || !style) return;
82
83 {int glyph_len = 0;
84 nk_rune unicode = 0;
85 int text_len = 0;
86 float line_width = 0;
87 float glyph_width;
88 const char *line = text;
89 float line_offset = 0;
90 int line_count = 0;
91
92 struct nk_text txt;
93 txt.padding = nk_vec2(0,0);
94 txt.background = background;
95 txt.text = foreground;
96
97 foreground = nk_rgb_factor(foreground, style->color_factor);
98 background = nk_rgb_factor(background, style->color_factor);
99
100 glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
101 if (!glyph_len) return;
102 while ((text_len < byte_len) && glyph_len)
103 {
104 if (unicode == '\n') {
105 /* new line separator so draw previous line */
106 struct nk_rect label;
107 label.y = pos_y + line_offset;
108 label.h = row_height;
109 label.w = line_width;
110 label.x = pos_x;
111 if (!line_count)
112 label.x += x_offset;
113
114 if (is_selected) /* selection needs to draw different background color */
115 nk_fill_rect(out, label, 0, background);
116 nk_widget_text(out, label, line, (int)((text + text_len) - line),
117 &txt, NK_TEXT_CENTERED, font);
118
119 text_len++;
120 line_count++;
121 line_width = 0;
122 line = text + text_len;
123 line_offset += row_height;
124 glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));
125 continue;
126 }
127 if (unicode == '\r') {
128 text_len++;
129 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
130 continue;
131 }
132 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
133 line_width += (float)glyph_width;
134 text_len += glyph_len;
135 glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);
136 continue;
137 }
138 if (line_width > 0) {
139 /* draw last line */
140 struct nk_rect label;
141 label.y = pos_y + line_offset;
142 label.h = row_height;
143 label.w = line_width;
144 label.x = pos_x;
145 if (!line_count)
146 label.x += x_offset;
147
148 if (is_selected)
149 nk_fill_rect(out, label, 0, background);
150 nk_widget_text(out, label, line, (int)((text + text_len) - line),
151 &txt, NK_TEXT_LEFT, font);
152 }}
153}
154NK_LIB nk_flags
155nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
156 struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,
157 struct nk_text_edit *edit, const struct nk_style_edit *style,
158 struct nk_input *in, const struct nk_user_font *font)
159{
160 struct nk_rect area;
161 nk_flags ret = 0;
162 float row_height;
163 char prev_state = 0;
164 char is_hovered = 0;
165 char select_all = 0;
166 char cursor_follow = 0;
167 struct nk_rect old_clip;
168 struct nk_rect clip;
169
170 NK_ASSERT(state);
171 NK_ASSERT(out);
172 NK_ASSERT(style);
173 if (!state || !out || !style)
174 return ret;
175
176 /* visible text area calculation */
177 area.x = bounds.x + style->padding.x + style->border;
178 area.y = bounds.y + style->padding.y + style->border;
179 area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);
180 area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);
181 if (flags & NK_EDIT_MULTILINE)
182 area.w = NK_MAX(0, area.w - style->scrollbar_size.x);
183 row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;
184
185 /* calculate clipping rectangle */
186 old_clip = out->clip;
187 nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
188
189 /* update edit state */
190 prev_state = (char)edit->active;
191 if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {
192 edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,
193 bounds.x, bounds.y, bounds.w, bounds.h);
194 }
195
196 /* (de)activate text editor */
197 if (!prev_state && edit->active) {
198 const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?
199 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;
200 /* keep scroll position when re-activating edit widget */
201 struct nk_vec2 oldscrollbar = edit->scrollbar;
202 nk_textedit_clear_state(edit, type, filter);
203 edit->scrollbar = oldscrollbar;
204 if (flags & NK_EDIT_AUTO_SELECT)
205 select_all = nk_true;
206 if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {
207 edit->cursor = edit->string.len;
208 in = 0;
209 }
210 } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;
211 if (flags & NK_EDIT_READ_ONLY)
212 edit->mode = NK_TEXT_EDIT_MODE_VIEW;
213 else if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
214 edit->mode = NK_TEXT_EDIT_MODE_INSERT;
215
216 ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;
217 if (prev_state != edit->active)
218 ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;
219
220 /* handle user input */
221 if (edit->active && in)
222 {
223 int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;
224 const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;
225 const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;
226
227 /* mouse click handler */
228 is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);
229 if (select_all) {
230 nk_textedit_select_all(edit);
231 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
232 in->mouse.buttons[NK_BUTTON_LEFT].clicked) {
233 nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);
234 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&
235 (in->mouse.delta.x != 0.0f || in->mouse.delta.y != 0.0f)) {
236 nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);
237 cursor_follow = nk_true;
238 } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&
239 in->mouse.buttons[NK_BUTTON_RIGHT].down) {
240 nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);
241 nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);
242 cursor_follow = nk_true;
243 }
244
245 {int i; /* keyboard input */
246 int old_mode = edit->mode;
247 for (i = 0; i < NK_KEY_MAX; ++i) {
248 if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */
249 if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {
250 nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);
251 cursor_follow = nk_true;
252 }
253 }
254 if (old_mode != edit->mode) {
255 in->keyboard.text_len = 0;
256 }}
257
258 /* text input */
259 edit->filter = filter;
260 if (in->keyboard.text_len) {
261 nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);
262 cursor_follow = nk_true;
263 in->keyboard.text_len = 0;
264 }
265
266 /* enter key handler */
267 if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {
268 cursor_follow = nk_true;
269 if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)
270 nk_textedit_text(edit, "\n", 1);
271 else if (flags & NK_EDIT_SIG_ENTER)
272 ret |= NK_EDIT_COMMITED;
273 else nk_textedit_text(edit, "\n", 1);
274 }
275
276 /* cut & copy handler */
277 {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);
278 int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);
279 if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))
280 {
281 int glyph_len;
282 nk_rune unicode;
283 const char *text;
284 int b = edit->select_start;
285 int e = edit->select_end;
286
287 int begin = NK_MIN(b, e);
288 int end = NK_MAX(b, e);
289 text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);
290 if (edit->clip.copy)
291 edit->clip.copy(edit->clip.userdata, text, end - begin);
292 if (cut && !(flags & NK_EDIT_READ_ONLY)){
293 nk_textedit_cut(edit);
294 cursor_follow = nk_true;
295 }
296 }}
297
298 /* paste handler */
299 {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);
300 if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {
301 edit->clip.paste(edit->clip.userdata, edit);
302 cursor_follow = nk_true;
303 }}
304
305 /* tab handler */
306 {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);
307 if (tab && (flags & NK_EDIT_ALLOW_TAB)) {
308 nk_textedit_text(edit, " ", 4);
309 cursor_follow = nk_true;
310 }}
311 }
312
313 /* set widget state */
314 if (edit->active)
315 *state = NK_WIDGET_STATE_ACTIVE;
316 else nk_widget_state_reset(state);
317
318 if (is_hovered)
319 *state |= NK_WIDGET_STATE_HOVERED;
320
321 /* DRAW EDIT */
322 {const char *text = nk_str_get_const(&edit->string);
323 int len = nk_str_len_char(&edit->string);
324
325 {/* select background colors/images */
326 const struct nk_style_item *background;
327 if (*state & NK_WIDGET_STATE_ACTIVED)
328 background = &style->active;
329 else if (*state & NK_WIDGET_STATE_HOVER)
330 background = &style->hover;
331 else background = &style->normal;
332
333 /* draw background frame */
334 switch(background->type) {
335 case NK_STYLE_ITEM_IMAGE:
336 nk_draw_image(out, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));
337 break;
338 case NK_STYLE_ITEM_NINE_SLICE:
339 nk_draw_nine_slice(out, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));
340 break;
341 case NK_STYLE_ITEM_COLOR:
342 nk_fill_rect(out, bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));
343 nk_stroke_rect(out, bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));
344 break;
345 }}
346
347
348 area.w = NK_MAX(0, area.w - style->cursor_size);
349 if (edit->active)
350 {
351 int total_lines = 1;
352 struct nk_vec2 text_size = nk_vec2(0,0);
353
354 /* text pointer positions */
355 const char *cursor_ptr = 0;
356 const char *select_begin_ptr = 0;
357 const char *select_end_ptr = 0;
358
359 /* 2D pixel positions */
360 struct nk_vec2 cursor_pos = nk_vec2(0,0);
361 struct nk_vec2 selection_offset_start = nk_vec2(0,0);
362 struct nk_vec2 selection_offset_end = nk_vec2(0,0);
363
364 int selection_begin = NK_MIN(edit->select_start, edit->select_end);
365 int selection_end = NK_MAX(edit->select_start, edit->select_end);
366
367 /* calculate total line count + total space + cursor/selection position */
368 float line_width = 0.0f;
369 if (text && len)
370 {
371 /* utf8 encoding */
372 float glyph_width;
373 int glyph_len = 0;
374 nk_rune unicode = 0;
375 int text_len = 0;
376 int glyphs = 0;
377 int row_begin = 0;
378
379 glyph_len = nk_utf_decode(text, &unicode, len);
380 glyph_width = font->width(font->userdata, font->height, text, glyph_len);
381 line_width = 0;
382
383 /* iterate all lines */
384 while ((text_len < len) && glyph_len)
385 {
386 /* set cursor 2D position and line */
387 if (!cursor_ptr && glyphs == edit->cursor)
388 {
389 int glyph_offset;
390 struct nk_vec2 out_offset;
391 struct nk_vec2 row_size;
392 const char *remaining;
393
394 /* calculate 2d position */
395 cursor_pos.y = (float)(total_lines-1) * row_height;
396 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
397 text_len-row_begin, row_height, &remaining,
398 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
399 cursor_pos.x = row_size.x;
400 cursor_ptr = text + text_len;
401 }
402
403 /* set start selection 2D position and line */
404 if (!select_begin_ptr && edit->select_start != edit->select_end &&
405 glyphs == selection_begin)
406 {
407 int glyph_offset;
408 struct nk_vec2 out_offset;
409 struct nk_vec2 row_size;
410 const char *remaining;
411
412 /* calculate 2d position */
413 selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;
414 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
415 text_len-row_begin, row_height, &remaining,
416 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
417 selection_offset_start.x = row_size.x;
418 select_begin_ptr = text + text_len;
419 }
420
421 /* set end selection 2D position and line */
422 if (!select_end_ptr && edit->select_start != edit->select_end &&
423 glyphs == selection_end)
424 {
425 int glyph_offset;
426 struct nk_vec2 out_offset;
427 struct nk_vec2 row_size;
428 const char *remaining;
429
430 /* calculate 2d position */
431 selection_offset_end.y = (float)(total_lines-1) * row_height;
432 row_size = nk_text_calculate_text_bounds(font, text+row_begin,
433 text_len-row_begin, row_height, &remaining,
434 &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);
435 selection_offset_end.x = row_size.x;
436 select_end_ptr = text + text_len;
437 }
438 if (unicode == '\n') {
439 text_size.x = NK_MAX(text_size.x, line_width);
440 total_lines++;
441 line_width = 0;
442 text_len++;
443 glyphs++;
444 row_begin = text_len;
445 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
446 glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);
447 continue;
448 }
449
450 glyphs++;
451 text_len += glyph_len;
452 line_width += (float)glyph_width;
453
454 glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);
455 glyph_width = font->width(font->userdata, font->height,
456 text+text_len, glyph_len);
457 continue;
458 }
459 text_size.y = (float)total_lines * row_height;
460
461 /* handle case when cursor is at end of text buffer */
462 if (!cursor_ptr && edit->cursor == edit->string.len) {
463 cursor_pos.x = line_width;
464 cursor_pos.y = text_size.y - row_height;
465 }
466 }
467 {
468 /* scrollbar */
469 if (cursor_follow)
470 {
471 /* update scrollbar to follow cursor */
472 if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {
473 /* horizontal scroll */
474 const float scroll_increment = area.w * 0.25f;
475 if (cursor_pos.x < edit->scrollbar.x)
476 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);
477 if (cursor_pos.x >= edit->scrollbar.x + area.w)
478 edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - area.w + scroll_increment);
479 } else edit->scrollbar.x = 0;
480
481 if (flags & NK_EDIT_MULTILINE) {
482 /* vertical scroll: like horizontal, it only adjusts if the
483 * cursor leaves the visible area, and then only just enough
484 * to keep it visible */
485 if (cursor_pos.y < edit->scrollbar.y)
486 edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y);
487 if (cursor_pos.y > edit->scrollbar.y + area.h - row_height)
488 edit->scrollbar.y = edit->scrollbar.y + row_height;
489 } else edit->scrollbar.y = 0;
490 }
491
492 /* scrollbar widget */
493 if (flags & NK_EDIT_MULTILINE)
494 {
495 nk_flags ws;
496 struct nk_rect scroll;
497 float scroll_target;
498 float scroll_offset;
499 float scroll_step;
500 float scroll_inc;
501
502 scroll = area;
503 scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;
504 scroll.w = style->scrollbar_size.x;
505
506 scroll_offset = edit->scrollbar.y;
507 scroll_step = scroll.h * 0.10f;
508 scroll_inc = scroll.h * 0.01f;
509 scroll_target = text_size.y;
510 edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, is_hovered,
511 scroll_offset, scroll_target, scroll_step, scroll_inc,
512 &style->scrollbar, in, font);
513 /* Eat mouse scroll if we're active */
514 if (is_hovered && in->mouse.scroll_delta.y) {
515 in->mouse.scroll_delta.y = 0;
516 }
517 }
518 }
519
520 /* draw text */
521 {struct nk_color background_color;
522 struct nk_color text_color;
523 struct nk_color sel_background_color;
524 struct nk_color sel_text_color;
525 struct nk_color cursor_color;
526 struct nk_color cursor_text_color;
527 const struct nk_style_item *background;
528 nk_push_scissor(out, clip);
529
530 /* select correct colors to draw */
531 if (*state & NK_WIDGET_STATE_ACTIVED) {
532 background = &style->active;
533 text_color = style->text_active;
534 sel_text_color = style->selected_text_hover;
535 sel_background_color = style->selected_hover;
536 cursor_color = style->cursor_hover;
537 cursor_text_color = style->cursor_text_hover;
538 } else if (*state & NK_WIDGET_STATE_HOVER) {
539 background = &style->hover;
540 text_color = style->text_hover;
541 sel_text_color = style->selected_text_hover;
542 sel_background_color = style->selected_hover;
543 cursor_text_color = style->cursor_text_hover;
544 cursor_color = style->cursor_hover;
545 } else {
546 background = &style->normal;
547 text_color = style->text_normal;
548 sel_text_color = style->selected_text_normal;
549 sel_background_color = style->selected_normal;
550 cursor_color = style->cursor_normal;
551 cursor_text_color = style->cursor_text_normal;
552 }
553 if (background->type == NK_STYLE_ITEM_IMAGE)
554 background_color = nk_rgba(0,0,0,0);
555 else
556 background_color = background->data.color;
557
558 cursor_color = nk_rgb_factor(cursor_color, style->color_factor);
559 cursor_text_color = nk_rgb_factor(cursor_text_color, style->color_factor);
560
561 if (edit->select_start == edit->select_end) {
562 /* no selection so just draw the complete text */
563 const char *begin = nk_str_get_const(&edit->string);
564 int l = nk_str_len_char(&edit->string);
565 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
566 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
567 background_color, text_color, nk_false);
568 } else {
569 /* edit has selection so draw 1-3 text chunks */
570 if (edit->select_start != edit->select_end && selection_begin > 0){
571 /* draw unselected text before selection */
572 const char *begin = nk_str_get_const(&edit->string);
573 NK_ASSERT(select_begin_ptr);
574 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
575 area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),
576 row_height, font, background_color, text_color, nk_false);
577 }
578 if (edit->select_start != edit->select_end) {
579 /* draw selected text */
580 NK_ASSERT(select_begin_ptr);
581 if (!select_end_ptr) {
582 const char *begin = nk_str_get_const(&edit->string);
583 select_end_ptr = begin + nk_str_len_char(&edit->string);
584 }
585 nk_edit_draw_text(out, style,
586 area.x - edit->scrollbar.x,
587 area.y + selection_offset_start.y - edit->scrollbar.y,
588 selection_offset_start.x,
589 select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),
590 row_height, font, sel_background_color, sel_text_color, nk_true);
591 }
592 if ((edit->select_start != edit->select_end &&
593 selection_end < edit->string.len))
594 {
595 /* draw unselected text after selected text */
596 const char *begin = select_end_ptr;
597 const char *end = nk_str_get_const(&edit->string) +
598 nk_str_len_char(&edit->string);
599 NK_ASSERT(select_end_ptr);
600 nk_edit_draw_text(out, style,
601 area.x - edit->scrollbar.x,
602 area.y + selection_offset_end.y - edit->scrollbar.y,
603 selection_offset_end.x,
604 begin, (int)(end - begin), row_height, font,
605 background_color, text_color, nk_true);
606 }
607 }
608
609 /* cursor */
610 if (edit->select_start == edit->select_end)
611 {
612 if (edit->cursor >= nk_str_len(&edit->string) ||
613 (cursor_ptr && *cursor_ptr == '\n')) {
614 /* draw cursor at end of line */
615 struct nk_rect cursor;
616 cursor.w = style->cursor_size;
617 cursor.h = font->height;
618 cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;
619 cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;
620 cursor.y -= edit->scrollbar.y;
621 nk_fill_rect(out, cursor, 0, cursor_color);
622 } else {
623 /* draw cursor inside text */
624 int glyph_len;
625 struct nk_rect label;
626 struct nk_text txt;
627
628 nk_rune unicode;
629 NK_ASSERT(cursor_ptr);
630 glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);
631
632 label.x = area.x + cursor_pos.x - edit->scrollbar.x;
633 label.y = area.y + cursor_pos.y - edit->scrollbar.y;
634 label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);
635 label.h = row_height;
636
637 txt.padding = nk_vec2(0,0);
638 txt.background = cursor_color;;
639 txt.text = cursor_text_color;
640 nk_fill_rect(out, label, 0, cursor_color);
641 nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);
642 }
643 }}
644 } else {
645 /* not active so just draw text */
646 int l = nk_str_len_char(&edit->string);
647 const char *begin = nk_str_get_const(&edit->string);
648
649 const struct nk_style_item *background;
650 struct nk_color background_color;
651 struct nk_color text_color;
652 nk_push_scissor(out, clip);
653 if (*state & NK_WIDGET_STATE_ACTIVED) {
654 background = &style->active;
655 text_color = style->text_active;
656 } else if (*state & NK_WIDGET_STATE_HOVER) {
657 background = &style->hover;
658 text_color = style->text_hover;
659 } else {
660 background = &style->normal;
661 text_color = style->text_normal;
662 }
663 if (background->type == NK_STYLE_ITEM_IMAGE)
664 background_color = nk_rgba(0,0,0,0);
665 else
666 background_color = background->data.color;
667
668 background_color = nk_rgb_factor(background_color, style->color_factor);
669 text_color = nk_rgb_factor(text_color, style->color_factor);
670
671 nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,
672 area.y - edit->scrollbar.y, 0, begin, l, row_height, font,
673 background_color, text_color, nk_false);
674 }
675 nk_push_scissor(out, old_clip);}
676 return ret;
677}
678NK_API void
679nk_edit_focus(struct nk_context *ctx, nk_flags flags)
680{
681 nk_hash hash;
682 struct nk_window *win;
683
684 NK_ASSERT(ctx);
685 NK_ASSERT(ctx->current);
686 if (!ctx || !ctx->current) return;
687
688 win = ctx->current;
689 hash = win->edit.seq;
690 win->edit.active = nk_true;
691 win->edit.name = hash;
692 if (flags & NK_EDIT_ALWAYS_INSERT_MODE)
693 win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;
694}
695NK_API void
696nk_edit_unfocus(struct nk_context *ctx)
697{
698 struct nk_window *win;
699 NK_ASSERT(ctx);
700 NK_ASSERT(ctx->current);
701 if (!ctx || !ctx->current) return;
702
703 win = ctx->current;
704 win->edit.active = nk_false;
705 win->edit.name = 0;
706}
707NK_API nk_flags
708nk_edit_string(struct nk_context *ctx, nk_flags flags,
709 char *memory, int *len, int max, nk_plugin_filter filter)
710{
711 nk_hash hash;
712 nk_flags state;
713 struct nk_text_edit *edit;
714 struct nk_window *win;
715
716 NK_ASSERT(ctx);
717 NK_ASSERT(memory);
718 NK_ASSERT(len);
719 if (!ctx || !memory || !len)
720 return 0;
721
722 filter = (!filter) ? nk_filter_default: filter;
723 win = ctx->current;
724 hash = win->edit.seq;
725 edit = &ctx->text_edit;
726 nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?
727 NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);
728
729 if (win->edit.active && hash == win->edit.name) {
730 if (flags & NK_EDIT_NO_CURSOR)
731 edit->cursor = nk_utf_len(memory, *len);
732 else edit->cursor = win->edit.cursor;
733 if (!(flags & NK_EDIT_SELECTABLE)) {
734 edit->select_start = win->edit.cursor;
735 edit->select_end = win->edit.cursor;
736 } else {
737 edit->select_start = win->edit.sel_start;
738 edit->select_end = win->edit.sel_end;
739 }
740 edit->mode = win->edit.mode;
741 edit->scrollbar.x = (float)win->edit.scrollbar.x;
742 edit->scrollbar.y = (float)win->edit.scrollbar.y;
743 edit->active = nk_true;
744 } else edit->active = nk_false;
745
746 max = NK_MAX(1, max);
747 *len = NK_MIN(*len, max-1);
748 nk_str_init_fixed(&edit->string, memory, (nk_size)max);
749 edit->string.buffer.allocated = (nk_size)*len;
750 edit->string.len = nk_utf_len(memory, *len);
751 state = nk_edit_buffer(ctx, flags, edit, filter);
752 *len = (int)edit->string.buffer.allocated;
753
754 if (edit->active) {
755 win->edit.cursor = edit->cursor;
756 win->edit.sel_start = edit->select_start;
757 win->edit.sel_end = edit->select_end;
758 win->edit.mode = edit->mode;
759 win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;
760 win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;
761 } return state;
762}
763NK_API nk_flags
764nk_edit_buffer(struct nk_context *ctx, nk_flags flags,
765 struct nk_text_edit *edit, nk_plugin_filter filter)
766{
767 struct nk_window *win;
768 struct nk_style *style;
769 struct nk_input *in;
770
771 enum nk_widget_layout_states state;
772 struct nk_rect bounds;
773
774 nk_flags ret_flags = 0;
775 unsigned char prev_state;
776 nk_hash hash;
777
778 /* make sure correct values */
779 NK_ASSERT(ctx);
780 NK_ASSERT(edit);
781 NK_ASSERT(ctx->current);
782 NK_ASSERT(ctx->current->layout);
783 if (!ctx || !ctx->current || !ctx->current->layout)
784 return 0;
785
786 win = ctx->current;
787 style = &ctx->style;
788 state = nk_widget(&bounds, ctx);
789 if (!state) return state;
790 else if (state == NK_WIDGET_DISABLED)
791 flags |= NK_EDIT_READ_ONLY;
792 in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
793
794 /* check if edit is currently hot item */
795 hash = win->edit.seq++;
796 if (win->edit.active && hash == win->edit.name) {
797 if (flags & NK_EDIT_NO_CURSOR)
798 edit->cursor = edit->string.len;
799 if (!(flags & NK_EDIT_SELECTABLE)) {
800 edit->select_start = edit->cursor;
801 edit->select_end = edit->cursor;
802 }
803 if (flags & NK_EDIT_CLIPBOARD)
804 edit->clip = ctx->clip;
805 edit->active = (unsigned char)win->edit.active;
806 } else edit->active = nk_false;
807 edit->mode = win->edit.mode;
808
809 filter = (!filter) ? nk_filter_default: filter;
810 prev_state = (unsigned char)edit->active;
811 in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
812 ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,
813 filter, edit, &style->edit, in, style->font);
814
815 if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
816 ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
817 if (edit->active && prev_state != edit->active) {
818 /* current edit is now hot */
819 win->edit.active = nk_true;
820 win->edit.name = hash;
821 } else if (prev_state && !edit->active) {
822 /* current edit is now cold */
823 win->edit.active = nk_false;
824 } return ret_flags;
825}
826NK_API nk_flags
827nk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,
828 char *buffer, int max, nk_plugin_filter filter)
829{
830 nk_flags result;
831 int len = nk_strlen(buffer);
832 result = nk_edit_string(ctx, flags, buffer, &len, max, filter);
833 buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\0';
834 return result;
835}
836
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_API nk_bool nk_filter_default(const struct nk_text_edit *, nk_rune unicode)
filter function
@ NK_WIDGET_STATE_ACTIVED
!< widget is being hovered
Definition nuklear.h:3092
@ 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
@ NK_EDIT_INACTIVE
!< edit widget is currently being modified
Definition nuklear.h:3503
@ NK_EDIT_DEACTIVATED
!< edit widget went from state inactive to state active
Definition nuklear.h:3505
@ NK_EDIT_COMMITED
!< edit widget went from state active to state inactive
Definition nuklear.h:3506
@ NK_EDIT_ACTIVATED
!< edit widget is not active and is not being modified
Definition nuklear.h:3504
nk_size allocated
!< growing factor for dynamic memory management
Definition nuklear.h:4195
struct nk_text_edit text_edit
text editor objects are quite big because of an internal undo/redo stack.
Definition nuklear.h:5728
nk_text_width_f width
!< max height of the font
Definition nuklear.h:4009
float height
!< user provided font handle
Definition nuklear.h:4008