diff --git a/extra/swayimgrc b/extra/swayimgrc index ac1dfc5..0ad8408 100644 --- a/extra/swayimgrc +++ b/extra/swayimgrc @@ -91,9 +91,9 @@ Up = step_up k = step_up Down = step_down j = step_down -equal = zoom_in -plus = zoom_in -minus = zoom_out +equal = zoom_in 10 +plus = zoom_in 10 +minus = zoom_out 10 x = zoom_optimal z = zoom_fit Z = zoom_fill diff --git a/extra/swayimgrc.5 b/extra/swayimgrc.5 index 344de07..40cb291 100644 --- a/extra/swayimgrc.5 +++ b/extra/swayimgrc.5 @@ -87,8 +87,8 @@ Valid action are: .IP "\fBstep_right\fR: move viewport right;" .IP "\fBstep_up\fR: move viewport up;" .IP "\fBstep_down\fR: move viewport down;" -.IP "\fBzoom_in\fR: zoom in;" -.IP "\fBzoom_out\fR: zoom out;" +.IP "\fBzoom_in\fR \fI[PERCENT]\fR: zoom in, by default increases scale by 10%;" +.IP "\fBzoom_out\fR \fI[PERCENT]\fR: zoom out, by default decreases scale by 10%;" .IP "\fBzoom_optimal\fR: set to optimal zoom (100% or less to fit to window);" .IP "\fBzoom_fit\fR: set scale to fit the window;" .IP "\fBzoom_fill\fR: set scale to fill the window;" diff --git a/src/canvas.c b/src/canvas.c index 4d554c9..5a45016 100644 --- a/src/canvas.c +++ b/src/canvas.c @@ -395,59 +395,64 @@ bool canvas_move(enum canvas_move mv) return (ctx.image.x != prev_x || ctx.image.y != prev_y); } -void canvas_set_scale(enum canvas_scale sc) +void canvas_zoom(ssize_t percent) { - const float prev = ctx.scale; - - // set new scale factor - if (sc == cs_fit_or100 || sc == cs_fit_window || sc == cs_fill_window) { - const float sw = 1.0 / ((float)ctx.image.width / ctx.window.width); - const float sh = 1.0 / ((float)ctx.image.height / ctx.window.height); - if (sc == cs_fill_window) { - ctx.scale = max(sw, sh); - } else { - ctx.scale = min(sw, sh); - if (sc == cs_fit_or100 && ctx.scale > 1.0) { - ctx.scale = 1.0; - } + const size_t old_w = ctx.scale * ctx.image.width; + const size_t old_h = ctx.scale * ctx.image.height; + const float step = (ctx.scale / 100) * percent; + + if (percent > 0) { + ctx.scale += step; + if (ctx.scale > MAX_SCALE) { + ctx.scale = MAX_SCALE; } - } else if (sc == cs_real_size) { - ctx.scale = 1.0; // 100 % } else { - const float step = ctx.scale / 10.0; - if (sc == cs_zoom_in) { - ctx.scale += step; - if (ctx.scale > MAX_SCALE) { - ctx.scale = MAX_SCALE; - } - } else if (sc == cs_zoom_out) { - const float sw = (float)MIN_SCALE / ctx.image.width; - const float sh = (float)MIN_SCALE / ctx.image.height; - const float scale_min = max(sw, sh); - ctx.scale -= step; - if (ctx.scale < scale_min) { - ctx.scale = scale_min; - } + const float scale_w = (float)MIN_SCALE / ctx.image.width; + const float scale_h = (float)MIN_SCALE / ctx.image.height; + const float scale_min = max(scale_w, scale_h); + ctx.scale += step; + if (ctx.scale < scale_min) { + ctx.scale = scale_min; } } - // move viewport - if (sc != cs_zoom_in && sc != cs_zoom_out) { - canvas_move(cm_center); - } else { - // move to save the center of previous coordinates - const size_t old_w = prev * ctx.image.width; - const size_t old_h = prev * ctx.image.height; - const size_t new_w = ctx.scale * ctx.image.width; - const size_t new_h = ctx.scale * ctx.image.height; - const ssize_t delta_w = old_w - new_w; - const ssize_t delta_h = old_h - new_h; - const ssize_t cntr_x = ctx.window.width / 2 - ctx.image.x; - const ssize_t cntr_y = ctx.window.height / 2 - ctx.image.y; - ctx.image.x += ((float)cntr_x / old_w) * delta_w; - ctx.image.y += ((float)cntr_y / old_h) * delta_h; - fix_viewport(); + // move viewport to save the center of previous coordinates + const size_t new_w = ctx.scale * ctx.image.width; + const size_t new_h = ctx.scale * ctx.image.height; + const ssize_t delta_w = old_w - new_w; + const ssize_t delta_h = old_h - new_h; + const ssize_t cntr_x = ctx.window.width / 2 - ctx.image.x; + const ssize_t cntr_y = ctx.window.height / 2 - ctx.image.y; + ctx.image.x += ((float)cntr_x / old_w) * delta_w; + ctx.image.y += ((float)cntr_y / old_h) * delta_h; + + fix_viewport(); +} + +void canvas_set_scale(enum canvas_scale sc) +{ + const float scale_w = 1.0 / ((float)ctx.image.width / ctx.window.width); + const float scale_h = 1.0 / ((float)ctx.image.height / ctx.window.height); + + switch (sc) { + case cs_fit_or100: + ctx.scale = min(scale_w, scale_h); + if (ctx.scale > 1.0) { + ctx.scale = 1.0; + } + break; + case cs_fit_window: + ctx.scale = min(scale_w, scale_h); + break; + case cs_fill_window: + ctx.scale = max(scale_w, scale_h); + break; + case cs_real_size: + ctx.scale = 1.0; // 100 % + break; } + + canvas_move(cm_center); } float canvas_get_scale(void) diff --git a/src/canvas.h b/src/canvas.h index c9fbe6a..071799b 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -23,8 +23,6 @@ enum canvas_scale { cs_fit_window, ///< Fit to window size cs_fill_window, ///< Fill the window cs_real_size, ///< Real image size (100%) - cs_zoom_in, ///< Enlarge by one step - cs_zoom_out ///< Reduce by one step }; /** Corner position. */ @@ -95,8 +93,14 @@ void canvas_print_info(argb_t* wnd, size_t num, const struct info_table* info); bool canvas_move(enum canvas_move mv); /** - * Scale image on the canvas. - * @param sc scale operation + * Zoom in/out. + * @param percent percentage increment to current scale + */ +void canvas_zoom(ssize_t percent); + +/** + * Set fixed scale for the image. + * @param sc scale to set */ void canvas_set_scale(enum canvas_scale sc); diff --git a/src/viewer.c b/src/viewer.c index 74be3ba..9c86f72 100644 --- a/src/viewer.c +++ b/src/viewer.c @@ -277,6 +277,32 @@ __attribute__((format(printf, 1, 2))) static void set_message(const char* fmt, } } +/** + * Zoom in/out. + * @param zoom_in in/out flag + * @param params optional zoom step in percents + */ +static void zoom_image(bool zoom_in, const char* params) +{ + ssize_t percent = 10; + + if (params) { + char* endptr; + const unsigned long val = strtoul(params, &endptr, 0); + if (val != 0 && val <= 1000 && !*endptr) { + percent = val; + } else { + fprintf(stderr, "Invalid zoom value: \"%s\"\n", params); + } + } + + if (!zoom_in) { + percent = -percent; + } + + canvas_zoom(percent); +} + /** * Animation timer event handler. */ @@ -419,10 +445,8 @@ bool viewer_on_keyboard(xkb_keysym_t key) case kb_step_down: return canvas_move(cm_step_down); case kb_zoom_in: - canvas_set_scale(cs_zoom_in); - return true; case kb_zoom_out: - canvas_set_scale(cs_zoom_out); + zoom_image(kbind->action == kb_zoom_in, kbind->params); return true; case kb_zoom_optimal: canvas_set_scale(cs_fit_or100);