diff --git a/man/feh.pre b/man/feh.pre index af1def16..6a9db0e6 100644 --- a/man/feh.pre +++ b/man/feh.pre @@ -1003,12 +1003,19 @@ zoom the image like the .Cm --bg-fill mode. . -.It Cm --zoom-step Ar percent +.It Cm --zoom-step Ar index . -Zoom images in and out by -.Ar percent -.Pq default: 25 -when using the zoom keys and buttons. +Zoom images in and out by a factor of the nth root +.Pq Ar index +of 2 when using the zoom keys and buttons. The default is the 3rd root, +which means that there will be 3 steps between powers of 2. +. +.It Cm --zoom-rate Ar index +. +Zoom images in and out by a factor of the nth root +.Pq Ar index +of 2 upon entering zoom mode. The default is the 128th root, +which means that there will be 128 pixels between powers of 2. . .El . diff --git a/src/events.c b/src/events.c index 524ccad7..49515901 100644 --- a/src/events.c +++ b/src/events.c @@ -242,29 +242,31 @@ static void feh_event_handle_ButtonPress(XEvent * ev) D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y)); winwid->click_offset_x = ev->xbutton.x; winwid->click_offset_y = ev->xbutton.y; - winwid->old_zoom = winwid->zoom; + winwid->old_step = round(log(winwid->zoom) / opt.zoom_rate); /* required to adjust the image position in zoom mode */ winwid->im_click_offset_x = (winwid->click_offset_x - - winwid->im_x) / winwid->old_zoom; + - winwid->im_x) / winwid->zoom; winwid->im_click_offset_y = (winwid->click_offset_y - - winwid->im_y) / winwid->old_zoom; + - winwid->im_y) / winwid->zoom; } else if (feh_is_bb(EVENT_zoom_in, button, state)) { D(("Zoom_In Button Press event\n")); D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y)); + if (winwid->zoom >= ZOOM_MAX || opt.step_rate <= 0) + return; + winwid->click_offset_x = ev->xbutton.x; winwid->click_offset_y = ev->xbutton.y; - winwid->old_zoom = winwid->zoom; /* required to adjust the image position in zoom mode */ winwid->im_click_offset_x = (winwid->click_offset_x - - winwid->im_x) / winwid->old_zoom; + - winwid->im_x) / winwid->zoom; winwid->im_click_offset_y = (winwid->click_offset_y - - winwid->im_y) / winwid->old_zoom; + - winwid->im_y) / winwid->zoom; /* copied from zoom_in, keyevents.c */ - winwid->zoom = winwid->zoom * opt.zoom_rate; + winwid->zoom = exp(++winwid->zoom_step * opt.step_rate); if (winwid->zoom > ZOOM_MAX) winwid->zoom = ZOOM_MAX; @@ -281,18 +283,20 @@ static void feh_event_handle_ButtonPress(XEvent * ev) } else if (feh_is_bb(EVENT_zoom_out, button, state)) { D(("Zoom_Out Button Press event\n")); D(("click offset is %d,%d\n", ev->xbutton.x, ev->xbutton.y)); + if (winwid->zoom <= ZOOM_MIN || opt.step_rate <= 0) + return; + winwid->click_offset_x = ev->xbutton.x; winwid->click_offset_y = ev->xbutton.y; - winwid->old_zoom = winwid->zoom; /* required to adjust the image position in zoom mode */ winwid->im_click_offset_x = (winwid->click_offset_x - - winwid->im_x) / winwid->old_zoom; + - winwid->im_x) / winwid->zoom; winwid->im_click_offset_y = (winwid->click_offset_y - - winwid->im_y) / winwid->old_zoom; + - winwid->im_y) / winwid->zoom; /* copied from zoom_out, keyevents.c */ - winwid->zoom = winwid->zoom / opt.zoom_rate; + winwid->zoom = exp(--winwid->zoom_step * opt.step_rate); if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; @@ -400,11 +404,16 @@ static void feh_event_handle_ButtonRelease(XEvent * ev) opt.mode = MODE_NORMAL; winwid->mode = MODE_NORMAL; - if ((feh_is_bb(EVENT_zoom, button, state)) - && (ev->xbutton.x == winwid->click_offset_x) - && (ev->xbutton.y == winwid->click_offset_y)) { - winwid->zoom = 1.0; - winwidget_center_image(winwid); + if ((feh_is_bb(EVENT_zoom, button, state))) { + if ((ev->xbutton.x == winwid->click_offset_x) + && (ev->xbutton.y == winwid->click_offset_y)) { + winwid->zoom = 1.0; + winwid->zoom_step = 0; + winwidget_center_image(winwid); + } else { + winwid->zoom_step = round(log(winwid->zoom) / opt.step_rate); + winwidget_sanitise_offsets(winwid); + } } else winwidget_sanitise_offsets(winwid); @@ -542,15 +551,9 @@ static void feh_event_handle_MotionNotify(XEvent * ev) while (XCheckTypedWindowEvent(disp, ev->xmotion.window, MotionNotify, ev)); winwid = winwidget_get_from_window(ev->xmotion.window); - if (winwid) { - if (ev->xmotion.x > winwid->click_offset_x) - winwid->zoom = winwid->old_zoom + ( - ((double) ev->xmotion.x - (double) winwid->click_offset_x) - / 128.0); - else - winwid->zoom = winwid->old_zoom - ( - ((double) winwid->click_offset_x - (double) ev->xmotion.x) - / 128.0); + if (winwid && opt.zoom_rate > 0) { + int step = winwid->old_step + ev->xmotion.x - winwid->click_offset_x; + winwid->zoom = exp(step * opt.zoom_rate); if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; diff --git a/src/keyevents.c b/src/keyevents.c index ecb4c9d4..781f4f7f 100644 --- a/src/keyevents.c +++ b/src/keyevents.c @@ -602,35 +602,42 @@ void feh_event_handle_generic(winwidget winwid, unsigned int state, KeySym keysy feh_event_invoke_action(winwid, 9); } else if (feh_is_kp(EVENT_zoom_in, state, keysym, button)) { - winwid->old_zoom = winwid->zoom; - winwid->zoom = winwid->zoom * opt.zoom_rate; + if (winwid->zoom >= ZOOM_MAX || opt.step_rate <= 0) + return; + + double old_zoom = winwid->zoom; + winwid->zoom = exp(++winwid->zoom_step * opt.step_rate); if (winwid->zoom > ZOOM_MAX) winwid->zoom = ZOOM_MAX; winwid->im_x = (winwid->w / 2) - (((winwid->w / 2) - winwid->im_x) / - winwid->old_zoom * winwid->zoom); + old_zoom * winwid->zoom); winwid->im_y = (winwid->h / 2) - (((winwid->h / 2) - winwid->im_y) / - winwid->old_zoom * winwid->zoom); + old_zoom * winwid->zoom); winwidget_sanitise_offsets(winwid); winwidget_render_image(winwid, 0, 0); } else if (feh_is_kp(EVENT_zoom_out, state, keysym, button)) { - winwid->old_zoom = winwid->zoom; - winwid->zoom = winwid->zoom / opt.zoom_rate; + if (winwid->zoom <= ZOOM_MIN || opt.step_rate <= 0) + return; + + double old_zoom = winwid->zoom; + winwid->zoom = exp(--winwid->zoom_step * opt.step_rate); if (winwid->zoom < ZOOM_MIN) winwid->zoom = ZOOM_MIN; winwid->im_x = (winwid->w / 2) - (((winwid->w / 2) - winwid->im_x) / - winwid->old_zoom * winwid->zoom); + old_zoom * winwid->zoom); winwid->im_y = (winwid->h / 2) - (((winwid->h / 2) - winwid->im_y) / - winwid->old_zoom * winwid->zoom); + old_zoom * winwid->zoom); winwidget_sanitise_offsets(winwid); winwidget_render_image(winwid, 0, 0); } else if (feh_is_kp(EVENT_zoom_default, state, keysym, button)) { winwid->zoom = 1.0; + winwid->zoom_step = 0; winwidget_center_image(winwid); winwidget_render_image(winwid, 0, 0); } diff --git a/src/options.c b/src/options.c index 80f13b66..b00d7cf0 100644 --- a/src/options.c +++ b/src/options.c @@ -63,7 +63,8 @@ void init_parse_options(int argc, char **argv) opt.font = NULL; opt.max_height = opt.max_width = UINT_MAX; - opt.zoom_rate = 1.25; + opt.zoom_rate = M_LN2 / 128.0; + opt.step_rate = M_LN2 / 3.0; opt.start_list_at = NULL; opt.jump_on_resort = 1; @@ -395,6 +396,7 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) {"bg-center" , 0, 0, OPTION_bg_center}, {"bg-scale" , 0, 0, OPTION_bg_scale}, {"zoom" , 1, 0, OPTION_zoom}, + {"zoom-rate" , 1, 0, OPTION_zoom_rate}, {"zoom-step" , 1, 0, OPTION_zoom_step}, {"no-screen-clip", 0, 0, OPTION_no_screen_clip}, {"index-info" , 1, 0, OPTION_index_info}, @@ -847,13 +849,22 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun) case OPTION_window_id: opt.x11_windowid = strtol(optarg, NULL, 0); break; - case OPTION_zoom_step: + case OPTION_zoom_rate: opt.zoom_rate = atof(optarg); if ((opt.zoom_rate <= 0)) { - weprintf("Zooming disabled due to --zoom-step=%f", opt.zoom_rate); - opt.zoom_rate = 1.0; + weprintf("Zoom mode disabled due to --zoom-rate=%f", opt.zoom_rate); + opt.zoom_rate = 0.0; + } else { + opt.zoom_rate = M_LN2 / opt.zoom_rate; + } + break; + case OPTION_zoom_step: + opt.step_rate = atof(optarg); + if ((opt.step_rate <= 0)) { + weprintf("Zoom steps disabled due to --zoom-step=%f", opt.step_rate); + opt.step_rate = 0.0; } else { - opt.zoom_rate = 1 + ((float)opt.zoom_rate / 100); + opt.step_rate = M_LN2 / opt.step_rate; } break; default: diff --git a/src/options.h b/src/options.h index 6441e8bc..e1599d3a 100644 --- a/src/options.h +++ b/src/options.h @@ -128,6 +128,7 @@ struct __fehoptions { int default_zoom; int zoom_mode; double zoom_rate; + double step_rate; unsigned char adjust_reload; int xinerama_index; char *x11_class; @@ -216,6 +217,7 @@ OPTION_bg_scale, OPTION_bg_fill, OPTION_bg_max, OPTION_zoom, +OPTION_zoom_rate, OPTION_zoom_step, OPTION_zoom_in_rate, OPTION_zoom_out_rate, diff --git a/src/winwidget.c b/src/winwidget.c index 132b57e9..5c110086 100644 --- a/src/winwidget.c +++ b/src/winwidget.c @@ -77,7 +77,8 @@ static winwidget winwidget_allocate(void) ret->im_x = 0; ret->im_y = 0; ret->zoom = 1.0; - ret->old_zoom = 1.0; + ret->zoom_step = 0; + ret->old_step = 0; ret->click_offset_x = 0; ret->click_offset_y = 0; @@ -494,6 +495,8 @@ void winwidget_render_image(winwidget winwid, int resize, int force_alias) && (!opt.default_zoom || required_zoom < winwid->zoom)) winwid->zoom = required_zoom; + winwid->zoom_step = round(log(winwid->zoom) / opt.step_rate); + if (opt.offset_flags & XValue) { if (opt.offset_flags & XNegative) { winwid->im_x = winwid->w - (winwid->im_w * winwid->zoom) - opt.offset_x; @@ -1065,12 +1068,12 @@ void feh_debug_print_winwid(winwidget w) "h = %d\n" "im_w = %d\n" "im_h = %d\n" "im_angle = %f\n" "type = %d\n" "had_resize = %d\n" "im = %p\n" "GC = %p\n" "pixmap = %ld\n" "name = %s\n" "file = %p\n" "mode = %d\n" - "im_x = %d\n" "im_y = %d\n" "zoom = %f\n" "old_zoom = %f\n" - "click_offset_x = %d\n" "click_offset_y = %d\n" + "im_x = %d\n" "im_y = %d\n" "zoom = %f\n" "zoom_step = %d\n" + "old_step = %d" "click_offset_x = %d\n" "click_offset_y = %d\n" "has_rotated = %d\n", (void *)w, w->win, w->w, w->h, w->im_w, w->im_h, w->im_angle, w->type, w->had_resize, w->im, (void *)w->gc, w->bg_pmap, w->name, (void *)w->file, w->mode, w->im_x, w->im_y, - w->zoom, w->old_zoom, w->click_offset_x, w->click_offset_y, + w->zoom, w->zoom_step, w->old_step, w->click_offset_x, w->click_offset_y, w->has_rotated); } @@ -1078,7 +1081,7 @@ void winwidget_reset_image(winwidget winwid) { if (!opt.keep_zoom_vp) { winwid->zoom = 1.0; - winwid->old_zoom = 1.0; + winwid->zoom_step = 0; winwid->im_x = 0; winwid->im_y = 0; } diff --git a/src/winwidget.h b/src/winwidget.h index 9d742864..f03287fe 100644 --- a/src/winwidget.h +++ b/src/winwidget.h @@ -107,7 +107,8 @@ struct __winwidget { * all the way up to INT_MAX (eww) */ double zoom; - double old_zoom; + int zoom_step; + int old_step; int click_offset_x; int click_offset_y;