285#ifndef INCLUDE_STB_TEXTEDIT_H
286#define INCLUDE_STB_TEXTEDIT_H
297#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
298#define STB_TEXTEDIT_UNDOSTATECOUNT 99
300#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
301#define STB_TEXTEDIT_UNDOCHARCOUNT 999
303#ifndef STB_TEXTEDIT_CHARTYPE
304#define STB_TEXTEDIT_CHARTYPE int
306#ifndef STB_TEXTEDIT_POSITIONTYPE
307#define STB_TEXTEDIT_POSITIONTYPE int
313 STB_TEXTEDIT_POSITIONTYPE where;
314 STB_TEXTEDIT_POSITIONTYPE insert_length;
315 STB_TEXTEDIT_POSITIONTYPE delete_length;
323 STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
324 short undo_point, redo_point;
325 int undo_char_point, redo_char_point;
345 unsigned char insert_mode;
349 int row_count_per_page;
357 unsigned char cursor_at_end_of_line;
358 unsigned char initialized;
359 unsigned char has_preferred_x;
360 unsigned char single_line;
361 unsigned char padding1, padding2, padding3;
377 float baseline_y_delta;
392#ifdef STB_TEXTEDIT_IMPLEMENTATION
394#ifndef STB_TEXTEDIT_memmove
396#define STB_TEXTEDIT_memmove memmove
407static int stb_text_locate_coord(STB_TEXTEDIT_STRING* str,
float x,
float y)
410 int n = STB_TEXTEDIT_STRINGLEN(str);
411 float base_y = 0, prev_x;
420 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
421 if (r.num_chars <= 0)
424 if (i == 0 && y < base_y + r.ymin)
427 if (y < base_y + r.ymax)
431 base_y += r.baseline_y_delta;
446 for (k = 0; k < r.num_chars; ++k) {
447 float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
448 if (x < prev_x + w) {
449 if (x < prev_x + w / 2)
460 if (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) == STB_TEXTEDIT_NEWLINE)
461 return i + r.num_chars - 1;
463 return i + r.num_chars;
467static void stb_textedit_click(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
float x,
float y)
471 if (state->single_line)
474 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
478 state->cursor = stb_text_locate_coord(str, x, y);
479 state->select_start = state->cursor;
480 state->select_end = state->cursor;
481 state->has_preferred_x = 0;
485static void stb_textedit_drag(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
float x,
float y)
491 if (state->single_line)
494 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
498 if (state->select_start == state->select_end)
499 state->select_start = state->cursor;
501 p = stb_text_locate_coord(str, x, y);
502 state->cursor = state->select_end = p;
513static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int length);
514static void stb_text_makeundo_insert(
STB_TexteditState* state,
int where,
int length);
515static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int old_length,
int new_length);
521 int first_char, length;
527static void stb_textedit_find_charpos(StbFindState* find, STB_TEXTEDIT_STRING* str,
int n,
int single_line)
531 int z = STB_TEXTEDIT_STRINGLEN(str);
538 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
540 find->first_char = 0;
542 find->height = r.ymax - r.ymin;
550 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
554 find->first_char = i;
556 find->prev_first = prev_start;
565 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
566 if (n < i + r.num_chars)
570 find->y += r.baseline_y_delta;
573 find->first_char = first = i;
574 find->length = r.num_chars;
575 find->height = r.ymax - r.ymin;
576 find->prev_first = prev_start;
580 for (i = 0; first + i < n; ++i)
581 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
584#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
587static void stb_textedit_clamp(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
589 int n = STB_TEXTEDIT_STRINGLEN(str);
590 if (STB_TEXT_HAS_SELECTION(state)) {
591 if (state->select_start > n) state->select_start = n;
592 if (state->select_end > n) state->select_end = n;
594 if (state->select_start == state->select_end)
595 state->cursor = state->select_start;
597 if (state->cursor > n) state->cursor = n;
601static void stb_textedit_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int len)
603 stb_text_makeundo_delete(str, state, where, len);
604 STB_TEXTEDIT_DELETECHARS(str, where, len);
605 state->has_preferred_x = 0;
609static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
611 stb_textedit_clamp(str, state);
612 if (STB_TEXT_HAS_SELECTION(state)) {
613 if (state->select_start < state->select_end) {
614 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
615 state->select_end = state->cursor = state->select_start;
618 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
619 state->select_start = state->cursor = state->select_end;
621 state->has_preferred_x = 0;
628 if (state->select_end < state->select_start) {
629 int temp = state->select_end;
630 state->select_end = state->select_start;
631 state->select_start = temp;
638 if (STB_TEXT_HAS_SELECTION(state)) {
639 stb_textedit_sortselection(state);
640 state->cursor = state->select_start;
641 state->select_end = state->select_start;
642 state->has_preferred_x = 0;
647static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
649 if (STB_TEXT_HAS_SELECTION(state)) {
650 stb_textedit_sortselection(state);
651 stb_textedit_clamp(str, state);
652 state->cursor = state->select_end;
653 state->select_start = state->select_end;
654 state->has_preferred_x = 0;
658#ifdef STB_TEXTEDIT_IS_SPACE
659static int is_word_boundary(STB_TEXTEDIT_STRING* str,
int idx)
661 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;
664#ifndef STB_TEXTEDIT_MOVEWORDLEFT
665static int stb_textedit_move_to_word_previous(STB_TEXTEDIT_STRING* str,
int c)
668 while (c >= 0 && !is_word_boundary(str, c))
676#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
679#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
680static int stb_textedit_move_to_word_next(STB_TEXTEDIT_STRING* str,
int c)
682 const int len = STB_TEXTEDIT_STRINGLEN(str);
684 while (c < len && !is_word_boundary(str, c))
692#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
700 if (!STB_TEXT_HAS_SELECTION(state))
701 state->select_start = state->select_end = state->cursor;
703 state->cursor = state->select_end;
709 if (STB_TEXT_HAS_SELECTION(state)) {
710 stb_textedit_delete_selection(str, state);
711 state->has_preferred_x = 0;
718static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE* text,
int len)
721 stb_textedit_clamp(str, state);
722 stb_textedit_delete_selection(str, state);
724 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
725 stb_text_makeundo_insert(state, state->cursor, len);
726 state->cursor += len;
727 state->has_preferred_x = 0;
734#ifndef STB_TEXTEDIT_KEYTYPE
735#define STB_TEXTEDIT_KEYTYPE int
739static void stb_textedit_key(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_KEYTYPE key)
744 int c = STB_TEXTEDIT_KEYTOTEXT(key);
746 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c;
749 if (c ==
'\n' && state->single_line)
752 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
753 stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
754 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
755 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
757 state->has_preferred_x = 0;
761 stb_textedit_delete_selection(str, state);
762 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
763 stb_text_makeundo_insert(state, state->cursor, 1);
765 state->has_preferred_x = 0;
772#ifdef STB_TEXTEDIT_K_INSERT
773 case STB_TEXTEDIT_K_INSERT:
774 state->insert_mode = !state->insert_mode;
778 case STB_TEXTEDIT_K_UNDO:
779 stb_text_undo(str, state);
780 state->has_preferred_x = 0;
783 case STB_TEXTEDIT_K_REDO:
784 stb_text_redo(str, state);
785 state->has_preferred_x = 0;
788 case STB_TEXTEDIT_K_LEFT:
790 if (STB_TEXT_HAS_SELECTION(state))
791 stb_textedit_move_to_first(state);
793 if (state->cursor > 0)
795 state->has_preferred_x = 0;
798 case STB_TEXTEDIT_K_RIGHT:
800 if (STB_TEXT_HAS_SELECTION(state))
801 stb_textedit_move_to_last(str, state);
804 stb_textedit_clamp(str, state);
805 state->has_preferred_x = 0;
808 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
809 stb_textedit_clamp(str, state);
810 stb_textedit_prep_selection_at_cursor(state);
812 if (state->select_end > 0)
814 state->cursor = state->select_end;
815 state->has_preferred_x = 0;
818#ifdef STB_TEXTEDIT_MOVEWORDLEFT
819 case STB_TEXTEDIT_K_WORDLEFT:
820 if (STB_TEXT_HAS_SELECTION(state))
821 stb_textedit_move_to_first(state);
823 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
824 stb_textedit_clamp(str, state);
828 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
829 if (!STB_TEXT_HAS_SELECTION(state))
830 stb_textedit_prep_selection_at_cursor(state);
832 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
833 state->select_end = state->cursor;
835 stb_textedit_clamp(str, state);
839#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
840 case STB_TEXTEDIT_K_WORDRIGHT:
841 if (STB_TEXT_HAS_SELECTION(state))
842 stb_textedit_move_to_last(str, state);
844 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
845 stb_textedit_clamp(str, state);
849 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
850 if (!STB_TEXT_HAS_SELECTION(state))
851 stb_textedit_prep_selection_at_cursor(state);
853 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
854 state->select_end = state->cursor;
856 stb_textedit_clamp(str, state);
860 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
861 stb_textedit_prep_selection_at_cursor(state);
864 stb_textedit_clamp(str, state);
865 state->cursor = state->select_end;
866 state->has_preferred_x = 0;
869 case STB_TEXTEDIT_K_DOWN:
870 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
871 case STB_TEXTEDIT_K_PGDOWN:
872 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
875 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
876 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
877 int row_count = is_page ? state->row_count_per_page : 1;
879 if (!is_page && state->single_line) {
881 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
886 stb_textedit_prep_selection_at_cursor(state);
887 else if (STB_TEXT_HAS_SELECTION(state))
888 stb_textedit_move_to_last(str, state);
891 stb_textedit_clamp(str, state);
892 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
894 for (j = 0; j < row_count; ++j) {
895 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
896 int start = find.first_char + find.length;
898 if (find.length == 0)
903 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
907 state->cursor = start;
908 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
910 for (i = 0; i < row.num_chars; ++i) {
911 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
912#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
913 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
921 stb_textedit_clamp(str, state);
923 state->has_preferred_x = 1;
924 state->preferred_x = goal_x;
927 state->select_end = state->cursor;
930 find.first_char = find.first_char + find.length;
931 find.length = row.num_chars;
936 case STB_TEXTEDIT_K_UP:
937 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
938 case STB_TEXTEDIT_K_PGUP:
939 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
942 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
943 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
944 int row_count = is_page ? state->row_count_per_page : 1;
946 if (!is_page && state->single_line) {
948 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
953 stb_textedit_prep_selection_at_cursor(state);
954 else if (STB_TEXT_HAS_SELECTION(state))
955 stb_textedit_move_to_first(state);
958 stb_textedit_clamp(str, state);
959 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
961 for (j = 0; j < row_count; ++j) {
962 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
965 if (find.prev_first == find.first_char)
969 state->cursor = find.prev_first;
970 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
972 for (i = 0; i < row.num_chars; ++i) {
973 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
974#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
975 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
983 stb_textedit_clamp(str, state);
985 state->has_preferred_x = 1;
986 state->preferred_x = goal_x;
989 state->select_end = state->cursor;
993 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
994 while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
996 find.first_char = find.prev_first;
997 find.prev_first = prev_scan;
1002 case STB_TEXTEDIT_K_DELETE:
1003 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
1004 if (STB_TEXT_HAS_SELECTION(state))
1005 stb_textedit_delete_selection(str, state);
1007 int n = STB_TEXTEDIT_STRINGLEN(str);
1008 if (state->cursor < n)
1009 stb_textedit_delete(str, state, state->cursor, 1);
1011 state->has_preferred_x = 0;
1014 case STB_TEXTEDIT_K_BACKSPACE:
1015 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
1016 if (STB_TEXT_HAS_SELECTION(state))
1017 stb_textedit_delete_selection(str, state);
1019 stb_textedit_clamp(str, state);
1020 if (state->cursor > 0) {
1021 stb_textedit_delete(str, state, state->cursor - 1, 1);
1025 state->has_preferred_x = 0;
1028#ifdef STB_TEXTEDIT_K_TEXTSTART2
1029 case STB_TEXTEDIT_K_TEXTSTART2:
1031 case STB_TEXTEDIT_K_TEXTSTART:
1032 state->cursor = state->select_start = state->select_end = 0;
1033 state->has_preferred_x = 0;
1036#ifdef STB_TEXTEDIT_K_TEXTEND2
1037 case STB_TEXTEDIT_K_TEXTEND2:
1039 case STB_TEXTEDIT_K_TEXTEND:
1040 state->cursor = STB_TEXTEDIT_STRINGLEN(str);
1041 state->select_start = state->select_end = 0;
1042 state->has_preferred_x = 0;
1045#ifdef STB_TEXTEDIT_K_TEXTSTART2
1046 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
1048 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
1049 stb_textedit_prep_selection_at_cursor(state);
1050 state->cursor = state->select_end = 0;
1051 state->has_preferred_x = 0;
1054#ifdef STB_TEXTEDIT_K_TEXTEND2
1055 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
1057 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
1058 stb_textedit_prep_selection_at_cursor(state);
1059 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
1060 state->has_preferred_x = 0;
1063#ifdef STB_TEXTEDIT_K_LINESTART2
1064 case STB_TEXTEDIT_K_LINESTART2:
1066 case STB_TEXTEDIT_K_LINESTART:
1067 stb_textedit_clamp(str, state);
1068 stb_textedit_move_to_first(state);
1069 if (state->single_line)
1071 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
1073 state->has_preferred_x = 0;
1076#ifdef STB_TEXTEDIT_K_LINEEND2
1077 case STB_TEXTEDIT_K_LINEEND2:
1079 case STB_TEXTEDIT_K_LINEEND: {
1080 int n = STB_TEXTEDIT_STRINGLEN(str);
1081 stb_textedit_clamp(str, state);
1082 stb_textedit_move_to_first(state);
1083 if (state->single_line)
1085 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1087 state->has_preferred_x = 0;
1091#ifdef STB_TEXTEDIT_K_LINESTART2
1092 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1094 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1095 stb_textedit_clamp(str, state);
1096 stb_textedit_prep_selection_at_cursor(state);
1097 if (state->single_line)
1099 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
1101 state->select_end = state->cursor;
1102 state->has_preferred_x = 0;
1105#ifdef STB_TEXTEDIT_K_LINEEND2
1106 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1108 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1109 int n = STB_TEXTEDIT_STRINGLEN(str);
1110 stb_textedit_clamp(str, state);
1111 stb_textedit_prep_selection_at_cursor(state);
1112 if (state->single_line)
1114 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1116 state->select_end = state->cursor;
1117 state->has_preferred_x = 0;
1129static void stb_textedit_flush_redo(
StbUndoState* state)
1131 state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1132 state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1136static void stb_textedit_discard_undo(
StbUndoState* state)
1138 if (state->undo_point > 0) {
1140 if (state->undo_rec[0].char_storage >= 0) {
1141 int n = state->undo_rec[0].insert_length, i;
1143 state->undo_char_point -= n;
1144 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (
size_t)(state->undo_char_point *
sizeof(STB_TEXTEDIT_CHARTYPE)));
1145 for (i = 0; i < state->undo_point; ++i)
1146 if (state->undo_rec[i].char_storage >= 0)
1147 state->undo_rec[i].char_storage -= n;
1149 --state->undo_point;
1150 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (
size_t)(state->undo_point *
sizeof(state->undo_rec[0])));
1158static void stb_textedit_discard_redo(
StbUndoState* state)
1160 int k = STB_TEXTEDIT_UNDOSTATECOUNT - 1;
1162 if (state->redo_point <= k) {
1164 if (state->undo_rec[k].char_storage >= 0) {
1165 int n = state->undo_rec[k].insert_length, i;
1167 state->redo_char_point += n;
1168 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)));
1170 for (i = state->redo_point; i < k; ++i)
1171 if (state->undo_rec[i].char_storage >= 0)
1172 state->undo_rec[i].char_storage += n;
1176 size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) *
sizeof(state->undo_rec[0]));
1177 const char* buf_begin = (
char*)state->undo_rec; (void)buf_begin;
1178 const char* buf_end = (
char*)state->undo_rec +
sizeof(state->undo_rec); (void)buf_end;
1179 KR_CORE_ASSERT(((
char*)(state->undo_rec + state->redo_point)) >= buf_begin,
"");
1180 KR_CORE_ASSERT(((
char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end,
"");
1181 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point + 1, state->undo_rec + state->redo_point, move_size);
1184 ++state->redo_point;
1191 stb_textedit_flush_redo(state);
1195 if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1196 stb_textedit_discard_undo(state);
1199 if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
1200 state->undo_point = 0;
1201 state->undo_char_point = 0;
1206 while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
1207 stb_textedit_discard_undo(state);
1209 return &state->undo_rec[state->undo_point++];
1212static STB_TEXTEDIT_CHARTYPE* stb_text_createundo(
StbUndoState* state,
int pos,
int insert_len,
int delete_len)
1214 StbUndoRecord* r = stb_text_create_undo_record(state, insert_len);
1219 r->insert_length = (STB_TEXTEDIT_POSITIONTYPE)insert_len;
1220 r->delete_length = (STB_TEXTEDIT_POSITIONTYPE)delete_len;
1222 if (insert_len == 0) {
1223 r->char_storage = -1;
1227 r->char_storage = state->undo_char_point;
1228 state->undo_char_point += insert_len;
1229 return &state->undo_char[r->char_storage];
1237 if (s->undo_point == 0)
1241 u = s->undo_rec[s->undo_point - 1];
1242 r = &s->undo_rec[s->redo_point - 1];
1243 r->char_storage = -1;
1245 r->insert_length = u.delete_length;
1246 r->delete_length = u.insert_length;
1249 if (u.delete_length) {
1260 if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
1262 r->insert_length = 0;
1268 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1270 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1273 stb_textedit_discard_redo(s);
1275 r = &s->undo_rec[s->redo_point - 1];
1277 r->char_storage = s->redo_char_point - u.delete_length;
1278 s->redo_char_point = s->redo_char_point - u.delete_length;
1281 for (i = 0; i < u.delete_length; ++i)
1282 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1286 STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1290 if (u.insert_length) {
1292 STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1293 s->undo_char_point -= u.insert_length;
1296 state->cursor = u.where + u.insert_length;
1306 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1310 u = &s->undo_rec[s->undo_point];
1311 r = s->undo_rec[s->redo_point];
1316 u->delete_length = r.insert_length;
1317 u->insert_length = r.delete_length;
1319 u->char_storage = -1;
1321 if (r.delete_length) {
1325 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1326 u->insert_length = 0;
1327 u->delete_length = 0;
1331 u->char_storage = s->undo_char_point;
1332 s->undo_char_point = s->undo_char_point + u->insert_length;
1335 for (i = 0; i < u->insert_length; ++i)
1336 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1339 STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1342 if (r.insert_length) {
1344 STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1345 s->redo_char_point += r.insert_length;
1348 state->cursor = r.where + r.insert_length;
1354static void stb_text_makeundo_insert(
STB_TexteditState* state,
int where,
int length)
1356 stb_text_createundo(&state->undostate, where, 0, length);
1359static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int length)
1362 STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, length, 0);
1364 for (i = 0; i < length; ++i)
1365 p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
1369static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int old_length,
int new_length)
1372 STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1374 for (i = 0; i < old_length; ++i)
1375 p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
1380static void stb_textedit_clear_state(
STB_TexteditState* state,
int is_single_line)
1382 state->undostate.undo_point = 0;
1383 state->undostate.undo_char_point = 0;
1384 state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1385 state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1386 state->select_end = state->select_start = 0;
1388 state->has_preferred_x = 0;
1389 state->preferred_x = 0;
1390 state->cursor_at_end_of_line = 0;
1391 state->initialized = 1;
1392 state->single_line = (
unsigned char)is_single_line;
1393 state->insert_mode = 0;
1394 state->row_count_per_page = 0;
1398static void stb_textedit_initialize_state(
STB_TexteditState* state,
int is_single_line)
1400 stb_textedit_clear_state(state, is_single_line);
1403#if defined(__GNUC__) || defined(__clang__)
1404#pragma GCC diagnostic push
1405#pragma GCC diagnostic ignored "-Wcast-qual"
1408static int stb_textedit_paste(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE
const* ctext,
int len)
1410 return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE*)ctext, len);
1413#if defined(__GNUC__) || defined(__clang__)
1414#pragma GCC diagnostic pop
This file contains the macros for Karma's classes' general purpose use, including assertions and stor...
Definition KarmaSTBTextEdit.h:329
Definition KarmaSTBTextEdit.h:375
Definition KarmaSTBTextEdit.h:311
Definition KarmaSTBTextEdit.h:320