@@ -123,11 +123,13 @@ void img_render(img_t *img, win_t *win) { | |||
/* center image in window */ | |||
img->x = (win->w - img->w * img->zoom) / 2; | |||
img->y = (win->h - img->h * img->zoom) / 2; | |||
} else { | |||
/* typically after zooming and panning */ | |||
} else if (img->cp) { | |||
/* only useful after zooming */ | |||
img_check_pan(img, win); | |||
img->cp = 0; | |||
} | |||
/* calculate source and destination offsets */ | |||
if (img->x < 0) { | |||
sx = -img->x / img->zoom; | |||
sw = win->w / img->zoom; | |||
@@ -172,6 +174,7 @@ int img_zoom(img_t *img, float z) { | |||
img->x -= (img->w * z - img->w * img->zoom) / 2; | |||
img->y -= (img->h * z - img->h * img->zoom) / 2; | |||
img->zoom = z; | |||
img->cp = 1; | |||
return 1; | |||
} else { | |||
return 0; | |||
@@ -205,3 +208,32 @@ int img_zoom_out(img_t *img) { | |||
return 0; | |||
} | |||
int img_pan(img_t *img, win_t *win, pandir_t dir) { | |||
int ox, oy; | |||
if (!img || !win) | |||
return 0; | |||
ox = img->x; | |||
oy = img->y; | |||
switch (dir) { | |||
case PAN_LEFT: | |||
img->x += win->w / 5; | |||
break; | |||
case PAN_RIGHT: | |||
img->x -= win->w / 5; | |||
break; | |||
case PAN_UP: | |||
img->y += win->h / 5; | |||
break; | |||
case PAN_DOWN: | |||
img->y -= win->h / 5; | |||
break; | |||
} | |||
img_check_pan(img, win); | |||
return ox != img->x || oy != img->y; | |||
} |
@@ -27,9 +27,17 @@ enum scalemode { | |||
SCALE_ZOOM | |||
}; | |||
typedef enum pandir_e { | |||
PAN_LEFT = 0, | |||
PAN_RIGHT, | |||
PAN_UP, | |||
PAN_DOWN | |||
} pandir_t; | |||
typedef struct img_s { | |||
float zoom; | |||
unsigned char re; | |||
unsigned char cp; | |||
int x; | |||
int y; | |||
int w; | |||
@@ -45,4 +53,6 @@ void img_render(img_t*, win_t*); | |||
int img_zoom_in(img_t*); | |||
int img_zoom_out(img_t*); | |||
int img_pan(img_t*, win_t*, pandir_t); | |||
#endif /* IMAGE_H */ |
@@ -108,13 +108,14 @@ void cleanup() { | |||
void on_keypress(XEvent *ev) { | |||
char key; | |||
int len; | |||
KeySym keysym; | |||
int changed; | |||
if (!ev) | |||
return; | |||
len = XLookupString(&ev->xkey, &key, 1, &keysym, NULL); | |||
XLookupString(&ev->xkey, &key, 1, &keysym, NULL); | |||
changed = 0; | |||
switch (keysym) { | |||
case XK_Escape: | |||
@@ -122,48 +123,58 @@ void on_keypress(XEvent *ev) { | |||
exit(2); | |||
case XK_space: | |||
key = 'n'; | |||
len = 1; | |||
break; | |||
case XK_BackSpace: | |||
key = 'p'; | |||
len = 1; | |||
break; | |||
} | |||
if (!len) | |||
return; | |||
switch (key) { | |||
case 'q': | |||
cleanup(); | |||
exit(0); | |||
/* navigate through image list */ | |||
case 'n': | |||
if (fileidx + 1 < filecnt) { | |||
img_load(&img, filenames[++fileidx]); | |||
img_render(&img, &win); | |||
update_title(); | |||
changed = 1; | |||
} | |||
break; | |||
case 'p': | |||
if (fileidx > 0) { | |||
img_load(&img, filenames[--fileidx]); | |||
img_render(&img, &win); | |||
update_title(); | |||
changed = 1; | |||
} | |||
break; | |||
/* zooming */ | |||
case '+': | |||
case '=': | |||
if (img_zoom_in(&img)) { | |||
img_render(&img, &win); | |||
update_title(); | |||
} | |||
changed = img_zoom_in(&img); | |||
break; | |||
case '-': | |||
if (img_zoom_out(&img)) { | |||
img_render(&img, &win); | |||
update_title(); | |||
} | |||
changed = img_zoom_out(&img); | |||
break; | |||
/* panning */ | |||
case 'h': | |||
changed = img_pan(&img, &win, PAN_LEFT); | |||
break; | |||
case 'j': | |||
changed = img_pan(&img, &win, PAN_DOWN); | |||
break; | |||
case 'k': | |||
changed = img_pan(&img, &win, PAN_UP); | |||
break; | |||
case 'l': | |||
changed = img_pan(&img, &win, PAN_RIGHT); | |||
break; | |||
} | |||
if (changed) { | |||
img_render(&img, &win); | |||
update_title(); | |||
} | |||
} | |||