Implement rectangular mouse selection.

Thanks Alexander Sedov <alex0player@gmail.com>!
This commit is contained in:
Christoph Lohmann 2013-02-19 19:08:41 +01:00
parent e5295629cd
commit 3865e9eaaf
2 changed files with 66 additions and 14 deletions

View File

@ -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,
};

52
st.c
View File

@ -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,6 +1246,8 @@ selscroll(int orig, int n) {
sel.bx = -1; sel.bx = -1;
return; return;
} }
switch(sel.type) {
case SEL_REGULAR:
if(sel.by < term.top) { if(sel.by < term.top) {
sel.by = term.top; sel.by = term.top;
sel.bx = 0; sel.bx = 0;
@ -1224,6 +1256,14 @@ selscroll(int orig, int n) {
sel.ey = term.bot; sel.ey = term.bot;
sel.ex = term.col; 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;
} }