nsxiv7a75c42
make thumbnail bindings configureable via config.h (#167)
this allows for configuring thumbnail mode mouse bindings similar to image mode bindings. however we can't put the thumbnails bindings into the existing buttons[] array due to fallthrough. For example M3 would switch mode and then end up selecting an image. which is why thumbnail bindings have been put into it's own array `buttons_tns[]` and `buttons[]` has been renamed to `buttons_img[]` for consistency.
+82 −53
4 files changed
- M commands.c +55 −0
- M commands.h +6 −0
- M config.def.h +12 −1
- M main.c +9 −52
| @@ -42,6 +42,7 @@ extern appmode_t mode; | |||
| 42 | 42 | extern img_t img; | |
| 43 | 43 | extern tns_t tns; | |
| 44 | 44 | extern win_t win; | |
| 45 | + | extern const XButtonEvent *xbutton_ev; | |
| 45 | 46 | ||
| 46 | 47 | extern fileinfo_t *files; | |
| 47 | 48 | extern int filecnt, fileidx; | |
| @@ -436,3 +437,57 @@ bool ct_reload_all(arg_t _) | |||
| 436 | 437 | tns.dirty = true; | |
| 437 | 438 | return true; | |
| 438 | 439 | } | |
| 440 | + | ||
| 441 | + | bool ct_scroll(arg_t dir) | |
| 442 | + | { | |
| 443 | + | return tns_scroll(&tns, dir, false); | |
| 444 | + | } | |
| 445 | + | ||
| 446 | + | bool ct_drag_mark_image(arg_t _) | |
| 447 | + | { | |
| 448 | + | int sel; | |
| 449 | + | ||
| 450 | + | if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) { | |
| 451 | + | XEvent e; | |
| 452 | + | bool on = !(files[sel].flags & FF_MARK); | |
| 453 | + | ||
| 454 | + | while (true) { | |
| 455 | + | if (sel >= 0 && mark_image(sel, on)) | |
| 456 | + | redraw(); | |
| 457 | + | XMaskEvent(win.env.dpy, | |
| 458 | + | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); | |
| 459 | + | if (e.type == ButtonPress || e.type == ButtonRelease) | |
| 460 | + | break; | |
| 461 | + | while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); | |
| 462 | + | sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y); | |
| 463 | + | } | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | return false; | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | bool ct_select(arg_t _) | |
| 470 | + | { | |
| 471 | + | int sel; | |
| 472 | + | bool dirty = false; | |
| 473 | + | static Time firstclick; | |
| 474 | + | ||
| 475 | + | if ((sel = tns_translate(&tns, xbutton_ev->x, xbutton_ev->y)) >= 0) { | |
| 476 | + | if (sel != fileidx) { | |
| 477 | + | tns_highlight(&tns, fileidx, false); | |
| 478 | + | tns_highlight(&tns, sel, true); | |
| 479 | + | fileidx = sel; | |
| 480 | + | firstclick = xbutton_ev->time; | |
| 481 | + | dirty = true; | |
| 482 | + | } else if (xbutton_ev->time - firstclick <= TO_DOUBLE_CLICK) { | |
| 483 | + | mode = MODE_IMAGE; | |
| 484 | + | set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | |
| 485 | + | load_image(fileidx); | |
| 486 | + | dirty = true; | |
| 487 | + | } else { | |
| 488 | + | firstclick = xbutton_ev->time; | |
| 489 | + | } | |
| 490 | + | } | |
| 491 | + | ||
| 492 | + | return dirty; | |
| 493 | + | } | |
| @@ -39,6 +39,9 @@ bool ci_toggle_antialias(arg_t); | |||
| 39 | 39 | /* thumbnails mode */ | |
| 40 | 40 | bool ct_move_sel(arg_t); | |
| 41 | 41 | bool ct_reload_all(arg_t); | |
| 42 | + | bool ct_scroll(arg_t); | |
| 43 | + | bool ct_drag_mark_image(arg_t); | |
| 44 | + | bool ct_select(arg_t); | |
| 42 | 45 | ||
| 43 | 46 | /* global */ | |
| 44 | 47 | #define g_change_gamma { cg_change_gamma, MODE_ALL } | |
| @@ -79,5 +82,8 @@ bool ct_reload_all(arg_t); | |||
| 79 | 82 | /* thumbnails mode */ | |
| 80 | 83 | #define t_move_sel { ct_move_sel, MODE_THUMB } | |
| 81 | 84 | #define t_reload_all { ct_reload_all, MODE_THUMB } | |
| 85 | + | #define t_scroll { ct_scroll, MODE_THUMB } | |
| 86 | + | #define t_drag_mark_image { ct_drag_mark_image, MODE_THUMB } | |
| 87 | + | #define t_select { ct_select, MODE_THUMB } | |
| 82 | 88 | ||
| 83 | 89 | #endif /* COMMANDS_H */ | |
| @@ -175,7 +175,7 @@ static const keymap_t keys[] = { | |||
| 175 | 175 | }; | |
| 176 | 176 | ||
| 177 | 177 | /* mouse button mappings for image mode: */ | |
| 178 | − | static const button_t buttons[] = { | |
| 178 | + | static const button_t buttons_img[] = { | |
| 179 | 179 | /* modifiers button function argument */ | |
| 180 | 180 | { 0, 1, i_cursor_navigate, None }, | |
| 181 | 181 | { ControlMask, 1, i_drag, DRAG_RELATIVE }, | |
| @@ -185,6 +185,17 @@ static const button_t buttons[] = { | |||
| 185 | 185 | { 0, 5, g_zoom, -1 }, | |
| 186 | 186 | }; | |
| 187 | 187 | ||
| 188 | + | /* mouse button mappings for thumbnail mode: */ | |
| 189 | + | static const button_t buttons_tns[] = { | |
| 190 | + | /* modifiers button function argument */ | |
| 191 | + | { 0, 1, t_select, None }, | |
| 192 | + | { 0, 3, t_drag_mark_image, None }, | |
| 193 | + | { 0, 4, t_scroll, DIR_UP }, | |
| 194 | + | { 0, 5, t_scroll, DIR_DOWN }, | |
| 195 | + | { ControlMask, 4, g_scroll_screen, DIR_UP }, | |
| 196 | + | { ControlMask, 5, g_scroll_screen, DIR_DOWN }, | |
| 197 | + | }; | |
| 198 | + | ||
| 188 | 199 | /* true means NAV_WIDTH is relative (33%), false means absolute (33 pixels) */ | |
| 189 | 200 | static const bool NAV_IS_REL = true; | |
| 190 | 201 | /* width of navigation area, 0 disables cursor navigation, */ | |
| @@ -57,6 +57,7 @@ arl_t arl; | |||
| 57 | 57 | img_t img; | |
| 58 | 58 | tns_t tns; | |
| 59 | 59 | win_t win; | |
| 60 | + | const XButtonEvent *xbutton_ev; | |
| 60 | 61 | ||
| 61 | 62 | fileinfo_t *files; | |
| 62 | 63 | int filecnt, fileidx; | |
| @@ -661,64 +662,19 @@ static void on_keypress(XKeyEvent *kev) | |||
| 661 | 662 | prefix = 0; | |
| 662 | 663 | } | |
| 663 | 664 | ||
| 664 | − | static void on_buttonpress(XButtonEvent *bev) | |
| 665 | + | static void on_buttonpress(const XButtonEvent *bev) | |
| 665 | 666 | { | |
| 666 | − | int sel; | |
| 667 | 667 | bool dirty = false; | |
| 668 | − | static Time firstclick; | |
| 669 | 668 | ||
| 670 | 669 | if (mode == MODE_IMAGE) { | |
| 671 | 670 | set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | |
| 672 | 671 | reset_cursor(); | |
| 673 | − | dirty = process_bindings(buttons, ARRLEN(buttons), bev->button, bev->state, 0); | |
| 674 | − | if (dirty) | |
| 675 | − | redraw(); | |
| 676 | − | } else { | |
| 677 | − | /* thumbnail mode (hard-coded) */ | |
| 678 | − | switch (bev->button) { | |
| 679 | − | case Button1: | |
| 680 | − | if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) { | |
| 681 | − | if (sel != fileidx) { | |
| 682 | − | tns_highlight(&tns, fileidx, false); | |
| 683 | − | tns_highlight(&tns, sel, true); | |
| 684 | − | fileidx = sel; | |
| 685 | − | firstclick = bev->time; | |
| 686 | − | redraw(); | |
| 687 | − | } else if (bev->time - firstclick <= TO_DOUBLE_CLICK) { | |
| 688 | − | mode = MODE_IMAGE; | |
| 689 | − | set_timeout(reset_cursor, TO_CURSOR_HIDE, true); | |
| 690 | − | load_image(fileidx); | |
| 691 | − | redraw(); | |
| 692 | − | } else { | |
| 693 | − | firstclick = bev->time; | |
| 694 | − | } | |
| 695 | − | } | |
| 696 | − | break; | |
| 697 | − | case Button3: | |
| 698 | − | if ((sel = tns_translate(&tns, bev->x, bev->y)) >= 0) { | |
| 699 | − | bool on = !(files[sel].flags & FF_MARK); | |
| 700 | − | XEvent e; | |
| 701 | − | ||
| 702 | − | while (true) { | |
| 703 | − | if (sel >= 0 && mark_image(sel, on)) | |
| 704 | − | redraw(); | |
| 705 | − | XMaskEvent(win.env.dpy, | |
| 706 | − | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e); | |
| 707 | − | if (e.type == ButtonPress || e.type == ButtonRelease) | |
| 708 | − | break; | |
| 709 | − | while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e)); | |
| 710 | − | sel = tns_translate(&tns, e.xbutton.x, e.xbutton.y); | |
| 711 | − | } | |
| 712 | − | } | |
| 713 | − | break; | |
| 714 | − | case Button4: | |
| 715 | − | case Button5: | |
| 716 | − | if (tns_scroll(&tns, bev->button == Button4 ? DIR_UP : DIR_DOWN, | |
| 717 | − | (bev->state & ControlMask) != 0)) | |
| 718 | − | redraw(); | |
| 719 | − | break; | |
| 720 | − | } | |
| 672 | + | dirty = process_bindings(buttons_img, ARRLEN(buttons_img), bev->button, bev->state, 0); | |
| 673 | + | } else { /* thumbnail mode */ | |
| 674 | + | dirty = process_bindings(buttons_tns, ARRLEN(buttons_tns), bev->button, bev->state, 0); | |
| 721 | 675 | } | |
| 676 | + | if (dirty) | |
| 677 | + | redraw(); | |
| 722 | 678 | prefix = 0; | |
| 723 | 679 | } | |
| 724 | 680 | ||
| @@ -731,13 +687,14 @@ static void run(void) | |||
| 731 | 687 | bool discard, init_thumb, load_thumb, to_set; | |
| 732 | 688 | XEvent ev, nextev; | |
| 733 | 689 | ||
| 690 | + | xbutton_ev = &ev.xbutton; | |
| 734 | 691 | while (true) { | |
| 735 | 692 | to_set = check_timeouts(&timeout); | |
| 736 | 693 | init_thumb = mode == MODE_THUMB && tns.initnext < filecnt; | |
| 737 | 694 | load_thumb = mode == MODE_THUMB && tns.loadnext < tns.end; | |
| 738 | 695 | ||
| 739 | 696 | if ((init_thumb || load_thumb || to_set || info.fd != -1 || | |
| 740 | − | arl.fd != -1) && XPending(win.env.dpy) == 0) | |
| 697 | + | arl.fd != -1) && XPending(win.env.dpy) == 0) | |
| 741 | 698 | { | |
| 742 | 699 | if (load_thumb) { | |
| 743 | 700 | set_timeout(redraw, TO_REDRAW_THUMBS, false); | |