From 3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26 Mon Sep 17 00:00:00 2001 From: Christoph Lohmann <20h@r-36.net> Date: Tue, 19 Feb 2013 19:08:41 +0100 Subject: [PATCH] Implement rectangular mouse selection. Thanks Alexander Sedov ! --- config.def.h | 12 ++++++++++ st.c | 68 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/config.def.h b/config.def.h index 07a22ed..a31a235 100644 --- a/config.def.h +++ b/config.def.h @@ -305,3 +305,15 @@ static Key key[] = { { 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, +}; + diff --git a/st.c b/st.c index 7befdc0..300e5ec 100644 --- a/st.c +++ b/st.c @@ -137,6 +137,11 @@ enum window_state { WIN_FOCUSED = 4 }; +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + /* bit macro */ #undef B0 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... */ typedef struct { int mode; + int type; int bx, by; int ex, ey; struct { @@ -651,10 +657,23 @@ selected(int x, int 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)); + 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 getbuttoninfo(XEvent *e) { + int type; + uint state = e->xbutton.state &~Button1Mask; + sel.alt = IS_SET(MODE_ALTSCREEN); sel.ex = x2col(e->xbutton.x); @@ -664,6 +683,14 @@ getbuttoninfo(XEvent *e) { sel.b.y = MIN(sel.by, sel.ey); sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; 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 @@ -724,6 +751,7 @@ bpress(XEvent *e) { draw(); } sel.mode = 1; + sel.type = SEL_REGULAR; sel.ex = sel.bx = x2col(e->xbutton.x); sel.ey = sel.by = y2row(e->xbutton.y); } else if(e->xbutton.button == Button4) { @@ -746,7 +774,8 @@ selcopy(void) { ptr = str = xmalloc(bufsize); /* 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]; last = gp + term.col; @@ -754,8 +783,11 @@ selcopy(void) { /* nothing */; for(x = 0; gp <= last; x++, ++gp) { - if(!(is_selected = selected(x, y))) + if(!selected(x, y)) { continue; + } else { + is_selected = 1; + } p = (gp->state & GLYPH_SET) ? gp->c : " "; size = utf8size(p); @@ -907,7 +939,7 @@ brelease(XEvent *e) { void bmotion(XEvent *e) { - int starty, endy, oldey, oldex; + int oldey, oldex; if(IS_SET(MODE_MOUSE)) { mousereport(e); @@ -922,9 +954,7 @@ bmotion(XEvent *e) { getbuttoninfo(e); if(oldey != sel.ey || oldex != sel.ex) { - starty = MIN(oldey, sel.ey); - endy = MAX(oldey, sel.ey); - tsetdirt(starty, endy); + tsetdirt(sel.b.y, sel.e.y); } } @@ -1216,14 +1246,24 @@ selscroll(int orig, int n) { sel.bx = -1; return; } - if(sel.by < term.top) { - sel.by = term.top; - sel.bx = 0; - } - if(sel.ey > term.bot) { - sel.ey = term.bot; - sel.ex = term.col; - } + switch(sel.type) { + case SEL_REGULAR: + if(sel.by < term.top) { + sel.by = term.top; + sel.bx = 0; + } + 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.e.y = sel.ey, sel.e.x = sel.ex; }