X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;ds=sidebyside;f=shell%2Fev-view.c;h=476c791b0a93cde94367c4325a18bed6e5f37ddf;hb=de3612f2a4b46b555edc50ca344a04bc3a8f7280;hp=29c87a2914ffd108285436c5203b7496d71b54bd;hpb=e93b3a265bbc02546d230204402e3f41e83d6ab5;p=evince.git diff --git a/shell/ev-view.c b/shell/ev-view.c index 29c87a29..476c791b 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -78,6 +78,7 @@ static guint signals[N_SIGNALS]; typedef enum { EV_VIEW_CURSOR_NORMAL, + EV_VIEW_CURSOR_IBEAM, EV_VIEW_CURSOR_LINK, EV_VIEW_CURSOR_WAIT, EV_VIEW_CURSOR_HIDDEN, @@ -350,7 +351,8 @@ static void jump_to_find_page (EvView /*** Selection ***/ static void compute_selections (EvView *view, - GdkRectangle *view_rect); + GdkPoint *start, + GdkPoint *stop); static void clear_selection (EvView *view); static char* get_selected_text (EvView *ev_view); static void ev_view_primary_get_cb (GtkClipboard *clipboard, @@ -862,16 +864,27 @@ get_page_extents (EvView *view, return TRUE; } +static void +view_point_to_doc_point (EvView *view, + GdkPoint *view_point, + GdkRectangle *page_area, + double *doc_point_x, + double *doc_point_y) +{ + *doc_point_x = (double) (view_point->x - page_area->x) / view->scale; + *doc_point_y = (double) (view_point->y - page_area->y) / view->scale; +} + static void view_rect_to_doc_rect (EvView *view, GdkRectangle *view_rect, GdkRectangle *page_area, EvRectangle *doc_rect) { - doc_rect->x1 = floor ((view_rect->x - page_area->x) / view->scale); - doc_rect->y1 = floor ((view_rect->y - page_area->y) / view->scale); - doc_rect->x2 = doc_rect->x1 + ceil (view_rect->width / view->scale); - doc_rect->y2 = doc_rect->y1 + ceil (view_rect->height / view->scale); + doc_rect->x1 = (double) (view_rect->x - page_area->x) / view->scale; + doc_rect->y1 = (double) (view_rect->y - page_area->y) / view->scale; + doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale; + doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale; } static void @@ -932,6 +945,28 @@ find_page_at_location (EvView *view, *page = -1; } +static gboolean +location_in_text (EvView *view, + gdouble x, + gdouble y) +{ + GdkRegion *region; + gint page = -1; + gint x_offset = 0, y_offset = 0; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + + if (page == -1) + return FALSE; + + region = ev_pixbuf_cache_get_text_mapping (view->pixbuf_cache, page); + + if (region) + return gdk_region_point_in (region, x_offset / view->scale, y_offset / view->scale); + else + return FALSE; +} + /*** Hyperref ***/ static EvLink * get_link_at_location (EvView *view, @@ -1324,8 +1359,8 @@ ev_view_button_press_event (GtkWidget *widget, gtk_widget_queue_draw (widget); } - view->selection_info.start.x = event->x; - view->selection_info.start.y = event->y; + view->selection_info.start.x = event->x + view->scroll_x; + view->selection_info.start.y = event->y + view->scroll_y; return TRUE; case 2: /* use root coordinates as reference point because @@ -1353,15 +1388,12 @@ ev_view_motion_notify_event (GtkWidget *widget, return FALSE; if (view->pressed_button == 1) { - GdkRectangle selection; - view->selection_info.in_selection = TRUE; + GdkPoint point; - selection.x = MIN (view->selection_info.start.x, event->x) + view->scroll_x; - selection.y = MIN (view->selection_info.start.y, event->y) + view->scroll_y; - selection.width = ABS (view->selection_info.start.x - event->x) + 1; - selection.height = ABS (view->selection_info.start.y - event->y) + 1; - - compute_selections (view, &selection); + view->selection_info.in_selection = TRUE; + point.x = event->x + view->scroll_x; + point.y = event->y + view->scroll_y; + compute_selections (view, &view->selection_info.start, &point); return TRUE; } else if (view->pressed_button == 2) { @@ -1411,11 +1443,13 @@ ev_view_motion_notify_event (GtkWidget *widget, ev_view_set_status (view, msg); ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); g_free (msg); + } else if (location_in_text (view, event->x + view->scroll_x, event->y + view->scroll_y)) { + ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM); } else { ev_view_set_status (view, NULL); - if (view->cursor == EV_VIEW_CURSOR_LINK) { + if (view->cursor == EV_VIEW_CURSOR_LINK || + view->cursor == EV_VIEW_CURSOR_IBEAM) ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL); - } } return TRUE; } @@ -2698,23 +2732,30 @@ ev_view_find_previous (EvView *view) */ static GList * compute_new_selection_rect (EvView *view, - GdkRectangle *view_rect) + GdkPoint *start, + GdkPoint *stop) { + GdkRectangle view_rect; int n_pages, i; GList *list = NULL; g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE); + + view_rect.x = MIN (start->x, stop->x); + view_rect.y = MIN (start->y, stop->y); + view_rect.width = MAX (start->x, stop->x) - view_rect.x; + view_rect.width = MAX (start->y, stop->y) - view_rect.y; n_pages = ev_page_cache_get_n_pages (view->page_cache); for (i = 0; i < n_pages; i++) { GdkRectangle page_area; GtkBorder border; - + if (get_page_extents (view, i, &page_area, &border)) { GdkRectangle overlap; - if (gdk_rectangle_intersect (&page_area, view_rect, &overlap)) { + if (gdk_rectangle_intersect (&page_area, &view_rect, &overlap)) { EvViewSelection *selection; selection = g_new0 (EvViewSelection, 1); @@ -2730,82 +2771,92 @@ compute_new_selection_rect (EvView *view, return list; } +static gboolean +gdk_rectangle_point_in (GdkRectangle *rectangle, + GdkPoint *point) +{ + return rectangle->x <= point->x && + rectangle->y <= point->y && + point->x < rectangle->x + rectangle->width && + point->y < rectangle->y + rectangle->height; +} + static GList * -compute_new_selection_text (EvView *view, - GdkRectangle *view_rect) +compute_new_selection_text (EvView *view, + GdkPoint *start, + GdkPoint *stop) { - int n_pages, i; + int n_pages, i, first, last; GList *list = NULL; - EvViewSelection *first_selection = NULL; - EvViewSelection *last_selection = NULL; + EvViewSelection *selection; gint width, height; g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT); n_pages = ev_page_cache_get_n_pages (view->page_cache); - /* We get the two edge pages */ + /* First figure out the range of pages the selection + * affects. */ + first = n_pages; + last = 0; for (i = 0; i < n_pages; i++) { GdkRectangle page_area; GtkBorder border; - - if (get_page_extents (view, i, &page_area, &border)) { - GdkRectangle overlap; - - if (gdk_rectangle_intersect (&page_area, view_rect, &overlap)) { - EvViewSelection *selection; - - if (first_selection == NULL) { - first_selection = g_new0 (EvViewSelection, 1); - selection = first_selection; - } else if (last_selection == NULL) { - last_selection = g_new0 (EvViewSelection, 1); - selection = last_selection; - } else { - selection = last_selection; - } - - selection->page = i; - view_rect_to_doc_rect (view, &overlap, &page_area, - &(selection->rect)); - } + + get_page_extents (view, i, &page_area, &border); + if (gdk_rectangle_point_in (&page_area, start) || + gdk_rectangle_point_in (&page_area, stop)) { + if (first == n_pages) + first = i; + last = i; } + } - /* No overlap */ - if (first_selection == NULL) - return NULL; - /* only one selection. Return a page of it */ - if (last_selection == NULL) - return g_list_append (NULL, first_selection); - /*clean up the selections; - */ - ev_page_cache_get_size (view->page_cache, first_selection->page, - 1.0, &width, &height); - first_selection->rect.x2 = width; - first_selection->rect.y2 = height; - list = g_list_append (NULL, first_selection); - - /* Add all the intervening pages */ - for (i = first_selection->page + 1; i < last_selection->page; i++) { - EvViewSelection *selection; + /* Now create a list of EvViewSelection's for the affected + * pages. This could be an empty list, a list of just one + * page or a number of pages.*/ + for (i = first; i < last + 1; i++) { + GdkRectangle page_area; + GtkBorder border; + GdkPoint *point; - selection = g_new0 (EvViewSelection, 1); - selection->page = i; ev_page_cache_get_size (view->page_cache, i, 1.0, &width, &height); + + selection = g_new0 (EvViewSelection, 1); + selection->page = i; selection->rect.x1 = selection->rect.y1 = 0; selection->rect.x2 = width; selection->rect.y2 = height; - g_list_append (list, selection); - } - /* Clean up the last page */ - last_selection->rect.x1 = 0; - last_selection->rect.y1 = 0; - list = g_list_append (list, last_selection); + get_page_extents (view, i, &page_area, &border); + + if (gdk_rectangle_point_in (&page_area, start)) + point = start; + else + point = stop; + + if (i == first) + view_point_to_doc_point (view, point, &page_area, + &selection->rect.x1, + &selection->rect.y1); + + /* If the selection is contained within just one page, + * make sure we don't write 'start' into both points + * in selection->rect. */ + if (first == last) + point = stop; + + if (i == last) + view_point_to_doc_point (view, point, &page_area, + &selection->rect.x2, + &selection->rect.y2); + + list = g_list_append (list, selection); + } return list; } @@ -2827,15 +2878,16 @@ merge_selection_region (EvView *view, } static void -compute_selections (EvView *view, - GdkRectangle *view_rect) +compute_selections (EvView *view, + GdkPoint *start, + GdkPoint *stop) { GList *list; if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE) - list = compute_new_selection_rect (view, view_rect); + list = compute_new_selection_rect (view, start, stop); else - list = compute_new_selection_text (view, view_rect); + list = compute_new_selection_text (view, start, stop); merge_selection_region (view, list); } @@ -3009,6 +3061,9 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor) case EV_VIEW_CURSOR_NORMAL: gdk_window_set_cursor (widget->window, NULL); break; + case EV_VIEW_CURSOR_IBEAM: + cursor = gdk_cursor_new_for_display (display, GDK_XTERM); + break; case EV_VIEW_CURSOR_LINK: cursor = gdk_cursor_new_for_display (display, GDK_HAND2); break;