~exec64/imv-devel

Add absolue and relative zoom functionality v1 PROPOSED

Fabian Specht: 1
 Add absolue and relative zoom functionality

 6 files changed, 116 insertions(+), 85 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~exec64/imv-devel/patches/47616/mbox | git am -3
Learn more about email & git

[PATCH] Add absolue and relative zoom functionality Export this patch

---
 .gitignore     |   1 +
 CHANGELOG      |   6 ++
 doc/imv.1.txt  |   7 ++-
 src/imv.c      |  24 +++++++-
 src/viewport.c | 156 ++++++++++++++++++++++++-------------------------
 src/viewport.h |   7 ++-
 6 files changed, 116 insertions(+), 85 deletions(-)

diff --git a/.gitignore b/.gitignore
index b022387..a766ed3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ imv
*.o
test_*
build/
.cache/
diff --git a/CHANGELOG b/CHANGELOG
index a1daf78..a5d125c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,12 @@
imv Changelog
=============

unversioned
-----------

* Changed zoom to set absolute values
* old zoom command is now 'zoom_rel'

v4.4.0 - 2023-01-18
-------------------

diff --git a/doc/imv.1.txt b/doc/imv.1.txt
index b0dfbf7..8de8cfb 100644
--- a/doc/imv.1.txt
+++ b/doc/imv.1.txt
@@ -99,10 +99,15 @@ Commands can be entered by pressing *:*. imv supports the following commands:
	Aliased to 'g'.

*zoom* <amount|'actual'>::
	Zoom into the image by the given amount. Negative values zoom out.
	Zoom into the image with the given amount in percent.
	'actual' resets the zoom to 100%, showing the image at its actual size.
	Aliased to 'z'.

*zoom_rel* <amount|'actual'>::
	Zoom into the image by the given amount. Negative values zoom out.
	'actual' resets the zoom to 100%, showing the image at its actual size.
	Aliased to 'zr'.

*rotate* <'to'|'by'> <angle>::
	Rotate image clockwise by/to the given amount in degrees.

diff --git a/src/imv.c b/src/imv.c
index bca52fd..b20c4d8 100644
--- a/src/imv.c
+++ b/src/imv.c
@@ -200,6 +200,7 @@ static void command_next(struct list *args, const char *argstr, void *data);
static void command_prev(struct list *args, const char *argstr, void *data);
static void command_goto(struct list *args, const char *argstr, void *data);
static void command_zoom(struct list *args, const char *argstr, void *data);
static void command_zoom_rel(struct list *args, const char *argstr, void *data);
static void command_rotate(struct list *args, const char *argstr, void *data);
static void command_flip(struct list *args, const char *argstr, void *data);
static void command_open(struct list *args, const char *argstr, void *data);
@@ -466,7 +467,7 @@ static void event_handler(void *data, const struct imv_event *e)
        double x, y;
        imv_window_get_mouse_position(imv->window, &x, &y);
        imv_viewport_zoom(imv->view, imv->current_image, IMV_ZOOM_MOUSE,
            x, y, -e->data.mouse_scroll.dy);
            IMV_ZOOM_RELATIVE, x, y, -e->data.mouse_scroll.dy);
      }
      break;
    case IMV_EVENT_CUSTOM:
@@ -568,6 +569,7 @@ struct imv *imv_create(void)
  imv_command_register(imv->commands, "prev", &command_prev);
  imv_command_register(imv->commands, "goto", &command_goto);
  imv_command_register(imv->commands, "zoom", &command_zoom);
  imv_command_register(imv->commands, "zoom_rel", &command_zoom_rel);
  imv_command_register(imv->commands, "rotate", &command_rotate);
  imv_command_register(imv->commands, "flip", &command_flip);
  imv_command_register(imv->commands, "open", &command_open);
@@ -590,6 +592,7 @@ struct imv *imv_create(void)
  imv_command_alias(imv->commands, "p", "prev");
  imv_command_alias(imv->commands, "g", "goto");
  imv_command_alias(imv->commands, "z", "zoom");
  imv_command_alias(imv->commands, "zr", "zoom_rel");
  imv_command_alias(imv->commands, "o", "open");
  imv_command_alias(imv->commands, "bg", "background");
  imv_command_alias(imv->commands, "ss", "slideshow");
