|
46 | 46 | */ |
47 | 47 | #define ZOOM_DURATION (0.5) |
48 | 48 |
|
| 49 | +/* Snap if closer than this. |
| 50 | + */ |
| 51 | +const int imageui_snap_threshold = 10; |
| 52 | + |
| 53 | +/* Drag state machine. |
| 54 | + */ |
| 55 | +typedef enum { |
| 56 | + IMAGEUI_WAIT, /* Waiting for left down */ |
| 57 | + IMAGEUI_SELECT, /* Manipulating a selected region */ |
| 58 | + IMAGEUI_SCROLL, /* Drag-scrolling the iamge */ |
| 59 | + IMAGEUI_CREATE, /* Dragging out a new region */ |
| 60 | +} ImageuiState; |
| 61 | + |
49 | 62 | struct _Imageui { |
50 | 63 | GtkWidget parent_instance; |
51 | 64 |
|
@@ -81,16 +94,18 @@ struct _Imageui { |
81 | 94 | double zoom_x; |
82 | 95 | double zoom_y; |
83 | 96 |
|
| 97 | + /* Interaction state. |
| 98 | + */ |
| 99 | + ImageuiState state; |
| 100 | + |
84 | 101 | /* TRUE for an eased zoom (eg. magin), FALSE for a continuous zoom (eg. |
85 | 102 | * 'i'). |
86 | 103 | */ |
87 | 104 | gboolean eased; |
88 | 105 |
|
89 | | - /* Drag scroll. |
90 | | - */ |
91 | | - int window_left; /* Window position at start of scroll */ |
| 106 | + int window_left; /* Window position at start of scroll */ |
92 | 107 | int window_top; |
93 | | - int start_x; /* Mouse position at start of scroll */ |
| 108 | + int start_x; /* Mouse position at start of scroll */ |
94 | 109 | int start_y; |
95 | 110 |
|
96 | 111 | GtkWidget *scrolled_window; |
@@ -514,10 +529,8 @@ imageui_bestfit(Imageui *imageui) |
514 | 529 | int widget_width = gtk_widget_get_width(imageui->scrolled_window); |
515 | 530 | int widget_height = gtk_widget_get_height(imageui->scrolled_window); |
516 | 531 |
|
517 | | - double hzoom = (double) widget_width / |
518 | | - imageui->tilesource->display_width; |
519 | | - double vzoom = (double) widget_height / |
520 | | - imageui->tilesource->display_height; |
| 532 | + double hzoom = (double) widget_width / imageui->tilesource->image_width; |
| 533 | + double vzoom = (double) widget_height / imageui->tilesource->image_height; |
521 | 534 | double zoom = VIPS_MIN(hzoom, vzoom); |
522 | 535 |
|
523 | 536 | imageui_zoom_to_eased(imageui, zoom * imageui->tilesource->zoom); |
@@ -592,21 +605,30 @@ imageui_scale(Imageui *imageui) |
592 | 605 | VipsImage *image; |
593 | 606 |
|
594 | 607 | if ((image = tilesource_get_image(imageui->tilesource))) { |
595 | | - double image_zoom; |
| 608 | + /* Get the view rect in level0 coordinates. |
| 609 | + */ |
| 610 | + double image_zoom = imageui_get_zoom(imageui); |
596 | 611 | int left, top, width, height; |
597 | | - double scale, offset; |
598 | | - |
599 | | - image_zoom = imageui_get_zoom(imageui); |
600 | 612 | imageui_get_position(imageui, &left, &top, &width, &height); |
| 613 | + |
601 | 614 | left /= image_zoom; |
602 | 615 | top /= image_zoom; |
603 | 616 | width /= image_zoom; |
604 | 617 | height /= image_zoom; |
605 | 618 |
|
| 619 | + /* image is scaled down by current_z, so we must scale the rect by |
| 620 | + * that. |
| 621 | + */ |
| 622 | + left /= 1 << imageui->tilesource->current_z; |
| 623 | + top /= 1 << imageui->tilesource->current_z; |
| 624 | + width /= 1 << imageui->tilesource->current_z; |
| 625 | + height /= 1 << imageui->tilesource->current_z; |
| 626 | + |
606 | 627 | /* FIXME ... this will be incredibly slow, esp. for large |
607 | 628 | * images. Instead, it would be better to just search the |
608 | 629 | * cached tiles we have. |
609 | 630 | */ |
| 631 | + double scale, offset; |
610 | 632 | if (imageui_find_scale(image, |
611 | 633 | left, top, width, height, &scale, &offset)) |
612 | 634 | return FALSE; |
@@ -834,8 +856,35 @@ imageui_drag_update(GtkEventControllerMotion *self, |
834 | 856 | offset_x, offset_y); |
835 | 857 | #endif /*DEBUG_VERBOSE*/ |
836 | 858 |
|
837 | | - imageui_set_position(imageui, |
838 | | - imageui->window_left - offset_x, imageui->window_top - offset_y); |
| 859 | + switch (imageui->state) { |
| 860 | + case IMAGEUI_WAIT: |
| 861 | + if (fabs(offset_x) > 5 || |
| 862 | + fabs(offset_y) > 5) |
| 863 | + imageui->state = IMAGEUI_SCROLL; |
| 864 | + break; |
| 865 | + |
| 866 | + case IMAGEUI_SCROLL: |
| 867 | + imageui_set_position(imageui, |
| 868 | + imageui->window_left - offset_x, imageui->window_top - offset_y); |
| 869 | + break; |
| 870 | + |
| 871 | + default: |
| 872 | + break; |
| 873 | + } |
| 874 | +} |
| 875 | + |
| 876 | +static void |
| 877 | +imageui_drag_end(GtkEventControllerMotion *self, |
| 878 | + gdouble offset_x, gdouble offset_y, gpointer user_data) |
| 879 | +{ |
| 880 | + Imageui *imageui = IMAGEUI(user_data); |
| 881 | + |
| 882 | +#ifdef DEBUG_VERBOSE |
| 883 | + printf("imageui_drag_end: offset_x = %g, offset_y = %g\n", |
| 884 | + offset_x, offset_y); |
| 885 | +#endif /*DEBUG_VERBOSE*/ |
| 886 | + |
| 887 | + imageui->state = IMAGEUI_WAIT; |
839 | 888 | } |
840 | 889 |
|
841 | 890 | static void |
@@ -916,6 +965,7 @@ imageui_class_init(ImageuiClass *class) |
916 | 965 |
|
917 | 966 | BIND_CALLBACK(imageui_drag_begin); |
918 | 967 | BIND_CALLBACK(imageui_drag_update); |
| 968 | + BIND_CALLBACK(imageui_drag_end); |
919 | 969 | BIND_CALLBACK(imageui_key_pressed); |
920 | 970 | BIND_CALLBACK(imageui_key_released); |
921 | 971 | BIND_CALLBACK(imageui_motion); |
@@ -968,6 +1018,7 @@ imageui_class_init(ImageuiClass *class) |
968 | 1018 | NULL, NULL, |
969 | 1019 | g_cclosure_marshal_VOID__VOID, |
970 | 1020 | G_TYPE_NONE, 0); |
| 1021 | + |
971 | 1022 | } |
972 | 1023 |
|
973 | 1024 | Imageui * |
|
0 commit comments