mirror of
				https://github.com/pikami/st.git
				synced 2025-11-04 00:40:05 +00:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									3c546ae739
								
							
						
					
					
						commit
						872a7f18ea
					
				
							
								
								
									
										90
									
								
								st.c
									
									
									
									
									
								
							
							
						
						
									
										90
									
								
								st.c
									
									
									
									
									
								
							@ -135,6 +135,11 @@ enum selection_type {
 | 
				
			|||||||
	SEL_RECTANGULAR = 2
 | 
						SEL_RECTANGULAR = 2
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum selection_snap {
 | 
				
			||||||
 | 
						SNAP_WORD = 1,
 | 
				
			||||||
 | 
						SNAP_LINE = 2
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* bit macro */
 | 
					/* bit macro */
 | 
				
			||||||
#undef B0
 | 
					#undef B0
 | 
				
			||||||
enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
 | 
					enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 };
 | 
				
			||||||
@ -232,6 +237,7 @@ typedef struct {
 | 
				
			|||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	int mode;
 | 
						int mode;
 | 
				
			||||||
	int type;
 | 
						int type;
 | 
				
			||||||
 | 
						int snap;
 | 
				
			||||||
	int bx, by;
 | 
						int bx, by;
 | 
				
			||||||
	int ex, ey;
 | 
						int ex, ey;
 | 
				
			||||||
	struct {
 | 
						struct {
 | 
				
			||||||
@ -372,6 +378,7 @@ static void selinit(void);
 | 
				
			|||||||
static inline bool selected(int, int);
 | 
					static inline bool selected(int, int);
 | 
				
			||||||
static void selcopy(void);
 | 
					static void selcopy(void);
 | 
				
			||||||
static void selscroll(int, int);
 | 
					static void selscroll(int, int);
 | 
				
			||||||
 | 
					static void selsnap(int, int *, int *, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int utf8decode(char *, long *);
 | 
					static int utf8decode(char *, long *);
 | 
				
			||||||
static int utf8encode(long *, char *);
 | 
					static int utf8encode(long *, char *);
 | 
				
			||||||
@ -657,6 +664,25 @@ selected(int x, int y) {
 | 
				
			|||||||
			&& (x <= sel.e.x || sel.b.y != sel.e.y));
 | 
								&& (x <= sel.e.x || sel.b.y != sel.e.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 + direction].c[0] != ' ') {
 | 
				
			||||||
 | 
								*x += direction;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case SNAP_LINE:
 | 
				
			||||||
 | 
							*x = (direction < 0) ? 0 : term.col - 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							/* do nothing */
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
getbuttoninfo(XEvent *e) {
 | 
					getbuttoninfo(XEvent *e) {
 | 
				
			||||||
	int type;
 | 
						int type;
 | 
				
			||||||
@ -667,6 +693,15 @@ getbuttoninfo(XEvent *e) {
 | 
				
			|||||||
	sel.ex = x2col(e->xbutton.x);
 | 
						sel.ex = x2col(e->xbutton.x);
 | 
				
			||||||
	sel.ey = y2row(e->xbutton.y);
 | 
						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.x = sel.by < sel.ey ? sel.bx : sel.ex;
 | 
				
			||||||
	sel.b.y = MIN(sel.by, sel.ey);
 | 
						sel.b.y = MIN(sel.by, sel.ey);
 | 
				
			||||||
	sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
 | 
						sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
 | 
				
			||||||
@ -730,9 +765,13 @@ mousereport(XEvent *e) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
bpress(XEvent *e) {
 | 
					bpress(XEvent *e) {
 | 
				
			||||||
 | 
						struct timeval now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(IS_SET(MODE_MOUSE)) {
 | 
						if(IS_SET(MODE_MOUSE)) {
 | 
				
			||||||
		mousereport(e);
 | 
							mousereport(e);
 | 
				
			||||||
	} else if(e->xbutton.button == Button1) {
 | 
						} else if(e->xbutton.button == Button1) {
 | 
				
			||||||
 | 
							gettimeofday(&now, NULL);
 | 
				
			||||||
 | 
							/* Clear previous selection, logically and visually. */
 | 
				
			||||||
		if(sel.bx != -1) {
 | 
							if(sel.bx != -1) {
 | 
				
			||||||
			sel.bx = -1;
 | 
								sel.bx = -1;
 | 
				
			||||||
			tsetdirt(sel.b.y, sel.e.y);
 | 
								tsetdirt(sel.b.y, sel.e.y);
 | 
				
			||||||
@ -742,6 +781,30 @@ bpress(XEvent *e) {
 | 
				
			|||||||
		sel.type = SEL_REGULAR;
 | 
							sel.type = SEL_REGULAR;
 | 
				
			||||||
		sel.ex = sel.bx = x2col(e->xbutton.x);
 | 
							sel.ex = sel.bx = x2col(e->xbutton.x);
 | 
				
			||||||
		sel.ey = sel.by = y2row(e->xbutton.y);
 | 
							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 selected more;
 | 
				
			||||||
 | 
							 * 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 = sel.ey;
 | 
				
			||||||
 | 
							/* Draw selection, unless it's regular and we don't want to make clicks visible */
 | 
				
			||||||
 | 
							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) {
 | 
						} else if(e->xbutton.button == Button4) {
 | 
				
			||||||
		ttywrite("\031", 1);
 | 
							ttywrite("\031", 1);
 | 
				
			||||||
	} else if(e->xbutton.button == Button5) {
 | 
						} else if(e->xbutton.button == Button5) {
 | 
				
			||||||
@ -907,8 +970,6 @@ xsetsel(char *str) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
brelease(XEvent *e) {
 | 
					brelease(XEvent *e) {
 | 
				
			||||||
	struct timeval now;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(IS_SET(MODE_MOUSE)) {
 | 
						if(IS_SET(MODE_MOUSE)) {
 | 
				
			||||||
		mousereport(e);
 | 
							mousereport(e);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@ -922,35 +983,10 @@ brelease(XEvent *e) {
 | 
				
			|||||||
		term.dirty[sel.ey] = 1;
 | 
							term.dirty[sel.ey] = 1;
 | 
				
			||||||
		if(sel.bx == sel.ex && sel.by == sel.ey) {
 | 
							if(sel.bx == sel.ex && sel.by == sel.ey) {
 | 
				
			||||||
			sel.bx = -1;
 | 
								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) <= doubleclicktimeout) {
 | 
					 | 
				
			||||||
				/* double click to select word */
 | 
					 | 
				
			||||||
				sel.bx = sel.ex;
 | 
					 | 
				
			||||||
				while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].c[0] != ' ') {
 | 
					 | 
				
			||||||
					sel.bx--;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				sel.b.x = sel.bx;
 | 
					 | 
				
			||||||
				while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].c[0] != ' ') {
 | 
					 | 
				
			||||||
					sel.ex++;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				sel.e.x = sel.ex;
 | 
					 | 
				
			||||||
				sel.b.y = sel.e.y = sel.ey;
 | 
					 | 
				
			||||||
				selcopy();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			selcopy();
 | 
								selcopy();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval));
 | 
					 | 
				
			||||||
	gettimeofday(&sel.tclick1, NULL);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user