diff options
| author | Alexander Sedov <alex0player@gmail.com> | 2013-04-15 10:28:31 +0400 |
|---|---|---|
| committer | Christoph Lohmann <20h@r-36.net> | 2013-04-20 15:54:19 +0200 |
| commit | 872a7f18eaffd96eefb31e3dcb45fd86bc67029b (patch) | |
| tree | dab72f5f74dc713a17cc3f4b94ca3d36ccf016cc /st.c | |
| parent | 0.4.1 release. (diff) | |
| download | st-872a7f18eaffd96eefb31e3dcb45fd86bc67029b.tar.gz st-872a7f18eaffd96eefb31e3dcb45fd86bc67029b.zip | |
Added support for double/triple click+dragging.
Now double-click+dragging automatically snaps both ends to word boundaries
(unless on series of spaces), and triple-click selects whole lines.
As a side effect, snapping now occurs on button press, not button release
like it previously was, but I hope that won't be inconvenient for anyone.
Signed-off-by: Christoph Lohmann <20h@r-36.net>
Diffstat (limited to '')
| -rw-r--r-- | st.c | 90 |
1 files changed, 63 insertions, 27 deletions
| @@ -135,6 +135,11 @@ enum selection_type { | |||
| 135 | SEL_RECTANGULAR = 2 | 135 | SEL_RECTANGULAR = 2 |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | enum selection_snap { | ||
| 139 | SNAP_WORD = 1, | ||
| 140 | SNAP_LINE = 2 | ||
| 141 | }; | ||
| 142 | |||
| 138 | /* bit macro */ | 143 | /* bit macro */ |
| 139 | #undef B0 | 144 | #undef B0 |
| 140 | enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; | 145 | enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; |
| @@ -232,6 +237,7 @@ typedef struct { | |||
| 232 | typedef struct { | 237 | typedef struct { |
| 233 | int mode; | 238 | int mode; |
| 234 | int type; | 239 | int type; |
| 240 | int snap; | ||
| 235 | int bx, by; | 241 | int bx, by; |
| 236 | int ex, ey; | 242 | int ex, ey; |
| 237 | struct { | 243 | struct { |
| @@ -372,6 +378,7 @@ static void selinit(void); | |||
| 372 | static inline bool selected(int, int); | 378 | static inline bool selected(int, int); |
| 373 | static void selcopy(void); | 379 | static void selcopy(void); |
| 374 | static void selscroll(int, int); | 380 | static void selscroll(int, int); |
| 381 | static void selsnap(int, int *, int *, int); | ||
| 375 | 382 | ||
| 376 | static int utf8decode(char *, long *); | 383 | static int utf8decode(char *, long *); |
| 377 | static int utf8encode(long *, char *); | 384 | static int utf8encode(long *, char *); |
| @@ -658,6 +665,25 @@ selected(int x, int y) { | |||
| 658 | } | 665 | } |
| 659 | 666 | ||
| 660 | void | 667 | void |
| 668 | selsnap(int mode, int *x, int *y, int direction) { | ||
| 669 | switch(mode) { | ||
| 670 | case SNAP_WORD: | ||
| 671 | while(*x > 0 && *x < term.col-1 && term.line[*y][*x + direction].c[0] != ' ') { | ||
| 672 | *x += direction; | ||
| 673 | } | ||
| 674 | break; | ||
| 675 | |||
| 676 | case SNAP_LINE: | ||
| 677 | *x = (direction < 0) ? 0 : term.col - 1; | ||
| 678 | break; | ||
| 679 | |||
| 680 | default: | ||
| 681 | /* do nothing */ | ||
| 682 | break; | ||
| 683 | } | ||
| 684 | } | ||
| 685 | |||
| 686 | void | ||
| 661 | getbuttoninfo(XEvent *e) { | 687 | getbuttoninfo(XEvent *e) { |
| 662 | int type; | 688 | int type; |
| 663 | uint state = e->xbutton.state &~Button1Mask; | 689 | uint state = e->xbutton.state &~Button1Mask; |
| @@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) { | |||
| 667 | sel.ex = x2col(e->xbutton.x); | 693 | sel.ex = x2col(e->xbutton.x); |
| 668 | sel.ey = y2row(e->xbutton.y); | 694 | sel.ey = y2row(e->xbutton.y); |
| 669 | 695 | ||
| 696 | if (sel.by < sel.ey | ||
| 697 | || (sel.by == sel.ey && sel.bx < sel.ex)) { | ||
| 698 | selsnap(sel.snap, &sel.bx, &sel.by, -1); | ||
| 699 | selsnap(sel.snap, &sel.ex, &sel.ey, +1); | ||
| 700 | } else { | ||
| 701 | selsnap(sel.snap, &sel.ex, &sel.ey, -1); | ||
| 702 | selsnap(sel.snap, &sel.bx, &sel.by, +1); | ||
| 703 | } | ||
| 704 | |||
| 670 | sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; | 705 | sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; |
| 671 | sel.b.y = MIN(sel.by, sel.ey); | 706 | sel.b.y = MIN(sel.by, sel.ey); |
| 672 | sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; | 707 | sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; |
| @@ -730,9 +765,13 @@ mousereport(XEvent *e) { | |||
| 730 | 765 | ||
| 731 | void | 766 | void |
| 732 | bpress(XEvent *e) { | 767 | bpress(XEvent *e) { |
| 768 | struct timeval now; | ||
| 769 | |||
| 733 | if(IS_SET(MODE_MOUSE)) { | 770 | if(IS_SET(MODE_MOUSE)) { |
| 734 | mousereport(e); | 771 | mousereport(e); |
| 735 | } else if(e->xbutton.button == Button1) { | 772 | } else if(e->xbutton.button == Button1) { |
| 773 | gettimeofday(&now, NULL); | ||
| 774 | /* Clear previous selection, logically and visually. */ | ||
| 736 | if(sel.bx != -1) { | 775 | if(sel.bx != -1) { |
| 737 | sel.bx = -1; | 776 | sel.bx = -1; |
| 738 | tsetdirt(sel.b.y, sel.e.y); | 777 | tsetdirt(sel.b.y, sel.e.y); |
| @@ -742,6 +781,30 @@ bpress(XEvent *e) { | |||
| 742 | sel.type = SEL_REGULAR; | 781 | sel.type = SEL_REGULAR; |
| 743 | sel.ex = sel.bx = x2col(e->xbutton.x); | 782 | sel.ex = sel.bx = x2col(e->xbutton.x); |
| 744 | sel.ey = sel.by = y2row(e->xbutton.y); | 783 | sel.ey = sel.by = y2row(e->xbutton.y); |
| 784 | /* | ||
| 785 | * Snap handling. | ||
| 786 | * If user clicks are fasst enough (e.g. below timeouts), | ||
| 787 | * we ignore if his hand slipped left or down and accidentally selected more; | ||
| 788 | * we are just snapping to whatever we're snapping. | ||
| 789 | */ | ||
| 790 | if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { | ||
| 791 | /* Snap to line */ | ||
| 792 | sel.snap = SNAP_LINE; | ||
| 793 | } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { | ||
| 794 | sel.snap = SNAP_WORD; | ||
| 795 | } else { | ||
| 796 | sel.snap = 0; | ||
| 797 | } | ||
| 798 | selsnap(sel.snap, &sel.bx, &sel.by, -1); | ||
| 799 | selsnap(sel.snap, &sel.ex, &sel.ey, 1); | ||
| 800 | sel.b.x = sel.bx, sel.b.y = sel.by, sel.e.x = sel.ex, sel.e.y = sel.ey; | ||
| 801 | /* Draw selection, unless it's regular and we don't want to make clicks visible */ | ||
| 802 | if (sel.snap != 0) { | ||
| 803 | tsetdirt(sel.b.y, sel.e.y); | ||
| 804 | draw(); | ||
| 805 | } | ||
| 806 | sel.tclick2 = sel.tclick1; | ||
| 807 | sel.tclick1 = now; | ||
| 745 | } else if(e->xbutton.button == Button4) { | 808 | } else if(e->xbutton.button == Button4) { |
| 746 | ttywrite("\031", 1); | 809 | ttywrite("\031", 1); |
| 747 | } else if(e->xbutton.button == Button5) { | 810 | } else if(e->xbutton.button == Button5) { |
| @@ -907,8 +970,6 @@ xsetsel(char *str) { | |||
| 907 | 970 | ||
| 908 | void | 971 | void |
| 909 | brelease(XEvent *e) { | 972 | brelease(XEvent *e) { |
| 910 | struct timeval now; | ||
| 911 | |||
| 912 | if(IS_SET(MODE_MOUSE)) { | 973 | if(IS_SET(MODE_MOUSE)) { |
| 913 | mousereport(e); | 974 | mousereport(e); |
| 914 | return; | 975 | return; |
| @@ -922,35 +983,10 @@ brelease(XEvent *e) { | |||
| 922 | term.dirty[sel.ey] = 1; | 983 | term.dirty[sel.ey] = 1; |
| 923 | if(sel.bx == sel.ex && sel.by == sel.ey) { | 984 | if(sel.bx == sel.ex && sel.by == sel.ey) { |
| 924 | sel.bx = -1; | 985 | sel.bx = -1; |
| 925 | gettimeofday(&now, NULL); | ||
| 926 | |||
| 927 | if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { | ||
| 928 | /* triple click on the line */ | ||
| 929 | sel.b.x = sel.bx = 0; | ||
| 930 | sel.e.x = sel.ex = term.col; | ||
| 931 | sel.b.y = sel.e.y = sel.ey; | ||
| 932 | selcopy(); | ||
| 933 | } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { | ||
| 934 | /* double click to select word */ | ||
| 935 | sel.bx = sel.ex; | ||
| 936 | while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].c[0] != ' ') { | ||
| 937 | sel.bx--; | ||
| 938 | } | ||
| 939 | sel.b.x = sel.bx; | ||
| 940 | while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].c[0] != ' ') { | ||
| 941 | sel.ex++; | ||
| 942 | } | ||
| 943 | sel.e.x = sel.ex; | ||
| 944 | sel.b.y = sel.e.y = sel.ey; | ||
| 945 | selcopy(); | ||
| 946 | } | ||
| 947 | } else { | 986 | } else { |
| 948 | selcopy(); | 987 | selcopy(); |
| 949 | } | 988 | } |
| 950 | } | 989 | } |
| 951 | |||
| 952 | memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval)); | ||
| 953 | gettimeofday(&sel.tclick1, NULL); | ||
| 954 | } | 990 | } |
| 955 | 991 | ||
| 956 | void | 992 | void |
