typedef enum {
EV_VIEW_CURSOR_NORMAL,
+ EV_VIEW_CURSOR_IBEAM,
EV_VIEW_CURSOR_LINK,
EV_VIEW_CURSOR_WAIT,
EV_VIEW_CURSOR_HIDDEN,
int find_result;
int spacing;
+ EvOrientation orientation;
double scale;
gboolean continuous;
GdkEventMotion *event);
static gboolean ev_view_button_release_event (GtkWidget *widget,
GdkEventButton *event);
+static gboolean ev_view_leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event);
/*** Drawing ***/
static guint32 ev_gdk_color_to_rgb (const GdkColor *color);
/*** 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,
GdkRectangle page_area;
GtkBorder border;
+ if (view->document == NULL) {
+ return;
+ }
+
get_page_extents (view, view->current_page, &page_area, &border);
if (orientation == GTK_ORIENTATION_VERTICAL) {
ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
view->start_page,
view->end_page,
+ view->orientation,
view->scale,
view->selection_info.selections);
}
GtkAdjustment *adjustment;
int value;
+ view->pending_scroll = SCROLL_TO_KEEP_POSITION;
+
adjustment = view->vadjustment;
if (rect->y < adjustment->value) {
}
}
-static void get_page_y_offset (EvView *view,
- int page,
- double zoom,
- int *y_offset)
+static void
+get_page_y_offset (EvView *view, int page, double zoom, int *y_offset)
{
int max_width, offset;
GtkBorder border;
g_return_if_fail (y_offset != NULL);
- ev_page_cache_get_max_width (view->page_cache, zoom, &max_width);
+ ev_page_cache_get_max_width (view->page_cache, view->orientation, zoom, &max_width);
compute_border (view, max_width, max_width, &border);
if (view->dual_page) {
- ev_page_cache_get_height_to_page (view->page_cache, page, zoom, NULL, &offset);
+ ev_page_cache_get_height_to_page (view->page_cache, page,
+ view->orientation, zoom, NULL, &offset);
offset += (page / 2 + 1) * view->spacing + (page / 2) * (border.top + border.bottom);
} else {
- ev_page_cache_get_height_to_page (view->page_cache, page, zoom, &offset, NULL);
+ ev_page_cache_get_height_to_page (view->page_cache, page,
+ view->orientation, zoom, &offset, NULL);
offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
}
/* Get the size of the page */
ev_page_cache_get_size (view->page_cache, page,
+ view->orientation,
view->scale,
&width, &height);
compute_border (view, width, height, border);
gint max_width;
gint x, y;
- ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+ ev_page_cache_get_max_width (view->page_cache, view->scale,
+ view->orientation, &max_width);
max_width = max_width + border->left + border->right;
/* Get the location of the bounding box */
if (view->dual_page) {
if (other_page < ev_page_cache_get_n_pages (view->page_cache)) {
ev_page_cache_get_size (view->page_cache,
other_page,
+ view->orientation,
view->scale,
&width_2, &height_2);
if (width_2 > width)
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
*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,
gint n_pages;
GtkBorder border;
- ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+ ev_page_cache_get_max_width (view->page_cache, view->orientation,
+ view->scale, &max_width);
compute_border (view, max_width, max_width, &border);
n_pages = ev_page_cache_get_n_pages (view->page_cache) + 1;
GtkBorder border;
- ev_page_cache_get_max_width (view->page_cache, view->scale, &max_width);
+ ev_page_cache_get_max_width (view->page_cache, view->orientation,
+ view->scale, &max_width);
n_pages = ev_page_cache_get_n_pages (view->page_cache);
compute_border (view, max_width, max_width, &border);
/* Find the largest of the two. */
ev_page_cache_get_size (view->page_cache,
view->current_page,
+ view->orientation,
view->scale,
&width, &height);
if (view->current_page + 1 < ev_page_cache_get_n_pages (view->page_cache)) {
gint width_2, height_2;
ev_page_cache_get_size (view->page_cache,
view->current_page + 1,
+ view->orientation,
view->scale,
&width_2, &height_2);
if (width_2 > width) {
ev_page_cache_get_size (view->page_cache,
view->current_page,
+ view->orientation,
view->scale,
&width, &height);
compute_border (view, width, height, &border);
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
return FALSE;
if (view->pressed_button == 1) {
- GdkRectangle selection;
- view->selection_info.in_selection = TRUE;
-
- 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;
+ GdkPoint point;
- 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) {
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;
}
return FALSE;
}
+static gboolean
+ev_view_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
+{
+ EvView *view = EV_VIEW (widget);
+
+ ev_view_set_status (view, NULL);
+
+ if (view->cursor == EV_VIEW_CURSOR_LINK ||
+ view->cursor == EV_VIEW_CURSOR_IBEAM)
+ ev_view_set_cursor (view, EV_VIEW_CURSOR_NORMAL);
+
+ return FALSE;
+}
+
/*** Drawing ***/
static guint32
selection = find_selection_for_page (view, page);
ev_page_cache_get_size (view->page_cache,
- page, view->scale,
+ page, view->orientation,
+ view->scale,
&width, &height);
/* Render the document itself */
real_page_area = *page_area;
widget_class->realize = ev_view_realize;
widget_class->unrealize = ev_view_unrealize;
widget_class->scroll_event = ev_view_scroll_event;
+ widget_class->leave_notify_event = ev_view_leave_notify_event;
gtk_object_class->destroy = ev_view_destroy;
class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
view->pixbuf_cache = NULL;
}
- if (view->document) {
- ev_page_cache_clear (view->document);
+ if (view->page_cache) {
+ g_object_unref (view->page_cache);
+ view->page_cache = NULL;
}
}
return view->scale;
}
+gboolean
+ev_view_get_continuous (EvView *view)
+{
+ g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
+
+ return view->continuous;
+}
+
void
ev_view_set_continuous (EvView *view,
gboolean continuous)
g_object_notify (G_OBJECT (view), "continuous");
}
+gboolean
+ev_view_get_dual_page (EvView *view)
+{
+ g_return_val_if_fail (EV_IS_VIEW (view), FALSE);
+
+ return view->dual_page;
+}
+
void
ev_view_set_dual_page (EvView *view,
gboolean dual_page)
fullscreen = fullscreen != FALSE;
- if (view->fullscreen != fullscreen) {
- view->fullscreen = fullscreen;
- gtk_widget_queue_resize (GTK_WIDGET (view));
- }
-
+ if (view->fullscreen == fullscreen)
+ return;
+
+ view->fullscreen = fullscreen;
+ gtk_widget_queue_resize (GTK_WIDGET (view));
+
g_object_notify (G_OBJECT (view), "fullscreen");
}
return;
view->presentation = presentation;
+ view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
gtk_widget_queue_resize (GTK_WIDGET (view));
+
if (GTK_WIDGET_REALIZED (view)) {
if (view->presentation)
gdk_window_set_background (GTK_WIDGET(view)->window,
ev_view_set_orientation (EvView *view,
EvOrientation orientation)
{
- ev_document_set_orientation (view->document, orientation);
-
- clear_caches (view);
- setup_caches (view);
+ view->orientation = orientation;
gtk_widget_queue_resize (GTK_WIDGET (view));
}
void
ev_view_rotate_right (EvView *view)
{
- EvOrientation orientation, new_orientation;
+ EvOrientation orientation;
- orientation = ev_document_get_orientation (view->document);
- if (orientation == EV_ORIENTATION_PORTRAIT) {
- new_orientation = EV_ORIENTATION_LANDSCAPE;
- } else if (orientation == EV_ORIENTATION_LANDSCAPE) {
- new_orientation = EV_ORIENTATION_UPSIDEDOWN;
- } else if (orientation == EV_ORIENTATION_UPSIDEDOWN) {
- new_orientation = EV_ORIENTATION_SEASCAPE;
+ if (view->orientation == EV_ORIENTATION_PORTRAIT) {
+ orientation = EV_ORIENTATION_LANDSCAPE;
+ } else if (view->orientation == EV_ORIENTATION_LANDSCAPE) {
+ orientation = EV_ORIENTATION_UPSIDEDOWN;
+ } else if (view->orientation == EV_ORIENTATION_UPSIDEDOWN) {
+ orientation = EV_ORIENTATION_SEASCAPE;
} else {
- new_orientation = EV_ORIENTATION_PORTRAIT;
+ orientation = EV_ORIENTATION_PORTRAIT;
}
- ev_view_set_orientation (view, new_orientation);
+
+ ev_view_set_orientation (view, orientation);
}
void
ev_view_rotate_left (EvView *view)
{
- EvOrientation orientation, new_orientation;
+ EvOrientation orientation;
- orientation = ev_document_get_orientation (view->document);
- if (orientation == EV_ORIENTATION_PORTRAIT) {
- new_orientation = EV_ORIENTATION_SEASCAPE;
- } else if (orientation == EV_ORIENTATION_SEASCAPE) {
- new_orientation = EV_ORIENTATION_UPSIDEDOWN;
- } else if (orientation == EV_ORIENTATION_UPSIDEDOWN) {
- new_orientation = EV_ORIENTATION_LANDSCAPE;
+ if (view->orientation == EV_ORIENTATION_PORTRAIT) {
+ orientation = EV_ORIENTATION_SEASCAPE;
+ } else if (view->orientation == EV_ORIENTATION_SEASCAPE) {
+ orientation = EV_ORIENTATION_UPSIDEDOWN;
+ } else if (view->orientation == EV_ORIENTATION_UPSIDEDOWN) {
+ orientation = EV_ORIENTATION_LANDSCAPE;
} else {
- new_orientation = EV_ORIENTATION_PORTRAIT;
+ orientation = EV_ORIENTATION_PORTRAIT;
}
- ev_view_set_orientation (view, new_orientation);
+
+ ev_view_set_orientation (view, orientation);
}
static double
ev_page_cache_get_size (view->page_cache,
view->current_page,
+ view->orientation,
1.0,
&doc_width,
&doc_height);
gdouble scale;
ev_page_cache_get_max_width (view->page_cache,
+ view->orientation,
1.0,
&doc_width);
ev_page_cache_get_max_height (view->page_cache,
+ view->orientation,
1.0,
&doc_height);
compute_border (view, doc_width, doc_height, &border);
gdouble scale;
ev_page_cache_get_max_width (view->page_cache,
+ view->orientation,
1.0,
&doc_width);
ev_page_cache_get_max_height (view->page_cache,
+ view->orientation,
1.0,
&doc_height);
compute_border (view, doc_width, doc_height, &border);
/* Find the largest of the two. */
ev_page_cache_get_size (view->page_cache,
view->current_page,
+ view->orientation,
1.0,
&doc_width, &doc_height);
gint width_2, height_2;
ev_page_cache_get_size (view->page_cache,
other_page,
+ view->orientation,
1.0,
&width_2, &height_2);
if (width_2 > doc_width)
ev_page_cache_get_size (view->page_cache,
view->current_page,
+ view->orientation,
1.0,
&doc_width,
&doc_height);
*/
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);
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,
+ view->orientation,
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;
}
}
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);
}
EvViewSelection *selection;
ev_page_cache_get_size (view->page_cache,
+ view->orientation,
i, 1.0, &width, &height);
selection = g_new0 (EvViewSelection, 1);
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;