From a3029ddff614db03ba5a4939b1dfb4f3e30d6ea6 Mon Sep 17 00:00:00 2001 From: Rahul Aggarwal Date: Fri, 4 Nov 2022 22:40:47 -0400 Subject: [PATCH] Add selection api, data, drawing functions --- zathura/page-widget.c | 83 ++++++++++++++++++++++++++++++++++++++----- zathura/page.c | 22 ++++++++++++ zathura/page.h | 10 ++++++ zathura/plugin-api.h | 10 ++++++ 4 files changed, 116 insertions(+), 9 deletions(-) diff --git a/zathura/page-widget.c b/zathura/page-widget.c index f38249a..3b4ce72 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "links.h" #include "page-widget.h" @@ -15,6 +16,7 @@ #include "utils.h" #include "shortcuts.h" #include "zathura.h" +#include "zathura/document.h" typedef struct zathura_page_widget_private_s { zathura_page_t* page; /**< Page object */ @@ -38,6 +40,12 @@ typedef struct zathura_page_widget_private_s { gboolean draw; /**< Draw search results */ } search; + struct { + girara_list_t *list; /**< List of selection rectangles that should be drawn */ + zathura_rectangle_t bounds; /** Bounds of highlighted selection */ + gboolean draw; /** Used to clear previous selection */ + } selection; + struct { girara_list_t* list; /**< List of images on the page */ gboolean retrieved; /**< True if we already tried to retrieve the list of images */ @@ -617,14 +625,25 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) ++idx; ); } - /* draw selection */ - if (priv->mouse.selection.y2 != -1 && priv->mouse.selection.x2 != -1) { + if (priv->selection.list != NULL && priv->selection.draw == true) { + int i = 0; const GdkRGBA color = priv->zathura->ui.colors.highlight_color; cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency); - cairo_rectangle(cairo, priv->mouse.selection.x1, priv->mouse.selection.y1, - (priv->mouse.selection.x2 - priv->mouse.selection.x1), (priv->mouse.selection.y2 - priv->mouse.selection.y1)); - cairo_fill(cairo); + GIRARA_LIST_FOREACH_BODY(priv->selection.list, zathura_rectangle_t*, rect, + zathura_rectangle_t rectangle = recalc_rectangle(priv->page, *rect); + cairo_rectangle(cairo, rectangle.x1, rectangle.y1, rectangle.x2 - rectangle.x1, rectangle.y2 - rectangle.y1); + cairo_fill(cairo); + ++i; + ); } + /* draw selection */ + /* if (priv->mouse.selection.y2 != -1 && priv->mouse.selection.x2 != -1) { */ + /* const GdkRGBA color = priv->zathura->ui.colors.highlight_color; */ + /* cairo_set_source_rgba(cairo, color.red, color.green, color.blue, transparency); */ + /* cairo_rectangle(cairo, priv->mouse.selection.x1, priv->mouse.selection.y1, */ + /* (priv->mouse.selection.x2 - priv->mouse.selection.x1), (priv->mouse.selection.y2 - priv->mouse.selection.y1)); */ + /* cairo_fill(cairo); */ + /* } */ } else { /* set background color */ if (zathura_renderer_recolor_enabled(priv->zathura->sync.render_thread) == true) { @@ -881,8 +900,14 @@ cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* but return true; } + if (priv->selection.list != NULL) { + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + } + if (button->button == GDK_BUTTON_PRIMARY) { /* left click */ if (button->type == GDK_BUTTON_PRESS) { + /* start the selection */ priv->mouse.selection_basepoint.x = button->x; priv->mouse.selection_basepoint.y = button->y; @@ -891,6 +916,7 @@ cb_zathura_page_widget_button_press_event(GtkWidget* widget, GdkEventButton* but priv->mouse.selection.y1 = button->y; priv->mouse.selection.x2 = button->x; priv->mouse.selection.y2 = button->y; + } else if (button->type == GDK_2BUTTON_PRESS || button->type == GDK_3BUTTON_PRESS) { /* abort the selection */ priv->mouse.selection_basepoint.x = -1; @@ -962,8 +988,6 @@ cb_zathura_page_widget_button_release_event(GtkWidget* widget, GdkEventButton* b ); } } else { - redraw_rect(ZATHURA_PAGE(widget), &priv->mouse.selection); - zathura_rectangle_t tmp = priv->mouse.selection; tmp.x1 /= scale; @@ -999,6 +1023,9 @@ cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event) ZathuraPage* page = ZATHURA_PAGE(widget); ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(page); + zathura_document_t* document = zathura_page_get_document(priv->page); + const double scale = zathura_document_get_scale(document); + if ((event->state & GDK_BUTTON1_MASK) == 0) { if (priv->links.retrieved == false) { priv->links.list = zathura_page_links_get(priv->page, NULL); @@ -1045,8 +1072,42 @@ cb_zathura_page_widget_motion_notify(GtkWidget* widget, GdkEventMotion* event) tmp.y2 = event->y; } - redraw_rect(ZATHURA_PAGE(widget), &priv->mouse.selection); - redraw_rect(ZATHURA_PAGE(widget), &tmp); + if (priv->selection.list != NULL) { + girara_list_free(priv->selection.list); + } + + zathura_rectangle_t scaled_mouse_selection = priv->mouse.selection; + + scaled_mouse_selection.x1 /= scale; + scaled_mouse_selection.x2 /= scale; + scaled_mouse_selection.y1 /= scale; + scaled_mouse_selection.y2 /= scale; + + /* zathura_rectangle_t redraw_bounds = {0, DBL_MAX, zathura_page_get_width(priv->page) * scale, 0}; */ + zathura_rectangle_t redraw_bounds = {DBL_MAX, DBL_MAX, 0, 0}; + priv->selection.list = zathura_page_get_selection(priv->page, scaled_mouse_selection, NULL); + + priv->selection.list = zathura_page_get_selection(priv->page, scaled_mouse_selection, NULL); + if (priv->selection.list != NULL && girara_list_size(priv->selection.list) != 0) { + GIRARA_LIST_FOREACH_BODY(priv->selection.list, zathura_rectangle_t*, rect, + double x1_s = rect->x1 * scale; + if (x1_s < redraw_bounds.x1) redraw_bounds.x1 = x1_s; + double y1_s = rect->y1 * scale; + if (y1_s < redraw_bounds.y1) redraw_bounds.y1 = y1_s; + double x2_s = rect->x2 * scale; + if (x2_s > redraw_bounds.x2) redraw_bounds.x2 = x2_s; + double y2_s = rect->y2 * scale; + if (y2_s > redraw_bounds.y2) redraw_bounds.y2 = y2_s; + ); + + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + priv->selection.draw = true; + redraw_rect(page, &redraw_bounds); + + priv->selection.bounds = redraw_bounds; + + } priv->mouse.selection = tmp; return false; @@ -1059,6 +1120,10 @@ cb_zathura_page_widget_leave_notify(GtkWidget* widget, GdkEventCrossing* UNUSED( ZathuraPage* page = ZATHURA_PAGE(widget); ZathuraPagePrivate* priv = zathura_page_widget_get_instance_private(page); + if (priv->selection.list != NULL) { + priv->selection.draw = false; + redraw_rect(page, &priv->selection.bounds); + } if (priv->mouse.over_link == true) { g_signal_emit(ZATHURA_PAGE(widget), signals[LEAVE_LINK], 0); priv->mouse.over_link = false; diff --git a/zathura/page.c b/zathura/page.c index 1a28951..8c7be99 100644 --- a/zathura/page.c +++ b/zathura/page.c @@ -344,6 +344,28 @@ zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathu return functions->page_get_text(page, page->data, rectangle, error); } +girara_list_t* +zathura_page_get_selection(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error) +{ + if (page == NULL || page->document == NULL ) { + if (error) { + *error = ZATHURA_ERROR_INVALID_ARGUMENTS; + } + return NULL; + } + + zathura_plugin_t* plugin = zathura_document_get_plugin(page->document); + const zathura_plugin_functions_t* functions = zathura_plugin_get_functions(plugin); + if (functions->page_get_selection == NULL) { + if (error) { + *error = ZATHURA_ERROR_NOT_IMPLEMENTED; + } + return NULL; + } + + return functions->page_get_selection(page, page->data, rectangle, error); +} + zathura_error_t zathura_page_render(zathura_page_t* page, cairo_t* cairo, bool printing) { diff --git a/zathura/page.h b/zathura/page.h index 572157e..da14278 100644 --- a/zathura/page.h +++ b/zathura/page.h @@ -192,6 +192,16 @@ ZATHURA_PLUGIN_API cairo_surface_t* zathura_page_image_get_cairo(zathura_page_t* */ ZATHURA_PLUGIN_API char* zathura_page_get_text(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); +/** + * Get rectangles from selection + * @param page Page + * @param rectangle Selection + * @param error Set to an error value (see \ref zathura_error_t) if an error + * occurred + * @return List of rectangles or NULL if an error occurred + */ +ZATHURA_PLUGIN_API girara_list_t* zathura_page_get_selection(zathura_page_t* page, zathura_rectangle_t rectangle, zathura_error_t* error); + /** * Render page * diff --git a/zathura/plugin-api.h b/zathura/plugin-api.h index 9077927..c090918 100644 --- a/zathura/plugin-api.h +++ b/zathura/plugin-api.h @@ -88,6 +88,11 @@ typedef cairo_surface_t* (*zathura_plugin_page_image_get_cairo_t)(zathura_page_t */ typedef char* (*zathura_plugin_page_get_text_t)(zathura_page_t* page, void* data, zathura_rectangle_t rectangle, zathura_error_t* error); +/** + * Get rectangles from selection + */ +typedef girara_list_t* (*zathura_plugin_page_get_selection_t)(zathura_page_t* page, void* data, zathura_rectangle_t rectangle, zathura_error_t* error); + /** * Renders the page */ @@ -181,6 +186,11 @@ struct zathura_plugin_functions_s */ zathura_plugin_page_get_text_t page_get_text; + /** + * Get text for selection + */ + zathura_plugin_page_get_selection_t page_get_selection; + /** * Renders the page */