summaryrefslogtreecommitdiff
path: root/libview/ev-view.c
diff options
context:
space:
mode:
authorAntia Puentes <[email protected]>2013-09-20 11:51:11 +0200
committerraveit65 <[email protected]>2017-08-28 16:04:00 +0200
commit4cd8ca27cdc099338dbc09f192231de9d6390071 (patch)
treeabbef461875b2573479a3e3aa27ac5ce3b378365 /libview/ev-view.c
parentf03b70d2cd8ea6099af7b24fe2f7c024e9fdd323 (diff)
downloadatril-4cd8ca27cdc099338dbc09f192231de9d6390071.tar.bz2
atril-4cd8ca27cdc099338dbc09f192231de9d6390071.tar.xz
libview: Grab focus for form fields and links on mouse press
Rewritten focus annotations in a generic way. https://bugzilla.gnome.org/show_bug.cgi?id=706244 origin commit: https://git.gnome.org/browse/evince/commit/?id=fddb9ee
Diffstat (limited to 'libview/ev-view.c')
-rw-r--r--libview/ev-view.c421
1 files changed, 278 insertions, 143 deletions
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 20fc0470..07553c72 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -182,10 +182,6 @@ static void highlight_find_results (EvView
static void highlight_forward_search_results (EvView *view,
cairo_t *cr,
int page);
-static void focus_annotation (EvView *view,
- cairo_t *cr,
- int page,
- GdkRectangle *clip);
static void draw_one_page (EvView *view,
gint page,
cairo_t *cr,
@@ -1511,27 +1507,39 @@ ev_view_put_to_doc_rect (EvView *view,
}
/*** Hyperref ***/
-static EvLink *
-ev_view_get_link_at_location (EvView *view,
- gdouble x,
- gdouble y)
+static EvMapping *
+get_link_mapping_at_location (EvView *view,
+ gdouble x,
+ gdouble y,
+ gint *page)
{
- gint page = -1;
gint x_new = 0, y_new = 0;
EvMappingList *link_mapping;
if (!EV_IS_DOCUMENT_LINKS (view->document))
return NULL;
- if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+ if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
return NULL;
- link_mapping = ev_page_cache_get_link_mapping (view->page_cache, page);
-
+ link_mapping = ev_page_cache_get_link_mapping (view->page_cache, *page);
if (link_mapping)
- return ev_mapping_list_get_data (link_mapping, x_new, y_new);
- else
- return NULL;
+ return ev_mapping_list_get (link_mapping, x_new, y_new);
+
+ return NULL;
+}
+
+static EvLink *
+ev_view_get_link_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvMapping *mapping;
+ gint page;
+
+ mapping = get_link_mapping_at_location (view, x, y, &page);
+
+ return mapping ? mapping->data : NULL;
}
static void
@@ -1967,28 +1975,97 @@ ev_view_get_image_at_location (EvView *view,
return NULL;
}
+/*** Focus ***/
+static gboolean
+ev_view_get_focused_area (EvView *view,
+ GdkRectangle *area)
+{
+ if (!view->focused_element)
+ return FALSE;
+
+ _ev_view_transform_doc_rect_to_view_rect (view,
+ view->focused_element_page,
+ &view->focused_element->area,
+ area);
+ area->x -= view->scroll_x + 1;
+ area->y -= view->scroll_y + 1;
+ area->width += 1;
+ area->height += 1;
+
+ return TRUE;
+}
+
+static void
+ev_view_set_focused_element (EvView *view,
+ EvMapping *element_mapping,
+ gint page)
+{
+ GdkRectangle view_rect;
+ cairo_region_t *region = NULL;
+
+ if (view->focused_element == element_mapping)
+ return;
+
+ if (ev_view_get_focused_area (view, &view_rect))
+ region = cairo_region_create_rectangle (&view_rect);
+
+ view->focused_element = element_mapping;
+ view->focused_element_page = page;
+
+ if (ev_view_get_focused_area (view, &view_rect)) {
+ if (!region)
+ region = cairo_region_create_rectangle (&view_rect);
+ else
+ cairo_region_union_rectangle (region, &view_rect);
+
+ ev_document_model_set_page (view->model, page);
+ view_rect.x += view->scroll_x;
+ view_rect.y += view->scroll_y;
+ ensure_rectangle_is_visible (view, &view_rect);
+ }
+
+ if (region) {
+ gdk_window_invalidate_region (gtk_widget_get_window (GTK_WIDGET (view)),
+ region, TRUE);
+ cairo_region_destroy (region);
+ }
+}
+
/*** Forms ***/
-static EvFormField *
-ev_view_get_form_field_at_location (EvView *view,
- gdouble x,
- gdouble y)
+static EvMapping *
+get_form_field_mapping_at_location (EvView *view,
+ gdouble x,
+ gdouble y,
+ gint *page)
{
- gint page = -1;
gint x_new = 0, y_new = 0;
EvMappingList *forms_mapping;
-
+
if (!EV_IS_DOCUMENT_FORMS (view->document))
return NULL;
- if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+ if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
return NULL;
- forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache, page);
+ forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache, *page);
if (forms_mapping)
- return ev_mapping_list_get_data (forms_mapping, x_new, y_new);
- else
- return NULL;
+ return ev_mapping_list_get (forms_mapping, x_new, y_new);
+
+ return NULL;
+}
+
+static EvFormField *
+ev_view_get_form_field_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvMapping *field_mapping;
+ gint page;
+
+ field_mapping = get_form_field_mapping_at_location (view, x, y, &page);
+
+ return field_mapping ? field_mapping->data : NULL;
}
static cairo_region_t *
@@ -2022,65 +2099,74 @@ ev_view_form_field_destroy (GtkWidget *widget,
g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view);
}
-static GtkWidget *
-ev_view_form_field_button_create_widget (EvView *view,
- EvFormField *field)
+static void
+ev_view_form_field_button_toggle (EvView *view,
+ EvFormField *field)
{
+ EvMappingList *forms_mapping;
+ cairo_region_t *region;
+ gboolean state;
+ GList *l;
EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field);
- cairo_region_t *field_region = NULL;
-
- switch (field_button->type) {
- case EV_FORM_FIELD_BUTTON_PUSH:
- return NULL;
- case EV_FORM_FIELD_BUTTON_CHECK:
- case EV_FORM_FIELD_BUTTON_RADIO: {
- gboolean state;
- EvMappingList *forms_mapping;
- GList *l;
-
- state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
- field);
-
- /* FIXME: it actually depends on NoToggleToOff flags */
- if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO &&
- state && field_button->state)
- return NULL;
-
- field_region = ev_view_form_field_get_region (view, field);
-
- /* For radio buttons and checkbox buttons that are in a set
- * we need to update also the region for the current selected item
- */
- forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
- field->page->index);
- for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)) {
- EvFormField *button = ((EvMapping *)(l->data))->data;
- cairo_region_t *button_region;
-
- if (button->id == field->id)
- continue;
- /* FIXME: only buttons in the same group should be updated */
- if (!EV_IS_FORM_FIELD_BUTTON (button) ||
- EV_FORM_FIELD_BUTTON (button)->type != field_button->type ||
- EV_FORM_FIELD_BUTTON (button)->state != TRUE)
- continue;
+ if (field_button->type == EV_FORM_FIELD_BUTTON_PUSH)
+ return;
- button_region = ev_view_form_field_get_region (view, button);
- cairo_region_union (field_region, button_region);
- cairo_region_destroy (button_region);
- }
-
- ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
- field, !state);
- field_button->state = !state;
- }
- break;
+ state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document),
+ field);
+
+ /* FIXME: it actually depends on NoToggleToOff flags */
+ if (field_button->type == EV_FORM_FIELD_BUTTON_RADIO && state && field_button->state)
+ return;
+
+ region = ev_view_form_field_get_region (view, field);
+
+ /* For radio buttons and checkbox buttons that are in a set
+ * we need to update also the region for the current selected item
+ */
+ forms_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
+ field->page->index);
+
+ for (l = ev_mapping_list_get_list (forms_mapping); l; l = g_list_next (l)) {
+ EvFormField *button = ((EvMapping *)(l->data))->data;
+ cairo_region_t *button_region;
+
+ if (button->id == field->id)
+ continue;
+
+ /* FIXME: only buttons in the same group should be updated */
+ if (!EV_IS_FORM_FIELD_BUTTON (button) ||
+ EV_FORM_FIELD_BUTTON (button)->type != field_button->type ||
+ EV_FORM_FIELD_BUTTON (button)->state != TRUE)
+ continue;
+
+ button_region = ev_view_form_field_get_region (view, button);
+ cairo_region_union (region, button_region);
+ cairo_region_destroy (button_region);
}
- ev_view_reload_page (view, field->page->index, field_region);
- cairo_region_destroy (field_region);
-
+ /* Update state */
+ ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document),
+ field,
+ !state);
+ field_button->state = !state;
+
+ ev_view_reload_page (view, field->page->index, region);
+ cairo_region_destroy (region);
+}
+
+static GtkWidget *
+ev_view_form_field_button_create_widget (EvView *view,
+ EvFormField *field)
+{
+ EvMappingList *form_mapping;
+ EvMapping *mapping;
+
+ form_mapping = ev_page_cache_get_form_field_mapping (view->page_cache,
+ field->page->index);
+ mapping = ev_mapping_list_find (form_mapping, field);
+ ev_view_set_focused_element (view, mapping, field->page->index);
+
return NULL;
}
@@ -2423,21 +2509,18 @@ ev_view_form_field_choice_create_widget (EvView *view,
}
static void
-ev_view_handle_form_field (EvView *view,
- EvFormField *field,
- gdouble x,
- gdouble y)
+ev_view_focus_form_field (EvView *view,
+ EvFormField *field)
{
GtkWidget *field_widget = NULL;
EvMappingList *form_field_mapping;
EvMapping *mapping;
+ ev_view_set_focused_element (view, NULL, -1);
+
if (field->is_read_only)
return;
- if (field->activation_link)
- ev_view_handle_link (view, field->activation_link);
-
if (EV_IS_FORM_FIELD_BUTTON (field)) {
field_widget = ev_view_form_field_button_create_widget (view, field);
} else if (EV_IS_FORM_FIELD_TEXT (field)) {
@@ -2464,6 +2547,23 @@ ev_view_handle_form_field (EvView *view,
gtk_widget_grab_focus (field_widget);
}
+static void
+ev_view_handle_form_field (EvView *view,
+ EvFormField *field)
+{
+ if (field->is_read_only)
+ return;
+
+ ev_view_focus_form_field (view, field);
+
+ if (field->activation_link)
+ ev_view_handle_link (view, field->activation_link);
+
+ if (EV_IS_FORM_FIELD_BUTTON (field))
+ ev_view_form_field_button_toggle (view, field);
+
+}
+
/* Annotations */
static EvViewWindowChild *
ev_view_get_window_child (EvView *view,
@@ -2782,27 +2882,40 @@ hide_annotation_windows (EvView *view,
}
}
-static EvAnnotation *
-ev_view_get_annotation_at_location (EvView *view,
- gdouble x,
- gdouble y)
+static EvMapping *
+get_annotation_mapping_at_location (EvView *view,
+ gdouble x,
+ gdouble y,
+ gint *page)
{
- gint page = -1;
gint x_new = 0, y_new = 0;
EvMappingList *annotations_mapping;
if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
return NULL;
- if (!get_doc_point_from_location (view, x, y, &page, &x_new, &y_new))
+ if (!get_doc_point_from_location (view, x, y, page, &x_new, &y_new))
return NULL;
- annotations_mapping = ev_page_cache_get_annot_mapping (view->page_cache, page);
+ annotations_mapping = ev_page_cache_get_annot_mapping (view->page_cache, *page);
if (annotations_mapping)
- return ev_mapping_list_get_data (annotations_mapping, x_new, y_new);
- else
- return NULL;
+ return ev_mapping_list_get (annotations_mapping, x_new, y_new);
+
+ return NULL;
+}
+
+static EvAnnotation *
+ev_view_get_annotation_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvMapping *annotation_mapping;
+ gint page;
+
+ annotation_mapping = get_annotation_mapping_at_location (view, x, y, &page);
+
+ return annotation_mapping ? annotation_mapping->data : NULL;
}
static void
@@ -2944,27 +3057,12 @@ void
ev_view_focus_annotation (EvView *view,
EvMapping *annot_mapping)
{
- GdkRectangle view_rect;
- EvAnnotation *annot;
- guint page;
if (!EV_IS_DOCUMENT_ANNOTATIONS (view->document))
return;
- if (view->focus_annotation == annot_mapping)
- return;
-
- view->focus_annotation = annot_mapping;
- annot = (EvAnnotation *)annot_mapping->data;
-
- page = ev_annotation_get_page_index (annot);
- ev_document_model_set_page (view->model, page);
-
- _ev_view_transform_doc_rect_to_view_rect (view, page,
- &annot_mapping->area,
- &view_rect);
- ensure_rectangle_is_visible (view, &view_rect);
- gtk_widget_queue_draw (GTK_WIDGET (view));
+ ev_view_set_focused_element (view, annot_mapping,
+ ev_annotation_get_page_index (EV_ANNOTATION (annot_mapping->data)));
}
void
@@ -3457,6 +3555,32 @@ ev_view_realize (GtkWidget *widget)
window);
}
+static void
+draw_focus (EvView *view,
+ cairo_t *cr,
+ gint page,
+ GdkRectangle *clip)
+{
+ GtkWidget *widget = GTK_WIDGET (view);
+ GdkRectangle rect;
+ GdkRectangle intersect;
+
+ if (view->focused_element_page != page)
+ return;
+
+ if (!ev_view_get_focused_area (view, &rect))
+ return;
+
+ if (gdk_rectangle_intersect (&rect, clip, &intersect)) {
+ gtk_render_focus (gtk_widget_get_style_context (widget),
+ cr,
+ intersect.x,
+ intersect.y,
+ intersect.width,
+ intersect.height);
+ }
+}
+
static gboolean
ev_view_draw (GtkWidget *widget,
cairo_t *cr)
@@ -3502,8 +3626,8 @@ ev_view_draw (GtkWidget *widget,
highlight_find_results (view, cr, i);
if (page_ready && EV_IS_DOCUMENT_ANNOTATIONS (view->document))
show_annotation_windows (view, i);
- if (page_ready && view->focus_annotation)
- focus_annotation (view, cr, i, area);
+ if (page_ready && view->focused_element)
+ draw_focus (view, cr, i, &clip_rect);
if (page_ready && view->synctex_result)
highlight_forward_search_results (view, cr, i);
}
@@ -3514,6 +3638,36 @@ ev_view_draw (GtkWidget *widget,
return FALSE;
}
+static void
+ev_view_set_focused_element_at_location (EvView *view,
+ gdouble x,
+ gdouble y)
+{
+ EvMapping *mapping;
+ EvFormField *field;
+ gint page;
+
+ mapping = get_annotation_mapping_at_location (view, x, y, &page);
+ if (mapping) {
+ ev_view_set_focused_element (view, mapping, page);
+ return;
+ }
+
+ mapping = get_link_mapping_at_location (view, x, y, &page);
+ if (mapping) {
+ ev_view_set_focused_element (view, mapping, page);
+ return;
+ }
+
+ if ((field = ev_view_get_form_field_at_location (view, x, y))) {
+ ev_view_remove_all (view);
+ ev_view_focus_form_field (view, field);
+ return;
+ }
+
+ ev_view_set_focused_element (view, NULL, -1);
+}
+
static gboolean
ev_view_do_popup_menu (EvView *view,
gdouble x,
@@ -3703,12 +3857,14 @@ ev_view_button_press_event (GtkWidget *widget,
if (view->scroll_info.autoscrolling)
return TRUE;
-
+
switch (event->button) {
case 1: {
EvImage *image;
EvAnnotation *annot;
EvFormField *field;
+ EvMapping *link;
+ gint page;
if (event->state & GDK_CONTROL_MASK)
return ev_view_synctex_backward_search (view, event->x , event->y);
@@ -3729,7 +3885,9 @@ ev_view_button_press_event (GtkWidget *widget,
ev_view_handle_annotation (view, annot, event->x, event->y, event->time);
} else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) {
ev_view_remove_all (view);
- ev_view_handle_form_field (view, field, event->x, event->y);
+ ev_view_handle_form_field (view, field);
+ } else if ((link = get_link_mapping_at_location (view, event->x, event->y, &page))){
+ ev_view_set_focused_element (view, link, page);
} else if (!location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y) &&
(image = ev_view_get_image_at_location (view, event->x, event->y))) {
if (view->image_dnd_info.image)
@@ -3741,6 +3899,7 @@ ev_view_button_press_event (GtkWidget *widget,
view->image_dnd_info.start.y = event->y + view->scroll_y;
} else {
ev_view_remove_all (view);
+ ev_view_set_focused_element (view, NULL, -1);
if (view->synctex_result) {
g_free (view->synctex_result);
@@ -3748,9 +3907,6 @@ ev_view_button_press_event (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
- if (view->focus_annotation)
- view->focus_annotation = NULL;
-
if (EV_IS_SELECTION (view->document))
start_selection_for_event (view, event);
}
@@ -3765,10 +3921,11 @@ ev_view_button_press_event (GtkWidget *widget,
view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment);
ev_view_set_cursor (view, EV_VIEW_CURSOR_DRAG);
-
+ ev_view_set_focused_element_at_location (view, event->x, event->y);
return TRUE;
case 3:
view->scroll_info.start_y = event->y;
+ ev_view_set_focused_element_at_location (view, event->x, event->y);
return ev_view_do_popup_menu (view, event->x, event->y);
}
@@ -4408,28 +4565,6 @@ highlight_forward_search_results (EvView *view, cairo_t *cr, int page)
}
static void
-focus_annotation (EvView *view,
- cairo_t *cr,
- gint page,
- GdkRectangle *clip)
-{
- GtkWidget *widget = GTK_WIDGET (view);
- GdkRectangle rect;
- EvMapping *mapping = view->focus_annotation;
- EvAnnotation *annot = (EvAnnotation *)mapping->data;
-
- if (ev_annotation_get_page_index (annot) != page)
- return;
-
- _ev_view_transform_doc_rect_to_view_rect (view, page, &mapping->area, &rect);
- gtk_render_focus (gtk_widget_get_style_context (widget),
- cr,
- rect.x - view->scroll_x,
- rect.y - view->scroll_y,
- rect.width + 1, rect.height + 1);
-}
-
-static void
ev_view_loading_window_move (EvView *view)
{
GtkWidget *widget = GTK_WIDGET (view);