Skip to content
This repository has been archived by the owner on Dec 2, 2019. It is now read-only.

Bug fixes and add feature: text edit wrap #819

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
170 changes: 162 additions & 8 deletions nuklear.h
Original file line number Diff line number Diff line change
Expand Up @@ -3379,6 +3379,7 @@ enum nk_edit_events {
NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);
NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);
NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
NK_API nk_flags nk_edit_buffer_wrap(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
NK_API void nk_edit_focus(struct nk_context*, nk_flags flags);
NK_API void nk_edit_unfocus(struct nk_context*);
/* =============================================================================
Expand Down Expand Up @@ -7330,7 +7331,7 @@ nk_text_calculate_text_bounds(const struct nk_user_font *font,

*glyphs = 0;
while ((text_len < byte_len) && glyph_len) {
if (unicode == '\n') {
if ((unicode == '\n') || (unicode == '\v')) {
text_size.x = NK_MAX(text_size.x, line_width);
text_size.y += line_height;
line_width = 0;
Expand Down Expand Up @@ -8378,12 +8379,17 @@ nk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)
NK_API int
nk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)
{
return nk_str_insert_text_utf8(str, pos, text, len);
NK_ASSERT(str);
NK_ASSERT(text);
if (!str || !text || !len) return 0;

nk_str_insert_at_char(str, pos, text, len);
return len;
}
NK_API int
nk_str_insert_str_char(struct nk_str *str, int pos, const char *text)
{
return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));
return nk_str_insert_text_char(str, pos, text, nk_strlen(text));
}
NK_API int
nk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)
Expand Down Expand Up @@ -21827,6 +21833,11 @@ nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)
{
/* API paste: replace existing selection with passed-in text */
int glyphs;
int glyph_len;
nk_rune unicode;
char *str_cursor;
int cursor;

const char *text = (const char *) ctext;
if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;

Expand All @@ -21835,10 +21846,13 @@ nk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)
nk_textedit_delete_selection(state);

/* try to insert the characters */
str_cursor = nk_str_at_rune(&state->string, state->cursor, &unicode, &glyph_len);
cursor = (void *)str_cursor - state->string.buffer.memory.ptr;

