diff options
| author | Christoph Lohmann <20h@r-36.net> | 2013-02-19 19:08:41 +0100 |
|---|---|---|
| committer | Christoph Lohmann <20h@r-36.net> | 2013-02-19 19:08:41 +0100 |
| commit | 3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26 (patch) | |
| tree | 1c54d60e09105dbc2894a5a62b85d990f8937b72 | |
| parent | e5295629cdffb711001f3fdffbb9aa4ef772add0 (diff) | |
| download | st-3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26.tar.gz st-3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26.zip | |
Implement rectangular mouse selection.
Thanks Alexander Sedov <alex0player@gmail.com>!
| -rw-r--r-- | config.def.h | 12 | ||||
| -rw-r--r-- | 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[] = { | |||
| 305 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0, 0}, | 305 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0, 0}, |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | /* | ||
| 309 | * Selection types' masks. | ||
| 310 | * Use the same masks as usual. | ||
| 311 | * Button1Mask is always unset, to make masks match between ButtonPress. | ||
| 312 | * ButtonRelease and MotionNotify. | ||
| 313 | * If no match is found, regular selection is used. | ||
| 314 | */ | ||
| 315 | |||
| 316 | static uint selmasks[] = { | ||
| 317 | [SEL_RECTANGULAR] = Mod1Mask, | ||
| 318 | }; | ||
| 319 | |||
| @@ -137,6 +137,11 @@ enum window_state { | |||
| 137 | WIN_FOCUSED = 4 | 137 | WIN_FOCUSED = 4 |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | enum selection_type { | ||
| 141 | SEL_REGULAR = 1, | ||
| 142 | SEL_RECTANGULAR = 2 | ||
| 143 | }; | ||
| 144 | |||
| 140 | /* bit macro */ | 145 | /* bit macro */ |
| 141 | #undef B0 | 146 | #undef B0 |
| 142 | enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; | 147 | enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; |
| @@ -234,6 +239,7 @@ typedef struct { | |||
| 234 | /* TODO: use better name for vars... */ | 239 | /* TODO: use better name for vars... */ |
| 235 | typedef struct { | 240 | typedef struct { |
| 236 | int mode; | 241 | int mode; |
| 242 | int type; | ||
| 237 | int bx, by; | 243 | int bx, by; |
| 238 | int ex, ey; | 244 | int ex, ey; |
| 239 | struct { | 245 | struct { |
| @@ -651,10 +657,23 @@ selected(int x, int y) { | |||
| 651 | || (y == sel.e.y && x <= sel.e.x)) | 657 | || (y == sel.e.y && x <= sel.e.x)) |
| 652 | || (y == sel.b.y && x >= sel.b.x | 658 | || (y == sel.b.y && x >= sel.b.x |
| 653 | && (x <= sel.e.x || sel.b.y != sel.e.y)); | 659 | && (x <= sel.e.x || sel.b.y != sel.e.y)); |
| 660 | switch(sel.type) { | ||
| 661 | case SEL_REGULAR: | ||
| 662 | return ((sel.b.y < y && y < sel.e.y) | ||
| 663 | || (y == sel.e.y && x <= sel.e.x)) | ||
| 664 | || (y == sel.b.y && x >= sel.b.x | ||
| 665 | && (x <= sel.e.x || sel.b.y != sel.e.y)); | ||
| 666 | case SEL_RECTANGULAR: | ||
| 667 | return ((sel.b.y <= y && y <= sel.e.y) | ||
| 668 | && (sel.b.x <= x && x <= sel.e.x)); | ||
| 669 | }; | ||
| 654 | } | 670 | } |
| 655 | 671 | ||
| 656 | void | 672 | void |
| 657 | getbuttoninfo(XEvent *e) { | 673 | getbuttoninfo(XEvent *e) { |
| 674 | int type; | ||
| 675 | uint state = e->xbutton.state &~Button1Mask; | ||
| 676 | |||
| 658 | sel.alt = IS_SET(MODE_ALTSCREEN); | 677 | sel.alt = IS_SET(MODE_ALTSCREEN); |
| 659 | 678 | ||
| 660 | sel.ex = x2col(e->xbutton.x); | 679 | sel.ex = x2col(e->xbutton.x); |
| @@ -664,6 +683,14 @@ getbuttoninfo(XEvent *e) { | |||
| 664 | sel.b.y = MIN(sel.by, sel.ey); | 683 | sel.b.y = MIN(sel.by, sel.ey); |
| 665 | sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; | 684 | sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; |
| 666 | sel.e.y = MAX(sel.by, sel.ey); | 685 | sel.e.y = MAX(sel.by, sel.ey); |
| 686 | |||
| 687 | sel.type = SEL_REGULAR; | ||
| 688 | for(type = 1; type < LEN(selmasks); ++type) { | ||
| 689 | if(match(selmasks[type], state)) { | ||
| 690 | sel.type = type; | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | } | ||
| 667 | } | 694 | } |
| 668 | 695 | ||
| 669 | void | 696 | void |
| @@ -724,6 +751,7 @@ bpress(XEvent *e) { | |||
| 724 | draw(); | 751 | draw(); |
| 725 | } | 752 | } |
| 726 | sel.mode = 1; | 753 | sel.mode = 1; |
| 754 | sel.type = SEL_REGULAR; | ||
| 727 | sel.ex = sel.bx = x2col(e->xbutton.x); | 755 | sel.ex = sel.bx = x2col(e->xbutton.x); |
| 728 | sel.ey = sel.by = y2row(e->xbutton.y); | 756 | sel.ey = sel.by = y2row(e->xbutton.y); |
| 729 | } else if(e->xbutton.button == Button4) { | 757 | } else if(e->xbutton.button == Button4) { |
| @@ -746,7 +774,8 @@ selcopy(void) { | |||
| 746 | ptr = str = xmalloc(bufsize); | 774 | ptr = str = xmalloc(bufsize); |
| 747 | 775 | ||
| 748 | /* append every set & selected glyph to the selection */ | 776 | /* append every set & selected glyph to the selection */ |
| 749 | for(y = 0; y < term.row; y++) { | 777 | for(y = sel.b.y; y < sel.e.y + 1; y++) { |
| 778 | is_selected = 0; | ||
| 750 | gp = &term.line[y][0]; | 779 | gp = &term.line[y][0]; |
| 751 | last = gp + term.col; | 780 | last = gp + term.col; |
| 752 | 781 | ||
| @@ -754,8 +783,11 @@ selcopy(void) { | |||
| 754 | /* nothing */; | 783 | /* nothing */; |
| 755 | 784 | ||
| 756 | for(x = 0; gp <= last; x++, ++gp) { | 785 | for(x = 0; gp <= last; x++, ++gp) { |
| 757 | if(!(is_selected = selected(x, y))) | 786 | if(!selected(x, y)) { |
| 758 | continue; | 787 | continue; |
| 788 | } else { | ||
| 789 | is_selected = 1; | ||
| 790 | } | ||
| 759 | 791 | ||
| 760 | p = (gp->state & GLYPH_SET) ? gp->c : " "; | 792 | p = (gp->state & GLYPH_SET) ? gp->c : " "; |
| 761 | size = utf8size(p); | 793 | size = utf8size(p); |
| @@ -907,7 +939,7 @@ brelease(XEvent *e) { | |||
| 907 | 939 | ||
| 908 | void | 940 | void |
| 909 | bmotion(XEvent *e) { | 941 | bmotion(XEvent *e) { |
| 910 | int starty, endy, oldey, oldex; | 942 | int oldey, oldex; |
| 911 | 943 | ||
| 912 | if(IS_SET(MODE_MOUSE)) { | 944 | if(IS_SET(MODE_MOUSE)) { |
| 913 | mousereport(e); | 945 | mousereport(e); |
| @@ -922,9 +954,7 @@ bmotion(XEvent *e) { | |||
| 922 | getbuttoninfo(e); | 954 | getbuttoninfo(e); |
| 923 | 955 | ||
| 924 | if(oldey != sel.ey || oldex != sel.ex) { | 956 | if(oldey != sel.ey || oldex != sel.ex) { |
| 925 | starty = MIN(oldey, sel.ey); | 957 | tsetdirt(sel.b.y, sel.e.y); |
| 926 | endy = MAX(oldey, sel.ey); | ||
| 927 | tsetdirt(starty, endy); | ||
| 928 | } | 958 | } |
| 929 | } | 959 | } |
| 930 | 960 | ||
| @@ -1216,14 +1246,24 @@ selscroll(int orig, int n) { | |||
| 1216 | sel.bx = -1; | 1246 | sel.bx = -1; |
| 1217 | return; | 1247 | return; |
| 1218 | } | 1248 | } |
| 1219 | if(sel.by < term.top) { | 1249 | switch(sel.type) { |
| 1220 | sel.by = term.top; | 1250 | case SEL_REGULAR: |
| 1221 | sel.bx = 0; | 1251 | if(sel.by < term.top) { |
| 1222 | } | 1252 | sel.by = term.top; |
| 1223 | if(sel.ey > term.bot) { | 1253 | sel.bx = 0; |
| 1224 | sel.ey = term.bot; | 1254 | } |
| 1225 | sel.ex = term.col; | 1255 | if(sel.ey > term.bot) { |
| 1226 | } | 1256 | sel.ey = term.bot; |
| 1257 | sel.ex = term.col; | ||
| 1258 | } | ||
| 1259 | break; | ||
| 1260 | case SEL_RECTANGULAR: | ||
| 1261 | if(sel.by < term.top) | ||
| 1262 | sel.by = term.top; | ||
| 1263 | if(sel.ey > term.bot) | ||
| 1264 | sel.ey = term.bot; | ||
| 1265 | break; | ||
| 1266 | }; | ||
| 1227 | sel.b.y = sel.by, sel.b.x = sel.bx; | 1267 | sel.b.y = sel.by, sel.b.x = sel.bx; |
| 1228 | sel.e.y = sel.ey, sel.e.x = sel.ex; | 1268 | sel.e.y = sel.ey, sel.e.x = sel.ex; |
| 1229 | } | 1269 | } |
