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-patched-3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26.tar.bz2 st-patched-3865e9eaaf4e1c7820b1f41ce9d0b1d7b109fb26.tar.xz st-patched-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 | } |