Mouse drag translates pointer position to image area
This makes mouse panning more direct and faster.
This commit is contained in:
parent
9b6acc781e
commit
e310136e02
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
VERSION := git-20170908
|
VERSION := git-20171004
|
||||||
|
|
||||||
all: sxiv
|
all: sxiv
|
||||||
|
|
||||||
|
73
commands.c
73
commands.c
@ -320,72 +320,41 @@ bool ci_scroll_to_edge(arg_t dir)
|
|||||||
return img_pan_edge(&img, dir);
|
return img_pan_edge(&img, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Xlib helper function for i_drag() */
|
|
||||||
Bool is_motionnotify(Display *d, XEvent *e, XPointer a)
|
|
||||||
{
|
|
||||||
return e != NULL && e->type == MotionNotify;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define WARP(x,y) \
|
|
||||||
XWarpPointer(win.env.dpy, None, win.xwin, 0, 0, 0, 0, x, y); \
|
|
||||||
ox = x, oy = y; \
|
|
||||||
break
|
|
||||||
|
|
||||||
bool ci_drag(arg_t _)
|
bool ci_drag(arg_t _)
|
||||||
{
|
{
|
||||||
int dx = 0, dy = 0, i, ox, oy, x, y;
|
int i, x, y;
|
||||||
|
float px, py;
|
||||||
unsigned int ui;
|
unsigned int ui;
|
||||||
bool dragging = true, next = false;
|
|
||||||
XEvent e;
|
XEvent e;
|
||||||
Window w;
|
Window w;
|
||||||
|
|
||||||
if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &ox, &oy, &ui))
|
if ((int)(img.w * img.zoom) < win.w && (int)(img.h * img.zoom) < win.h)
|
||||||
|
return false;
|
||||||
|
if (!XQueryPointer(win.env.dpy, win.xwin, &w, &w, &i, &i, &x, &y, &ui))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
win_set_cursor(&win, CURSOR_HAND);
|
win_set_cursor(&win, CURSOR_DRAG);
|
||||||
|
|
||||||
while (dragging) {
|
for (;;) {
|
||||||
if (!next)
|
px = MIN(MAX(0.0, x - win.w*0.1), win.w*0.8) / (win.w*0.8)
|
||||||
XMaskEvent(win.env.dpy,
|
* (win.w - img.w * img.zoom);
|
||||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
|
py = MIN(MAX(0.0, y - win.h*0.1), win.h*0.8) / (win.h*0.8)
|
||||||
switch (e.type) {
|
* (win.h - img.h * img.zoom);
|
||||||
case ButtonPress:
|
|
||||||
case ButtonRelease:
|
|
||||||
dragging = false;
|
|
||||||
break;
|
|
||||||
case MotionNotify:
|
|
||||||
x = e.xmotion.x;
|
|
||||||
y = e.xmotion.y;
|
|
||||||
|
|
||||||
/* wrap the mouse around */
|
if (img_pos(&img, px, py)) {
|
||||||
if (x <= 0) {
|
img_render(&img);
|
||||||
WARP(win.w - 2, y);
|
win_draw(&win);
|
||||||
} else if (x >= win.w - 1) {
|
|
||||||
WARP(1, y);
|
|
||||||
} else if (y <= 0) {
|
|
||||||
WARP(x, win.h - 2);
|
|
||||||
} else if (y >= win.h - 1) {
|
|
||||||
WARP(x, 1);
|
|
||||||
}
|
|
||||||
dx += x - ox;
|
|
||||||
dy += y - oy;
|
|
||||||
ox = x;
|
|
||||||
oy = y;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (dragging)
|
|
||||||
next = XCheckIfEvent(win.env.dpy, &e, is_motionnotify, None);
|
|
||||||
if ((!dragging || !next) && (dx != 0 || dy != 0)) {
|
|
||||||
if (img_move(&img, dx, dy)) {
|
|
||||||
img_render(&img);
|
|
||||||
win_draw(&win);
|
|
||||||
}
|
|
||||||
dx = dy = 0;
|
|
||||||
}
|
}
|
||||||
|
XMaskEvent(win.env.dpy,
|
||||||
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &e);
|
||||||
|
if (e.type == ButtonPress || e.type == ButtonRelease)
|
||||||
|
break;
|
||||||
|
while (XCheckTypedEvent(win.env.dpy, MotionNotify, &e));
|
||||||
|
x = e.xmotion.x;
|
||||||
|
y = e.xmotion.y;
|
||||||
}
|
}
|
||||||
win_set_cursor(&win, CURSOR_ARROW);
|
win_set_cursor(&win, CURSOR_ARROW);
|
||||||
set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
|
set_timeout(reset_cursor, TO_CURSOR_HIDE, true);
|
||||||
reset_timeout(redraw);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
11
image.c
11
image.c
@ -567,15 +567,15 @@ bool img_zoom_out(img_t *img)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool img_move(img_t *img, float dx, float dy)
|
bool img_pos(img_t *img, float x, float y)
|
||||||
{
|
{
|
||||||
float ox, oy;
|
float ox, oy;
|
||||||
|
|
||||||
ox = img->x;
|
ox = img->x;
|
||||||
oy = img->y;
|
oy = img->y;
|
||||||
|
|
||||||
img->x += dx;
|
img->x = x;
|
||||||
img->y += dy;
|
img->y = y;
|
||||||
|
|
||||||
img_check_pan(img, true);
|
img_check_pan(img, true);
|
||||||
|
|
||||||
@ -587,6 +587,11 @@ bool img_move(img_t *img, float dx, float dy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool img_move(img_t *img, float dx, float dy)
|
||||||
|
{
|
||||||
|
return img_pos(img, img->x + dx, img->y + dy);
|
||||||
|
}
|
||||||
|
|
||||||
bool img_pan(img_t *img, direction_t dir, int d)
|
bool img_pan(img_t *img, direction_t dir, int d)
|
||||||
{
|
{
|
||||||
/* d < 0: screen-wise
|
/* d < 0: screen-wise
|
||||||
|
1
image.h
1
image.h
@ -80,6 +80,7 @@ bool img_zoom(img_t*, float);
|
|||||||
bool img_zoom_in(img_t*);
|
bool img_zoom_in(img_t*);
|
||||||
bool img_zoom_out(img_t*);
|
bool img_zoom_out(img_t*);
|
||||||
|
|
||||||
|
bool img_pos(img_t*, float, float);
|
||||||
bool img_move(img_t*, float, float);
|
bool img_move(img_t*, float, float);
|
||||||
bool img_pan(img_t*, direction_t, int);
|
bool img_pan(img_t*, direction_t, int);
|
||||||
bool img_pan_edge(img_t*, direction_t);
|
bool img_pan_edge(img_t*, direction_t);
|
||||||
|
1
main.c
1
main.c
@ -741,6 +741,7 @@ void run(void)
|
|||||||
XPeekEvent(win.env.dpy, &nextev);
|
XPeekEvent(win.env.dpy, &nextev);
|
||||||
switch (ev.type) {
|
switch (ev.type) {
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
|
case MotionNotify:
|
||||||
discard = ev.type == nextev.type;
|
discard = ev.type == nextev.type;
|
||||||
break;
|
break;
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
|
2
types.h
2
types.h
@ -66,7 +66,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CURSOR_ARROW,
|
CURSOR_ARROW,
|
||||||
CURSOR_NONE,
|
CURSOR_NONE,
|
||||||
CURSOR_HAND,
|
CURSOR_DRAG,
|
||||||
CURSOR_WATCH
|
CURSOR_WATCH
|
||||||
} cursor_t;
|
} cursor_t;
|
||||||
|
|
||||||
|
10
window.c
10
window.c
@ -37,7 +37,7 @@ enum {
|
|||||||
|
|
||||||
static Cursor carrow;
|
static Cursor carrow;
|
||||||
static Cursor cnone;
|
static Cursor cnone;
|
||||||
static Cursor chand;
|
static Cursor cdrag;
|
||||||
static Cursor cwatch;
|
static Cursor cwatch;
|
||||||
static GC gc;
|
static GC gc;
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ void win_open(win_t *win)
|
|||||||
PointerMotionMask | StructureNotifyMask);
|
PointerMotionMask | StructureNotifyMask);
|
||||||
|
|
||||||
carrow = XCreateFontCursor(e->dpy, XC_left_ptr);
|
carrow = XCreateFontCursor(e->dpy, XC_left_ptr);
|
||||||
chand = XCreateFontCursor(e->dpy, XC_fleur);
|
cdrag = XCreateFontCursor(e->dpy, XC_dotbox);
|
||||||
cwatch = XCreateFontCursor(e->dpy, XC_watch);
|
cwatch = XCreateFontCursor(e->dpy, XC_watch);
|
||||||
|
|
||||||
if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), "black",
|
if (XAllocNamedColor(e->dpy, DefaultColormap(e->dpy, e->scr), "black",
|
||||||
@ -277,7 +277,7 @@ CLEANUP void win_close(win_t *win)
|
|||||||
{
|
{
|
||||||
XFreeCursor(win->env.dpy, carrow);
|
XFreeCursor(win->env.dpy, carrow);
|
||||||
XFreeCursor(win->env.dpy, cnone);
|
XFreeCursor(win->env.dpy, cnone);
|
||||||
XFreeCursor(win->env.dpy, chand);
|
XFreeCursor(win->env.dpy, cdrag);
|
||||||
XFreeCursor(win->env.dpy, cwatch);
|
XFreeCursor(win->env.dpy, cwatch);
|
||||||
|
|
||||||
XFreeGC(win->env.dpy, gc);
|
XFreeGC(win->env.dpy, gc);
|
||||||
@ -465,8 +465,8 @@ void win_set_cursor(win_t *win, cursor_t cursor)
|
|||||||
case CURSOR_NONE:
|
case CURSOR_NONE:
|
||||||
XDefineCursor(win->env.dpy, win->xwin, cnone);
|
XDefineCursor(win->env.dpy, win->xwin, cnone);
|
||||||
break;
|
break;
|
||||||
case CURSOR_HAND:
|
case CURSOR_DRAG:
|
||||||
XDefineCursor(win->env.dpy, win->xwin, chand);
|
XDefineCursor(win->env.dpy, win->xwin, cdrag);
|
||||||
break;
|
break;
|
||||||
case CURSOR_WATCH:
|
case CURSOR_WATCH:
|
||||||
XDefineCursor(win->env.dpy, win->xwin, cwatch);
|
XDefineCursor(win->env.dpy, win->xwin, cwatch);
|
||||||
|
Loading…
Reference in New Issue
Block a user