Implement rectangular mouse selection.
Thanks Alexander Sedov <alex0player@gmail.com>!
This commit is contained in:
		
							parent
							
								
									e5295629cd
								
							
						
					
					
						commit
						3865e9eaaf
					
				
							
								
								
									
										12
									
								
								config.def.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								config.def.h
									
									
									
									
									
								
							| @ -305,3 +305,15 @@ static Key key[] = { | |||||||
| 	{ XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    0,    0}, | 	{ XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    0,    0}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Selection types' masks. | ||||||
|  |  * Use the same masks as usual. | ||||||
|  |  * Button1Mask is always unset, to make masks match between ButtonPress. | ||||||
|  |  * ButtonRelease and MotionNotify. | ||||||
|  |  * If no match is found, regular selection is used. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | static uint selmasks[] = { | ||||||
|  | 	[SEL_RECTANGULAR] = Mod1Mask, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								st.c
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								st.c
									
									
									
									
									
								
							| @ -137,6 +137,11 @@ enum window_state { | |||||||
| 	WIN_FOCUSED = 4 | 	WIN_FOCUSED = 4 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum selection_type { | ||||||
|  | 	SEL_REGULAR = 1, | ||||||
|  | 	SEL_RECTANGULAR = 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 }; | ||||||
| @ -234,6 +239,7 @@ typedef struct { | |||||||
| /* TODO: use better name for vars... */ | /* TODO: use better name for vars... */ | ||||||
| typedef struct { | typedef struct { | ||||||
| 	int mode; | 	int mode; | ||||||
|  | 	int type; | ||||||
| 	int bx, by; | 	int bx, by; | ||||||
| 	int ex, ey; | 	int ex, ey; | ||||||
| 	struct { | 	struct { | ||||||
| @ -651,10 +657,23 @@ selected(int x, int y) { | |||||||
| 			|| (y == sel.e.y && x <= sel.e.x)) | 			|| (y == sel.e.y && x <= sel.e.x)) | ||||||
| 			|| (y == sel.b.y && x >= sel.b.x | 			|| (y == sel.b.y && x >= sel.b.x | ||||||
| 				&& (x <= sel.e.x || sel.b.y != sel.e.y)); | 				&& (x <= sel.e.x || sel.b.y != sel.e.y)); | ||||||
|  | 	switch(sel.type) { | ||||||
|  | 	case SEL_REGULAR: | ||||||
|  | 		return ((sel.b.y < y && y < sel.e.y) | ||||||
|  | 			|| (y == sel.e.y && x <= sel.e.x)) | ||||||
|  | 			|| (y == sel.b.y && x >= sel.b.x | ||||||
|  | 				&& (x <= sel.e.x || sel.b.y != sel.e.y)); | ||||||
|  | 	case SEL_RECTANGULAR: | ||||||
|  | 		return ((sel.b.y <= y && y <= sel.e.y) | ||||||
|  | 			&& (sel.b.x <= x && x <= sel.e.x)); | ||||||
|  | 	}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| getbuttoninfo(XEvent *e) { | getbuttoninfo(XEvent *e) { | ||||||
|  | 	int type; | ||||||
|  | 	uint state = e->xbutton.state &~Button1Mask; | ||||||
|  | 
 | ||||||
| 	sel.alt = IS_SET(MODE_ALTSCREEN); | 	sel.alt = IS_SET(MODE_ALTSCREEN); | ||||||
| 
 | 
 | ||||||
| 	sel.ex = x2col(e->xbutton.x); | 	sel.ex = x2col(e->xbutton.x); | ||||||
| @ -664,6 +683,14 @@ getbuttoninfo(XEvent *e) { | |||||||
| 	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; | ||||||
| 	sel.e.y = MAX(sel.by, sel.ey); | 	sel.e.y = MAX(sel.by, sel.ey); | ||||||
|  | 
 | ||||||
|  | 	sel.type = SEL_REGULAR; | ||||||
|  | 	for(type = 1; type < LEN(selmasks); ++type) { | ||||||
|  | 		if(match(selmasks[type], state)) { | ||||||
|  | 			sel.type = type; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void | void | ||||||
| @ -724,6 +751,7 @@ bpress(XEvent *e) { | |||||||
| 			draw(); | 			draw(); | ||||||
| 		} | 		} | ||||||
| 		sel.mode = 1; | 		sel.mode = 1; | ||||||
|  | 		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); | ||||||
| 	} else if(e->xbutton.button == Button4) { | 	} else if(e->xbutton.button == Button4) { | ||||||
| @ -746,7 +774,8 @@ selcopy(void) { | |||||||
| 		ptr = str = xmalloc(bufsize); | 		ptr = str = xmalloc(bufsize); | ||||||
| 
 | 
 | ||||||
| 		/* append every set & selected glyph to the selection */ | 		/* append every set & selected glyph to the selection */ | ||||||
| 		for(y = 0; y < term.row; y++) { | 		for(y = sel.b.y; y < sel.e.y + 1; y++) { | ||||||
|  | 			is_selected = 0; | ||||||
| 			gp = &term.line[y][0]; | 			gp = &term.line[y][0]; | ||||||
| 			last = gp + term.col; | 			last = gp + term.col; | ||||||
| 
 | 
 | ||||||
| @ -754,8 +783,11 @@ selcopy(void) { | |||||||
| 				/* nothing */; | 				/* nothing */; | ||||||
| 
 | 
 | ||||||
| 			for(x = 0; gp <= last; x++, ++gp) { | 			for(x = 0; gp <= last; x++, ++gp) { | ||||||
| 				if(!(is_selected = selected(x, y))) | 				if(!selected(x, y)) { | ||||||
| 					continue; | 					continue; | ||||||
|  | 				} else { | ||||||
|  | 					is_selected = 1; | ||||||
|  | 				} | ||||||
| 
 | 
 | ||||||
| 				p = (gp->state & GLYPH_SET) ? gp->c : " "; | 				p = (gp->state & GLYPH_SET) ? gp->c : " "; | ||||||
| 				size = utf8size(p); | 				size = utf8size(p); | ||||||
| @ -907,7 +939,7 @@ brelease(XEvent *e) { | |||||||
| 
 | 
 | ||||||
| void | void | ||||||
| bmotion(XEvent *e) { | bmotion(XEvent *e) { | ||||||
| 	int starty, endy, oldey, oldex; | 	int oldey, oldex; | ||||||
| 
 | 
 | ||||||
| 	if(IS_SET(MODE_MOUSE)) { | 	if(IS_SET(MODE_MOUSE)) { | ||||||
| 		mousereport(e); | 		mousereport(e); | ||||||
| @ -922,9 +954,7 @@ bmotion(XEvent *e) { | |||||||
| 	getbuttoninfo(e); | 	getbuttoninfo(e); | ||||||
| 
 | 
 | ||||||
| 	if(oldey != sel.ey || oldex != sel.ex) { | 	if(oldey != sel.ey || oldex != sel.ex) { | ||||||
| 		starty = MIN(oldey, sel.ey); | 		tsetdirt(sel.b.y, sel.e.y); | ||||||
| 		endy = MAX(oldey, sel.ey); |  | ||||||
| 		tsetdirt(starty, endy); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1216,14 +1246,24 @@ selscroll(int orig, int n) { | |||||||
| 			sel.bx = -1; | 			sel.bx = -1; | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		if(sel.by < term.top) { | 		switch(sel.type) { | ||||||
| 			sel.by = term.top; | 		case SEL_REGULAR: | ||||||
| 			sel.bx = 0; | 			if(sel.by < term.top) { | ||||||
| 		} | 				sel.by = term.top; | ||||||
| 		if(sel.ey > term.bot) { | 				sel.bx = 0; | ||||||
| 			sel.ey = term.bot; | 			} | ||||||
| 			sel.ex = term.col; | 			if(sel.ey > term.bot) { | ||||||
| 		} | 				sel.ey = term.bot; | ||||||
|  | 				sel.ex = term.col; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case SEL_RECTANGULAR: | ||||||
|  | 			if(sel.by < term.top) | ||||||
|  | 				sel.by = term.top; | ||||||
|  | 			if(sel.ey > term.bot) | ||||||
|  | 				sel.ey = term.bot; | ||||||
|  | 			break; | ||||||
|  | 		}; | ||||||
| 		sel.b.y = sel.by, sel.b.x = sel.bx; | 		sel.b.y = sel.by, sel.b.x = sel.bx; | ||||||
| 		sel.e.y = sel.ey, sel.e.x = sel.ex; | 		sel.e.y = sel.ey, sel.e.x = sel.ex; | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user