Skip to content

Commit

Permalink
Add support for custom zoom step
Browse files Browse the repository at this point in the history
Step is specified as a percentage delta of current scale.
Stored as a custom parameter in the key binding section of config file:
```
[keys]
plus = zoom_in 10
```

Relates to #81.

Signed-off-by: Artem Senichev <[email protected]>
  • Loading branch information
artemsen committed Dec 23, 2023
1 parent d26d066 commit c804353
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 58 deletions.
6 changes: 3 additions & 3 deletions extra/swayimgrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -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;"
Expand Down
97 changes: 51 additions & 46 deletions src/canvas.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 8 additions & 4 deletions src/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);

Expand Down
30 changes: 27 additions & 3 deletions src/viewer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit c804353

Please sign in to comment.