296 #ifndef INCLUDE_IMSTB_TEXTEDIT_H 297 #define INCLUDE_IMSTB_TEXTEDIT_H 308 #ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT 309 #define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 311 #ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT 312 #define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 314 #ifndef IMSTB_TEXTEDIT_CHARTYPE 315 #define IMSTB_TEXTEDIT_CHARTYPE int 317 #ifndef IMSTB_TEXTEDIT_POSITIONTYPE 318 #define IMSTB_TEXTEDIT_POSITIONTYPE int 324 IMSTB_TEXTEDIT_POSITIONTYPE where;
325 IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
326 IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
334 IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
335 short undo_point, redo_point;
336 int undo_char_point, redo_char_point;
356 unsigned char insert_mode;
360 int row_count_per_page;
368 unsigned char cursor_at_end_of_line;
369 unsigned char initialized;
370 unsigned char has_preferred_x;
371 unsigned char single_line;
372 unsigned char padding1, padding2, padding3;
389 float baseline_y_delta;
393 #endif //INCLUDE_IMSTB_TEXTEDIT_H 406 #ifdef IMSTB_TEXTEDIT_IMPLEMENTATION 408 #ifndef IMSTB_TEXTEDIT_memmove 410 #define IMSTB_TEXTEDIT_memmove memmove 417 #ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX 418 #define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1) 420 #ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX 421 #define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1) 430 static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str,
float x,
float y)
433 int n = STB_TEXTEDIT_STRINGLEN(str);
434 float base_y = 0, prev_x;
443 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
444 if (r.num_chars <= 0)
447 if (i==0 && y < base_y + r.ymin)
450 if (y < base_y + r.ymax)
454 base_y += r.baseline_y_delta;
469 for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
470 float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
475 return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
483 if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
484 return i+r.num_chars-1;
486 return i+r.num_chars;
490 static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
494 if( state->single_line )
497 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
501 state->cursor = stb_text_locate_coord(str, x, y);
502 state->select_start = state->cursor;
503 state->select_end = state->cursor;
504 state->has_preferred_x = 0;
508 static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
514 if( state->single_line )
517 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
521 if (state->select_start == state->select_end)
522 state->select_start = state->cursor;
524 p = stb_text_locate_coord(str, x, y);
525 state->cursor = state->select_end = p;
536 static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length);
537 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length);
538 static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length);
544 int first_char, length;
550 static void stb_textedit_find_charpos(StbFindState *
find, IMSTB_TEXTEDIT_STRING *str,
int n,
int single_line)
554 int z = STB_TEXTEDIT_STRINGLEN(str);
557 if (n == z && single_line) {
559 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
561 find->first_char = 0;
563 find->height = r.ymax - r.ymin;
572 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
573 if (n < i + r.num_chars)
575 if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE)
579 find->y += r.baseline_y_delta;
587 find->first_char = first = i;
588 find->length = r.num_chars;
589 find->height = r.ymax - r.ymin;
590 find->prev_first = prev_start;
594 for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
595 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
598 #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 601 static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
603 int n = STB_TEXTEDIT_STRINGLEN(str);
604 if (STB_TEXT_HAS_SELECTION(state)) {
605 if (state->select_start > n) state->select_start = n;
606 if (state->select_end > n) state->select_end = n;
608 if (state->select_start == state->select_end)
609 state->cursor = state->select_start;
611 if (state->cursor > n) state->cursor = n;
615 static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int len)
617 stb_text_makeundo_delete(str, state, where, len);
618 STB_TEXTEDIT_DELETECHARS(str, where, len);
619 state->has_preferred_x = 0;
623 static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
625 stb_textedit_clamp(str, state);
626 if (STB_TEXT_HAS_SELECTION(state)) {
627 if (state->select_start < state->select_end) {
628 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
629 state->select_end = state->cursor = state->select_start;
631 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
632 state->select_start = state->cursor = state->select_end;
634 state->has_preferred_x = 0;
641 if (state->select_end < state->select_start) {
642 int temp = state->select_end;
643 state->select_end = state->select_start;
644 state->select_start = temp;
651 if (STB_TEXT_HAS_SELECTION(state)) {
652 stb_textedit_sortselection(state);
653 state->cursor = state->select_start;
654 state->select_end = state->select_start;
655 state->has_preferred_x = 0;
660 static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
662 if (STB_TEXT_HAS_SELECTION(state)) {
663 stb_textedit_sortselection(state);
664 stb_textedit_clamp(str, state);
665 state->cursor = state->select_end;
666 state->select_start = state->select_end;
667 state->has_preferred_x = 0;
671 #ifdef STB_TEXTEDIT_IS_SPACE 672 static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str,
int idx )
674 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
677 #ifndef STB_TEXTEDIT_MOVEWORDLEFT 678 static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str,
int c )
680 c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c );
681 while (c >= 0 && !is_word_boundary(str, c))
682 c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
689 #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 692 #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 693 static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str,
int c )
695 const int len = STB_TEXTEDIT_STRINGLEN(str);
696 c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
697 while( c < len && !is_word_boundary( str, c ) )
698 c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
705 #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 713 if (!STB_TEXT_HAS_SELECTION(state))
714 state->select_start = state->select_end = state->cursor;
716 state->cursor = state->select_end;
720 static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
722 if (STB_TEXT_HAS_SELECTION(state)) {
723 stb_textedit_delete_selection(str,state);
724 state->has_preferred_x = 0;
731 static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text,
int len)
734 stb_textedit_clamp(str, state);
735 stb_textedit_delete_selection(str,state);
737 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
738 stb_text_makeundo_insert(state, state->cursor, len);
739 state->cursor += len;
740 state->has_preferred_x = 0;
747 #ifndef STB_TEXTEDIT_KEYTYPE 748 #define STB_TEXTEDIT_KEYTYPE int 753 static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
const IMSTB_TEXTEDIT_CHARTYPE* text,
int text_len)
756 if (text[0] ==
'\n' && state->single_line)
759 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
760 stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
761 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
762 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
763 state->cursor += text_len;
764 state->has_preferred_x = 0;
767 stb_textedit_delete_selection(str, state);
768 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
769 stb_text_makeundo_insert(state, state->cursor, text_len);
770 state->cursor += text_len;
771 state->has_preferred_x = 0;
777 static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
782 #ifdef STB_TEXTEDIT_KEYTOTEXT 784 int c = STB_TEXTEDIT_KEYTOTEXT(key);
786 IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
787 stb_textedit_text(str, state, &ch, 1);
793 #ifdef STB_TEXTEDIT_K_INSERT 794 case STB_TEXTEDIT_K_INSERT:
795 state->insert_mode = !state->insert_mode;
799 case STB_TEXTEDIT_K_UNDO:
800 stb_text_undo(str, state);
801 state->has_preferred_x = 0;
804 case STB_TEXTEDIT_K_REDO:
805 stb_text_redo(str, state);
806 state->has_preferred_x = 0;
809 case STB_TEXTEDIT_K_LEFT:
811 if (STB_TEXT_HAS_SELECTION(state))
812 stb_textedit_move_to_first(state);
814 if (state->cursor > 0)
815 state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
816 state->has_preferred_x = 0;
819 case STB_TEXTEDIT_K_RIGHT:
821 if (STB_TEXT_HAS_SELECTION(state))
822 stb_textedit_move_to_last(str, state);
824 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
825 stb_textedit_clamp(str, state);
826 state->has_preferred_x = 0;
829 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
830 stb_textedit_clamp(str, state);
831 stb_textedit_prep_selection_at_cursor(state);
833 if (state->select_end > 0)
834 state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
835 state->cursor = state->select_end;
836 state->has_preferred_x = 0;
839 #ifdef STB_TEXTEDIT_MOVEWORDLEFT 840 case STB_TEXTEDIT_K_WORDLEFT:
841 if (STB_TEXT_HAS_SELECTION(state))
842 stb_textedit_move_to_first(state);
844 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
845 stb_textedit_clamp( str, state );
849 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
850 if( !STB_TEXT_HAS_SELECTION( state ) )
851 stb_textedit_prep_selection_at_cursor(state);
853 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
854 state->select_end = state->cursor;
856 stb_textedit_clamp( str, state );
860 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 861 case STB_TEXTEDIT_K_WORDRIGHT:
862 if (STB_TEXT_HAS_SELECTION(state))
863 stb_textedit_move_to_last(str, state);
865 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
866 stb_textedit_clamp( str, state );
870 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
871 if( !STB_TEXT_HAS_SELECTION( state ) )
872 stb_textedit_prep_selection_at_cursor(state);
874 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
875 state->select_end = state->cursor;
877 stb_textedit_clamp( str, state );
881 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
882 stb_textedit_prep_selection_at_cursor(state);
884 state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
885 stb_textedit_clamp(str, state);
886 state->cursor = state->select_end;
887 state->has_preferred_x = 0;
890 case STB_TEXTEDIT_K_DOWN:
891 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
892 case STB_TEXTEDIT_K_PGDOWN:
893 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
896 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
897 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
898 int row_count = is_page ? state->row_count_per_page : 1;
900 if (!is_page && state->single_line) {
902 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
907 stb_textedit_prep_selection_at_cursor(state);
908 else if (STB_TEXT_HAS_SELECTION(state))
909 stb_textedit_move_to_last(str, state);
912 stb_textedit_clamp(str, state);
913 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
915 for (j = 0; j < row_count; ++j) {
916 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
917 int start = find.first_char + find.length;
919 if (find.length == 0)
924 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
928 state->cursor = start;
929 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
931 for (i=0; i < row.num_chars; ) {
932 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
933 int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
934 #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE 935 if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
941 i += next - state->cursor;
942 state->cursor = next;
944 stb_textedit_clamp(str, state);
946 state->has_preferred_x = 1;
947 state->preferred_x = goal_x;
950 state->select_end = state->cursor;
953 find.first_char = find.first_char + find.length;
954 find.length = row.num_chars;
959 case STB_TEXTEDIT_K_UP:
960 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
961 case STB_TEXTEDIT_K_PGUP:
962 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
965 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
966 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
967 int row_count = is_page ? state->row_count_per_page : 1;
969 if (!is_page && state->single_line) {
971 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
976 stb_textedit_prep_selection_at_cursor(state);
977 else if (STB_TEXT_HAS_SELECTION(state))
978 stb_textedit_move_to_first(state);
981 stb_textedit_clamp(str, state);
982 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
984 for (j = 0; j < row_count; ++j) {
985 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
988 if (find.prev_first == find.first_char)
992 state->cursor = find.prev_first;
993 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
995 for (i=0; i < row.num_chars; ) {
996 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
997 int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
998 #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE 999 if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
1005 i += next - state->cursor;
1006 state->cursor = next;
1008 stb_textedit_clamp(str, state);
1010 state->has_preferred_x = 1;
1011 state->preferred_x = goal_x;
1014 state->select_end = state->cursor;
1018 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
1019 while (prev_scan > 0)
1021 int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan);
1022 if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
1026 find.first_char = find.prev_first;
1027 find.prev_first = prev_scan;
1032 case STB_TEXTEDIT_K_DELETE:
1033 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
1034 if (STB_TEXT_HAS_SELECTION(state))
1035 stb_textedit_delete_selection(str, state);
1037 int n = STB_TEXTEDIT_STRINGLEN(str);
1038 if (state->cursor < n)
1039 stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
1041 state->has_preferred_x = 0;
1044 case STB_TEXTEDIT_K_BACKSPACE:
1045 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
1046 if (STB_TEXT_HAS_SELECTION(state))
1047 stb_textedit_delete_selection(str, state);
1049 stb_textedit_clamp(str, state);
1050 if (state->cursor > 0) {
1051 int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
1052 stb_textedit_delete(str, state, prev, state->cursor - prev);
1053 state->cursor = prev;
1056 state->has_preferred_x = 0;
1059 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1060 case STB_TEXTEDIT_K_TEXTSTART2:
1062 case STB_TEXTEDIT_K_TEXTSTART:
1063 state->cursor = state->select_start = state->select_end = 0;
1064 state->has_preferred_x = 0;
1067 #ifdef STB_TEXTEDIT_K_TEXTEND2 1068 case STB_TEXTEDIT_K_TEXTEND2:
1070 case STB_TEXTEDIT_K_TEXTEND:
1071 state->cursor = STB_TEXTEDIT_STRINGLEN(str);
1072 state->select_start = state->select_end = 0;
1073 state->has_preferred_x = 0;
1076 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1077 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
1079 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
1080 stb_textedit_prep_selection_at_cursor(state);
1081 state->cursor = state->select_end = 0;
1082 state->has_preferred_x = 0;
1085 #ifdef STB_TEXTEDIT_K_TEXTEND2 1086 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
1088 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
1089 stb_textedit_prep_selection_at_cursor(state);
1090 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
1091 state->has_preferred_x = 0;
1095 #ifdef STB_TEXTEDIT_K_LINESTART2 1096 case STB_TEXTEDIT_K_LINESTART2:
1098 case STB_TEXTEDIT_K_LINESTART:
1099 stb_textedit_clamp(str, state);
1100 stb_textedit_move_to_first(state);
1101 if (state->single_line)
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);
1105 state->has_preferred_x = 0;
1108 #ifdef STB_TEXTEDIT_K_LINEEND2 1109 case STB_TEXTEDIT_K_LINEEND2:
1111 case STB_TEXTEDIT_K_LINEEND: {
1112 int n = STB_TEXTEDIT_STRINGLEN(str);
1113 stb_textedit_clamp(str, state);
1114 stb_textedit_move_to_first(state);
1115 if (state->single_line)
1117 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1118 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
1119 state->has_preferred_x = 0;
1123 #ifdef STB_TEXTEDIT_K_LINESTART2 1124 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1126 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1127 stb_textedit_clamp(str, state);
1128 stb_textedit_prep_selection_at_cursor(state);
1129 if (state->single_line)
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);
1133 state->select_end = state->cursor;
1134 state->has_preferred_x = 0;
1137 #ifdef STB_TEXTEDIT_K_LINEEND2 1138 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1140 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1141 int n = STB_TEXTEDIT_STRINGLEN(str);
1142 stb_textedit_clamp(str, state);
1143 stb_textedit_prep_selection_at_cursor(state);
1144 if (state->single_line)
1146 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1147 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
1148 state->select_end = state->cursor;
1149 state->has_preferred_x = 0;
1161 static void stb_textedit_flush_redo(
StbUndoState *state)
1163 state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
1164 state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
1168 static void stb_textedit_discard_undo(
StbUndoState *state)
1170 if (state->undo_point > 0) {
1172 if (state->undo_rec[0].char_storage >= 0) {
1173 int n = state->undo_rec[0].insert_length, i;
1175 state->undo_char_point -= n;
1176 IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (
size_t) (state->undo_char_point*
sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
1177 for (i=0; i < state->undo_point; ++i)
1178 if (state->undo_rec[i].char_storage >= 0)
1179 state->undo_rec[i].char_storage -= n;
1181 --state->undo_point;
1182 IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (
size_t) (state->undo_point*
sizeof(state->undo_rec[0])));
1190 static void stb_textedit_discard_redo(
StbUndoState *state)
1192 int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
1194 if (state->redo_point <= k) {
1196 if (state->undo_rec[k].char_storage >= 0) {
1197 int n = state->undo_rec[k].insert_length, i;
1199 state->redo_char_point += n;
1200 IMSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (
size_t) ((IMSTB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*
sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
1202 for (i=state->redo_point; i < k; ++i)
1203 if (state->undo_rec[i].char_storage >= 0)
1204 state->undo_rec[i].char_storage += n;
1208 size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) *
sizeof(state->undo_rec[0]));
1209 const char* buf_begin = (
char*)state->undo_rec; (
void)buf_begin;
1210 const char* buf_end = (
char*)state->undo_rec +
sizeof(state->undo_rec); (void)buf_end;
1211 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point)) >= buf_begin);
1212 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
1213 IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
1216 ++state->redo_point;
1223 stb_textedit_flush_redo(state);
1227 if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1228 stb_textedit_discard_undo(state);
1231 if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
1232 state->undo_point = 0;
1233 state->undo_char_point = 0;
1238 while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
1239 stb_textedit_discard_undo(state);
1241 return &state->undo_rec[state->undo_point++];
1244 static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(
StbUndoState *state,
int pos,
int insert_len,
int delete_len)
1246 StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
1251 r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
1252 r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
1254 if (insert_len == 0) {
1255 r->char_storage = -1;
1258 r->char_storage = state->undo_char_point;
1259 state->undo_char_point += insert_len;
1260 return &state->undo_char[r->char_storage];
1268 if (s->undo_point == 0)
1272 u = s->undo_rec[s->undo_point-1];
1273 r = &s->undo_rec[s->redo_point-1];
1274 r->char_storage = -1;
1276 r->insert_length = u.delete_length;
1277 r->delete_length = u.insert_length;
1280 if (u.delete_length) {
1291 if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
1293 r->insert_length = 0;
1298 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1300 if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1303 stb_textedit_discard_redo(s);
1305 r = &s->undo_rec[s->redo_point-1];
1307 r->char_storage = s->redo_char_point - u.delete_length;
1308 s->redo_char_point = s->redo_char_point - u.delete_length;
1311 for (i=0; i < u.delete_length; ++i)
1312 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1316 STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1320 if (u.insert_length) {
1322 STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1323 s->undo_char_point -= u.insert_length;
1326 state->cursor = u.where + u.insert_length;
1336 if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1340 u = &s->undo_rec[s->undo_point];
1341 r = s->undo_rec[s->redo_point];
1346 u->delete_length = r.insert_length;
1347 u->insert_length = r.delete_length;
1349 u->char_storage = -1;
1351 if (r.delete_length) {
1355 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1356 u->insert_length = 0;
1357 u->delete_length = 0;
1360 u->char_storage = s->undo_char_point;
1361 s->undo_char_point = s->undo_char_point + u->insert_length;
1364 for (i=0; i < u->insert_length; ++i)
1365 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1368 STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1371 if (r.insert_length) {
1373 STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1374 s->redo_char_point += r.insert_length;
1377 state->cursor = r.where + r.insert_length;
1383 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length)
1385 stb_text_createundo(&state->undostate, where, 0, length);
1388 static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length)
1391 IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
1393 for (i=0; i < length; ++i)
1394 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1398 static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length)
1401 IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1403 for (i=0; i < old_length; ++i)
1404 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1409 static void stb_textedit_clear_state(
STB_TexteditState *state,
int is_single_line)
1411 state->undostate.undo_point = 0;
1412 state->undostate.undo_char_point = 0;
1413 state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
1414 state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
1415 state->select_end = state->select_start = 0;
1417 state->has_preferred_x = 0;
1418 state->preferred_x = 0;
1419 state->cursor_at_end_of_line = 0;
1420 state->initialized = 1;
1421 state->single_line = (
unsigned char) is_single_line;
1422 state->insert_mode = 0;
1423 state->row_count_per_page = 0;
1427 static void stb_textedit_initialize_state(
STB_TexteditState *state,
int is_single_line)
1429 stb_textedit_clear_state(state, is_single_line);
1432 #if defined(__GNUC__) || defined(__clang__) 1433 #pragma GCC diagnostic push 1434 #pragma GCC diagnostic ignored "-Wcast-qual" 1437 static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE
const *ctext,
int len)
1439 return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
1442 #if defined(__GNUC__) || defined(__clang__) 1443 #pragma GCC diagnostic pop 1446 #endif//IMSTB_TEXTEDIT_IMPLEMENTATION Definition: imstb_textedit.h:330
In find(In first, In last, const T &v)
Definition: algorithm.h:225
Definition: imstb_textedit.h:386
Definition: imstb_textedit.h:321
Definition: imstb_textedit.h:339