tAdded support for double/triple click+dragging. - st - [fork] customized build… | |
git clone git://src.adamsgaard.dk/st | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 872a7f18eaffd96eefb31e3dcb45fd86bc67029b | |
parent 3c546ae73924804ddc6d29dc3ab2f12a93287009 | |
Author: Alexander Sedov <[email protected]> | |
Date: Mon, 15 Apr 2013 10:28:31 +0400 | |
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 <[email protected]> | |
Diffstat: | |
M st.c | 90 ++++++++++++++++++++++-------… | |
1 file changed, 63 insertions(+), 27 deletions(-) | |
--- | |
diff --git a/st.c b/st.c | |
t@@ -135,6 +135,11 @@ enum selection_type { | |
SEL_RECTANGULAR = 2 | |
}; | |
+enum selection_snap { | |
+ SNAP_WORD = 1, | |
+ SNAP_LINE = 2 | |
+}; | |
+ | |
/* bit macro */ | |
#undef B0 | |
enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; | |
t@@ -232,6 +237,7 @@ typedef struct { | |
typedef struct { | |
int mode; | |
int type; | |
+ int snap; | |
int bx, by; | |
int ex, ey; | |
struct { | |
t@@ -372,6 +378,7 @@ static void selinit(void); | |
static inline bool selected(int, int); | |
static void selcopy(void); | |
static void selscroll(int, int); | |
+static void selsnap(int, int *, int *, int); | |
static int utf8decode(char *, long *); | |
static int utf8encode(long *, char *); | |
t@@ -658,6 +665,25 @@ selected(int x, int y) { | |
} | |
void | |
+selsnap(int mode, int *x, int *y, int direction) { | |
+ switch(mode) { | |
+ case SNAP_WORD: | |
+ while(*x > 0 && *x < term.col-1 && term.line[*y][*x + directio… | |
+ *x += direction; | |
+ } | |
+ break; | |
+ | |
+ case SNAP_LINE: | |
+ *x = (direction < 0) ? 0 : term.col - 1; | |
+ break; | |
+ | |
+ default: | |
+ /* do nothing */ | |
+ break; | |
+ } | |
+} | |
+ | |
+void | |
getbuttoninfo(XEvent *e) { | |
int type; | |
uint state = e->xbutton.state &~Button1Mask; | |
t@@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) { | |
sel.ex = x2col(e->xbutton.x); | |
sel.ey = y2row(e->xbutton.y); | |
+ if (sel.by < sel.ey | |
+ || (sel.by == sel.ey && sel.bx < sel.ex)) { | |
+ selsnap(sel.snap, &sel.bx, &sel.by, -1); | |
+ selsnap(sel.snap, &sel.ex, &sel.ey, +1); | |
+ } else { | |
+ selsnap(sel.snap, &sel.ex, &sel.ey, -1); | |
+ selsnap(sel.snap, &sel.bx, &sel.by, +1); | |
+ } | |
+ | |
sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; | |
sel.b.y = MIN(sel.by, sel.ey); | |
sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; | |
t@@ -730,9 +765,13 @@ mousereport(XEvent *e) { | |
void | |
bpress(XEvent *e) { | |
+ struct timeval now; | |
+ | |
if(IS_SET(MODE_MOUSE)) { | |
mousereport(e); | |
} else if(e->xbutton.button == Button1) { | |
+ gettimeofday(&now, NULL); | |
+ /* Clear previous selection, logically and visually. */ | |
if(sel.bx != -1) { | |
sel.bx = -1; | |
tsetdirt(sel.b.y, sel.e.y); | |
t@@ -742,6 +781,30 @@ bpress(XEvent *e) { | |
sel.type = SEL_REGULAR; | |
sel.ex = sel.bx = x2col(e->xbutton.x); | |
sel.ey = sel.by = y2row(e->xbutton.y); | |
+ /* | |
+ * Snap handling. | |
+ * If user clicks are fasst enough (e.g. below timeouts), | |
+ * we ignore if his hand slipped left or down and accidentally… | |
+ * we are just snapping to whatever we're snapping. | |
+ */ | |
+ if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { | |
+ /* Snap to line */ | |
+ sel.snap = SNAP_LINE; | |
+ } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { | |
+ sel.snap = SNAP_WORD; | |
+ } else { | |
+ sel.snap = 0; | |
+ } | |
+ selsnap(sel.snap, &sel.bx, &sel.by, -1); | |
+ selsnap(sel.snap, &sel.ex, &sel.ey, 1); | |
+ sel.b.x = sel.bx, sel.b.y = sel.by, sel.e.x = sel.ex, sel.e.y … | |
+ /* Draw selection, unless it's regular and we don't want to ma… | |
+ if (sel.snap != 0) { | |
+ tsetdirt(sel.b.y, sel.e.y); | |
+ draw(); | |
+ } | |
+ sel.tclick2 = sel.tclick1; | |
+ sel.tclick1 = now; | |
} else if(e->xbutton.button == Button4) { | |
ttywrite("\031", 1); | |
} else if(e->xbutton.button == Button5) { | |
t@@ -907,8 +970,6 @@ xsetsel(char *str) { | |
void | |
brelease(XEvent *e) { | |
- struct timeval now; | |
- | |
if(IS_SET(MODE_MOUSE)) { | |
mousereport(e); | |
return; | |
t@@ -922,35 +983,10 @@ brelease(XEvent *e) { | |
term.dirty[sel.ey] = 1; | |
if(sel.bx == sel.ex && sel.by == sel.ey) { | |
sel.bx = -1; | |
- gettimeofday(&now, NULL); | |
- | |
- if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { | |
- /* triple click on the line */ | |
- sel.b.x = sel.bx = 0; | |
- sel.e.x = sel.ex = term.col; | |
- sel.b.y = sel.e.y = sel.ey; | |
- selcopy(); | |
- } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktim… | |
- /* double click to select word */ | |
- sel.bx = sel.ex; | |
- while(sel.bx > 0 && term.line[sel.ey][sel.bx-1… | |
- sel.bx--; | |
- } | |
- sel.b.x = sel.bx; | |
- while(sel.ex < term.col-1 && term.line[sel.ey]… | |
- sel.ex++; | |
- } | |
- sel.e.x = sel.ex; | |
- sel.b.y = sel.e.y = sel.ey; | |
- selcopy(); | |
- } | |
} else { | |
selcopy(); | |
} | |
} | |
- | |
- memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval)); | |
- gettimeofday(&sel.tclick1, NULL); | |
} | |
void |