286 #ifndef INCLUDE_IMSTB_TEXTEDIT_H 287 #define INCLUDE_IMSTB_TEXTEDIT_H 298 #ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT 299 #define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 301 #ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT 302 #define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 304 #ifndef IMSTB_TEXTEDIT_CHARTYPE 305 #define IMSTB_TEXTEDIT_CHARTYPE int 307 #ifndef IMSTB_TEXTEDIT_POSITIONTYPE 308 #define IMSTB_TEXTEDIT_POSITIONTYPE int 314 IMSTB_TEXTEDIT_POSITIONTYPE where;
315 IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
316 IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
324 IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
325 short undo_point, redo_point;
326 int undo_char_point, redo_char_point;
346 unsigned char insert_mode;
350 int row_count_per_page;
358 unsigned char cursor_at_end_of_line;
359 unsigned char initialized;
360 unsigned char has_preferred_x;
361 unsigned char single_line;
362 unsigned char padding1, padding2, padding3;
379 float baseline_y_delta;
383 #endif //INCLUDE_IMSTB_TEXTEDIT_H 396 #ifdef IMSTB_TEXTEDIT_IMPLEMENTATION 398 #ifndef IMSTB_TEXTEDIT_memmove 400 #define IMSTB_TEXTEDIT_memmove memmove 410 static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str,
float x,
float y)
413 int n = STB_TEXTEDIT_STRINGLEN(str);
414 float base_y = 0, prev_x;
423 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
424 if (r.num_chars <= 0)
427 if (i==0 && y < base_y + r.ymin)
430 if (y < base_y + r.ymax)
434 base_y += r.baseline_y_delta;
449 for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
450 float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
455 return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
463 if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
464 return i+r.num_chars-1;
466 return i+r.num_chars;
470 static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
474 if( state->single_line )
477 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
481 state->cursor = stb_text_locate_coord(str, x, y);
482 state->select_start = state->cursor;
483 state->select_end = state->cursor;
484 state->has_preferred_x = 0;
488 static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
float x,
float y)
494 if( state->single_line )
497 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
501 if (state->select_start == state->select_end)
502 state->select_start = state->cursor;
504 p = stb_text_locate_coord(str, x, y);
505 state->cursor = state->select_end = p;
516 static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length);
517 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length);
518 static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length);
524 int first_char, length;
530 static void stb_textedit_find_charpos(StbFindState *
find, IMSTB_TEXTEDIT_STRING *str,
int n,
int single_line)
534 int z = STB_TEXTEDIT_STRINGLEN(str);
537 if (n == z && single_line) {
539 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
541 find->first_char = 0;
543 find->height = r.ymax - r.ymin;
552 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
553 if (n < i + r.num_chars)
555 if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE)
559 find->y += r.baseline_y_delta;
567 find->first_char = first = i;
568 find->length = r.num_chars;
569 find->height = r.ymax - r.ymin;
570 find->prev_first = prev_start;
574 for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
575 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
578 #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 581 static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
583 int n = STB_TEXTEDIT_STRINGLEN(str);
584 if (STB_TEXT_HAS_SELECTION(state)) {
585 if (state->select_start > n) state->select_start = n;
586 if (state->select_end > n) state->select_end = n;
588 if (state->select_start == state->select_end)
589 state->cursor = state->select_start;
591 if (state->cursor > n) state->cursor = n;
595 static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int len)
597 stb_text_makeundo_delete(str, state, where, len);
598 STB_TEXTEDIT_DELETECHARS(str, where, len);
599 state->has_preferred_x = 0;
603 static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
605 stb_textedit_clamp(str, state);
606 if (STB_TEXT_HAS_SELECTION(state)) {
607 if (state->select_start < state->select_end) {
608 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
609 state->select_end = state->cursor = state->select_start;
611 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
612 state->select_start = state->cursor = state->select_end;
614 state->has_preferred_x = 0;
621 if (state->select_end < state->select_start) {
622 int temp = state->select_end;
623 state->select_end = state->select_start;
624 state->select_start = temp;
631 if (STB_TEXT_HAS_SELECTION(state)) {
632 stb_textedit_sortselection(state);
633 state->cursor = state->select_start;
634 state->select_end = state->select_start;
635 state->has_preferred_x = 0;
640 static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
642 if (STB_TEXT_HAS_SELECTION(state)) {
643 stb_textedit_sortselection(state);
644 stb_textedit_clamp(str, state);
645 state->cursor = state->select_end;
646 state->select_start = state->select_end;
647 state->has_preferred_x = 0;
655 #ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX 656 #define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1) 658 #ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX 659 #define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1) 662 #ifdef STB_TEXTEDIT_IS_SPACE 663 static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str,
int idx )
665 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
668 #ifndef STB_TEXTEDIT_MOVEWORDLEFT 669 static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str,
int c )
672 while( c >= 0 && !is_word_boundary( str, c ) )
680 #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 683 #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 684 static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str,
int c )
686 const int len = STB_TEXTEDIT_STRINGLEN(str);
688 while( c < len && !is_word_boundary( str, c ) )
696 #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 704 if (!STB_TEXT_HAS_SELECTION(state))
705 state->select_start = state->select_end = state->cursor;
707 state->cursor = state->select_end;
711 static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state)
713 if (STB_TEXT_HAS_SELECTION(state)) {
714 stb_textedit_delete_selection(str,state);
715 state->has_preferred_x = 0;
722 static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text,
int len)
725 stb_textedit_clamp(str, state);
726 stb_textedit_delete_selection(str,state);
728 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
729 stb_text_makeundo_insert(state, state->cursor, len);
730 state->cursor += len;
731 state->has_preferred_x = 0;
738 #ifndef STB_TEXTEDIT_KEYTYPE 739 #define STB_TEXTEDIT_KEYTYPE int 743 static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
const IMSTB_TEXTEDIT_CHARTYPE* text,
int text_len)
746 if (text[0] ==
'\n' && state->single_line)
749 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
750 stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
751 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
752 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
753 state->cursor += text_len;
754 state->has_preferred_x = 0;
758 stb_textedit_delete_selection(str, state);
759 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
760 stb_text_makeundo_insert(state, state->cursor, text_len);
761 state->cursor += text_len;
762 state->has_preferred_x = 0;
768 static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
773 #ifdef STB_TEXTEDIT_KEYTOTEXT 774 int c = STB_TEXTEDIT_KEYTOTEXT(key);
776 IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
777 stb_textedit_text(str, state, &ch, 1);
783 #ifdef STB_TEXTEDIT_K_INSERT 784 case STB_TEXTEDIT_K_INSERT:
785 state->insert_mode = !state->insert_mode;
789 case STB_TEXTEDIT_K_UNDO:
790 stb_text_undo(str, state);
791 state->has_preferred_x = 0;
794 case STB_TEXTEDIT_K_REDO:
795 stb_text_redo(str, state);
796 state->has_preferred_x = 0;
799 case STB_TEXTEDIT_K_LEFT:
801 if (STB_TEXT_HAS_SELECTION(state))
802 stb_textedit_move_to_first(state);
804 if (state->cursor > 0)
805 state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
806 state->has_preferred_x = 0;
809 case STB_TEXTEDIT_K_RIGHT:
811 if (STB_TEXT_HAS_SELECTION(state))
812 stb_textedit_move_to_last(str, state);
814 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
815 stb_textedit_clamp(str, state);
816 state->has_preferred_x = 0;
819 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
820 stb_textedit_clamp(str, state);
821 stb_textedit_prep_selection_at_cursor(state);
823 if (state->select_end > 0)
824 state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
825 state->cursor = state->select_end;
826 state->has_preferred_x = 0;
829 #ifdef STB_TEXTEDIT_MOVEWORDLEFT 830 case STB_TEXTEDIT_K_WORDLEFT:
831 if (STB_TEXT_HAS_SELECTION(state))
832 stb_textedit_move_to_first(state);
834 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
835 stb_textedit_clamp( str, state );
839 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
840 if( !STB_TEXT_HAS_SELECTION( state ) )
841 stb_textedit_prep_selection_at_cursor(state);
843 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
844 state->select_end = state->cursor;
846 stb_textedit_clamp( str, state );
850 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 851 case STB_TEXTEDIT_K_WORDRIGHT:
852 if (STB_TEXT_HAS_SELECTION(state))
853 stb_textedit_move_to_last(str, state);
855 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
856 stb_textedit_clamp( str, state );
860 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
861 if( !STB_TEXT_HAS_SELECTION( state ) )
862 stb_textedit_prep_selection_at_cursor(state);
864 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
865 state->select_end = state->cursor;
867 stb_textedit_clamp( str, state );
871 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
872 stb_textedit_prep_selection_at_cursor(state);
874 state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
875 stb_textedit_clamp(str, state);
876 state->cursor = state->select_end;
877 state->has_preferred_x = 0;
880 case STB_TEXTEDIT_K_DOWN:
881 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
882 case STB_TEXTEDIT_K_PGDOWN:
883 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
886 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
887 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
888 int row_count = is_page ? state->row_count_per_page : 1;
890 if (!is_page && state->single_line) {
892 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
897 stb_textedit_prep_selection_at_cursor(state);
898 else if (STB_TEXT_HAS_SELECTION(state))
899 stb_textedit_move_to_last(str, state);
902 stb_textedit_clamp(str, state);
903 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
905 for (j = 0; j < row_count; ++j) {
906 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
907 int start = find.first_char + find.length;
909 if (find.length == 0)
914 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
918 state->cursor = start;
919 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
921 for (i=0; i < row.num_chars; ++i) {
922 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
923 #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE 924 if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
930 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
932 stb_textedit_clamp(str, state);
934 state->has_preferred_x = 1;
935 state->preferred_x = goal_x;
938 state->select_end = state->cursor;
941 find.first_char = find.first_char + find.length;
942 find.length = row.num_chars;
947 case STB_TEXTEDIT_K_UP:
948 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
949 case STB_TEXTEDIT_K_PGUP:
950 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
953 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
954 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
955 int row_count = is_page ? state->row_count_per_page : 1;
957 if (!is_page && state->single_line) {
959 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
964 stb_textedit_prep_selection_at_cursor(state);
965 else if (STB_TEXT_HAS_SELECTION(state))
966 stb_textedit_move_to_first(state);
969 stb_textedit_clamp(str, state);
970 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
972 for (j = 0; j < row_count; ++j) {
973 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
976 if (find.prev_first == find.first_char)
980 state->cursor = find.prev_first;
981 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
983 for (i=0; i < row.num_chars; ++i) {
984 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
985 #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE 986 if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
992 state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
994 stb_textedit_clamp(str, state);
996 state->has_preferred_x = 1;
997 state->preferred_x = goal_x;
1000 state->select_end = state->cursor;
1004 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
1005 while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
1007 find.first_char = find.prev_first;
1008 find.prev_first = prev_scan;
1013 case STB_TEXTEDIT_K_DELETE:
1014 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
1015 if (STB_TEXT_HAS_SELECTION(state))
1016 stb_textedit_delete_selection(str, state);
1018 int n = STB_TEXTEDIT_STRINGLEN(str);
1019 if (state->cursor < n)
1020 stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
1022 state->has_preferred_x = 0;
1025 case STB_TEXTEDIT_K_BACKSPACE:
1026 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
1027 if (STB_TEXT_HAS_SELECTION(state))
1028 stb_textedit_delete_selection(str, state);
1030 stb_textedit_clamp(str, state);
1031 if (state->cursor > 0) {
1032 int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
1033 stb_textedit_delete(str, state, prev, state->cursor - prev);
1034 state->cursor = prev;
1037 state->has_preferred_x = 0;
1040 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1041 case STB_TEXTEDIT_K_TEXTSTART2:
1043 case STB_TEXTEDIT_K_TEXTSTART:
1044 state->cursor = state->select_start = state->select_end = 0;
1045 state->has_preferred_x = 0;
1048 #ifdef STB_TEXTEDIT_K_TEXTEND2 1049 case STB_TEXTEDIT_K_TEXTEND2:
1051 case STB_TEXTEDIT_K_TEXTEND:
1052 state->cursor = STB_TEXTEDIT_STRINGLEN(str);
1053 state->select_start = state->select_end = 0;
1054 state->has_preferred_x = 0;
1057 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1058 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
1060 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
1061 stb_textedit_prep_selection_at_cursor(state);
1062 state->cursor = state->select_end = 0;
1063 state->has_preferred_x = 0;
1066 #ifdef STB_TEXTEDIT_K_TEXTEND2 1067 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
1069 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
1070 stb_textedit_prep_selection_at_cursor(state);
1071 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
1072 state->has_preferred_x = 0;
1076 #ifdef STB_TEXTEDIT_K_LINESTART2 1077 case STB_TEXTEDIT_K_LINESTART2:
1079 case STB_TEXTEDIT_K_LINESTART:
1080 stb_textedit_clamp(str, state);
1081 stb_textedit_move_to_first(state);
1082 if (state->single_line)
1084 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1086 state->has_preferred_x = 0;
1089 #ifdef STB_TEXTEDIT_K_LINEEND2 1090 case STB_TEXTEDIT_K_LINEEND2:
1092 case STB_TEXTEDIT_K_LINEEND: {
1093 int n = STB_TEXTEDIT_STRINGLEN(str);
1094 stb_textedit_clamp(str, state);
1095 stb_textedit_move_to_first(state);
1096 if (state->single_line)
1098 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1100 state->has_preferred_x = 0;
1104 #ifdef STB_TEXTEDIT_K_LINESTART2 1105 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1107 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1108 stb_textedit_clamp(str, state);
1109 stb_textedit_prep_selection_at_cursor(state);
1110 if (state->single_line)
1112 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
1114 state->select_end = state->cursor;
1115 state->has_preferred_x = 0;
1118 #ifdef STB_TEXTEDIT_K_LINEEND2 1119 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1121 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1122 int n = STB_TEXTEDIT_STRINGLEN(str);
1123 stb_textedit_clamp(str, state);
1124 stb_textedit_prep_selection_at_cursor(state);
1125 if (state->single_line)
1127 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1129 state->select_end = state->cursor;
1130 state->has_preferred_x = 0;
1142 static void stb_textedit_flush_redo(
StbUndoState *state)
1144 state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
1145 state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
1149 static void stb_textedit_discard_undo(
StbUndoState *state)
1151 if (state->undo_point > 0) {
1153 if (state->undo_rec[0].char_storage >= 0) {
1154 int n = state->undo_rec[0].insert_length, i;
1156 state->undo_char_point -= n;
1157 IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (
size_t) (state->undo_char_point*
sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
1158 for (i=0; i < state->undo_point; ++i)
1159 if (state->undo_rec[i].char_storage >= 0)
1160 state->undo_rec[i].char_storage -= n;
1162 --state->undo_point;
1163 IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (
size_t) (state->undo_point*
sizeof(state->undo_rec[0])));
1171 static void stb_textedit_discard_redo(
StbUndoState *state)
1173 int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
1175 if (state->redo_point <= k) {
1177 if (state->undo_rec[k].char_storage >= 0) {
1178 int n = state->undo_rec[k].insert_length, i;
1180 state->redo_char_point += n;
1181 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)));
1183 for (i=state->redo_point; i < k; ++i)
1184 if (state->undo_rec[i].char_storage >= 0)
1185 state->undo_rec[i].char_storage += n;
1189 size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) *
sizeof(state->undo_rec[0]));
1190 const char* buf_begin = (
char*)state->undo_rec; (
void)buf_begin;
1191 const char* buf_end = (
char*)state->undo_rec +
sizeof(state->undo_rec); (void)buf_end;
1192 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point)) >= buf_begin);
1193 IM_ASSERT(((
char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
1194 IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
1197 ++state->redo_point;
1204 stb_textedit_flush_redo(state);
1208 if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1209 stb_textedit_discard_undo(state);
1212 if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
1213 state->undo_point = 0;
1214 state->undo_char_point = 0;
1219 while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
1220 stb_textedit_discard_undo(state);
1222 return &state->undo_rec[state->undo_point++];
1225 static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(
StbUndoState *state,
int pos,
int insert_len,
int delete_len)
1227 StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
1232 r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
1233 r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
1235 if (insert_len == 0) {
1236 r->char_storage = -1;
1239 r->char_storage = state->undo_char_point;
1240 state->undo_char_point += insert_len;
1241 return &state->undo_char[r->char_storage];
1249 if (s->undo_point == 0)
1253 u = s->undo_rec[s->undo_point-1];
1254 r = &s->undo_rec[s->redo_point-1];
1255 r->char_storage = -1;
1257 r->insert_length = u.delete_length;
1258 r->delete_length = u.insert_length;
1261 if (u.delete_length) {
1272 if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
1274 r->insert_length = 0;
1279 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1281 if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1284 stb_textedit_discard_redo(s);
1286 r = &s->undo_rec[s->redo_point-1];
1288 r->char_storage = s->redo_char_point - u.delete_length;
1289 s->redo_char_point = s->redo_char_point - u.delete_length;
1292 for (i=0; i < u.delete_length; ++i)
1293 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1297 STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1301 if (u.insert_length) {
1303 STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1304 s->undo_char_point -= u.insert_length;
1307 state->cursor = u.where + u.insert_length;
1317 if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
1321 u = &s->undo_rec[s->undo_point];
1322 r = s->undo_rec[s->redo_point];
1327 u->delete_length = r.insert_length;
1328 u->insert_length = r.delete_length;
1330 u->char_storage = -1;
1332 if (r.delete_length) {
1336 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1337 u->insert_length = 0;
1338 u->delete_length = 0;
1341 u->char_storage = s->undo_char_point;
1342 s->undo_char_point = s->undo_char_point + u->insert_length;
1345 for (i=0; i < u->insert_length; ++i)
1346 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1349 STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1352 if (r.insert_length) {
1354 STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1355 s->redo_char_point += r.insert_length;
1358 state->cursor = r.where + r.insert_length;
1364 static void stb_text_makeundo_insert(
STB_TexteditState *state,
int where,
int length)
1366 stb_text_createundo(&state->undostate, where, 0, length);
1369 static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int length)
1372 IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
1374 for (i=0; i < length; ++i)
1375 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1379 static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state,
int where,
int old_length,
int new_length)
1382 IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1384 for (i=0; i < old_length; ++i)
1385 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
1390 static void stb_textedit_clear_state(
STB_TexteditState *state,
int is_single_line)
1392 state->undostate.undo_point = 0;
1393 state->undostate.undo_char_point = 0;
1394 state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
1395 state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
1396 state->select_end = state->select_start = 0;
1398 state->has_preferred_x = 0;
1399 state->preferred_x = 0;
1400 state->cursor_at_end_of_line = 0;
1401 state->initialized = 1;
1402 state->single_line = (
unsigned char) is_single_line;
1403 state->insert_mode = 0;
1404 state->row_count_per_page = 0;
1408 static void stb_textedit_initialize_state(
STB_TexteditState *state,
int is_single_line)
1410 stb_textedit_clear_state(state, is_single_line);
1413 #if defined(__GNUC__) || defined(__clang__) 1414 #pragma GCC diagnostic push 1415 #pragma GCC diagnostic ignored "-Wcast-qual" 1418 static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str,
STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE
const *ctext,
int len)
1420 return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
1423 #if defined(__GNUC__) || defined(__clang__) 1424 #pragma GCC diagnostic pop 1427 #endif//IMSTB_TEXTEDIT_IMPLEMENTATION Definition: imstb_textedit.h:320
In find(In first, In last, const T &v)
Definition: algorithm.h:225
Definition: imstb_textedit.h:376
Definition: imstb_textedit.h:311
Definition: imstb_textedit.h:329