|
@@ -141,6 +141,7 @@
|
|
// with previous char)
|
|
// with previous char)
|
|
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
|
|
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
|
|
// (return type is int, -1 means not valid to insert)
|
|
// (return type is int, -1 means not valid to insert)
|
|
|
|
+// (not supported if you want to use UTF-8, see below)
|
|
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
|
|
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
|
|
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
|
|
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
|
|
// as manually wordwrapping for end-of-line positioning
|
|
// as manually wordwrapping for end-of-line positioning
|
|
@@ -178,6 +179,13 @@
|
|
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
|
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
|
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
|
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
|
//
|
|
//
|
|
|
|
+// To support UTF-8:
|
|
|
|
+//
|
|
|
|
+// STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
|
|
|
|
+// STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
|
|
|
|
+// Do NOT define STB_TEXTEDIT_KEYTOTEXT.
|
|
|
|
+// Instead, call stb_textedit_text() directly for text contents.
|
|
|
|
+//
|
|
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
|
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
|
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
|
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
|
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
|
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
|
@@ -250,8 +258,10 @@
|
|
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
|
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
|
// transformed into text and stb_textedit_text() is automatically called.
|
|
// transformed into text and stb_textedit_text() is automatically called.
|
|
//
|
|
//
|
|
-// text: [DEAR IMGUI] added 2024-09
|
|
|
|
-// call this to text inputs sent to the textfield.
|
|
|
|
|
|
+// text: (added 2025)
|
|
|
|
+// call this to directly send text input the textfield, which is required
|
|
|
|
+// for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
|
|
|
|
+// cannot infer text length.
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// When rendering, you can read the cursor position and selection state from
|
|
// When rendering, you can read the cursor position and selection state from
|
|
@@ -400,6 +410,16 @@ typedef struct
|
|
#define IMSTB_TEXTEDIT_memmove memmove
|
|
#define IMSTB_TEXTEDIT_memmove memmove
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+// [DEAR IMGUI]
|
|
|
|
+// Functions must be implemented for UTF8 support
|
|
|
|
+// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
|
|
|
+// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
|
|
|
+#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
|
|
|
+#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1)
|
|
|
|
+#endif
|
|
|
|
+#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
|
|
|
+#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1)
|
|
|
|
+#endif
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
@@ -648,17 +668,6 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// [DEAR IMGUI]
|
|
|
|
-// Functions must be implemented for UTF8 support
|
|
|
|
-// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
|
|
|
-// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
|
|
|
-#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
|
|
|
-#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
|
|
|
|
-#endif
|
|
|
|
-#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
|
|
|
-#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
#ifdef STB_TEXTEDIT_IS_SPACE
|
|
#ifdef STB_TEXTEDIT_IS_SPACE
|
|
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
|
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
|
{
|
|
{
|
|
@@ -668,9 +677,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
|
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
|
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
|
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
|
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
|
{
|
|
{
|
|
- --c; // always move at least one character
|
|
|
|
- while( c >= 0 && !is_word_boundary( str, c ) )
|
|
|
|
- --c;
|
|
|
|
|
|
+ c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character
|
|
|
|
+ while (c >= 0 && !is_word_boundary(str, c))
|
|
|
|
+ c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
|
|
|
|
|
|
if( c < 0 )
|
|
if( c < 0 )
|
|
c = 0;
|
|
c = 0;
|
|
@@ -684,9 +693,9 @@ static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c
|
|
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
|
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
|
{
|
|
{
|
|
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
|
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
|
- ++c; // always move at least one character
|
|
|
|
|
|
+ c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); // always move at least one character
|
|
while( c < len && !is_word_boundary( str, c ) )
|
|
while( c < len && !is_word_boundary( str, c ) )
|
|
- ++c;
|
|
|
|
|
|
+ c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
|
|
|
|
|
|
if( c > len )
|
|
if( c > len )
|
|
c = len;
|
|
c = len;
|
|
@@ -739,6 +748,7 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
|
|
#define STB_TEXTEDIT_KEYTYPE int
|
|
#define STB_TEXTEDIT_KEYTYPE int
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+// API key: process text input
|
|
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
|
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
|
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
|
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
|
{
|
|
{
|
|
@@ -753,8 +763,7 @@ static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* sta
|
|
state->cursor += text_len;
|
|
state->cursor += text_len;
|
|
state->has_preferred_x = 0;
|
|
state->has_preferred_x = 0;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- else {
|
|
|
|
|
|
+ } else {
|
|
stb_textedit_delete_selection(str, state); // implicitly clamps
|
|
stb_textedit_delete_selection(str, state); // implicitly clamps
|
|
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
|
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
|
stb_text_makeundo_insert(state, state->cursor, text_len);
|
|
stb_text_makeundo_insert(state, state->cursor, text_len);
|
|
@@ -771,6 +780,7 @@ retry:
|
|
switch (key) {
|
|
switch (key) {
|
|
default: {
|
|
default: {
|
|
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
|
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
|
|
|
+ // This is not suitable for UTF-8 support.
|
|
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
|
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
|
if (c > 0) {
|
|
if (c > 0) {
|
|
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
|
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
|
@@ -918,8 +928,9 @@ retry:
|
|
state->cursor = start;
|
|
state->cursor = start;
|
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
|
x = row.x0;
|
|
x = row.x0;
|
|
- for (i=0; i < row.num_chars; ++i) {
|
|
|
|
|
|
+ for (i=0; i < row.num_chars; ) {
|
|
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
|
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
|
|
|
+ int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
|
break;
|
|
break;
|
|
@@ -927,7 +938,8 @@ retry:
|
|
x += dx;
|
|
x += dx;
|
|
if (x > goal_x)
|
|
if (x > goal_x)
|
|
break;
|
|
break;
|
|
- state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
|
|
|
|
+ i += next - state->cursor;
|
|
|
|
+ state->cursor = next;
|
|
}
|
|
}
|
|
stb_textedit_clamp(str, state);
|
|
stb_textedit_clamp(str, state);
|
|
|
|
|
|
@@ -980,8 +992,9 @@ retry:
|
|
state->cursor = find.prev_first;
|
|
state->cursor = find.prev_first;
|
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
|
x = row.x0;
|
|
x = row.x0;
|
|
- for (i=0; i < row.num_chars; ++i) {
|
|
|
|
|
|
+ for (i=0; i < row.num_chars; ) {
|
|
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
|
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
|
|
|
+ int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
|
break;
|
|
break;
|
|
@@ -989,7 +1002,8 @@ retry:
|
|
x += dx;
|
|
x += dx;
|
|
if (x > goal_x)
|
|
if (x > goal_x)
|
|
break;
|
|
break;
|
|
- state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
|
|
|
|
+ i += next - state->cursor;
|
|
|
|
+ state->cursor = next;
|
|
}
|
|
}
|
|
stb_textedit_clamp(str, state);
|
|
stb_textedit_clamp(str, state);
|
|
|
|
|
|
@@ -1002,8 +1016,13 @@ retry:
|
|
// go to previous line
|
|
// go to previous line
|
|
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
|
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
|
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
|
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
|
- while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
|
|
|
|
- --prev_scan;
|
|
|
|
|
|
+ while (prev_scan > 0)
|
|
|
|
+ {
|
|
|
|
+ int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan);
|
|
|
|
+ if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
|
|
|
|
+ break;
|
|
|
|
+ prev_scan = prev;
|
|
|
|
+ }
|
|
find.first_char = find.prev_first;
|
|
find.first_char = find.prev_first;
|
|
find.prev_first = prev_scan;
|
|
find.prev_first = prev_scan;
|
|
}
|
|
}
|
|
@@ -1082,7 +1101,7 @@ retry:
|
|
if (state->single_line)
|
|
if (state->single_line)
|
|
state->cursor = 0;
|
|
state->cursor = 0;
|
|
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
- --state->cursor;
|
|
|
|
|
|
+ state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
|
state->has_preferred_x = 0;
|
|
state->has_preferred_x = 0;
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -1094,9 +1113,9 @@ retry:
|
|
stb_textedit_clamp(str, state);
|
|
stb_textedit_clamp(str, state);
|
|
stb_textedit_move_to_first(state);
|
|
stb_textedit_move_to_first(state);
|
|
if (state->single_line)
|
|
if (state->single_line)
|
|
- state->cursor = n;
|
|
|
|
|
|
+ state->cursor = n;
|
|
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
- ++state->cursor;
|
|
|
|
|
|
+ state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
state->has_preferred_x = 0;
|
|
state->has_preferred_x = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1110,7 +1129,7 @@ retry:
|
|
if (state->single_line)
|
|
if (state->single_line)
|
|
state->cursor = 0;
|
|
state->cursor = 0;
|
|
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
- --state->cursor;
|
|
|
|
|
|
+ state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
|
state->select_end = state->cursor;
|
|
state->select_end = state->cursor;
|
|
state->has_preferred_x = 0;
|
|
state->has_preferred_x = 0;
|
|
break;
|
|
break;
|
|
@@ -1125,7 +1144,7 @@ retry:
|
|
if (state->single_line)
|
|
if (state->single_line)
|
|
state->cursor = n;
|
|
state->cursor = n;
|
|
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
- ++state->cursor;
|
|
|
|
|
|
+ state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
|
state->select_end = state->cursor;
|
|
state->select_end = state->cursor;
|
|
state->has_preferred_x = 0;
|
|
state->has_preferred_x = 0;
|
|
break;
|
|
break;
|