Changeset e66fd66 in opengl-game for IMGUI/imstb_textedit.h
- Timestamp:
- Dec 5, 2020, 7:14:31 PM (4 years ago)
- Branches:
- feature/imgui-sdl, master
- Children:
- 95c657f
- Parents:
- 78c3045
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
IMGUI/imstb_textedit.h
r78c3045 re66fd66 1 // [ ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb2 // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815)3 // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715)4 // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681)5 // [ImGui] - fixed some minor warnings6 7 // stb_textedit.h - v1. 9- public domain - Sean Barrett1 // [DEAR IMGUI] 2 // This is a slightly modified version of stb_textedit.h 1.13. 3 // Those changes would need to be pushed into nothings/stb: 4 // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) 5 // Grep for [DEAR IMGUI] to find the changes. 6 7 // stb_textedit.h - v1.13 - public domain - Sean Barrett 8 8 // Development of this library was sponsored by RAD Game Tools 9 9 // … … 24 24 // LICENSE 25 25 // 26 // This software is dual-licensed to the public domain and under the following 27 // license: you are granted a perpetual, irrevocable license to copy, modify, 28 // publish, and distribute this file as you see fit. 26 // See end of file for license information. 29 27 // 30 28 // … … 38 36 // VERSION HISTORY 39 37 // 38 // 1.13 (2019-02-07) fix bug in undo size management 39 // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash 40 // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield 41 // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual 40 42 // 1.9 (2016-08-27) customizable move-by-word 41 43 // 1.8 (2016-04-02) better keyboard handling when mouse button is down … … 56 58 // Ulf Winklemann: move-by-word in 1.1 57 59 // Fabian Giesen: secondary key inputs in 1.5 58 // Martins Mozeiko: STB_TEXTEDIT_memmove 60 // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 59 61 // 60 62 // Bugfixes: … … 62 64 // Daniel Keller 63 65 // Omar Cornut 66 // Dan Thompson 64 67 // 65 68 // USAGE … … 91 94 // it grows STB_TexteditState by the worst-case storage which is (in bytes): 92 95 // 93 // [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT94 // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT96 // [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT 97 // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHAR_COUNT 95 98 // 96 99 // … … 115 118 // 116 119 // STB_TEXTEDIT_CHARTYPE the character type 117 // STB_TEXTEDIT_POSITIONTYPE small type that a valid cursor position120 // STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position 118 121 // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 119 122 // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer … … 146 149 // STB_TEXTEDIT_K_UP keyboard input to move cursor up 147 150 // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 151 // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 152 // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 148 153 // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 149 154 // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END … … 168 173 // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 169 174 // 170 // Todo:171 // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page172 // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page173 //174 175 // Keyboard input must be encoded as a single integer value; e.g. a character code 175 176 // and some bitflags that represent shift states. to simplify the interface, SHIFT must 176 177 // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 177 // i.e. (STB_TEXTED _K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.178 // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 178 179 // 179 180 // You can encode other things, such as CONTROL or ALT, in additional bits, and … … 204 205 // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 205 206 // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 206 // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, intkey)207 // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) 207 208 // 208 209 // Each of these functions potentially updates the string and updates the … … 238 239 // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 239 240 // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 240 // clear. 241 // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to 242 // anything other type you wante before including. 243 // 241 244 // 242 245 // When rendering, you can read the cursor position and selection state from … … 298 301 // private data 299 302 STB_TEXTEDIT_POSITIONTYPE where; 300 shortinsert_length;301 shortdelete_length;302 shortchar_storage;303 STB_TEXTEDIT_POSITIONTYPE insert_length; 304 STB_TEXTEDIT_POSITIONTYPE delete_length; 305 int char_storage; 303 306 } StbUndoRecord; 304 307 … … 306 309 { 307 310 // private data 308 StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];311 StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 309 312 STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 310 313 short undo_point, redo_point; 311 short undo_char_point, redo_char_point;314 int undo_char_point, redo_char_point; 312 315 } StbUndoState; 313 316 … … 332 335 // each textfield keeps its own insert mode state. to keep an app-wide 333 336 // insert mode, copy this value in/out of the app state 337 338 int row_count_per_page; 339 // page size in number of row. 340 // this value MUST be set to >0 for pageup or pagedown in multilines documents. 334 341 335 342 ///////////////////// … … 357 364 typedef struct 358 365 { 359 float x0, 366 float x0,x1; // starting x location, end x location (allows for align=right, etc) 360 367 float baseline_y_delta; // position of baseline relative to previous row's baseline 361 float ymin, 368 float ymin,ymax; // height of row above and below baseline 362 369 int num_chars; 363 370 } StbTexteditRow; … … 394 401 int n = STB_TEXTEDIT_STRINGLEN(str); 395 402 float base_y = 0, prev_x; 396 int i =0, k;403 int i=0, k; 397 404 398 405 r.x0 = r.x1 = 0; … … 406 413 return n; 407 414 408 if (i ==0 && y < base_y + r.ymin)415 if (i==0 && y < base_y + r.ymin) 409 416 return 0; 410 417 … … 428 435 // search characters in row for one that straddles 'x' 429 436 prev_x = r.x0; 430 for (k =0; k < r.num_chars; ++k) {437 for (k=0; k < r.num_chars; ++k) { 431 438 float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 432 if (x < prev_x +w) {433 if (x < prev_x + w /2)434 return k +i;439 if (x < prev_x+w) { 440 if (x < prev_x+w/2) 441 return k+i; 435 442 else 436 return k + i +1;443 return k+i+1; 437 444 } 438 445 prev_x += w; … … 442 449 443 450 // if the last character is a newline, return that. otherwise return 'after' the last character 444 if (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars -1) == STB_TEXTEDIT_NEWLINE)445 return i + r.num_chars -1;451 if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 452 return i+r.num_chars-1; 446 453 else 447 return i +r.num_chars;454 return i+r.num_chars; 448 455 } 449 456 … … 451 458 static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 452 459 { 460 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 461 // goes off the top or bottom of the text 462 if( state->single_line ) 463 { 464 StbTexteditRow r; 465 STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 466 y = r.ymin; 467 } 468 453 469 state->cursor = stb_text_locate_coord(str, x, y); 454 470 state->select_start = state->cursor; … … 460 476 static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 461 477 { 462 int p = stb_text_locate_coord(str, x, y); 478 int p = 0; 479 480 // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 481 // goes off the top or bottom of the text 482 if( state->single_line ) 483 { 484 StbTexteditRow r; 485 STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 486 y = r.ymin; 487 } 488 463 489 if (state->select_start == state->select_end) 464 490 state->select_start = state->cursor; 491 492 p = stb_text_locate_coord(str, x, y); 465 493 state->cursor = state->select_end = p; 466 494 } … … 480 508 typedef struct 481 509 { 482 float x, 510 float x,y; // position of n'th character 483 511 float height; // height of line 484 512 int first_char, length; // first char of row, and length … … 493 521 int prev_start = 0; 494 522 int z = STB_TEXTEDIT_STRINGLEN(str); 495 int i =0, first;523 int i=0, first; 496 524 497 525 if (n == z) { … … 505 533 find->height = r.ymax - r.ymin; 506 534 find->x = r.x1; 507 } 508 else { 535 } else { 509 536 find->y = 0; 510 537 find->x = 0; … … 525 552 find->y = 0; 526 553 527 for 554 for(;;) { 528 555 STB_TEXTEDIT_LAYOUTROW(&r, str, i); 529 556 if (n < i + r.num_chars) … … 541 568 // now scan to find xpos 542 569 find->x = r.x0; 543 i = 0; 544 for (i = 0; first + i < n; ++i) 570 for (i=0; first+i < n; ++i) 545 571 find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 546 572 } … … 578 604 stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 579 605 state->select_end = state->cursor = state->select_start; 580 } 581 else { 606 } else { 582 607 stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 583 608 state->select_start = state->cursor = state->select_end; … … 621 646 622 647 #ifdef STB_TEXTEDIT_IS_SPACE 623 static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx)624 { 625 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;648 static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 649 { 650 return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 626 651 } 627 652 628 653 #ifndef STB_TEXTEDIT_MOVEWORDLEFT 629 static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c)654 static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 630 655 { 631 656 --c; // always move at least one character 632 while (c >= 0 && !is_word_boundary(str, c))657 while( c >= 0 && !is_word_boundary( str, c ) ) 633 658 --c; 634 659 635 if (c < 0)660 if( c < 0 ) 636 661 c = 0; 637 662 … … 642 667 643 668 #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 644 static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c)669 static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 645 670 { 646 671 const int len = STB_TEXTEDIT_STRINGLEN(str); 647 672 ++c; // always move at least one character 648 while (c < len && !is_word_boundary(str, c))673 while( c < len && !is_word_boundary( str, c ) ) 649 674 ++c; 650 675 651 if (c > len)676 if( c > len ) 652 677 c = len; 653 678 … … 672 697 { 673 698 if (STB_TEXT_HAS_SELECTION(state)) { 674 stb_textedit_delete_selection(str, state); // implicity clamps699 stb_textedit_delete_selection(str,state); // implicitly clamps 675 700 state->has_preferred_x = 0; 676 701 return 1; … … 680 705 681 706 // API paste: replace existing selection with passed-in text 682 static int stb_textedit_paste (STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const*text, int len)707 static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 683 708 { 684 709 // if there's a selection, the paste should delete it 685 710 stb_textedit_clamp(str, state); 686 stb_textedit_delete_selection(str, 711 stb_textedit_delete_selection(str,state); 687 712 // try to insert the characters 688 713 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { … … 698 723 } 699 724 725 #ifndef STB_TEXTEDIT_KEYTYPE 726 #define STB_TEXTEDIT_KEYTYPE int 727 #endif 728 700 729 // API key: process a keyboard input 701 static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, intkey)730 static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) 702 731 { 703 732 retry: 704 733 switch (key) { 705 default: { 706 int c = STB_TEXTEDIT_KEYTOTEXT(key); 707 if (c > 0) { 708 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c; 709 710 // can't add newline in single-line mode 711 if (c == '\n' && state->single_line) 712 break; 713 714 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 715 stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 716 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 717 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 718 ++state->cursor; 719 state->has_preferred_x = 0; 734 default: { 735 int c = STB_TEXTEDIT_KEYTOTEXT(key); 736 if (c > 0) { 737 STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 738 739 // can't add newline in single-line mode 740 if (c == '\n' && state->single_line) 741 break; 742 743 if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 744 stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 745 STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 746 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 747 ++state->cursor; 748 state->has_preferred_x = 0; 749 } 750 } else { 751 stb_textedit_delete_selection(str,state); // implicitly clamps 752 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 753 stb_text_makeundo_insert(state, state->cursor, 1); 754 ++state->cursor; 755 state->has_preferred_x = 0; 756 } 720 757 } 721 758 } 759 break; 760 } 761 762 #ifdef STB_TEXTEDIT_K_INSERT 763 case STB_TEXTEDIT_K_INSERT: 764 state->insert_mode = !state->insert_mode; 765 break; 766 #endif 767 768 case STB_TEXTEDIT_K_UNDO: 769 stb_text_undo(str, state); 770 state->has_preferred_x = 0; 771 break; 772 773 case STB_TEXTEDIT_K_REDO: 774 stb_text_redo(str, state); 775 state->has_preferred_x = 0; 776 break; 777 778 case STB_TEXTEDIT_K_LEFT: 779 // if currently there's a selection, move cursor to start of selection 780 if (STB_TEXT_HAS_SELECTION(state)) 781 stb_textedit_move_to_first(state); 782 else 783 if (state->cursor > 0) 784 --state->cursor; 785 state->has_preferred_x = 0; 786 break; 787 788 case STB_TEXTEDIT_K_RIGHT: 789 // if currently there's a selection, move cursor to end of selection 790 if (STB_TEXT_HAS_SELECTION(state)) 791 stb_textedit_move_to_last(str, state); 792 else 793 ++state->cursor; 794 stb_textedit_clamp(str, state); 795 state->has_preferred_x = 0; 796 break; 797 798 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 799 stb_textedit_clamp(str, state); 800 stb_textedit_prep_selection_at_cursor(state); 801 // move selection left 802 if (state->select_end > 0) 803 --state->select_end; 804 state->cursor = state->select_end; 805 state->has_preferred_x = 0; 806 break; 807 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); 722 812 else { 723 stb_textedit_delete_selection(str, state); // implicity clamps 724 if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 725 stb_text_makeundo_insert(state, state->cursor, 1); 813 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 814 stb_textedit_clamp( str, state ); 815 } 816 break; 817 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); 821 822 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 823 state->select_end = state->cursor; 824 825 stb_textedit_clamp( str, state ); 826 break; 827 #endif 828 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); 833 else { 834 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 835 stb_textedit_clamp( str, state ); 836 } 837 break; 838 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); 842 843 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 844 state->select_end = state->cursor; 845 846 stb_textedit_clamp( str, state ); 847 break; 848 #endif 849 850 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 851 stb_textedit_prep_selection_at_cursor(state); 852 // move selection right 853 ++state->select_end; 854 stb_textedit_clamp(str, state); 855 state->cursor = state->select_end; 856 state->has_preferred_x = 0; 857 break; 858 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: { 863 StbFindState find; 864 StbTexteditRow row; 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; 868 869 if (!is_page && state->single_line) { 870 // on windows, up&down in single-line behave like left&right 871 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 872 goto retry; 873 } 874 875 if (sel) 876 stb_textedit_prep_selection_at_cursor(state); 877 else if (STB_TEXT_HAS_SELECTION(state)) 878 stb_textedit_move_to_last(str, state); 879 880 // compute current position of cursor point 881 stb_textedit_clamp(str, state); 882 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 883 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; 887 888 if (find.length == 0) 889 break; 890 891 // [DEAR IMGUI] 892 // going down while being on the last line shouldn't bring us to that line end 893 if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) 894 break; 895 896 // now find character position down a row 897 state->cursor = start; 898 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 899 x = row.x0; 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) 904 break; 905 #endif 906 x += dx; 907 if (x > goal_x) 908 break; 726 909 ++state->cursor; 727 state->has_preferred_x = 0; 910 } 911 stb_textedit_clamp(str, state); 912 913 state->has_preferred_x = 1; 914 state->preferred_x = goal_x; 915 916 if (sel) 917 state->select_end = state->cursor; 918 919 // go to next line 920 find.first_char = find.first_char + find.length; 921 find.length = row.num_chars; 922 } 923 break; 924 } 925 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: { 930 StbFindState find; 931 StbTexteditRow row; 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; 935 936 if (!is_page && state->single_line) { 937 // on windows, up&down become left&right 938 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 939 goto retry; 940 } 941 942 if (sel) 943 stb_textedit_prep_selection_at_cursor(state); 944 else if (STB_TEXT_HAS_SELECTION(state)) 945 stb_textedit_move_to_first(state); 946 947 // compute current position of cursor point 948 stb_textedit_clamp(str, state); 949 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 950 951 for (j = 0; j < row_count; ++j) { 952 float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 953 954 // can only go up if there's a previous row 955 if (find.prev_first == find.first_char) 956 break; 957 958 // now find character position up a row 959 state->cursor = find.prev_first; 960 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 961 x = row.x0; 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) 966 break; 967 #endif 968 x += dx; 969 if (x > goal_x) 970 break; 971 ++state->cursor; 972 } 973 stb_textedit_clamp(str, state); 974 975 state->has_preferred_x = 1; 976 state->preferred_x = goal_x; 977 978 if (sel) 979 state->select_end = state->cursor; 980 981 // go to previous line 982 // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) 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) 985 --prev_scan; 986 find.first_char = find.prev_first; 987 find.prev_first = prev_scan; 988 } 989 break; 990 } 991 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); 996 else { 997 int n = STB_TEXTEDIT_STRINGLEN(str); 998 if (state->cursor < n) 999 stb_textedit_delete(str, state, state->cursor, 1); 1000 } 1001 state->has_preferred_x = 0; 1002 break; 1003 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); 1008 else { 1009 stb_textedit_clamp(str, state); 1010 if (state->cursor > 0) { 1011 stb_textedit_delete(str, state, state->cursor-1, 1); 1012 --state->cursor; 728 1013 } 729 1014 } 1015 state->has_preferred_x = 0; 1016 break; 1017 1018 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1019 case STB_TEXTEDIT_K_TEXTSTART2: 1020 #endif 1021 case STB_TEXTEDIT_K_TEXTSTART: 1022 state->cursor = state->select_start = state->select_end = 0; 1023 state->has_preferred_x = 0; 1024 break; 1025 1026 #ifdef STB_TEXTEDIT_K_TEXTEND2 1027 case STB_TEXTEDIT_K_TEXTEND2: 1028 #endif 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; 1033 break; 1034 1035 #ifdef STB_TEXTEDIT_K_TEXTSTART2 1036 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 1037 #endif 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; 1042 break; 1043 1044 #ifdef STB_TEXTEDIT_K_TEXTEND2 1045 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 1046 #endif 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; 1051 break; 1052 1053 1054 #ifdef STB_TEXTEDIT_K_LINESTART2 1055 case STB_TEXTEDIT_K_LINESTART2: 1056 #endif 1057 case STB_TEXTEDIT_K_LINESTART: 1058 stb_textedit_clamp(str, state); 1059 stb_textedit_move_to_first(state); 1060 if (state->single_line) 1061 state->cursor = 0; 1062 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1063 --state->cursor; 1064 state->has_preferred_x = 0; 1065 break; 1066 1067 #ifdef STB_TEXTEDIT_K_LINEEND2 1068 case STB_TEXTEDIT_K_LINEEND2: 1069 #endif 1070 case STB_TEXTEDIT_K_LINEEND: { 1071 int n = STB_TEXTEDIT_STRINGLEN(str); 1072 stb_textedit_clamp(str, state); 1073 stb_textedit_move_to_first(state); 1074 if (state->single_line) 1075 state->cursor = n; 1076 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1077 ++state->cursor; 1078 state->has_preferred_x = 0; 1079 break; 730 1080 } 731 break; 732 } 733 734 #ifdef STB_TEXTEDIT_K_INSERT 735 case STB_TEXTEDIT_K_INSERT: 736 state->insert_mode = !state->insert_mode; 737 break; 738 #endif 739 740 case STB_TEXTEDIT_K_UNDO: 741 stb_text_undo(str, state); 742 state->has_preferred_x = 0; 743 break; 744 745 case STB_TEXTEDIT_K_REDO: 746 stb_text_redo(str, state); 747 state->has_preferred_x = 0; 748 break; 749 750 case STB_TEXTEDIT_K_LEFT: 751 // if currently there's a selection, move cursor to start of selection 752 if (STB_TEXT_HAS_SELECTION(state)) 753 stb_textedit_move_to_first(state); 754 else 755 if (state->cursor > 0) 1081 1082 #ifdef STB_TEXTEDIT_K_LINESTART2 1083 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1084 #endif 1085 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1086 stb_textedit_clamp(str, state); 1087 stb_textedit_prep_selection_at_cursor(state); 1088 if (state->single_line) 1089 state->cursor = 0; 1090 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 756 1091 --state->cursor; 757 state->has_preferred_x = 0; 758 break; 759 760 case STB_TEXTEDIT_K_RIGHT: 761 // if currently there's a selection, move cursor to end of selection 762 if (STB_TEXT_HAS_SELECTION(state)) 763 stb_textedit_move_to_last(str, state); 764 else 765 ++state->cursor; 766 stb_textedit_clamp(str, state); 767 state->has_preferred_x = 0; 768 break; 769 770 case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 771 stb_textedit_clamp(str, state); 772 stb_textedit_prep_selection_at_cursor(state); 773 // move selection left 774 if (state->select_end > 0) 775 --state->select_end; 776 state->cursor = state->select_end; 777 state->has_preferred_x = 0; 778 break; 779 780 #ifdef STB_TEXTEDIT_MOVEWORDLEFT 781 case STB_TEXTEDIT_K_WORDLEFT: 782 if (STB_TEXT_HAS_SELECTION(state)) 783 stb_textedit_move_to_first(state); 784 else { 785 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 1092 state->select_end = state->cursor; 1093 state->has_preferred_x = 0; 1094 break; 1095 1096 #ifdef STB_TEXTEDIT_K_LINEEND2 1097 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1098 #endif 1099 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1100 int n = STB_TEXTEDIT_STRINGLEN(str); 786 1101 stb_textedit_clamp(str, state); 1102 stb_textedit_prep_selection_at_cursor(state); 1103 if (state->single_line) 1104 state->cursor = n; 1105 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1106 ++state->cursor; 1107 state->select_end = state->cursor; 1108 state->has_preferred_x = 0; 1109 break; 787 1110 } 788 break;789 790 case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:791 if (!STB_TEXT_HAS_SELECTION(state))792 stb_textedit_prep_selection_at_cursor(state);793 794 state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);795 state->select_end = state->cursor;796 797 stb_textedit_clamp(str, state);798 break;799 #endif800 801 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT802 case STB_TEXTEDIT_K_WORDRIGHT:803 if (STB_TEXT_HAS_SELECTION(state))804 stb_textedit_move_to_last(str, state);805 else {806 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);807 stb_textedit_clamp(str, state);808 }809 break;810 811 case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:812 if (!STB_TEXT_HAS_SELECTION(state))813 stb_textedit_prep_selection_at_cursor(state);814 815 state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);816 state->select_end = state->cursor;817 818 stb_textedit_clamp(str, state);819 break;820 #endif821 822 case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:823 stb_textedit_prep_selection_at_cursor(state);824 // move selection right825 ++state->select_end;826 stb_textedit_clamp(str, state);827 state->cursor = state->select_end;828 state->has_preferred_x = 0;829 break;830 831 case STB_TEXTEDIT_K_DOWN:832 case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: {833 StbFindState find;834 StbTexteditRow row;835 int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;836 837 if (state->single_line) {838 // on windows, up&down in single-line behave like left&right839 key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);840 goto retry;841 }842 843 if (sel)844 stb_textedit_prep_selection_at_cursor(state);845 else if (STB_TEXT_HAS_SELECTION(state))846 stb_textedit_move_to_last(str, state);847 848 // compute current position of cursor point849 stb_textedit_clamp(str, state);850 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);851 852 // now find character position down a row853 if (find.length) {854 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;855 float x;856 int start = find.first_char + find.length;857 state->cursor = start;858 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);859 x = row.x0;860 for (i = 0; i < row.num_chars; ++i) {861 float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);862 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE863 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)864 break;865 #endif866 x += dx;867 if (x > goal_x)868 break;869 ++state->cursor;870 }871 stb_textedit_clamp(str, state);872 873 state->has_preferred_x = 1;874 state->preferred_x = goal_x;875 876 if (sel)877 state->select_end = state->cursor;878 }879 break;880 }881 882 case STB_TEXTEDIT_K_UP:883 case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: {884 StbFindState find;885 StbTexteditRow row;886 int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;887 888 if (state->single_line) {889 // on windows, up&down become left&right890 key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);891 goto retry;892 }893 894 if (sel)895 stb_textedit_prep_selection_at_cursor(state);896 else if (STB_TEXT_HAS_SELECTION(state))897 stb_textedit_move_to_first(state);898 899 // compute current position of cursor point900 stb_textedit_clamp(str, state);901 stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);902 903 // can only go up if there's a previous row904 if (find.prev_first != find.first_char) {905 // now find character position up a row906 float goal_x = state->has_preferred_x ? state->preferred_x : find.x;907 float x;908 state->cursor = find.prev_first;909 STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);910 x = row.x0;911 for (i = 0; i < row.num_chars; ++i) {912 float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);913 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE914 if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)915 break;916 #endif917 x += dx;918 if (x > goal_x)919 break;920 ++state->cursor;921 }922 stb_textedit_clamp(str, state);923 924 state->has_preferred_x = 1;925 state->preferred_x = goal_x;926 927 if (sel)928 state->select_end = state->cursor;929 }930 break;931 }932 933 case STB_TEXTEDIT_K_DELETE:934 case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:935 if (STB_TEXT_HAS_SELECTION(state))936 stb_textedit_delete_selection(str, state);937 else {938 int n = STB_TEXTEDIT_STRINGLEN(str);939 if (state->cursor < n)940 stb_textedit_delete(str, state, state->cursor, 1);941 }942 state->has_preferred_x = 0;943 break;944 945 case STB_TEXTEDIT_K_BACKSPACE:946 case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:947 if (STB_TEXT_HAS_SELECTION(state))948 stb_textedit_delete_selection(str, state);949 else {950 stb_textedit_clamp(str, state);951 if (state->cursor > 0) {952 stb_textedit_delete(str, state, state->cursor - 1, 1);953 --state->cursor;954 }955 }956 state->has_preferred_x = 0;957 break;958 959 #ifdef STB_TEXTEDIT_K_TEXTSTART2960 case STB_TEXTEDIT_K_TEXTSTART2:961 #endif962 case STB_TEXTEDIT_K_TEXTSTART:963 state->cursor = state->select_start = state->select_end = 0;964 state->has_preferred_x = 0;965 break;966 967 #ifdef STB_TEXTEDIT_K_TEXTEND2968 case STB_TEXTEDIT_K_TEXTEND2:969 #endif970 case STB_TEXTEDIT_K_TEXTEND:971 state->cursor = STB_TEXTEDIT_STRINGLEN(str);972 state->select_start = state->select_end = 0;973 state->has_preferred_x = 0;974 break;975 976 #ifdef STB_TEXTEDIT_K_TEXTSTART2977 case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:978 #endif979 case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:980 stb_textedit_prep_selection_at_cursor(state);981 state->cursor = state->select_end = 0;982 state->has_preferred_x = 0;983 break;984 985 #ifdef STB_TEXTEDIT_K_TEXTEND2986 case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:987 #endif988 case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:989 stb_textedit_prep_selection_at_cursor(state);990 state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);991 state->has_preferred_x = 0;992 break;993 994 995 #ifdef STB_TEXTEDIT_K_LINESTART2996 case STB_TEXTEDIT_K_LINESTART2:997 #endif998 case STB_TEXTEDIT_K_LINESTART:999 stb_textedit_clamp(str, state);1000 stb_textedit_move_to_first(state);1001 if (state->single_line)1002 state->cursor = 0;1003 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)1004 --state->cursor;1005 state->has_preferred_x = 0;1006 break;1007 1008 #ifdef STB_TEXTEDIT_K_LINEEND21009 case STB_TEXTEDIT_K_LINEEND2:1010 #endif1011 case STB_TEXTEDIT_K_LINEEND: {1012 int n = STB_TEXTEDIT_STRINGLEN(str);1013 stb_textedit_clamp(str, state);1014 stb_textedit_move_to_first(state);1015 if (state->single_line)1016 state->cursor = n;1017 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)1018 ++state->cursor;1019 state->has_preferred_x = 0;1020 break;1021 }1022 1023 #ifdef STB_TEXTEDIT_K_LINESTART21024 case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:1025 #endif1026 case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:1027 stb_textedit_clamp(str, state);1028 stb_textedit_prep_selection_at_cursor(state);1029 if (state->single_line)1030 state->cursor = 0;1031 else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)1032 --state->cursor;1033 state->select_end = state->cursor;1034 state->has_preferred_x = 0;1035 break;1036 1037 #ifdef STB_TEXTEDIT_K_LINEEND21038 case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:1039 #endif1040 case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {1041 int n = STB_TEXTEDIT_STRINGLEN(str);1042 stb_textedit_clamp(str, state);1043 stb_textedit_prep_selection_at_cursor(state);1044 if (state->single_line)1045 state->cursor = n;1046 else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)1047 ++state->cursor;1048 state->select_end = state->cursor;1049 state->has_preferred_x = 0;1050 break;1051 }1052 1053 // @TODO:1054 // STB_TEXTEDIT_K_PGUP - move cursor up a page1055 // STB_TEXTEDIT_K_PGDOWN - move cursor down a page1056 1111 } 1057 1112 } … … 1077 1132 int n = state->undo_rec[0].insert_length, i; 1078 1133 // delete n characters from all other records 1079 state->undo_char_point = state->undo_char_point - (short)n; // vsnet051080 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point *sizeof(STB_TEXTEDIT_CHARTYPE)));1081 for (i =0; i < state->undo_point; ++i)1134 state->undo_char_point -= n; 1135 STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1136 for (i=0; i < state->undo_point; ++i) 1082 1137 if (state->undo_rec[i].char_storage >= 0) 1083 state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short)n; // vsnet05// @OPTIMIZE: get rid of char_storage and infer it1138 state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it 1084 1139 } 1085 1140 --state->undo_point; 1086 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (size_t)((size_t)state->undo_point *sizeof(state->undo_rec[0])));1141 STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); 1087 1142 } 1088 1143 } … … 1094 1149 static void stb_textedit_discard_redo(StbUndoState *state) 1095 1150 { 1096 int k = STB_TEXTEDIT_UNDOSTATECOUNT -1;1151 int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1097 1152 1098 1153 if (state->redo_point <= k) { … … 1100 1155 if (state->undo_rec[k].char_storage >= 0) { 1101 1156 int n = state->undo_rec[k].insert_length, i; 1102 // delete n characters from all other records 1103 state->redo_char_point = state->redo_char_point + (short)n; // vsnet05 1104 STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point - n, (size_t)((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point) * sizeof(STB_TEXTEDIT_CHARTYPE))); 1105 for (i = state->redo_point; i < k; ++i) 1157 // move the remaining redo character data to the end of the buffer 1158 state->redo_char_point += n; 1159 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 // adjust the position of all the other records to account for above memmove 1161 for (i=state->redo_point; i < k; ++i) 1106 1162 if (state->undo_rec[i].char_storage >= 0) 1107 state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short)n; // vsnet051163 state->undo_rec[i].char_storage += n; 1108 1164 } 1109 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point - 1, (size_t)((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point) * sizeof(state->undo_rec[0]))); 1165 // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' 1166 // [DEAR IMGUI] 1167 size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); 1168 const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; 1169 const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; 1170 IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); 1171 IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); 1172 STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); 1173 1174 // now move redo_point to point to the new one 1110 1175 ++state->redo_point; 1111 1176 } … … 1143 1208 1144 1209 r->where = pos; 1145 r->insert_length = ( short)insert_len;1146 r->delete_length = ( short)delete_len;1210 r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; 1211 r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; 1147 1212 1148 1213 if (insert_len == 0) { 1149 1214 r->char_storage = -1; 1150 1215 return NULL; 1151 } 1152 else { 1216 } else { 1153 1217 r->char_storage = state->undo_char_point; 1154 state->undo_char_point = state->undo_char_point + (short)insert_len;1218 state->undo_char_point += insert_len; 1155 1219 return &state->undo_char[r->char_storage]; 1156 1220 } … … 1165 1229 1166 1230 // we need to do two things: apply the undo record, and create a redo record 1167 u = s->undo_rec[s->undo_point -1];1168 r = &s->undo_rec[s->redo_point -1];1231 u = s->undo_rec[s->undo_point-1]; 1232 r = &s->undo_rec[s->redo_point-1]; 1169 1233 r->char_storage = -1; 1170 1234 … … 1187 1251 // the undo records take up too much character space; there's no space to store the redo characters 1188 1252 r->insert_length = 0; 1189 } 1190 else { 1253 } else { 1191 1254 int i; 1192 1255 1193 1256 // there's definitely room to store the characters eventually 1194 1257 while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1195 // there's currently not enough room, so discard a redo record1196 stb_textedit_discard_redo(s);1197 1258 // should never happen: 1198 1259 if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1199 1260 return; 1261 // there's currently not enough room, so discard a redo record 1262 stb_textedit_discard_redo(s); 1200 1263 } 1201 r = &s->undo_rec[s->redo_point -1];1264 r = &s->undo_rec[s->redo_point-1]; 1202 1265 1203 1266 r->char_storage = s->redo_char_point - u.delete_length; 1204 s->redo_char_point = s->redo_char_point - (short)u.delete_length;1267 s->redo_char_point = s->redo_char_point - u.delete_length; 1205 1268 1206 1269 // now save the characters 1207 for (i =0; i < u.delete_length; ++i)1270 for (i=0; i < u.delete_length; ++i) 1208 1271 s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1209 1272 } … … 1252 1315 u->insert_length = 0; 1253 1316 u->delete_length = 0; 1254 } 1255 else { 1317 } else { 1256 1318 int i; 1257 1319 u->char_storage = s->undo_char_point; … … 1259 1321 1260 1322 // now save the characters 1261 for (i =0; i < u->insert_length; ++i)1323 for (i=0; i < u->insert_length; ++i) 1262 1324 s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1263 1325 } … … 1288 1350 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1289 1351 if (p) { 1290 for (i =0; i < length; ++i)1291 p[i] = STB_TEXTEDIT_GETCHAR(str, where +i);1352 for (i=0; i < length; ++i) 1353 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1292 1354 } 1293 1355 } … … 1298 1360 STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1299 1361 if (p) { 1300 for (i =0; i < old_length; ++i)1301 p[i] = STB_TEXTEDIT_GETCHAR(str, where +i);1362 for (i=0; i < old_length; ++i) 1363 p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1302 1364 } 1303 1365 } … … 1316 1378 state->cursor_at_end_of_line = 0; 1317 1379 state->initialized = 1; 1318 state->single_line = (unsigned char) is_single_line;1380 state->single_line = (unsigned char) is_single_line; 1319 1381 state->insert_mode = 0; 1382 state->row_count_per_page = 0; 1320 1383 } 1321 1384 … … 1325 1388 stb_textedit_clear_state(state, is_single_line); 1326 1389 } 1390 1391 #if defined(__GNUC__) || defined(__clang__) 1392 #pragma GCC diagnostic push 1393 #pragma GCC diagnostic ignored "-Wcast-qual" 1394 #endif 1395 1396 static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 1397 { 1398 return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); 1399 } 1400 1401 #if defined(__GNUC__) || defined(__clang__) 1402 #pragma GCC diagnostic pop 1403 #endif 1404 1327 1405 #endif//STB_TEXTEDIT_IMPLEMENTATION 1406 1407 /* 1408 ------------------------------------------------------------------------------ 1409 This software is available under 2 licenses -- choose whichever you prefer. 1410 ------------------------------------------------------------------------------ 1411 ALTERNATIVE A - MIT License 1412 Copyright (c) 2017 Sean Barrett 1413 Permission is hereby granted, free of charge, to any person obtaining a copy of 1414 this software and associated documentation files (the "Software"), to deal in 1415 the Software without restriction, including without limitation the rights to 1416 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1417 of the Software, and to permit persons to whom the Software is furnished to do 1418 so, subject to the following conditions: 1419 The above copyright notice and this permission notice shall be included in all 1420 copies or substantial portions of the Software. 1421 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1422 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1423 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1424 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1425 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1426 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1427 SOFTWARE. 1428 ------------------------------------------------------------------------------ 1429 ALTERNATIVE B - Public Domain (www.unlicense.org) 1430 This is free and unencumbered software released into the public domain. 1431 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1432 software, either in source code form or as a compiled binary, for any purpose, 1433 commercial or non-commercial, and by any means. 1434 In jurisdictions that recognize copyright laws, the author or authors of this 1435 software dedicate any and all copyright interest in the software to the public 1436 domain. We make this dedication for the benefit of the public at large and to 1437 the detriment of our heirs and successors. We intend this dedication to be an 1438 overt act of relinquishment in perpetuity of all present and future rights to 1439 this software under copyright law. 1440 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1441 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1442 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1443 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1444 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1445 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1446 ------------------------------------------------------------------------------ 1447 */
Note:
See TracChangeset
for help on using the changeset viewer.