I have been using the touch navigation PR for about 2 years now and it works flawlessly (with the fix posted later in the comments) So I rebased it on master's HEAD from the new sourcehut repo. I am not really the one who wrote the code and I tried to make that clear in the commits messages. Though I did not use the name and email address from the original author for privacy reasons, only their github use names. If you prefer I could try to reach out to the two authors to get there aproval before this get merged. (if it does gets marged, in the ~2 years I have been using it I can't seem to recal ever encountering a bug 🙃) Nicolai Dagestad (2): Enabling touch navigation Fix the jump when switching from zoom to drag with touch src/.editorconfig | 3 + src/imv.c | 64 +++++++++- src/viewport.c | 85 ++++++++----- src/viewport.h | 15 ++- src/window.h | 17 +++ src/wl_window.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 449 insertions(+), 32 deletions(-) create mode 100644 src/.editorconfig -- 2.35.1
I just tried out the patch and there's two things I noticed immeditately. 1. Dragging the image with one finger (like scrolling) moves it slower than I move my finger over the screen. Almost as if the speed was reduced by some coefficient. I wonder if this is the effect of DPI scaling on Wayland (my screen is scaled by 1.4, since it's high DPI), I'm running Sway.
You seem quite right about that, when changing the scale things feel really more slugish. As I said, I am not the original author of these patches but I can have a look at the code to see if I can spot the culprit. But more generally I fell like panning the image with touch is lagging behind the touchpoint, whereas with the mouse it is more or instantaneous. So that would also need to be reworked. I also notice that the jumping mentioned in the seccond patch is still present to some extent, so maybe evrything just need to be reworked a little ¯\_(ツ)_/¯
Could out please test it with output <your output> scale 1.4 in ~/.config/sway/config? 2. When you zoom on image on Android or iOS with two fingers it usually allows you to move it at the same time. Feels a bit unnatural when it doesn't happen here, imv seems to either zoom or move the image but not simultaneously. How expensive would it be to allow both simultaneously? (This one is more of a wish, I don't think this should block the patches from being merged.)
This will be a matter of preference I think, for my part I usually lift one finger before moving the image no my phone so the current behaviour didn't bother me, but I understand the will to have a similar behaviour to smartphone, they are after all the way most of us usualy interact most with touchscreens. Anyways, I am gald to see that I am not the only one interested in having touch support for imv, and since I also plan on trying to use a linux phone as my daily driver in the not so far future, it would be really nice to have it in my favourite image viewer ❤️
Ivan
Hi On Mon May 30, 2022 at 2:16 PM CEST, Ivan Oleynikov wrote:
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~exec64/imv-devel/patches/29247/mbox | git am -3Learn more about email & git
* tap to left/right side to navigate to previous/next image * tap into the middle to show overlay * move single touch to pan the image * pinch in/out to zoom This is the PR[1] by gg-rewrite[2] for adding touch navigation from github rebased on HEAD from master. 1: https://github.com/eXeC64/imv/pull/245 2: https://github.com/gg-rewrite --- src/imv.c | 60 +++++++++++ src/viewport.c | 51 ++++++--- src/viewport.h | 11 +- src/window.h | 17 +++ src/wl_window.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 404 insertions(+), 13 deletions(-) diff --git a/src/imv.c b/src/imv.c index 8380a12..4ca12a7 100644 --- a/src/imv.c +++ b/src/imv.c @@ -192,6 +192,12 @@ struct imv { /* if reading an image from stdin, this is the buffer for it */ void *stdin_image_data; size_t stdin_image_data_len; + + /* initial scale for correct pinch zoom*/ + double initial_zoom; + + /* initial view offset for correct touch pan*/ + int initial_view_x, initial_view_y; }; static void command_quit(struct list *args, const char *argstr, void *data); @@ -472,6 +478,60 @@ static void event_handler(void *data, const struct imv_event *e) case IMV_EVENT_CUSTOM: consume_internal_event(imv, e->data.custom); break; + case IMV_EVENT_TOUCH_TAP: + { + double current_scale; + imv_viewport_get_scale(imv->view, ¤t_scale); + double default_scale = + imv_viewport_get_scale_to_window(imv->view, imv->current_image); + double x = e->data.touch_tap.x; + double width = e->data.touch_tap.width; + if (current_scale <= default_scale) { + if (x < width / 4) { + imv_navigator_select_rel(imv->navigator, -1); + } else if (x > width * 3 / 4) { + imv_navigator_select_rel(imv->navigator, 1); + } + } + if (x > width / 4 && x < width * 3 / 4) { + imv->overlay.enabled = !imv->overlay.enabled; + imv->need_redraw = true; + } + } + break; + case IMV_EVENT_TOUCH_ZOOM_START: + { + double current_scale; + imv_viewport_get_scale(imv->view, ¤t_scale); + imv->initial_zoom = current_scale; + } + break; + case IMV_EVENT_TOUCH_ZOOM_CHANGE: + { + double new_zoom = imv->initial_zoom * e->data.touch_zoom.zoom; + int new_zoom_int = (int) (new_zoom * 100); + imv_viewport_zoom(imv->view, imv->current_image, IMV_ZOOM_TOUCH, + e->data.touch_zoom.x, e->data.touch_zoom.y, + new_zoom_int); + } + break; + case IMV_EVENT_TOUCH_PAN_START: + { + int x,y; + imv_viewport_get_offset(imv->view, &x, &y); + imv->initial_view_x = x; + imv->initial_view_y = y; + } + break; + case IMV_EVENT_TOUCH_PAN_CHANGE: + { + imv_viewport_move_relative(imv->view, + imv->initial_view_x, + imv->initial_view_y, + (int) (e->data.touch_pan.current_x - e->data.touch_pan.initial_x), + (int) (e->data.touch_pan.current_y - e->data.touch_pan.initial_y), + imv->current_image); + } default: break; } diff --git a/src/viewport.c b/src/viewport.c index 095bf71..e226615 100644 --- a/src/viewport.c +++ b/src/viewport.c @@ -110,14 +110,9 @@ void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_f view->pan_factor_y = pan_factor_y; } -void imv_viewport_move(struct imv_viewport *view, int x, int y, +void imv_viewport_keep_onscreen(struct imv_viewport *view, const struct imv_image *image) { - input_xy_to_render_xy(view, &x, &y); - view->x += x; - view->y += y; - view->redraw = 1; - view->locked = 1; int w = (int)(imv_image_width(image) * view->scale); int h = (int)(imv_image_height(image) * view->scale); if (view->x < -w) { @@ -134,6 +129,29 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y, } } +void imv_viewport_move(struct imv_viewport *view, int x, int y, + const struct imv_image *image) +{ + input_xy_to_render_xy(view, &x, &y); + view->x += x; + view->y += y; + view->redraw = 1; + view->locked = 1; + imv_viewport_keep_onscreen(view, image); +} + +void imv_viewport_move_relative(struct imv_viewport *view, + int initial_x, int initial_y, + int delta_x, int delta_y, + struct imv_image *image) +{ + view->x = initial_x + delta_x; + view->y = initial_y + delta_y; + view->redraw = 1; + view->locked = 1; + imv_viewport_keep_onscreen(view, image); +} + 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) { @@ -144,7 +162,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 || src == IMV_ZOOM_TOUCH) { input_xy_to_render_xy(view, &mouse_x, &mouse_y); x = mouse_x - view->x; y = mouse_y - view->y; @@ -160,8 +178,12 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image, 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; + if (src == IMV_ZOOM_TOUCH) { + view->scale = amount / 100.0f; + } else { + double delta_scale = 0.04 * view->buffer.width * amount / image_width; + view->scale += delta_scale; + } const double min_scale = 0.1; const double max_scale = 100; @@ -245,7 +267,8 @@ 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) +double imv_viewport_get_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); @@ -254,12 +277,16 @@ void imv_viewport_scale_to_window(struct imv_viewport *view, const struct imv_im if(window_aspect > image_aspect) { /* Image will become too tall before it becomes too wide */ - view->scale = (double)view->buffer.height / (double)image_height; + return (double)view->buffer.height / (double)image_height; } else { /* Image will become too wide before it becomes too tall */ - view->scale = (double)view->buffer.width / (double)image_width; + return (double)view->buffer.width / (double)image_width; } +} +void imv_viewport_scale_to_window(struct imv_viewport *view, const struct imv_image *image) +{ + view->scale = imv_viewport_get_scale_to_window(view, image); imv_viewport_center(view, image); view->locked = 0; } diff --git a/src/viewport.h b/src/viewport.h index a24113c..b54cf06 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -17,7 +17,8 @@ enum scaling_mode { /* Used to signify how a a user requested a zoom */ enum imv_zoom_source { IMV_ZOOM_MOUSE, - IMV_ZOOM_KEYBOARD + IMV_ZOOM_KEYBOARD, + IMV_ZOOM_TOUCH }; /* Creates an instance of imv_viewport */ @@ -56,6 +57,10 @@ void imv_viewport_set_default_pan_factor(struct imv_viewport *view, double pan_f void imv_viewport_move(struct imv_viewport *view, int x, int y, const struct imv_image *image); +/* Pan the view relatively by coordinates */ +void imv_viewport_move_relative(struct imv_viewport *view, int initial_x, + int initial_y, int delta_x, int delta_y, struct imv_image *image); + /* 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, @@ -84,6 +89,10 @@ void imv_viewport_center(struct imv_viewport *view, void imv_viewport_scale_to_actual(struct imv_viewport *view, const struct imv_image *image); +/*get scale when scaled to window*/ +double imv_viewport_get_scale_to_window(struct imv_viewport *view, + const struct imv_image *image); + /* Scale the view so that the image fits in the window */ void imv_viewport_scale_to_window(struct imv_viewport *view, const struct imv_image *image); diff --git a/src/window.h b/src/window.h index a4786bb..40d5b74 100644 --- a/src/window.h +++ b/src/window.h @@ -13,6 +13,11 @@ enum imv_event_type { IMV_EVENT_MOUSE_MOTION, IMV_EVENT_MOUSE_BUTTON, IMV_EVENT_MOUSE_SCROLL, + IMV_EVENT_TOUCH_TAP, + IMV_EVENT_TOUCH_ZOOM_START, + IMV_EVENT_TOUCH_ZOOM_CHANGE, + IMV_EVENT_TOUCH_PAN_START, + IMV_EVENT_TOUCH_PAN_CHANGE, IMV_EVENT_CUSTOM }; @@ -42,6 +47,18 @@ struct imv_event { struct { double dx, dy; } mouse_scroll; + struct { + double x,y; + int height, width; + } touch_tap; + struct { + double x,y; + double zoom; + } touch_zoom; + struct { + double initial_x, initial_y; + double current_x, current_y; + } touch_pan; void *custom; } data; }; diff --git a/src/wl_window.c b/src/wl_window.c index 5efa42f..49bf35d 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -20,6 +20,27 @@ #define imv_min(a,b) ((a) > (b) ? (b) : (a)) +struct imv_point { + double x; + double y; +}; + +struct imv_touch_point { + struct wl_list link; + struct imv_point initial, current; + int32_t id; +}; + + +enum imv_touch_state { + TOUCH_STATE_IDLE, + TOUCH_STATE_TAP, + TOUCH_STATE_PAN_START, + TOUCH_STATE_PAN_CHANGE, + TOUCH_STATE_ZOOM_START, + TOUCH_STATE_ZOOM_CHANGE +}; + struct imv_window { struct wl_display *wl_display; struct wl_registry *wl_registry; @@ -31,6 +52,7 @@ struct imv_window { struct wl_seat *wl_seat; struct wl_keyboard *wl_keyboard; struct wl_pointer *wl_pointer; + struct wl_touch *wl_touch; EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; @@ -72,6 +94,242 @@ struct imv_window { double dy; } scroll; } pointer; + + struct { + struct wl_list points; + enum imv_touch_state state; + } touch; + +}; + +static void touch_down(void *data, struct wl_touch *touch, uint32_t serial, + uint32_t time, struct wl_surface *surface, int32_t id, + wl_fixed_t surface_x, wl_fixed_t surface_y) +{ + (void)touch; + (void)serial; + (void)surface; + + struct imv_window *window = data; + + uint32_t num_points = wl_list_length(&window->touch.points); + + if (num_points == 2) { + (void)id; + (void)time; + (void)surface_x; + (void)surface_y; + return; + } + if (num_points == 0) { + window->touch.state = TOUCH_STATE_TAP; + } + + double x = wl_fixed_to_double(surface_x); + double y = wl_fixed_to_double(surface_y); + + struct imv_touch_point *point = calloc(1, sizeof(struct imv_touch_point)); + + point->initial.x = x; + point->initial.y = y; + point->current.x = x; + point->current.y = y; + point->id = id; + + wl_list_insert(&window->touch.points, &point->link); +} + +static void touch_up(void *data, struct wl_touch *touch, uint32_t serial, + uint32_t time, int32_t id) +{ + (void)touch; + (void)serial; + + struct imv_window *window = data; + + struct imv_touch_point *point, *tmp; + wl_list_for_each_safe(point, tmp, &window->touch.points, link) { + if (point->id == id) { + + uint32_t num_points = wl_list_length(&window->touch.points); + if (num_points == 1 + && window->touch.state == TOUCH_STATE_TAP) { + + struct imv_event e = { + .type = IMV_EVENT_TOUCH_TAP, + .data = { + .touch_tap = { + .x = point->current.x, + .y = point->current.y, + .height = window->height, + .width = window->width + } + } + }; + imv_window_push_event(window, &e); + + window->touch.state = TOUCH_STATE_IDLE; + } else if (num_points == 2) { + window->touch.state = TOUCH_STATE_PAN_START; + } + + wl_list_remove(&point->link); + } + } +} + +static inline double measure_distance(double x1, double y1, + double x2, double y2) +{ + return sqrt((x2-x1) * (x2-x1) + (y2 - y1) * (y2-y1)); +} + +static void touch_motion(void *data, struct wl_touch *touch, uint32_t time, + int32_t id, wl_fixed_t x, wl_fixed_t y) +{ + (void)touch; + + struct imv_window *window = data; + struct imv_touch_point *point; + wl_list_for_each(point, &window->touch.points, link) { + if (point->id == id) { + point->current.x = wl_fixed_to_double(x); + point->current.y = wl_fixed_to_double(y); + + uint32_t num_points = wl_list_length(&window->touch.points); + if (num_points == 1) { + double distance = + measure_distance(point->current.x, + point->current.y, + point->initial.x, + point->initial.y); + + if (distance > 10.0) { + enum imv_event_type event_type; + switch (window->touch.state) { + case TOUCH_STATE_PAN_START: + case TOUCH_STATE_PAN_CHANGE: + { + window->touch.state = TOUCH_STATE_PAN_CHANGE; + event_type = IMV_EVENT_TOUCH_PAN_CHANGE; + } + break; + default: + { + window->touch.state = TOUCH_STATE_PAN_START; + event_type = IMV_EVENT_TOUCH_PAN_START; + } + break; + } + + struct imv_event e = { + .type = event_type, + .data = { + .touch_pan = { + .initial_x = (int) point->initial.x, + .initial_y = (int) point->initial.y, + .current_x = (int) point->current.x, + .current_y = (int) point->current.y + } + } + }; + imv_window_push_event(window, &e); + } + } else { + struct imv_touch_point *point2; + wl_list_for_each(point2, &window->touch.points, link) { + if (point2->id != point->id) { + double initial_distance = + measure_distance(point->initial.x, + point->initial.y, + point2->initial.x, + point2->initial.y); + double current_distance = + measure_distance(point->current.x, + point->current.y, + point2->current.x, + point2->current.y); + + double zoom_ratio = current_distance / initial_distance; + double cx = fabs(point->initial.x + point2->initial.x)/2; + double cy = fabs(point->initial.y + point2->initial.y)/2; + + enum imv_event_type event_type; + + switch (window->touch.state) { + case TOUCH_STATE_ZOOM_CHANGE: + case TOUCH_STATE_ZOOM_START: + event_type = IMV_EVENT_TOUCH_ZOOM_CHANGE; + window->touch.state = TOUCH_STATE_ZOOM_CHANGE; + break; + default: + event_type = IMV_EVENT_TOUCH_ZOOM_START; + window->touch.state = TOUCH_STATE_ZOOM_START; + break; + }; + + struct imv_event e = { + .type = event_type, + .data = { + .touch_zoom = { + .x = cx, + .y = cy, + .zoom = zoom_ratio + } + } + }; + imv_window_push_event(window, &e); + + break; + } + } + } + break; + } + } + +} + +static void touch_frame(void *data, struct wl_touch *touch) +{ + (void)data; + (void)touch; +} + +static void touch_orientation(void *data, struct wl_touch *touch, int32_t id, + wl_fixed_t orientation) +{ + (void)data; + (void)touch; + (void)id; + (void)orientation; +} + +static void touch_cancel(void *data, struct wl_touch *touch) +{ + (void)data; + (void)touch; +} + +static void touch_shape(void *data, struct wl_touch *touch, int32_t id, + wl_fixed_t major, wl_fixed_t minor) +{ + (void)data; + (void)touch; + (void)id; + (void)major; + (void)minor; +} + +static const struct wl_touch_listener touch_listener = +{ + .down = touch_down, + .up = touch_up, + .motion = touch_motion, + .frame = touch_frame, + .orientation = touch_orientation, + .shape = touch_shape, + .cancel = touch_cancel, }; struct output_data { @@ -436,6 +694,18 @@ static void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabil window->wl_keyboard = NULL; } } + + if (capabilities & WL_SEAT_CAPABILITY_TOUCH) { + if (!window->wl_touch) { + window->wl_touch = wl_seat_get_touch(window->wl_seat); + wl_touch_add_listener(window->wl_touch, &touch_listener, window); + } else { + if (window->wl_touch) { + wl_touch_release(window->wl_touch); + window->wl_touch = NULL; + } + } + } } static void seat_name(void *data, struct wl_seat *seat, const char *name) @@ -738,6 +1008,9 @@ static void shutdown_wayland(struct imv_window *window) { close(window->pipe_fds[0]); close(window->pipe_fds[1]); + if (window->wl_touch) { + wl_touch_destroy(window->wl_touch); + } if (window->wl_pointer) { wl_pointer_destroy(window->wl_pointer); } @@ -790,6 +1063,10 @@ struct imv_window *imv_window_create(int width, int height, const char *title) window->keyboard = imv_keyboard_create(); assert(window->keyboard); + + wl_list_init(&window->touch.points); + window->touch.state = TOUCH_STATE_IDLE; + window->wl_outputs = list_create(); connect_to_wayland(window); create_window(window, width, height, title); @@ -808,6 +1085,7 @@ void imv_window_free(struct imv_window *window) { timer_delete(window->timer_id); imv_keyboard_free(window->keyboard); + wl_list_remove(&window->touch.points); shutdown_wayland(window); list_deep_free(window->wl_outputs); free(window); -- 2.35.1
When using touch, if you the zoom image the image, then lift one finger and start draging the remaining finger, the image will jump mostly out of the viewport before starting the zoom. This is the patch proposed by mlngh[1] on the github PR regarding enabling touch navigation[2] 1: https://github.com/mlngh 2: https://github.com/eXeC64/imv/pull/245 --- src/.editorconfig | 3 + src/imv.c | 6 +- src/viewport.c | 42 ++++---- src/viewport.h | 8 +- src/wl_window.c | 249 +++++++++++++++++++++++++--------------------- 5 files changed, 167 insertions(+), 141 deletions(-) create mode 100644 src/.editorconfig diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 0000000..7f9845b --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,3 @@ +[*.{c,h}] +indent_style = space +indent_size = 2 diff --git a/src/imv.c b/src/imv.c index 4ca12a7..066a062 100644 --- a/src/imv.c +++ b/src/imv.c @@ -472,7 +472,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); + x, y, -e->data.mouse_scroll.dy, false); } break; case IMV_EVENT_CUSTOM: @@ -512,7 +512,7 @@ static void event_handler(void *data, const struct imv_event *e) int new_zoom_int = (int) (new_zoom * 100); imv_viewport_zoom(imv->view, imv->current_image, IMV_ZOOM_TOUCH, e->data.touch_zoom.x, e->data.touch_zoom.y, - new_zoom_int); + new_zoom_int, true); } break; case IMV_EVENT_TOUCH_PAN_START: @@ -1772,7 +1772,7 @@ 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, 0, 0, amount, false); } } } diff --git a/src/viewport.c b/src/viewport.c index e226615..f7230ab 100644 --- a/src/viewport.c +++ b/src/viewport.c @@ -14,7 +14,7 @@ struct imv_viewport { struct { int width, height; } buffer; /* rendering buffer dimensions */ - int x, y; + double x, y; double pan_factor_x, pan_factor_y; int redraw; int playing; @@ -141,9 +141,9 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y, } void imv_viewport_move_relative(struct imv_viewport *view, - int initial_x, int initial_y, - int delta_x, int delta_y, - struct imv_image *image) + int initial_x, int initial_y, + int delta_x, int delta_y, + struct imv_image *image) { view->x = initial_x + delta_x; view->y = initial_y + delta_y; @@ -153,7 +153,8 @@ void imv_viewport_move_relative(struct imv_viewport *view, } 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, int mouse_x, int mouse_y, int amount, + bool ignore_edges) { double prev_scale = view->scale; int x, y; @@ -192,20 +193,21 @@ void imv_viewport_zoom(struct imv_viewport *view, const struct imv_image *image, } 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(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_height < view->buffer.height) { - y = scaled_height/2; + if(!ignore_edges) { + 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; + } + } else { + if(scaled_width < view->buffer.width) { + x = scaled_width/2; + } + if(scaled_height < view->buffer.height) { + y = scaled_height/2; + } } } @@ -268,7 +270,7 @@ void imv_viewport_center(struct imv_viewport *view, const struct imv_image *imag } double imv_viewport_get_scale_to_window(struct imv_viewport *view, - const struct imv_image *image) + const struct imv_image *image) { const int image_width = imv_image_width(image); const int image_height = imv_image_height(image); diff --git a/src/viewport.h b/src/viewport.h index b54cf06..08c6299 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -59,12 +59,14 @@ void imv_viewport_move(struct imv_viewport *view, int x, int y, /* Pan the view relatively by coordinates */ void imv_viewport_move_relative(struct imv_viewport *view, int initial_x, - int initial_y, int delta_x, int delta_y, struct imv_image *image); + int initial_y, int delta_x, int delta_y, + struct imv_image *image); /* 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, int mouse_x, int mouse_y, int amount, + bool ignore_edges); /* Rotate the view by the given number of degrees */ void imv_viewport_rotate_by(struct imv_viewport *view, double degrees); @@ -91,7 +93,7 @@ void imv_viewport_scale_to_actual(struct imv_viewport *view, /*get scale when scaled to window*/ double imv_viewport_get_scale_to_window(struct imv_viewport *view, - const struct imv_image *image); + const struct imv_image *image); /* Scale the view so that the image fits in the window */ void imv_viewport_scale_to_window(struct imv_viewport *view, diff --git a/src/wl_window.c b/src/wl_window.c index 49bf35d..d97906b 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -33,12 +33,12 @@ struct imv_touch_point { enum imv_touch_state { - TOUCH_STATE_IDLE, - TOUCH_STATE_TAP, - TOUCH_STATE_PAN_START, - TOUCH_STATE_PAN_CHANGE, - TOUCH_STATE_ZOOM_START, - TOUCH_STATE_ZOOM_CHANGE + TOUCH_STATE_IDLE, + TOUCH_STATE_TAP, + TOUCH_STATE_PAN_START, + TOUCH_STATE_PAN_CHANGE, + TOUCH_STATE_ZOOM_START, + TOUCH_STATE_ZOOM_CHANGE }; struct imv_window { @@ -96,8 +96,8 @@ struct imv_window { } pointer; struct { - struct wl_list points; - enum imv_touch_state state; + struct wl_list points; + enum imv_touch_state state; } touch; }; @@ -115,14 +115,14 @@ static void touch_down(void *data, struct wl_touch *touch, uint32_t serial, uint32_t num_points = wl_list_length(&window->touch.points); if (num_points == 2) { - (void)id; - (void)time; - (void)surface_x; - (void)surface_y; - return; + (void)id; + (void)time; + (void)surface_x; + (void)surface_y; + return; } if (num_points == 0) { - window->touch.state = TOUCH_STATE_TAP; + window->touch.state = TOUCH_STATE_TAP; } double x = wl_fixed_to_double(surface_x); @@ -153,33 +153,52 @@ static void touch_up(void *data, struct wl_touch *touch, uint32_t serial, uint32_t num_points = wl_list_length(&window->touch.points); if (num_points == 1 - && window->touch.state == TOUCH_STATE_TAP) { + && window->touch.state == TOUCH_STATE_TAP) { - struct imv_event e = { + struct imv_event e = { .type = IMV_EVENT_TOUCH_TAP, - .data = { - .touch_tap = { - .x = point->current.x, - .y = point->current.y, - .height = window->height, - .width = window->width - } - } - }; - imv_window_push_event(window, &e); - - window->touch.state = TOUCH_STATE_IDLE; + .data = { + .touch_tap = { + .x = point->current.x, + .y = point->current.y, + .height = window->height, + .width = window->width + } + } + }; + imv_window_push_event(window, &e); + + window->touch.state = TOUCH_STATE_IDLE; } else if (num_points == 2) { - window->touch.state = TOUCH_STATE_PAN_START; + window->touch.state = TOUCH_STATE_PAN_START; } wl_list_remove(&point->link); } } + /* if after touch up we have one point, reinitiate pan */ + if (wl_list_length(&window->touch.points) == 1) { + wl_list_for_each_safe(point, tmp, &window->touch.points, link) { + point->initial.x = point->current.x; + point->initial.y = point->current.y; + struct imv_event e = { + .type = IMV_EVENT_TOUCH_PAN_START, + .data = { + .touch_pan = { + .initial_x = (int) point->initial.x * window->scale, + .initial_y = (int) point->initial.y * window->scale, + .current_x = (int) point->current.x * window->scale, + .current_y = (int) point->current.y * window->scale + } + } + }; + imv_window_push_event(window, &e); + } + } } static inline double measure_distance(double x1, double y1, - double x2, double y2) + double x2, double y2) { return sqrt((x2-x1) * (x2-x1) + (y2 - y1) * (y2-y1)); } @@ -198,91 +217,91 @@ static void touch_motion(void *data, struct wl_touch *touch, uint32_t time, uint32_t num_points = wl_list_length(&window->touch.points); if (num_points == 1) { - double distance = - measure_distance(point->current.x, - point->current.y, - point->initial.x, - point->initial.y); - - if (distance > 10.0) { - enum imv_event_type event_type; - switch (window->touch.state) { - case TOUCH_STATE_PAN_START: - case TOUCH_STATE_PAN_CHANGE: - { - window->touch.state = TOUCH_STATE_PAN_CHANGE; - event_type = IMV_EVENT_TOUCH_PAN_CHANGE; - } - break; - default: - { - window->touch.state = TOUCH_STATE_PAN_START; - event_type = IMV_EVENT_TOUCH_PAN_START; - } - break; - } - - struct imv_event e = { - .type = event_type, - .data = { - .touch_pan = { - .initial_x = (int) point->initial.x, - .initial_y = (int) point->initial.y, - .current_x = (int) point->current.x, - .current_y = (int) point->current.y - } - } - }; - imv_window_push_event(window, &e); - } + double distance = + measure_distance(point->current.x, + point->current.y, + point->initial.x, + point->initial.y); + + if (distance > 10.0) { + enum imv_event_type event_type; + switch (window->touch.state) { + case TOUCH_STATE_PAN_START: + case TOUCH_STATE_PAN_CHANGE: + { + window->touch.state = TOUCH_STATE_PAN_CHANGE; + event_type = IMV_EVENT_TOUCH_PAN_CHANGE; + } + break; + default: + { + window->touch.state = TOUCH_STATE_PAN_START; + event_type = IMV_EVENT_TOUCH_PAN_START; + } + break; + } + + struct imv_event e = { + .type = event_type, + .data = { + .touch_pan = { + .initial_x = (int) point->initial.x, + .initial_y = (int) point->initial.y, + .current_x = (int) point->current.x, + .current_y = (int) point->current.y + } + } + }; + imv_window_push_event(window, &e); + } } else { struct imv_touch_point *point2; - wl_list_for_each(point2, &window->touch.points, link) { - if (point2->id != point->id) { - double initial_distance = - measure_distance(point->initial.x, - point->initial.y, - point2->initial.x, - point2->initial.y); - double current_distance = - measure_distance(point->current.x, - point->current.y, - point2->current.x, - point2->current.y); - - double zoom_ratio = current_distance / initial_distance; - double cx = fabs(point->initial.x + point2->initial.x)/2; - double cy = fabs(point->initial.y + point2->initial.y)/2; - - enum imv_event_type event_type; - - switch (window->touch.state) { - case TOUCH_STATE_ZOOM_CHANGE: - case TOUCH_STATE_ZOOM_START: - event_type = IMV_EVENT_TOUCH_ZOOM_CHANGE; - window->touch.state = TOUCH_STATE_ZOOM_CHANGE; - break; - default: - event_type = IMV_EVENT_TOUCH_ZOOM_START; - window->touch.state = TOUCH_STATE_ZOOM_START; - break; - }; - - struct imv_event e = { - .type = event_type, - .data = { - .touch_zoom = { - .x = cx, - .y = cy, - .zoom = zoom_ratio - } - } - }; - imv_window_push_event(window, &e); - - break; - } - } + wl_list_for_each(point2, &window->touch.points, link) { + if (point2->id != point->id) { + double initial_distance = + measure_distance(point->initial.x, + point->initial.y, + point2->initial.x, + point2->initial.y); + double current_distance = + measure_distance(point->current.x, + point->current.y, + point2->current.x, + point2->current.y); + + double zoom_ratio = current_distance / initial_distance; + double cx = fabs(point->initial.x + point2->initial.x)/2; + double cy = fabs(point->initial.y + point2->initial.y)/2; + + enum imv_event_type event_type; + + switch (window->touch.state) { + case TOUCH_STATE_ZOOM_CHANGE: + case TOUCH_STATE_ZOOM_START: + event_type = IMV_EVENT_TOUCH_ZOOM_CHANGE; + window->touch.state = TOUCH_STATE_ZOOM_CHANGE; + break; + default: + event_type = IMV_EVENT_TOUCH_ZOOM_START; + window->touch.state = TOUCH_STATE_ZOOM_START; + break; + }; + + struct imv_event e = { + .type = event_type, + .data = { + .touch_zoom = { + .x = cx, + .y = cy, + .zoom = zoom_ratio + } + } + }; + imv_window_push_event(window, &e); + + break; + } + } } break; } @@ -701,8 +720,8 @@ static void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabil wl_touch_add_listener(window->wl_touch, &touch_listener, window); } else { if (window->wl_touch) { - wl_touch_release(window->wl_touch); - window->wl_touch = NULL; + wl_touch_release(window->wl_touch); + window->wl_touch = NULL; } } } -- 2.35.1