275#ifndef INCLUDE_STB_TEXTEDIT_H
276#define INCLUDE_STB_TEXTEDIT_H
287#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
288#define STB_TEXTEDIT_UNDOSTATECOUNT 99
290#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
291#define STB_TEXTEDIT_UNDOCHARCOUNT 999
293#ifndef STB_TEXTEDIT_CHARTYPE
294#define STB_TEXTEDIT_CHARTYPE int
296#ifndef STB_TEXTEDIT_POSITIONTYPE
297#define STB_TEXTEDIT_POSITIONTYPE int
303 STB_TEXTEDIT_POSITIONTYPE where;
304 STB_TEXTEDIT_POSITIONTYPE insert_length;
305 STB_TEXTEDIT_POSITIONTYPE delete_length;
313 STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
314 short undo_point, redo_point;
315 int undo_char_point, redo_char_point;
335 unsigned char insert_mode;
339 int row_count_per_page;
347 unsigned char cursor_at_end_of_line;
348 unsigned char initialized;
349 unsigned char has_preferred_x;
350 unsigned char single_line;
351 unsigned char padding1, padding2, padding3;
367 float baseline_y_delta;
382#ifdef STB_TEXTEDIT_IMPLEMENTATION
384#ifndef STB_TEXTEDIT_memmove
386#define STB_TEXTEDIT_memmove memmove
389#include "Karma/Core.h"
397static int stb_text_locate_coord(STB_TEXTEDIT_STRING* str,
float x,
float y)
400 int n = STB_TEXTEDIT_STRINGLEN(str);
401 float base_y = 0, prev_x;
410 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
411 if (r.num_chars <= 0)
414 if (i == 0 && y < base_y + r.ymin)
417 if (y < base_y + r.ymax)
421 base_y += r.baseline_y_delta;
436 for (k = 0; k < r.num_chars; ++k) {
437 float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
438 if (x < prev_x + w) {
439 if (x < prev_x + w / 2)
450 if (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) == STB_TEXTEDIT_NEWLINE)
451 return i + r.num_chars - 1;
453 return i + r.num_chars;
457static void stb_textedit_click(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
float x,
float y)
461 if (state->single_line)
464 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
468 state->cursor = stb_text_locate_coord(str, x, y);
469 state->select_start = state->cursor;
470 state->select_end = state->cursor;
471 state->has_preferred_x = 0;
475static void stb_textedit_drag(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
float x,
float y)
481 if (state->single_line)
484 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
488 if (state->select_start == state->select_end)
489 state->select_start = state->cursor;
491 p = stb_text_locate_coord(str, x, y);
492 state->cursor = state->select_end = p;
503static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int length);
504static void stb_text_makeundo_insert(
STB_TexteditState* state,
int where,
int length);
505static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int old_length,
int new_length);
511 int first_char, length;
517static void stb_textedit_find_charpos(StbFindState* find, STB_TEXTEDIT_STRING* str,
int n,
int single_line)
521 int z = STB_TEXTEDIT_STRINGLEN(str);
528 STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
530 find->first_char = 0;
532 find->height = r.ymax - r.ymin;
540 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
544 find->first_char = i;
546 find->prev_first = prev_start;
555 STB_TEXTEDIT_LAYOUTROW(&r, str, i);
556 if (n < i + r.num_chars)
560 find->y += r.baseline_y_delta;
563 find->first_char = first = i;
564 find->length = r.num_chars;
565 find->height = r.ymax - r.ymin;
566 find->prev_first = prev_start;
570 for (i = 0; first + i < n; ++i)
571 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
574#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
577static void stb_textedit_clamp(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
579 int n = STB_TEXTEDIT_STRINGLEN(str);
580 if (STB_TEXT_HAS_SELECTION(state)) {
581 if (state->select_start > n) state->select_start = n;
582 if (state->select_end > n) state->select_end = n;
584 if (state->select_start == state->select_end)
585 state->cursor = state->select_start;
587 if (state->cursor > n) state->cursor = n;
591static void stb_textedit_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int len)
593 stb_text_makeundo_delete(str, state, where, len);
594 STB_TEXTEDIT_DELETECHARS(str, where, len);
595 state->has_preferred_x = 0;
599static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
601 stb_textedit_clamp(str, state);
602 if (STB_TEXT_HAS_SELECTION(state)) {
603 if (state->select_start < state->select_end) {
604 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
605 state->select_end = state->cursor = state->select_start;
608 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
609 state->select_start = state->cursor = state->select_end;
611 state->has_preferred_x = 0;
618 if (state->select_end < state->select_start) {
619 int temp = state->select_end;
620 state->select_end = state->select_start;
621 state->select_start = temp;
628 if (STB_TEXT_HAS_SELECTION(state)) {
629 stb_textedit_sortselection(state);
630 state->cursor = state->select_start;
631 state->select_end = state->select_start;
632 state->has_preferred_x = 0;
637static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state)
639 if (STB_TEXT_HAS_SELECTION(state)) {
640 stb_textedit_sortselection(state);
641 stb_textedit_clamp(str, state);
642 state->cursor = state->select_end;
643 state->select_start = state->select_end;
644 state->has_preferred_x = 0;
648#ifdef STB_TEXTEDIT_IS_SPACE
649static int is_word_boundary(STB_TEXTEDIT_STRING* str,
int idx)
651 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;
654#ifndef STB_TEXTEDIT_MOVEWORDLEFT
655static int stb_textedit_move_to_word_previous(STB_TEXTEDIT_STRING* str,
int c)
658 while (c >= 0 && !is_word_boundary(str, c))
666#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous
669#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
670static int stb_textedit_move_to_word_next(STB_TEXTEDIT_STRING* str,
int c)
672 const int len = STB_TEXTEDIT_STRINGLEN(str);
674 while (c < len && !is_word_boundary(str, c))
682#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next
690 if (!STB_TEXT_HAS_SELECTION(state))
691 state->select_start = state->select_end = state->cursor;
693 state->cursor = state->select_end;
699 if (STB_TEXT_HAS_SELECTION(state)) {
700 stb_textedit_delete_selection(str, state);
701 state->has_preferred_x = 0;
708static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE* text,
int len)
711 stb_textedit_clamp(str, state);
712 stb_textedit_delete_selection(str, state);
714 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
715 stb_text_makeundo_insert(state, state->cursor, len);
716 state->cursor += len;
717 state->has_preferred_x = 0;
724#ifndef STB_TEXTEDIT_KEYTYPE
725#define STB_TEXTEDIT_KEYTYPE int
729static void stb_textedit_key(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_KEYTYPE key)
734 int c = STB_TEXTEDIT_KEYTOTEXT(key);
736 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c;
739 if (c ==
'\n' && state->single_line)
742 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
743 stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
744 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
745 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
747 state->has_preferred_x = 0;
751 stb_textedit_delete_selection(str, state);
752 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
753 stb_text_makeundo_insert(state, state->cursor, 1);
755 state->has_preferred_x = 0;
762#ifdef STB_TEXTEDIT_K_INSERT
763 case STB_TEXTEDIT_K_INSERT:
764 state->insert_mode = !state->insert_mode;
768 case STB_TEXTEDIT_K_UNDO:
769 stb_text_undo(str, state);
770 state->has_preferred_x = 0;
773 case STB_TEXTEDIT_K_REDO:
774 stb_text_redo(str, state);
775 state->has_preferred_x = 0;
778 case STB_TEXTEDIT_K_LEFT:
780 if (STB_TEXT_HAS_SELECTION(state))
781 stb_textedit_move_to_first(state);
783 if (state->cursor > 0)
785 state->has_preferred_x = 0;
788 case STB_TEXTEDIT_K_RIGHT:
790 if (STB_TEXT_HAS_SELECTION(state))
791 stb_textedit_move_to_last(str, state);
794 stb_textedit_clamp(str, state);
795 state->has_preferred_x = 0;
798 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
799 stb_textedit_clamp(str, state);
800 stb_textedit_prep_selection_at_cursor(state);
802 if (state->select_end > 0)
804 state->cursor = state->select_end;
805 state->has_preferred_x = 0;
808#ifdef STB_TEXTEDIT_MOVEWORDLEFT
809 case STB_TEXTEDIT_K_WORDLEFT:
810 if (STB_TEXT_HAS_SELECTION(state))
811 stb_textedit_move_to_first(state);
813 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
814 stb_textedit_clamp(str, state);
818 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
819 if (!STB_TEXT_HAS_SELECTION(state))
820 stb_textedit_prep_selection_at_cursor(state);
822 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
823 state->select_end = state->cursor;
825 stb_textedit_clamp(str, state);
829#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
830 case STB_TEXTEDIT_K_WORDRIGHT:
831 if (STB_TEXT_HAS_SELECTION(state))
832 stb_textedit_move_to_last(str, state);
834 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
835 stb_textedit_clamp(str, state);
839 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
840 if (!STB_TEXT_HAS_SELECTION(state))
841 stb_textedit_prep_selection_at_cursor(state);
843 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
844 state->select_end = state->cursor;
846 stb_textedit_clamp(str, state);
850 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
851 stb_textedit_prep_selection_at_cursor(state);
854 stb_textedit_clamp(str, state);
855 state->cursor = state->select_end;
856 state->has_preferred_x = 0;
859 case STB_TEXTEDIT_K_DOWN:
860 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
861 case STB_TEXTEDIT_K_PGDOWN:
862 case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
865 int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
866 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
867 int row_count = is_page ? state->row_count_per_page : 1;
869 if (!is_page && state->single_line) {
871 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
876 stb_textedit_prep_selection_at_cursor(state);
877 else if (STB_TEXT_HAS_SELECTION(state))
878 stb_textedit_move_to_last(str, state);
881 stb_textedit_clamp(str, state);
882 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
884 for (j = 0; j < row_count; ++j) {
885 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
886 int start = find.first_char + find.length;
888 if (find.length == 0)
893 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
897 state->cursor = start;
898 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
900 for (i = 0; i < row.num_chars; ++i) {
901 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
902#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
903 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
911 stb_textedit_clamp(str, state);
913 state->has_preferred_x = 1;
914 state->preferred_x = goal_x;
917 state->select_end = state->cursor;
920 find.first_char = find.first_char + find.length;
921 find.length = row.num_chars;
926 case STB_TEXTEDIT_K_UP:
927 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
928 case STB_TEXTEDIT_K_PGUP:
929 case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
932 int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
933 int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
934 int row_count = is_page ? state->row_count_per_page : 1;
936 if (!is_page && state->single_line) {
938 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
943 stb_textedit_prep_selection_at_cursor(state);
944 else if (STB_TEXT_HAS_SELECTION(state))
945 stb_textedit_move_to_first(state);
948 stb_textedit_clamp(str, state);
949 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
951 for (j = 0; j < row_count; ++j) {
952 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
955 if (find.prev_first == find.first_char)
959 state->cursor = find.prev_first;
960 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
962 for (i = 0; i < row.num_chars; ++i) {
963 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
964#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
965 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
973 stb_textedit_clamp(str, state);
975 state->has_preferred_x = 1;
976 state->preferred_x = goal_x;
979 state->select_end = state->cursor;
983 prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
984 while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
986 find.first_char = find.prev_first;
987 find.prev_first = prev_scan;
992 case STB_TEXTEDIT_K_DELETE:
993 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
994 if (STB_TEXT_HAS_SELECTION(state))
995 stb_textedit_delete_selection(str, state);
997 int n = STB_TEXTEDIT_STRINGLEN(str);
998 if (state->cursor < n)
999 stb_textedit_delete(str, state, state->cursor, 1);
1001 state->has_preferred_x = 0;
1004 case STB_TEXTEDIT_K_BACKSPACE:
1005 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
1006 if (STB_TEXT_HAS_SELECTION(state))
1007 stb_textedit_delete_selection(str, state);
1009 stb_textedit_clamp(str, state);
1010 if (state->cursor > 0) {
1011 stb_textedit_delete(str, state, state->cursor - 1, 1);
1015 state->has_preferred_x = 0;
1018#ifdef STB_TEXTEDIT_K_TEXTSTART2
1019 case STB_TEXTEDIT_K_TEXTSTART2:
1021 case STB_TEXTEDIT_K_TEXTSTART:
1022 state->cursor = state->select_start = state->select_end = 0;
1023 state->has_preferred_x = 0;
1026#ifdef STB_TEXTEDIT_K_TEXTEND2
1027 case STB_TEXTEDIT_K_TEXTEND2:
1029 case STB_TEXTEDIT_K_TEXTEND:
1030 state->cursor = STB_TEXTEDIT_STRINGLEN(str);
1031 state->select_start = state->select_end = 0;
1032 state->has_preferred_x = 0;
1035#ifdef STB_TEXTEDIT_K_TEXTSTART2
1036 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
1038 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
1039 stb_textedit_prep_selection_at_cursor(state);
1040 state->cursor = state->select_end = 0;
1041 state->has_preferred_x = 0;
1044#ifdef STB_TEXTEDIT_K_TEXTEND2
1045 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
1047 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
1048 stb_textedit_prep_selection_at_cursor(state);
1049 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
1050 state->has_preferred_x = 0;
1053#ifdef STB_TEXTEDIT_K_LINESTART2
1054 case STB_TEXTEDIT_K_LINESTART2:
1056 case STB_TEXTEDIT_K_LINESTART:
1057 stb_textedit_clamp(str, state);
1058 stb_textedit_move_to_first(state);
1059 if (state->single_line)
1061 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
1063 state->has_preferred_x = 0;
1066#ifdef STB_TEXTEDIT_K_LINEEND2
1067 case STB_TEXTEDIT_K_LINEEND2:
1069 case STB_TEXTEDIT_K_LINEEND: {
1070 int n = STB_TEXTEDIT_STRINGLEN(str);
1071 stb_textedit_clamp(str, state);
1072 stb_textedit_move_to_first(state);
1073 if (state->single_line)
1075 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1077 state->has_preferred_x = 0;
1081#ifdef STB_TEXTEDIT_K_LINESTART2
1082 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
1084 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
1085 stb_textedit_clamp(str, state);
1086 stb_textedit_prep_selection_at_cursor(state);
1087 if (state->single_line)
1089 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
1091 state->select_end = state->cursor;
1092 state->has_preferred_x = 0;
1095#ifdef STB_TEXTEDIT_K_LINEEND2
1096 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
1098 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
1099 int n = STB_TEXTEDIT_STRINGLEN(str);
1100 stb_textedit_clamp(str, state);
1101 stb_textedit_prep_selection_at_cursor(state);
1102 if (state->single_line)
1104 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
1106 state->select_end = state->cursor;
1107 state->has_preferred_x = 0;
1119static void stb_textedit_flush_redo(
StbUndoState* state)
1121 state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1122 state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1126static void stb_textedit_discard_undo(
StbUndoState* state)
1128 if (state->undo_point > 0) {
1130 if (state->undo_rec[0].char_storage >= 0) {
1131 int n = state->undo_rec[0].insert_length, i;
1133 state->undo_char_point -= n;
1134 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (
size_t)(state->undo_char_point *
sizeof(STB_TEXTEDIT_CHARTYPE)));
1135 for (i = 0; i < state->undo_point; ++i)
1136 if (state->undo_rec[i].char_storage >= 0)
1137 state->undo_rec[i].char_storage -= n;
1139 --state->undo_point;
1140 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (
size_t)(state->undo_point *
sizeof(state->undo_rec[0])));
1148static void stb_textedit_discard_redo(
StbUndoState* state)
1150 int k = STB_TEXTEDIT_UNDOSTATECOUNT - 1;
1152 if (state->redo_point <= k) {
1154 if (state->undo_rec[k].char_storage >= 0) {
1155 int n = state->undo_rec[k].insert_length, i;
1157 state->redo_char_point += n;
1158 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)));
1160 for (i = state->redo_point; i < k; ++i)
1161 if (state->undo_rec[i].char_storage >= 0)
1162 state->undo_rec[i].char_storage += n;
1166 size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) *
sizeof(state->undo_rec[0]));
1167 const char* buf_begin = (
char*)state->undo_rec; (void)buf_begin;
1168 const char* buf_end = (
char*)state->undo_rec +
sizeof(state->undo_rec); (void)buf_end;
1169 KR_CORE_ASSERT(((
char*)(state->undo_rec + state->redo_point)) >= buf_begin,
"");
1170 KR_CORE_ASSERT(((
char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end,
"");
1171 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point + 1, state->undo_rec + state->redo_point, move_size);
1174 ++state->redo_point;
1181 stb_textedit_flush_redo(state);
1185 if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1186 stb_textedit_discard_undo(state);
1189 if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
1190 state->undo_point = 0;
1191 state->undo_char_point = 0;
1196 while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
1197 stb_textedit_discard_undo(state);
1199 return &state->undo_rec[state->undo_point++];
1202static STB_TEXTEDIT_CHARTYPE* stb_text_createundo(
StbUndoState* state,
int pos,
int insert_len,
int delete_len)
1204 StbUndoRecord* r = stb_text_create_undo_record(state, insert_len);
1209 r->insert_length = (STB_TEXTEDIT_POSITIONTYPE)insert_len;
1210 r->delete_length = (STB_TEXTEDIT_POSITIONTYPE)delete_len;
1212 if (insert_len == 0) {
1213 r->char_storage = -1;
1217 r->char_storage = state->undo_char_point;
1218 state->undo_char_point += insert_len;
1219 return &state->undo_char[r->char_storage];
1227 if (s->undo_point == 0)
1231 u = s->undo_rec[s->undo_point - 1];
1232 r = &s->undo_rec[s->redo_point - 1];
1233 r->char_storage = -1;
1235 r->insert_length = u.delete_length;
1236 r->delete_length = u.insert_length;
1239 if (u.delete_length) {
1250 if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
1252 r->insert_length = 0;
1258 while (s->undo_char_point + u.delete_length > s->redo_char_point) {
1260 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1263 stb_textedit_discard_redo(s);
1265 r = &s->undo_rec[s->redo_point - 1];
1267 r->char_storage = s->redo_char_point - u.delete_length;
1268 s->redo_char_point = s->redo_char_point - u.delete_length;
1271 for (i = 0; i < u.delete_length; ++i)
1272 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
1276 STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length);
1280 if (u.insert_length) {
1282 STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
1283 s->undo_char_point -= u.insert_length;
1286 state->cursor = u.where + u.insert_length;
1296 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
1300 u = &s->undo_rec[s->undo_point];
1301 r = s->undo_rec[s->redo_point];
1306 u->delete_length = r.insert_length;
1307 u->insert_length = r.delete_length;
1309 u->char_storage = -1;
1311 if (r.delete_length) {
1315 if (s->undo_char_point + u->insert_length > s->redo_char_point) {
1316 u->insert_length = 0;
1317 u->delete_length = 0;
1321 u->char_storage = s->undo_char_point;
1322 s->undo_char_point = s->undo_char_point + u->insert_length;
1325 for (i = 0; i < u->insert_length; ++i)
1326 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
1329 STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length);
1332 if (r.insert_length) {
1334 STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
1335 s->redo_char_point += r.insert_length;
1338 state->cursor = r.where + r.insert_length;
1344static void stb_text_makeundo_insert(
STB_TexteditState* state,
int where,
int length)
1346 stb_text_createundo(&state->undostate, where, 0, length);
1349static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int length)
1352 STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, length, 0);
1354 for (i = 0; i < length; ++i)
1355 p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
1359static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state,
int where,
int old_length,
int new_length)
1362 STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->undostate, where, old_length, new_length);
1364 for (i = 0; i < old_length; ++i)
1365 p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
1370static void stb_textedit_clear_state(
STB_TexteditState* state,
int is_single_line)
1372 state->undostate.undo_point = 0;
1373 state->undostate.undo_char_point = 0;
1374 state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
1375 state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
1376 state->select_end = state->select_start = 0;
1378 state->has_preferred_x = 0;
1379 state->preferred_x = 0;
1380 state->cursor_at_end_of_line = 0;
1381 state->initialized = 1;
1382 state->single_line = (
unsigned char)is_single_line;
1383 state->insert_mode = 0;
1384 state->row_count_per_page = 0;
1388static void stb_textedit_initialize_state(
STB_TexteditState* state,
int is_single_line)
1390 stb_textedit_clear_state(state, is_single_line);
1393#if defined(__GNUC__) || defined(__clang__)
1394#pragma GCC diagnostic push
1395#pragma GCC diagnostic ignored "-Wcast-qual"
1398static int stb_textedit_paste(STB_TEXTEDIT_STRING* str,
STB_TexteditState* state, STB_TEXTEDIT_CHARTYPE
const* ctext,
int len)
1400 return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE*)ctext, len);
1403#if defined(__GNUC__) || defined(__clang__)
1404#pragma GCC diagnostic pop
Definition KarmaSTBTextEdit.h:319
Definition KarmaSTBTextEdit.h:365
Definition KarmaSTBTextEdit.h:301
Definition KarmaSTBTextEdit.h:310