Implement rectangular mouse selection. - st - Personal fork of st
 (HTM) git clone git://git.drkhsh.at/st.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26
 (DIR) parent e5295629cdffb711001f3fdffbb9aa4ef772add0
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Tue, 19 Feb 2013 19:08:41 +0100
       
       Implement rectangular mouse selection.
       
       Thanks Alexander Sedov <alex0player@gmail.com>!
       
       Diffstat:
         M config.def.h                        |      12 ++++++++++++
         M st.c                                |      68 ++++++++++++++++++++++++-------
       
       2 files changed, 66 insertions(+), 14 deletions(-)
       ---
 (DIR) diff --git 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,
       +};
       +
 (DIR) diff --git 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;
                }