glyphs = nk_utf_len(ctext, len);
if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {
if (nk_str_insert_text_char(&state->string, cursor, text, len)) {
nk_textedit_makeundo_insert(state, state->cursor, glyphs);
state->cursor += len;
state->cursor += glyphs;
state->has_preferred_x = 0;
return 1;
}
Expand Down Expand Up @@ -22621,7 +22635,7 @@ nk_edit_draw_text(struct nk_command_buffer *out,
if (!glyph_len) return;
while ((text_len < byte_len) && glyph_len)
{
if (unicode == '\n') {
if ((unicode == '\n') || (unicode == '\v')) {
/* new line separator so draw previous line */
struct nk_rect label;
label.y = pos_y + line_offset;
Expand Down Expand Up @@ -22855,6 +22869,14 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
} else nk_draw_image(out, bounds, &background->data.image, nk_white);}

area.w = NK_MAX(0, area.w - style->cursor_size);
if (flags & NK_EDIT_MULTILINE){
area.y += row_height/2.0f;
area.h -= row_height;

/* calculate clipping rectangle */
old_clip = out->clip;
nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);
}
if (edit->active)
{
int total_lines = 1;
Expand Down Expand Up @@ -22944,7 +22966,7 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
selection_offset_end.x = row_size.x;
select_end_ptr = text + text_len;
}
if (unicode == '\n') {
if ((unicode == '\n') || (unicode == '\v')) {
text_size.x = NK_MAX(text_size.x, line_width);
total_lines++;
line_width = 0;
Expand Down Expand Up @@ -22991,7 +23013,7 @@ nk_do_edit(nk_flags *state, struct nk_command_buffer *out,
/* vertical scroll */
if (cursor_pos.y < edit->scrollbar.y)
edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y - row_height);
if (cursor_pos.y >= edit->scrollbar.y + area.h)
if (cursor_pos.y >= edit->scrollbar.y + area.h - row_height)
edit->scrollbar.y = edit->scrollbar.y + row_height;
} else edit->scrollbar.y = 0;
}
Expand Down Expand Up @@ -25219,8 +25241,140 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
}
#endif

NK_API nk_flags
nk_edit_buffer_wrap(struct nk_context *ctx, nk_flags flags,
struct nk_text_edit *edit, nk_plugin_filter filter)
{
struct nk_window *win;
struct nk_style *style;
struct nk_input *in;

enum nk_widget_layout_states state;
struct nk_rect bounds;

nk_flags ret_flags = 0;
unsigned char prev_state;
nk_hash hash;

/* make sure correct values */
NK_ASSERT(ctx);
NK_ASSERT(edit);
NK_ASSERT(ctx->current);
NK_ASSERT(ctx->current->layout);
if (!ctx || !ctx->current || !ctx->current->layout)
return 0;

win = ctx->current;
style = &ctx->style;
state = nk_widget(&bounds, ctx);
if (!state) return state;

float wrap_w = bounds.w - (2.0f * style->edit.padding.x + 2 * style->edit.border) - 2 * style->font->height;
if (flags & NK_EDIT_MULTILINE)
wrap_w = NK_MAX(0, wrap_w - style->edit.scrollbar_size.x);

/* ---------------- wrap text in text edit widget ----------------------*/
char *text = nk_str_get(&edit->string);
int byte_len = nk_str_len_char(&edit->string);
double w = 0, line_w = 0;
if (text){
int text_len = 0, last_spc = 0;
int glyph_len = 0;
nk_rune unicode = 0;

glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
while ((text_len < byte_len) && glyph_len){ /* sweep the string */
glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);
/* find the good point for break a line (in space caracter) */
if ((unicode == ' ') || (unicode == '\t')){
last_spc = text_len;
glyph_len = 1;
}
/* convert line break to space temporaly, until find a good point to break */
else if (unicode == '\v'){
nk_str_delete_chars(&edit->string, text_len, 1);
if (edit->cursor >= text_len) edit->cursor--;
continue;
}
/* consider a \n caracter as a paragraph break */
else if (unicode == '\n'){
/* reset the line parameters */
last_spc = 0;
line_w = 0;
glyph_len = 1;
}

/* get graphical width of current glyph */
w = style->font->width(style->font->userdata, style->font->height, text+text_len, glyph_len);
/* update width of current line */
line_w += w;

if (line_w > wrap_w){ /* verify if current line width exceeds the drawing area */
byte_len = nk_str_len_char(&edit->string);
/* consider a tolerance of two glyphs to avoid repetitive breaks */
int tolerance = 0;
char *near_line = strpbrk(text + text_len, "\v\n");
if (near_line) tolerance = near_line - text - text_len; /* tolerance until the next break */
else tolerance = byte_len - text_len; /* tolerance until the string end */
if (tolerance > 3){ /* need to break */
if (last_spc){ /* if has a good point for break, use it */
nk_str_insert_text_char(&edit->string, last_spc + 1, "\v", 1);
if (edit->cursor >= last_spc) edit->cursor++;
/* start the current line in break point */
text_len = last_spc + 1;
glyph_len = 1;
last_spc = 0;
line_w = 0;
}
else{
nk_str_insert_text_char(&edit->string, text_len, "\v", 1);
if (edit->cursor >= text_len) edit->cursor++;
line_w = 0;
}
}
}

text_len += glyph_len;
text = nk_str_get(&edit->string);
byte_len = nk_str_len_char(&edit->string);
}
}
/*--------------------------------------------------------------*/

in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;

/* check if edit is currently hot item */
hash = win->edit.seq++;
if (win->edit.active && hash == win->edit.name) {
if (flags & NK_EDIT_NO_CURSOR)
edit->cursor = edit->string.len;
if (!(flags & NK_EDIT_SELECTABLE)) {
edit->select_start = edit->cursor;
edit->select_end = edit->cursor;
}
if (flags & NK_EDIT_CLIPBOARD)
edit->clip = ctx->clip;
edit->active = (unsigned char)win->edit.active;
} else edit->active = nk_false;
edit->mode = win->edit.mode;

filter = (!filter) ? nk_filter_default: filter;
prev_state = (unsigned char)edit->active;
in = (flags & NK_EDIT_READ_ONLY) ? 0: in;
ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags|NK_EDIT_NO_HORIZONTAL_SCROLL,
filter, edit, &style->edit, in, style->font);

if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];
if (edit->active && prev_state != edit->active) {
/* current edit is now hot */
win->edit.active = nk_true;
win->edit.name = hash;
} else if (prev_state && !edit->active) {
/* current edit is now cold */
win->edit.active = nk_false;
} return ret_flags;
}
#endif /* NK_IMPLEMENTATION */

/*
Expand Down
4 changes: 3 additions & 1 deletion src/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
/// - [yy]: Minor version with non-breaking API and library changes
/// - [zz]: Bug fix version with no direct changes to API
///
/// - 2019/03/14 (4.01.1) - Add feature: Multiline edit widget with automatic text wrap.
/// Fix some bugs too.
/// - 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to "fix" state based backends
like GLFW without breaking key repeat behavior on event based.
/// like GLFW without breaking key repeat behavior on event based.
/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame
/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to
/// clear provided buffers. So make sure to either free
Expand Down
1 change: 1 addition & 0 deletions src/nuklear.h
Original file line number Diff line number Diff line change
Expand Up @@ -3160,6 +3160,7 @@ enum nk_edit_events {
NK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);
NK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);
NK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
NK_API nk_flags nk_edit_buffer_wrap(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);
NK_API void nk_edit_focus(struct nk_context*, nk_flags flags);
NK_API void nk_edit_unfocus(struct nk_context*);
/* =============================================================================
Expand Down