277 #ifndef INCLUDE_STB_TEXTEDIT_H
278 #define INCLUDE_STB_TEXTEDIT_H
289 #ifndef STB_TEXTEDIT_UNDOSTATECOUNT
290 #define STB_TEXTEDIT_UNDOSTATECOUNT 99
292 #ifndef STB_TEXTEDIT_UNDOCHARCOUNT
293 #define STB_TEXTEDIT_UNDOCHARCOUNT 999
295 #ifndef STB_TEXTEDIT_CHARTYPE
296 #define STB_TEXTEDIT_CHARTYPE int
298 #ifndef STB_TEXTEDIT_POSITIONTYPE
299 #define STB_TEXTEDIT_POSITIONTYPE int
305 STB_TEXTEDIT_POSITIONTYPE where;
306 STB_TEXTEDIT_POSITIONTYPE insert_length;
307 STB_TEXTEDIT_POSITIONTYPE delete_length;
315 STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
316 short undo_point, redo_point;
317 int undo_char_point, redo_char_point;
337 unsigned char insert_mode;
341 int row_count_per_page;
349 unsigned char cursor_at_end_of_line;
350 unsigned char initialized;
351 unsigned char has_preferred_x;
352 unsigned char single_line;
353 unsigned char padding1, padding2, padding3;
370 float baseline_y_delta;
387 #ifdef STB_TEXTEDIT_IMPLEMENTATION
389 #ifndef STB_TEXTEDIT_memmove
391 #define STB_TEXTEDIT_memmove memmove
401 static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str,
float x,
float y)
404 int n = STB_TEXTEDIT_STRINGLEN(str);
405 float base_y = 0, prev_x;
414 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
415 if (r.num_chars <= 0)
418 if (i==0 && y < base_y + r.ymin)
421 if (y < base_y + r.ymax)
425 base_y += r.baseline_y_delta;
440 for (k=0; k < r.num_chars; ++k) {
441 float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
454 if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
455 return i+r.num_chars-1;
457 return i+r.num_chars;
461 static void stb_textedit_click(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
465 if( state->single_line )
468 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
472 state->cursor = stb_text_locate_coord(str, x, y);
473 state->select_start = state->cursor;
474 state->select_end = state->cursor;
475 state->has_preferred_x = 0;
479 static void stb_textedit_drag(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
485 if( state->single_line )
488 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
492 if (state->select_start == state->select_end)
493 state->select_start = state->cursor;
495 p = stb_text_locate_coord(str, x, y);
496 state->cursor = state->select_end = p;
507 static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length);
508 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length);
509 static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length);
515 int first_char, length;
521 static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str,
int n,
int single_line)
525 int z = STB_TEXTEDIT_STRINGLEN(str);
528 if (n == z && single_line) {
530 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
532 find->first_char = 0;
534 find->height = r.ymax - r.ymin;
543 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
544 if (n < i + r.num_chars)
546 if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE)
550 find->y += r.baseline_y_delta;
555 find->first_char = first = i;
556 find->length = r.num_chars;
557 find->height = r.ymax - r.ymin;
558 find->prev_first = prev_start;
562 for (i=0; first+i < n; ++i)
563 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
566 #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
569 static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
571 int n = STB_TEXTEDIT_STRINGLEN(str);
572 if (STB_TEXT_HAS_SELECTION(state)) {
573 if (state->select_start > n) state->select_start = n;
574 if (state->select_end > n) state->select_end = n;
576 if (state->select_start == state->select_end)
577 state->cursor = state->select_start;
579 if (state->cursor > n) state->cursor = n;
583 static void stb_textedit_delete(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int len)
585 stb_text_makeundo_delete(str, state, where, len);
586 STB_TEXTEDIT_DELETECHARS(str, where, len);
587 state->has_preferred_x = 0;
591 static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
593 stb_textedit_clamp(str, state);
594 if (STB_TEXT_HAS_SELECTION(state)) {
595 if (state->select_start < state->select_end) {
596 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
597 state->select_end = state->cursor = state->select_start;
599 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
600 state->select_start = state->cursor = state->select_end;
602 state->has_preferred_x = 0;
609 if (state->select_end < state->select_start) {
610 int temp = state->select_end;
611 state->select_end = state->select_start;
612 state->select_start = temp;
619 if (STB_TEXT_HAS_SELECTION(state)) {
620 stb_textedit_sortselection(state);
621 state->cursor = state->select_start;
622 state->select_end = state->select_start;
623 state->has_preferred_x = 0;
628 static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
630 if (STB_TEXT_HAS_SELECTION(state)) {
631 stb_textedit_sortselection(state);
632 stb_textedit_clamp(str, state);
633 state->cursor = state->select_end;
634 state->select_start = state->select_end;
635 state->has_preferred_x = 0;
639 #ifdef STB_TEXTEDIT_IS_SPACE
640 static int is_word_boundary( STB_TEXTEDIT_STRING *str,
int idx )
642 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
645 #ifndef STB_TEXTEDIT_MOVEWORDLEFT
646 static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str,
int c )
649 while( c >= 0 && !is_word_boundary( str, c ) )
657 #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
660 #ifndef STB_TEXTEDIT_MOVEWORDRIGHT
661 static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str,
int c )
663 const int len = STB_TEXTEDIT_STRINGLEN(str);
665 while( c < len && !is_word_boundary( str, c ) )
673 #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
681 if (!STB_TEXT_HAS_SELECTION(state))
682 state->select_start = state->select_end = state->cursor;
684 state->cursor = state->select_end;
690 if (STB_TEXT_HAS_SELECTION(state)) {
691 stb_textedit_delete_selection(str,state);
692 state->has_preferred_x = 0;
699 static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text,
int len)
702 stb_textedit_clamp(str, state);
703 stb_textedit_delete_selection(str,state);
705 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
706 stb_text_makeundo_insert(state, state->cursor, len);
707 state->cursor += len;
708 state->has_preferred_x = 0;
715 #ifndef STB_TEXTEDIT_KEYTYPE
716 #define STB_TEXTEDIT_KEYTYPE int
720 static void stb_textedit_key(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
725 int c = STB_TEXTEDIT_KEYTOTEXT(key);
727 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
730 if (c ==
'\n' && state->single_line)
733 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
734 stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
735 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
736 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
738 state->has_preferred_x = 0;
741 stb_textedit_delete_selection(str,state);
742 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
743 stb_text_makeundo_insert(state, state->cursor, 1);
745 state->has_preferred_x = 0;
752 #ifdef STB_TEXTEDIT_K_INSERT
753 case STB_TEXTEDIT_K_INSERT:
754 state->insert_mode = !state->insert_mode;
758 case STB_TEXTEDIT_K_UNDO:
759 stb_text_undo(str, state);
760 state->has_preferred_x = 0;
763 case STB_TEXTEDIT_K_REDO:
764 stb_text_redo(str, state);
765 state->has_preferred_x = 0;
768 case STB_TEXTEDIT_K_LEFT:
770 if (STB_TEXT_HAS_SELECTION(state))
771 stb_textedit_move_to_first(state);
773 if (state->cursor > 0)
775 state->has_preferred_x = 0;
778 case STB_TEXTEDIT_K_RIGHT:
780 if (STB_TEXT_HAS_SELECTION(state))
781 stb_textedit_move_to_last(str, state);
784 stb_textedit_clamp(str, state);
785 state->has_preferred_x = 0;
788 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
789 stb_textedit_clamp(str, state);
790 stb_textedit_prep_selection_at_cursor(state);
792 if (state->select_end > 0)
794 state->cursor = state->select_end;
795 state->has_preferred_x = 0;
798 #ifdef STB_TEXTEDIT_MOVEWORDLEFT
799 case STB_TEXTEDIT_K_WORDLEFT:
800 if (STB_TEXT_HAS_SELECTION(state))
801 stb_textedit_move_to_first(state);
803 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
804 stb_textedit_clamp( str, state );
808 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
809 if( !STB_TEXT_HAS_SELECTION( state ) )
810 stb_textedit_prep_selection_at_cursor(state);
812 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
813 state->select_end = state->cursor;
815 stb_textedit_clamp( str, state );
819 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT
820 case STB_TEXTEDIT_K_WORDRIGHT:
821 if (STB_TEXT_HAS_SELECTION(state))
822 stb_textedit_move_to_last(str, state);
824 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
825 stb_textedit_clamp( str, state );
829 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
830 if( !STB_TEXT_HAS_SELECTION( state ) )
831 stb_textedit_prep_selection_at_cursor(state);
833 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
834 state->select_end = state->cursor;
836 stb_textedit_clamp( str, state );
840 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
841 stb_textedit_prep_selection_at_cursor(state);
844 stb_textedit_clamp(str, state);
845 state->cursor = state->select_end;
846 state->has_preferred_x = 0;
849 case STB_TEXTEDIT_K_DOWN:
850 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
851 case STB_TEXTEDIT_K_PGDOWN:
852 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
855 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
856 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
857 int row_count = is_page ? state->row_count_per_page : 1;
859 if (!is_page && state->single_line) {
861 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
866 stb_textedit_prep_selection_at_cursor(state);
867 else if (STB_TEXT_HAS_SELECTION(state))
868 stb_textedit_move_to_last(str, state);
871 stb_textedit_clamp(str, state);
872 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
874 for (j = 0; j < row_count; ++j) {
875 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
876 int start = find.first_char + find.length;
878 if (find.length == 0)
883 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
887 state->cursor = start;
888 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
890 for (i=0; i < row.num_chars; ++i) {
891 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
892 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
893 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
901 stb_textedit_clamp(str, state);
903 state->has_preferred_x = 1;
904 state->preferred_x = goal_x;
907 state->select_end = state->cursor;
910 find.first_char = find.first_char + find.length;
911 find.length = row.num_chars;
916 case STB_TEXTEDIT_K_UP:
917 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
918 case STB_TEXTEDIT_K_PGUP:
919 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
922 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
923 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
924 int row_count = is_page ? state->row_count_per_page : 1;
926 if (!is_page && state->single_line) {
928 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
933 stb_textedit_prep_selection_at_cursor(state);
934 else if (STB_TEXT_HAS_SELECTION(state))
935 stb_textedit_move_to_first(state);
938 stb_textedit_clamp(str, state);
939 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
941 for (j = 0; j < row_count; ++j) {
942 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
945 if (find.prev_first == find.first_char)
949 state->cursor = find.prev_first;
950 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
952 for (i=0; i < row.num_chars; ++i) {
953 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
954 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
955 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
963 stb_textedit_clamp(str, state);
965 state->has_preferred_x = 1;
966 state->preferred_x = goal_x;
969 state->select_end = state->cursor;
973 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
974 while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
976 find.first_char = find.prev_first;
977 find.prev_first = prev_scan;
982 case STB_TEXTEDIT_K_DELETE:
983 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
984 if (STB_TEXT_HAS_SELECTION(state))
985 stb_textedit_delete_selection(str, state);
987 int n = STB_TEXTEDIT_STRINGLEN(str);
988 if (state->cursor < n)
989 stb_textedit_delete(str, state, state->cursor, 1);
991 state->has_preferred_x = 0;
994 case STB_TEXTEDIT_K_BACKSPACE:
995 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
996 if (STB_TEXT_HAS_SELECTION(state))
997 stb_textedit_delete_selection(str, state);
999 stb_textedit_clamp(str, state);
1000 if (state->cursor > 0) {
1001 stb_textedit_delete(str, state, state->cursor-1, 1);
1005 state->has_preferred_x = 0;
1008 #ifdef STB_TEXTEDIT_K_TEXTSTART2
1009 case STB_TEXTEDIT_K_TEXTSTART2:
1011 case STB_TEXTEDIT_K_TEXTSTART:
1012 state->cursor = state->select_start = state->select_end = 0;
1013 state->has_preferred_x = 0;
1016 #ifdef STB_TEXTEDIT_K_TEXTEND2
1017 case STB_TEXTEDIT_K_TEXTEND2:
1019 case STB_TEXTEDIT_K_TEXTEND:
1020 state->cursor = STB_TEXTEDIT_STRINGLEN(str);
1021 state->select_start = state->select_end = 0;
1022 state->has_preferred_x = 0;
1025 #ifdef STB_TEXTEDIT_K_TEXTSTART2
1026 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
1028 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
1029 stb_textedit_prep_selection_at_cursor(state);
1030 state->cursor = state->select_end = 0;
1031 state->has_preferred_x = 0;
1034 #ifdef STB_TEXTEDIT_K_TEXTEND2
1035 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
1037 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
1038 stb_textedit_prep_selection_at_cursor(state);
1039 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
1040 state->has_preferred_x = 0;
1044 #ifdef STB_TEXTEDIT_K_LINESTART2
1045 case STB_TEXTEDIT_K_LINESTART2:
1047 case STB_TEXTEDIT_K_LINESTART:
1048 stb_textedit_clamp(str, state);
1049 stb_textedit_move_to_first(state);
1050 if (state->single_line)
1052 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1054 state->has_preferred_x = 0;
1057 #ifdef STB_TEXTEDIT_K_LINEEND2
1058 case STB_TEXTEDIT_K_LINEEND2:
1060 case STB_TEXTEDIT_K_LINEEND: {
1061 int n = STB_TEXTEDIT_STRINGLEN(str);
1062 stb_textedit_clamp(str, state);
1063 stb_textedit_move_to_first(state);
1064 if (state->single_line)
1066 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1068 state->has_preferred_x = 0;
1072 #ifdef STB_TEXTEDIT_K_LINESTART2
1073 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1075 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1076 stb_textedit_clamp(str, state);
1077 stb_textedit_prep_selection_at_cursor(state);
1078 if (state->single_line)
1080 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1082 state->select_end = state->cursor;
1083 state->has_preferred_x = 0;
1086 #ifdef STB_TEXTEDIT_K_LINEEND2
1087 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1089 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1090 int n = STB_TEXTEDIT_STRINGLEN(str);
1091 stb_textedit_clamp(str, state);
1092 stb_textedit_prep_selection_at_cursor(state);
1093 if (state->single_line)
1095 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1097 state->select_end = state->cursor;
1098 state->has_preferred_x = 0;
1110 static void stb_textedit_flush_redo(
StbUndoState *state)
1112 state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1113 state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1117 static void stb_textedit_discard_undo(
StbUndoState *state)
1119 if (state->undo_point > 0) {
1121 if (state->undo_rec[0].char_storage >= 0) {
1122 int n = state->undo_rec[0].insert_length, i;
1124 state->undo_char_point -= n;
1125 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (
size_t) (state->undo_char_point*
sizeof(STB_TEXTEDIT_CHARTYPE)));
1126 for (i=0; i < state->undo_point; ++i)
1127 if (state->undo_rec[i].char_storage >= 0)
1128 state->undo_rec[i].char_storage -= n;
1130 --state->undo_point;
1131 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (
size_t) (state->undo_point*
sizeof(state->undo_rec[0])));
1139 static void stb_textedit_discard_redo(
StbUndoState *state)
1141 int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
1143 if (state->redo_point <= k) {
1145 if (state->undo_rec[k].char_storage >= 0) {
1146 int n = state->undo_rec[k].insert_length, i;
1148 state->redo_char_point += n;
1149 STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (
size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*
sizeof(STB_TEXTEDIT_CHARTYPE)));
1151 for (i=state->redo_point; i < k; ++i)
1152 if (state->undo_rec[i].char_storage >= 0)
1153 state->undo_rec[i].char_storage += n;
1157 size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) *
sizeof(state->undo_rec[0]));
1158 const char* buf_begin = (
char*)state->undo_rec; (
void)buf_begin;
1159 const char* buf_end = (
char*)state->undo_rec +
sizeof(state->undo_rec); (void)buf_end;
1160 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point)) >= buf_begin);
1161 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
1162 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
1165 ++state->redo_point;
1172 stb_textedit_flush_redo(state);
1176 if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1177 stb_textedit_discard_undo(state);
1180 if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
1181 state->undo_point = 0;
1182 state->undo_char_point = 0;
1187 while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
1188 stb_textedit_discard_undo(state);
1190 return &state->undo_rec[state->undo_point++];
1193 static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(
StbUndoState *state,
int pos,
int insert_len,
int delete_len)
1195 StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
1200 r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
1201 r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
1203 if (insert_len == 0) {
1204 r->char_storage = -1;
1207 r->char_storage = state->undo_char_point;
1208 state->undo_char_point += insert_len;
1209 return &state->undo_char[r->char_storage];
1217 if (s->undo_point == 0)
1221 u = s->undo_rec[s->undo_point-1];
1222 r = &s->undo_rec[s->redo_point-1];
1223 r->char_storage = -1;
1225 r->insert_length = u.delete_length;
1226 r->delete_length = u.insert_length;
1229 if (u.delete_length) {
1240 if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
1242 r->insert_length = 0;
1247 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1249 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1252 stb_textedit_discard_redo(s);
1254 r = &s->undo_rec[s->redo_point-1];
1256 r->char_storage = s->redo_char_point - u.delete_length;
1257 s->redo_char_point = s->redo_char_point - u.delete_length;
1260 for (i=0; i < u.delete_length; ++i)
1261 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1265 STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1269 if (u.insert_length) {
1271 STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1272 s->undo_char_point -= u.insert_length;
1275 state->cursor = u.where + u.insert_length;
1285 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1289 u = &s->undo_rec[s->undo_point];
1290 r = s->undo_rec[s->redo_point];
1295 u->delete_length = r.insert_length;
1296 u->insert_length = r.delete_length;
1298 u->char_storage = -1;
1300 if (r.delete_length) {
1304 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1305 u->insert_length = 0;
1306 u->delete_length = 0;
1309 u->char_storage = s->undo_char_point;
1310 s->undo_char_point = s->undo_char_point + u->insert_length;
1313 for (i=0; i < u->insert_length; ++i)
1314 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1317 STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1320 if (r.insert_length) {
1322 STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1323 s->redo_char_point += r.insert_length;
1326 state->cursor = r.where + r.insert_length;
1332 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length)
1334 stb_text_createundo(&state->undostate, where, 0, length);
1337 static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length)
1340 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
1342 for (i=0; i < length; ++i)
1343 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1347 static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length)
1350 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1352 for (i=0; i < old_length; ++i)
1353 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1358 static void stb_textedit_clear_state(
STB_TexteditState *state,
int is_single_line)
1360 state->undostate.undo_point = 0;
1361 state->undostate.undo_char_point = 0;
1362 state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1363 state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1364 state->select_end = state->select_start = 0;
1366 state->has_preferred_x = 0;
1367 state->preferred_x = 0;
1368 state->cursor_at_end_of_line = 0;
1369 state->initialized = 1;
1370 state->single_line = (
unsigned char) is_single_line;
1371 state->insert_mode = 0;
1372 state->row_count_per_page = 0;
1376 static void stb_textedit_initialize_state(
STB_TexteditState *state,
int is_single_line)
1378 stb_textedit_clear_state(state, is_single_line);
1381 #if defined(__GNUC__) || defined(__clang__)
1382 #pragma GCC diagnostic push
1383 #pragma GCC diagnostic ignored "-Wcast-qual"
1386 static int stb_textedit_paste(STB_TEXTEDIT_STRING *str,
STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE
const *ctext,
int len)
1388 return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
1391 #if defined(__GNUC__) || defined(__clang__)
1392 #pragma GCC diagnostic pop
Definition: imstb_textedit.h:321
Definition: imstb_textedit.h:368
Definition: imstb_textedit.h:303
Definition: imstb_textedit.h:312