@@ -1712,7 +1715,24 @@ static void command_zoom(struct list *args, const char *argstr, void *data)
      imv_viewport_scale_to_actual(imv->view, imv->current_image);
    } else {
      long int amount = strtol(args->items[1], NULL, 10);
      imv_viewport_zoom(imv->view, imv->current_image, IMV_ZOOM_KEYBOARD, 0, 0, amount);
      imv_viewport_zoom(imv->view, imv->current_image,
        IMV_ZOOM_KEYBOARD, IMV_ZOOM_ABSOLUTE, 0, 0, amount);
    }
  }
}

static void command_zoom_rel(struct list *args, const char *argstr, void *data)
{
  (void)argstr;
  struct imv *imv = data;
  if (args->len == 2) {
    const char *str = args->items[1];
    if (!strcmp(str, "actual")) {
      imv_viewport_scale_to_actual(imv->view, imv->current_image);
    } else {
      long int amount = strtol(args->items[1], NULL, 10);
      imv_viewport_zoom(imv->view, imv->current_image,
        IMV_ZOOM_KEYBOARD, IMV_ZOOM_RELATIVE, 0, 0, amount);
    }
  }
}
diff --git a/src/viewport.c b/src/viewport.c
index 095bf71..32d59c2 100644
--- a/src/viewport.c
+++ b/src/viewport.c
@@ -1,8 +1,8 @@
#include "viewport.h"

#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <math.h>

