aboutsummaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
authorAlexander Sedov <alex0player@gmail.com>2013-04-15 10:28:31 +0400
committerChristoph Lohmann <20h@r-36.net>2013-04-20 15:54:19 +0200
commit872a7f18eaffd96eefb31e3dcb45fd86bc67029b (patch)
treedab72f5f74dc713a17cc3f4b94ca3d36ccf016cc /st.c
parent3c546ae73924804ddc6d29dc3ab2f12a93287009 (diff)
downloadst-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 'st.c')
-rw-r--r--st.c90
1 files changed, 63 insertions, 27 deletions
diff --git a/st.c b/st.c
index 686ed5d..bca9dc7 100644
--- a/st.c
+++ b/st.c
@@ -135,6 +135,11 @@ enum selection_type {
135 SEL_RECTANGULAR = 2 135 SEL_RECTANGULAR = 2
136}; 136};
137 137
138enum selection_snap {
139 SNAP_WORD = 1,
140 SNAP_LINE = 2
141};
142
138/* bit macro */ 143/* bit macro */
139#undef B0 144#undef B0
140enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; 145enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
@@ -232,6 +237,7 @@ typedef struct {
232typedef struct { 237typedef 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);
372static inline bool selected(int, int); 378static inline bool selected(int, int);
373static void selcopy(void); 379static void selcopy(void);
374static void selscroll(int, int); 380static void selscroll(int, int);
381static void selsnap(int, int *, int *, int);
375 382
376static int utf8decode(char *, long *); 383static int utf8decode(char *, long *);
377static int utf8encode(long *, char *); 384static int utf8encode(long *, char *);
@@ -658,6 +665,25 @@ selected(int x, int y) {
658} 665}
659 666
660void 667void
668selsnap(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
686void
661getbuttoninfo(XEvent *e) { 687getbuttoninfo(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
731void 766void
732bpress(XEvent *e) { 767bpress(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
908void 971void
909brelease(XEvent *e) { 972brelease(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
956void 992void