181181//
182182// To support UTF-8:
183183//
184- // STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
185- // STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
184+ // STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
185+ // STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
186186// Do NOT define STB_TEXTEDIT_KEYTOTEXT.
187- // Instead, call stb_textedit_text() directly for text contents.
187+ // Instead, call stb_textedit_text() directly for text contents.
188188//
189189// Keyboard input must be encoded as a single integer value; e.g. a character code
190190// and some bitflags that represent shift states. to simplify the interface, SHIFT must
260260//
261261// text: (added 2025)
262262// call this to directly send text input the textfield, which is required
263- // for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
263+ // for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
264264// cannot infer text length.
265265//
266266//
@@ -427,7 +427,7 @@ typedef struct
427427//
428428
429429// traverse the layout to locate the nearest character to a display position
430- static int stb_text_locate_coord (IMSTB_TEXTEDIT_STRING * str , float x , float y )
430+ static int stb_text_locate_coord (IMSTB_TEXTEDIT_STRING * str , float x , float y , int * out_side_on_line )
431431{
432432 StbTexteditRow r ;
433433 int n = STB_TEXTEDIT_STRINGLEN (str );
@@ -437,6 +437,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
437437 r .x0 = r .x1 = 0 ;
438438 r .ymin = r .ymax = 0 ;
439439 r .num_chars = 0 ;
440+ * out_side_on_line = 0 ;
440441
441442 // search rows to find one that straddles 'y'
442443 while (i < n ) {
@@ -456,7 +457,10 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
456457
457458 // below all text, return 'after' last character
458459 if (i >= n )
460+ {
461+ * out_side_on_line = 1 ;
459462 return n ;
463+ }
460464
461465 // check if it's before the beginning of the line
462466 if (x < r .x0 )
@@ -469,6 +473,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
469473 for (k = 0 ; k < r .num_chars ; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX (str , i + k ) - i ) {
470474 float w = STB_TEXTEDIT_GETWIDTH (str , i , k );
471475 if (x < prev_x + w ) {
476+ * out_side_on_line = (k == 0 ) ? 0 : 1 ;
472477 if (x < prev_x + w /2 )
473478 return k + i ;
474479 else
@@ -480,6 +485,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
480485 }
481486
482487 // if the last character is a newline, return that. otherwise return 'after' the last character
488+ * out_side_on_line = 1 ;
483489 if (STB_TEXTEDIT_GETCHAR (str , i + r .num_chars - 1 ) == STB_TEXTEDIT_NEWLINE )
484490 return i + r .num_chars - 1 ;
485491 else
@@ -491,23 +497,26 @@ static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *st
491497{
492498 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
493499 // goes off the top or bottom of the text
500+ int side_on_line ;
494501 if ( state -> single_line )
495502 {
496503 StbTexteditRow r ;
497504 STB_TEXTEDIT_LAYOUTROW (& r , str , 0 );
498505 y = r .ymin ;
499506 }
500507
501- state -> cursor = stb_text_locate_coord (str , x , y );
508+ state -> cursor = stb_text_locate_coord (str , x , y , & side_on_line );
502509 state -> select_start = state -> cursor ;
503510 state -> select_end = state -> cursor ;
504511 state -> has_preferred_x = 0 ;
512+ str -> LastMoveDirectionLR = (ImS8 )(side_on_line ? ImGuiDir_Right : ImGuiDir_Left );
505513}
506514
507515// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
508516static void stb_textedit_drag (IMSTB_TEXTEDIT_STRING * str , STB_TexteditState * state , float x , float y )
509517{
510518 int p = 0 ;
519+ int side_on_line ;
511520
512521 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
513522 // goes off the top or bottom of the text
@@ -521,8 +530,9 @@ static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *sta
521530 if (state -> select_start == state -> select_end )
522531 state -> select_start = state -> cursor ;
523532
524- p = stb_text_locate_coord (str , x , y );
533+ p = stb_text_locate_coord (str , x , y , & side_on_line );
525534 state -> cursor = state -> select_end = p ;
535+ str -> LastMoveDirectionLR = (ImS8 )(side_on_line ? ImGuiDir_Right : ImGuiDir_Left );
526536}
527537
528538/////////////////////////////////////////////////////////////////////////////
@@ -572,6 +582,8 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
572582 STB_TEXTEDIT_LAYOUTROW (& r , str , i );
573583 if (n < i + r .num_chars )
574584 break ;
585+ if (str -> LastMoveDirectionLR == ImGuiDir_Right && str -> Stb -> cursor > 0 && str -> Stb -> cursor == i + r .num_chars && STB_TEXTEDIT_GETCHAR (str , i + r .num_chars - 1 ) != STB_TEXTEDIT_NEWLINE ) // [DEAR IMGUI] Wrapping point handling
586+ break ;
575587 if (i + r .num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR (str , z - 1 ) != STB_TEXTEDIT_NEWLINE ) // [DEAR IMGUI] special handling for last line
576588 break ; // [DEAR IMGUI]
577589 prev_start = i ;
@@ -668,6 +680,35 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
668680 }
669681}
670682
683+ // [DEAR IMGUI] Extracted this function so we can more easily add support for word-wrapping.
684+ #ifndef STB_TEXTEDIT_MOVELINESTART
685+ static int stb_textedit_move_line_start (IMSTB_TEXTEDIT_STRING * str , STB_TexteditState * state , int cursor )
686+ {
687+ if (state -> single_line )
688+ return 0 ;
689+ while (cursor > 0 ) {
690+ int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX (str , cursor );
691+ if (STB_TEXTEDIT_GETCHAR (str , prev ) == STB_TEXTEDIT_NEWLINE )
692+ break ;
693+ cursor = prev ;
694+ }
695+ return cursor ;
696+ }
697+ #define STB_TEXTEDIT_MOVELINESTART stb_textedit_move_line_start
698+ #endif
699+ #ifndef STB_TEXTEDIT_MOVELINEEND
700+ static int stb_textedit_move_line_end (IMSTB_TEXTEDIT_STRING * str , STB_TexteditState * state , int cursor )
701+ {
702+ int n = STB_TEXTEDIT_STRINGLEN (str );
703+ if (state -> single_line )
704+ return n ;
705+ while (cursor < n && STB_TEXTEDIT_GETCHAR (str , cursor ) != STB_TEXTEDIT_NEWLINE )
706+ cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX (str , cursor );
707+ return cursor ;
708+ }
709+ #define STB_TEXTEDIT_MOVELINEEND stb_textedit_move_line_end
710+ #endif
711+
671712#ifdef STB_TEXTEDIT_IS_SPACE
672713static int is_word_boundary ( IMSTB_TEXTEDIT_STRING * str , int idx )
673714{
@@ -921,8 +962,8 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
921962
922963 // [DEAR IMGUI]
923964 // going down while being on the last line shouldn't bring us to that line end
924- if (STB_TEXTEDIT_GETCHAR (str , find .first_char + find .length - 1 ) != STB_TEXTEDIT_NEWLINE )
925- break ;
965+ // if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
966+ // break;
926967
927968 // now find character position down a row
928969 state -> cursor = start ;
@@ -943,6 +984,8 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
943984 }
944985 stb_textedit_clamp (str , state );
945986
987+ if (state -> cursor == find .first_char + find .length )
988+ str -> LastMoveDirectionLR = ImGuiDir_Left ;
946989 state -> has_preferred_x = 1 ;
947990 state -> preferred_x = goal_x ;
948991
@@ -1007,6 +1050,10 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
10071050 }
10081051 stb_textedit_clamp (str , state );
10091052
1053+ if (state -> cursor == find .first_char )
1054+ str -> LastMoveDirectionLR = ImGuiDir_Right ;
1055+ else if (state -> cursor == find .prev_first )
1056+ str -> LastMoveDirectionLR = ImGuiDir_Left ;
10101057 state -> has_preferred_x = 1 ;
10111058 state -> preferred_x = goal_x ;
10121059
@@ -1024,7 +1071,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
10241071 prev_scan = prev ;
10251072 }
10261073 find .first_char = find .prev_first ;
1027- find .prev_first = prev_scan ;
1074+ find .prev_first = STB_TEXTEDIT_MOVELINESTART ( str , state , prev_scan ) ;
10281075 }
10291076 break ;
10301077 }
@@ -1098,24 +1145,17 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
10981145 case STB_TEXTEDIT_K_LINESTART :
10991146 stb_textedit_clamp (str , state );
11001147 stb_textedit_move_to_first (state );
1101- if (state -> single_line )
1102- state -> cursor = 0 ;
1103- else while (state -> cursor > 0 && STB_TEXTEDIT_GETCHAR (str , state -> cursor - 1 ) != STB_TEXTEDIT_NEWLINE )
1104- state -> cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX (str , state -> cursor );
1148+ state -> cursor = STB_TEXTEDIT_MOVELINESTART (str , state , state -> cursor );
11051149 state -> has_preferred_x = 0 ;
11061150 break ;
11071151
11081152#ifdef STB_TEXTEDIT_K_LINEEND2
11091153 case STB_TEXTEDIT_K_LINEEND2 :
11101154#endif
11111155 case STB_TEXTEDIT_K_LINEEND : {
1112- int n = STB_TEXTEDIT_STRINGLEN (str );
11131156 stb_textedit_clamp (str , state );
1114- stb_textedit_move_to_first (state );
1115- if (state -> single_line )
1116- state -> cursor = n ;
1117- else while (state -> cursor < n && STB_TEXTEDIT_GETCHAR (str , state -> cursor ) != STB_TEXTEDIT_NEWLINE )
1118- state -> cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX (str , state -> cursor );
1157+ stb_textedit_move_to_last (str , state );
1158+ state -> cursor = STB_TEXTEDIT_MOVELINEEND (str , state , state -> cursor );
11191159 state -> has_preferred_x = 0 ;
11201160 break ;
11211161 }
@@ -1126,10 +1166,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
11261166 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT :
11271167 stb_textedit_clamp (str , state );
11281168 stb_textedit_prep_selection_at_cursor (state );
1129- if (state -> single_line )
1130- state -> cursor = 0 ;
1131- else while (state -> cursor > 0 && STB_TEXTEDIT_GETCHAR (str , state -> cursor - 1 ) != STB_TEXTEDIT_NEWLINE )
1132- state -> cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX (str , state -> cursor );
1169+ state -> cursor = STB_TEXTEDIT_MOVELINESTART (str , state , state -> cursor );
11331170 state -> select_end = state -> cursor ;
11341171 state -> has_preferred_x = 0 ;
11351172 break ;
@@ -1138,13 +1175,9 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat
11381175 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT :
11391176#endif
11401177 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT : {
1141- int n = STB_TEXTEDIT_STRINGLEN (str );
11421178 stb_textedit_clamp (str , state );
11431179 stb_textedit_prep_selection_at_cursor (state );
1144- if (state -> single_line )
1145- state -> cursor = n ;
1146- else while (state -> cursor < n && STB_TEXTEDIT_GETCHAR (str , state -> cursor ) != STB_TEXTEDIT_NEWLINE )
1147- state -> cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX (str , state -> cursor );
1180+ state -> cursor = STB_TEXTEDIT_MOVELINEEND (str , state , state -> cursor );
11481181 state -> select_end = state -> cursor ;
11491182 state -> has_preferred_x = 0 ;
11501183 break ;
0 commit comments