struct imv_viewport {
  double scale;
@@ -21,15 +21,13 @@ struct imv_viewport {
  int locked;
};

static void input_xy_to_render_xy(struct imv_viewport *view, int *x, int *y)
{
static void input_xy_to_render_xy(struct imv_viewport *view, int *x, int *y) {
  *x *= view->buffer.width / view->window.width;
  *y *= view->buffer.height / view->window.height;
}

struct imv_viewport *imv_viewport_create(int window_width, int window_height,
                                         int buffer_width, int buffer_height)
{
                                         int buffer_width, int buffer_height) {
  struct imv_viewport *view = malloc(sizeof *view);
  view->window.width = window_width;
  view->window.height = window_height;
@@ -45,74 +43,64 @@ struct imv_viewport *imv_viewport_create(int window_width, int window_height,
  return view;
}

void imv_viewport_free(struct imv_viewport *view)
{
  free(view);
}
void imv_viewport_free(struct imv_viewport *view) { free(view); }

void imv_viewport_set_playing(struct imv_viewport *view, bool playing)
{
void imv_viewport_set_playing(struct imv_viewport *view, bool playing) {
  view->playing = playing;
}

bool imv_viewport_is_playing(struct imv_viewport *view)
{
bool imv_viewport_is_playing(struct imv_viewport *view) {
  return view->playing;
}

void imv_viewport_toggle_playing(struct imv_viewport *view)
{
void imv_viewport_toggle_playing(struct imv_viewport *view) {
  view->playing = !view->playing;
}

void imv_viewport_scale_to_actual(struct imv_viewport *view, const struct imv_image *image)
{
void imv_viewport_scale_to_actual(struct imv_viewport *view,
                                  const struct imv_image *image) {
  view->scale = 1;
  view->redraw = 1;
  view->locked = 1;
  imv_viewport_center(view, image);
}

void imv_viewport_get_offset(struct imv_viewport *view, int *x, int *y)
{
  if(x) {
void imv_viewport_get_offset(struct imv_viewport *view, int *x, int *y) {
  if (x) {
    *x = view->x;
  }
  if(y) {
  if (y) {
    *y = view->y;
  }
}

void imv_viewport_get_scale(struct imv_viewport *view, double *scale)
{
  if(scale) {
void imv_viewport_get_scale(struct imv_viewport *view, double *scale) {
  if (scale) {
    *scale = view->scale;
  }
}

void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation)
{
  if(rotation) {
void imv_viewport_get_rotation(struct imv_viewport *view, double *rotation) {
  if (rotation) {
    *rotation = view->rotation;
  }
}

void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored)
{
  if(mirrored) {
void imv_viewport_get_mirrored(struct imv_viewport *view, bool *mirrored) {
  if (mirrored) {
    *mirrored = view->mirrored;
  }
}

void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_factor_x, double pan_factor_y)
{
void imv_viewport_set_default_pan_factor(struct imv_viewport *view,
                                         double pan_factor_x,
                                         double pan_factor_y) {
  view->pan_factor_x = pan_factor_x;
  view->pan_factor_y = pan_factor_y;
}

void imv_viewport_move(struct imv_viewport *view, int x, int y,
    const struct imv_image *image)
{
                       const struct imv_image *image) {
  input_xy_to_render_xy(view, &x, &y);
  view->x += x;
  view->y += y;
@@ -134,9 +122,13 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y,
  }
}

/* zoom is specified through the given amount which is either applied as an
 * absolue or relative value depending on the value of type
 */

void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
                       enum imv_zoom_source src, int mouse_x, int mouse_y, int amount)
{
                       enum imv_zoom_source src, enum imv_zoom_type type, 
                       int mouse_x, int mouse_y, int amount) {
  double prev_scale = view->scale;
  int x, y;

@@ -144,7 +136,7 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
  const int image_height = imv_image_height(image);

  /* x and y coordinates are relative to the image */
  if(src == IMV_ZOOM_MOUSE) {
  if (src == IMV_ZOOM_MOUSE) {
    input_xy_to_render_xy(view, &mouse_x, &mouse_y);
    x = mouse_x - view->x;
    y = mouse_y - view->y;
@@ -155,35 +147,41 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,

  const int scaled_width = image_width * view->scale;
  const int scaled_height = image_height * view->scale;
  const int ic_x = view->x + scaled_width/2;
  const int ic_y = view->y + scaled_height/2;
  const int wc_x = view->buffer.width/2;
  const int wc_y = view->buffer.height/2;

  const double scale_factor = pow(1.04, amount);
  view->scale *= scale_factor;
  const int ic_x = view->x + scaled_width / 2;
  const int ic_y = view->y + scaled_height / 2;

  const int wc_x = view->buffer.width / 2;
  const int wc_y = view->buffer.height / 2;

  if (type == IMV_ZOOM_ABSOLUTE) {
    view->scale = amount * 0.01;
  } else {
    const double scale_factor = pow(1.04, amount);
    view->scale *= scale_factor;
  }

  const double min_scale = 0.1;
  const double max_scale = 100;
  if(view->scale > max_scale) {
  if (view->scale > max_scale) {
    view->scale = max_scale;
  } else if (view->scale < min_scale) {
    view->scale = min_scale;
  }

  if(view->scale < prev_scale) {
    if(scaled_width < view->buffer.width) {
      x = scaled_width/2 - (ic_x - wc_x)*2;
  if (view->scale < prev_scale) {
    if (scaled_width < view->buffer.width) {
      x = scaled_width / 2 - (ic_x - wc_x) * 2;
    }
    if(scaled_height < view->buffer.height) {
      y = scaled_height/2 - (ic_y - wc_y)*2;
    if (scaled_height < view->buffer.height) {
      y = scaled_height / 2 - (ic_y - wc_y) * 2;
    }
  } else {
    if(scaled_width < view->buffer.width) {
      x = scaled_width/2;
    if (scaled_width < view->buffer.width) {
      x = scaled_width / 2;
    }
    if(scaled_height < view->buffer.height) {
      y = scaled_height/2;
    if (scaled_height < view->buffer.height) {
      y = scaled_height / 2;
    }
  }

@@ -219,8 +217,8 @@ void imv_viewport_reset_transform(struct imv_viewport *view) {
  view->rotation = 0;
}

void imv_viewport_center(struct imv_viewport *view, const struct imv_image *image)
{
void imv_viewport_center(struct imv_viewport *view,
                         const struct imv_image *image) {
  const int image_width = imv_image_width(image);
  const int image_height = imv_image_height(image);

@@ -245,14 +243,15 @@ void imv_viewport_center(struct imv_viewport *view, const struct imv_image *imag
  view->redraw = 1;
}

void imv_viewport_scale_to_window(struct imv_viewport *view, const struct imv_image *image)
{
void imv_viewport_scale_to_window(struct imv_viewport *view,
                                  const struct imv_image *image) {
  const int image_width = imv_image_width(image);
  const int image_height = imv_image_height(image);
  const double window_aspect = (double)view->buffer.width / (double)view->buffer.height;
  const double window_aspect =
      (double)view->buffer.width / (double)view->buffer.height;
  const double image_aspect = (double)image_width / (double)image_height;

  if(window_aspect > image_aspect) {
  if (window_aspect > image_aspect) {
    /* Image will become too tall before it becomes too wide */
    view->scale = (double)view->buffer.height / (double)image_height;
  } else {
@@ -264,15 +263,16 @@ void imv_viewport_scale_to_window(struct imv_viewport *view, const struct imv_im
  view->locked = 0;
}

void imv_viewport_crop_to_window(struct imv_viewport *view, const struct imv_image *image)
{
void imv_viewport_crop_to_window(struct imv_viewport *view,
                                 const struct imv_image *image) {
  const int image_width = imv_image_width(image);
  const int image_height = imv_image_height(image);
  const double window_aspect = (double)view->buffer.width / (double)view->buffer.height;
  const double window_aspect =
      (double)view->buffer.width / (double)view->buffer.height;
  const double image_aspect = (double)image_width / (double)image_height;

  /* Scale the image so that it fills the whole window */
  if(window_aspect > image_aspect) {
  if (window_aspect > image_aspect) {
    view->scale = (double)view->buffer.width / (double)image_width;
  } else {
    view->scale = (double)view->buffer.height / (double)image_height;
@@ -282,17 +282,15 @@ void imv_viewport_crop_to_window(struct imv_viewport *view, const struct imv_ima
  view->locked = 0;
}

void imv_viewport_set_redraw(struct imv_viewport *view)
{
  view->redraw = 1;
}
void imv_viewport_set_redraw(struct imv_viewport *view) { view->redraw = 1; }

void imv_viewport_rescale(struct imv_viewport *view, const struct imv_image *image,
void imv_viewport_rescale(struct imv_viewport *view,
                          const struct imv_image *image,
                          enum scaling_mode scaling_mode) {
  if (scaling_mode == SCALING_NONE ||
      (scaling_mode == SCALING_DOWN
       && view->buffer.width > imv_image_width(image)
       && view->buffer.height > imv_image_height(image))) {
      (scaling_mode == SCALING_DOWN &&
       view->buffer.width > imv_image_width(image) &&
       view->buffer.height > imv_image_height(image))) {
    imv_viewport_scale_to_actual(view, image);
  } else if (scaling_mode == SCALING_CROP) {
    imv_viewport_crop_to_window(view, image);
@@ -301,19 +299,17 @@ void imv_viewport_rescale(struct imv_viewport *view, const struct imv_image *ima
  }
}

void imv_viewport_update(struct imv_viewport *view,
                         int window_width, int window_height,
                         int buffer_width, int buffer_height,
void imv_viewport_update(struct imv_viewport *view, int window_width,
                         int window_height, int buffer_width, int buffer_height,
                         struct imv_image *image,
                         enum scaling_mode scaling_mode)
{
                         enum scaling_mode scaling_mode) {
  view->window.width = window_width;
  view->window.height = window_height;
  view->buffer.width = buffer_width;
  view->buffer.height = buffer_height;

  view->redraw = 1;
  if(view->locked) {
  if (view->locked) {
    return;
  }

@@ -321,15 +317,13 @@ void imv_viewport_update(struct imv_viewport *view,
  imv_viewport_rescale(view, image, scaling_mode);
}

int imv_viewport_needs_redraw(struct imv_viewport *view)
{
int imv_viewport_needs_redraw(struct imv_viewport *view) {
  int redraw = 0;
  if(view->redraw) {
  if (view->redraw) {
    redraw = 1;
    view->redraw = 0;
  }
  return redraw;
}


/* vim:set ts=2 sts=2 sw=2 et: */
diff --git a/src/viewport.h b/src/viewport.h
index a24113c..2244715 100644
--- a/src/viewport.h
+++ b/src/viewport.h
@@ -20,6 +20,11 @@ enum imv_zoom_source {
  IMV_ZOOM_KEYBOARD
};

enum imv_zoom_type {
  IMV_ZOOM_ABSOLUTE,
  IMV_ZOOM_RELATIVE
};

/* Creates an instance of imv_viewport */
struct imv_viewport *imv_viewport_create(int window_width, int window_height,
                                         int buffer_width, int buffer_height);
@@ -59,7 +64,7 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y,
/* Zoom the view by the given amount. imv_image* is used to get the image
 * dimensions */
void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image,
                       enum imv_zoom_source, int mouse_x, int mouse_y, int amount);
                       enum imv_zoom_source, enum imv_zoom_type, int mouse_x, int mouse_y, int amount);

/* Rotate the view by the given number of degrees */
void imv_viewport_rotate_by(struct imv_viewport *view, double degrees);
-- 
2.43.0