From 3439819eb1ac4b50ee10e92c4fb09e4fd696f01e Mon Sep 17 00:00:00 2001 From: Philipp Reinkemeier Date: Tue, 9 Jun 2015 10:00:10 +0200 Subject: [PATCH] libview: Implement support for moving text annotations. This adds support for moving text annotations by simply dragging them to a new location. The call to ev_view_handle_annotation has been moved from callback ev_view_button_press_event to ev_view_button_release_event. https://bugzilla.gnome.org/show_bug.cgi?id=649043 --- libview/ev-view-private.h | 9 +++ libview/ev-view.c | 121 +++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h index 5d4537d9..a6862b13 100644 --- a/libview/ev-view-private.h +++ b/libview/ev-view-private.h @@ -122,6 +122,14 @@ typedef struct { EvAnnotation *annot; } AddingAnnotInfo; +typedef struct { + GdkPoint start; + EvPoint cursor_offset; + gboolean annot_clicked; + gboolean moving_annot; + EvAnnotation *annot; +} MovingAnnotInfo; + struct _EvView { GtkContainer layout; @@ -217,6 +225,7 @@ struct _EvView { GList *window_children; EvViewWindowChild *window_child_focus; AddingAnnotInfo adding_annot_info; + MovingAnnotInfo moving_annot_info; /* Focus */ EvMapping *focused_element; diff --git a/libview/ev-view.c b/libview/ev-view.c index 9e5e0e0b..6f2876d6 100644 --- a/libview/ev-view.c +++ b/libview/ev-view.c @@ -5006,7 +5006,42 @@ ev_view_button_press_event (GtkWidget *widget, } else if ((media = ev_view_get_media_at_location (view, event->x, event->y))) { ev_view_handle_media (view, media); } else if ((annot = ev_view_get_annotation_at_location (view, event->x, event->y))) { - ev_view_handle_annotation (view, annot, event->x, event->y, event->time); + if (EV_IS_ANNOTATION_TEXT (annot)) { + EvRectangle current_area; + GdkPoint view_point; + EvPoint doc_point; + GdkRectangle page_area; + GtkBorder border; + guint annot_page; + + /* annot_clicked remembers that we clicked + * on an annotation. We need moving_annot + * to distinguish moving an annotation from + * showing its popup upon button release. */ + view->moving_annot_info.annot_clicked = TRUE; + view->moving_annot_info.moving_annot = FALSE; + view->moving_annot_info.annot = annot; + ev_annotation_get_area (annot, ¤t_area); + + view_point.x = event->x + view->scroll_x; + view_point.y = event->y + view->scroll_y; + + /* Remember the coordinates of the button press event + * in order to implement a minimum threshold for moving + * annotations. */ + view->moving_annot_info.start = view_point; + annot_page = ev_annotation_get_page_index (annot); + ev_view_get_page_extents (view, annot_page, &page_area, &border); + _ev_view_transform_view_point_to_doc_point (view, &view_point, + &page_area, &border, + &doc_point.x, &doc_point.y); + + /* Remember the offset of the cursor with respect to + * the annotation area in order to prevent the annotation from + * jumping under the cursor while moving it. */ + view->moving_annot_info.cursor_offset.x = doc_point.x - current_area.x1; + view->moving_annot_info.cursor_offset.y = doc_point.y - current_area.y1; + } } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) { ev_view_remove_all_form_fields (view); ev_view_handle_form_field (view, field); @@ -5404,6 +5439,69 @@ ev_view_motion_notify_event (GtkWidget *widget, ev_document_doc_mutex_unlock (); + /* FIXME: reload only annotation area */ + ev_view_reload_page (view, annot_page, NULL); + } else if (view->moving_annot_info.annot_clicked) { + EvRectangle rect; + EvRectangle current_area; + GdkPoint view_point; + EvPoint doc_point; + GdkRectangle page_area; + GtkBorder border; + guint annot_page; + double page_width; + double page_height; + + if (!view->moving_annot_info.annot) + return TRUE; + + view_point.x = event->x + view->scroll_x; + view_point.y = event->y + view->scroll_y; + + if (!view->moving_annot_info.moving_annot) { + /* Only move the annotation if the threshold is exceeded */ + if (!gtk_drag_check_threshold (widget, + view->moving_annot_info.start.x, + view->moving_annot_info.start.y, + view_point.x, + view_point.y)) + return TRUE; + view->moving_annot_info.moving_annot = TRUE; + } + + ev_annotation_get_area (view->moving_annot_info.annot, ¤t_area); + annot_page = ev_annotation_get_page_index (view->moving_annot_info.annot); + ev_view_get_page_extents (view, annot_page, &page_area, &border); + _ev_view_transform_view_point_to_doc_point (view, &view_point, &page_area, &border, + &doc_point.x, &doc_point.y); + + ev_document_get_page_size (view->document, annot_page, &page_width, &page_height); + + rect.x1 = MAX (0, doc_point.x - view->moving_annot_info.cursor_offset.x); + rect.y1 = MAX (0, doc_point.y - view->moving_annot_info.cursor_offset.y); + rect.x2 = rect.x1 + current_area.x2 - current_area.x1; + rect.y2 = rect.y1 + current_area.y2 - current_area.y1; + + /* Prevent the annotation from being moved off the page */ + if (rect.x2 > page_width) { + rect.x2 = page_width; + rect.x1 = page_width - current_area.x2 + current_area.x1; + } + if (rect.y2 > page_height) { + rect.y2 = page_height; + rect.y1 = page_height - current_area.y2 + current_area.y1; + } + + /* Take the mutex before set_area, because the notify signal + * updates the mappings in the backend */ + ev_document_doc_mutex_lock (); + if (ev_annotation_set_area (view->moving_annot_info.annot, &rect)) { + ev_document_annotations_save_annotation (EV_DOCUMENT_ANNOTATIONS (view->document), + view->moving_annot_info.annot, + EV_ANNOTATIONS_SAVE_AREA); + } + ev_document_doc_mutex_unlock (); + /* FIXME: reload only annotation area */ ev_view_reload_page (view, annot_page, NULL); } else { @@ -5589,6 +5687,27 @@ ev_view_button_release_event (GtkWidget *widget, return FALSE; } + if (view->moving_annot_info.annot_clicked) { + if (view->moving_annot_info.moving_annot) + ev_view_handle_cursor_over_xy (view, event->x, event->y); + else + ev_view_handle_annotation (view, view->moving_annot_info.annot, event->x, event->y, event->time); + + view->moving_annot_info.annot_clicked = FALSE; + view->moving_annot_info.moving_annot = FALSE; + view->moving_annot_info.annot = NULL; + view->pressed_button = -1; + + return FALSE; + } + + if (view->pressed_button == 1) { + EvAnnotation *annot = ev_view_get_annotation_at_location (view, event->x, event->y); + + if (annot) + ev_view_handle_annotation (view, annot, event->x, event->y, event->time); + } + if (view->pressed_button == 2) { ev_view_handle_cursor_over_xy (view, event->x, event->y); }