[evince] libmisc: Enable popover menu in EvPageActionWidget



commit a6a0f608a635039bab2aca10da7067ebd765c7ce
Author: Germán Poo-Caamaño <gpoo gnome org>
Date:   Mon Jul 2 13:01:04 2018 -0400

    libmisc: Enable popover menu in EvPageActionWidget
    
    Enable to create an EvPageActionWidget with a menu, to provide
    a contextual menu (Popover) for actions related to navigate the
    document (or whatever the user would like to add).
    
    Fixes #564

 libmisc/ev-page-action-widget.c | 121 ++++++++++++++++++++++++++++++++++++++--
 libmisc/ev-page-action-widget.h |  21 ++++---
 2 files changed, 130 insertions(+), 12 deletions(-)
---
diff --git a/libmisc/ev-page-action-widget.c b/libmisc/ev-page-action-widget.c
index 511cac28..729f4e2f 100644
--- a/libmisc/ev-page-action-widget.c
+++ b/libmisc/ev-page-action-widget.c
@@ -1,6 +1,7 @@
 /*
  *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
  *  Copyright (C) 2003, 2004 Christian Persch
+ *  Copyright (C) 2018       Germán Poo-Caamaño
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -37,18 +38,28 @@ enum
        WIDGET_N_SIGNALS
 };
 
+enum
+{
+        PROP_0,
+
+        PROP_MENU
+};
+
 struct _EvPageActionWidget
 {
        GtkToolItem parent;
 
        EvDocument *document;
        EvDocumentModel *doc_model;
+       GMenu *menu;
 
        GtkWidget *entry;
        GtkWidget *label;
        guint signal_id;
        GtkTreeModel *filter_model;
        GtkTreeModel *model;
+       GtkPopover *popup;
+       gboolean popup_shown;
 };
 
 static guint widget_signals[WIDGET_N_SIGNALS] = {0, };
@@ -114,9 +125,18 @@ ev_page_action_widget_update_max_width (EvPageActionWidget *action_widget)
         gint   max_label_len;
         gchar *max_page_label;
         gchar *max_page_numeric_label;
+        gint   padding = 0;
 
         n_pages = ev_document_get_n_pages (action_widget->document);
 
+        if (action_widget->menu) {
+                gtk_entry_set_icon_from_icon_name (GTK_ENTRY (action_widget->label),
+                                                   GTK_ENTRY_ICON_SECONDARY,
+                                                   "go-down-symbolic");
+                /* width + 3 (for the icon). Similarly to EvZoomAction. */
+                padding = 3;
+        }
+
         max_page_label = ev_document_get_page_label (action_widget->document, n_pages - 1);
         max_page_numeric_label = g_strdup_printf ("%d", n_pages);
         if (ev_document_has_text_page_labels (action_widget->document) != 0) {
@@ -129,7 +149,7 @@ ev_page_action_widget_update_max_width (EvPageActionWidget *action_widget)
         }
         g_free (max_page_label);
 
-        gtk_entry_set_width_chars (GTK_ENTRY (action_widget->label), max_label_len);
+        gtk_entry_set_width_chars (GTK_ENTRY (action_widget->label), max_label_len + padding);
         g_free (max_label);
 
         max_label_len = ev_document_get_max_label_len (action_widget->document);
@@ -204,6 +224,51 @@ focus_out_cb (EvPageActionWidget *action_widget)
         return FALSE;
 }
 
+static void
+popup_menu_closed (GtkPopover         *popup,
+                   EvPageActionWidget *action_widget)
+{
+       if (action_widget->popup != popup)
+               return;
+
+       action_widget->popup_shown = FALSE;
+       action_widget->popup = NULL;
+}
+
+static GtkPopover *
+get_popup (EvPageActionWidget *action_widget)
+{
+       GdkRectangle rect;
+
+       if (action_widget->popup)
+               return action_widget->popup;
+
+       action_widget->popup = GTK_POPOVER (gtk_popover_new_from_model (GTK_WIDGET (action_widget),
+                                                                       G_MENU_MODEL (action_widget->menu)));
+       g_signal_connect (action_widget->popup, "closed",
+                         G_CALLBACK (popup_menu_closed),
+                          action_widget);
+       gtk_entry_get_icon_area (GTK_ENTRY (action_widget->label),
+                                GTK_ENTRY_ICON_SECONDARY, &rect);
+       gtk_popover_set_pointing_to (action_widget->popup, &rect);
+       gtk_popover_set_position (action_widget->popup, GTK_POS_BOTTOM);
+
+       return action_widget->popup;
+}
+
+static void
+entry_icon_press_callback (GtkEntry             *entry,
+                           GtkEntryIconPosition  icon_pos,
+                           GdkEventButton       *event,
+                           EvPageActionWidget   *action_widget)
+{
+       if (event->button != GDK_BUTTON_PRIMARY)
+               return;
+
+       gtk_popover_popup (get_popup (action_widget));
+       action_widget->popup_shown = TRUE;
+}
+
 static void
 ev_page_action_widget_init (EvPageActionWidget *action_widget)
 {
@@ -241,8 +306,9 @@ ev_page_action_widget_init (EvPageActionWidget *action_widget)
        gtk_widget_show (action_widget->entry);
 
        action_widget->label = gtk_entry_new ();
-        gtk_widget_set_sensitive (action_widget->label, FALSE);
-        gtk_entry_set_width_chars (GTK_ENTRY (action_widget->label), 5);
+       g_object_set (action_widget->label, "editable", FALSE, NULL);
+       gtk_entry_set_width_chars (GTK_ENTRY (action_widget->label), 5);
+
        gtk_box_pack_start (GTK_BOX (hbox), action_widget->label,
                            FALSE, FALSE, 0);
        gtk_widget_show (action_widget->label);
@@ -250,7 +316,19 @@ ev_page_action_widget_init (EvPageActionWidget *action_widget)
        gtk_container_add (GTK_CONTAINER (action_widget), hbox);
        gtk_widget_show (hbox);
 
-        gtk_widget_set_sensitive (GTK_WIDGET (action_widget), FALSE);
+       gtk_widget_set_sensitive (GTK_WIDGET (action_widget), FALSE);
+
+       g_signal_connect (action_widget->label, "icon-press",
+                         G_CALLBACK (entry_icon_press_callback),
+                         action_widget);
+}
+
+GtkWidget *
+ev_page_action_widget_new (GMenu *menu)
+{
+       return GTK_WIDGET (g_object_new (EV_TYPE_PAGE_ACTION_WIDGET,
+                                        "menu", menu,
+                                        NULL));
 }
 
 static void
@@ -334,6 +412,23 @@ ev_page_action_widget_finalize (GObject *object)
        G_OBJECT_CLASS (ev_page_action_widget_parent_class)->finalize (object);
 }
 
+static void
+ev_page_action_widget_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+       EvPageActionWidget *action_widget = EV_PAGE_ACTION_WIDGET (object);
+
+       switch (prop_id) {
+       case PROP_MENU:
+               action_widget->menu = g_value_dup_object (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
 static void
 ev_page_action_widget_get_preferred_width (GtkWidget *widget,
                                            gint      *minimum_width,
@@ -359,6 +454,17 @@ ev_page_action_widget_class_init (EvPageActionWidgetClass *klass)
 
        object_class->finalize = ev_page_action_widget_finalize;
         widget_class->get_preferred_width = ev_page_action_widget_get_preferred_width;
+       object_class->set_property = ev_page_action_widget_set_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_MENU,
+                                        g_param_spec_object ("menu",
+                                                       "Menu",
+                                                       "The navigation menu",
+                                                       G_TYPE_MENU,
+                                                       G_PARAM_WRITABLE |
+                                                       G_PARAM_CONSTRUCT_ONLY |
+                                                       G_PARAM_STATIC_STRINGS));
 
        widget_signals[WIDGET_ACTIVATE_LINK] =
                g_signal_new ("activate_link",
@@ -586,3 +692,10 @@ ev_page_action_widget_grab_focus (EvPageActionWidget *proxy)
        gtk_widget_grab_focus (proxy->entry);
 }
 
+gboolean
+ev_page_action_widget_get_popup_shown (EvPageActionWidget *action_widget)
+{
+       g_return_val_if_fail (EV_IS_PAGE_ACTION_WIDGET (action_widget), FALSE);
+
+       return action_widget->popup_shown;
+}
diff --git a/libmisc/ev-page-action-widget.h b/libmisc/ev-page-action-widget.h
index da70a3a8..1e1f71b7 100644
--- a/libmisc/ev-page-action-widget.h
+++ b/libmisc/ev-page-action-widget.h
@@ -1,6 +1,7 @@
 /*
  *  Copyright (C) 2003, 2004 Marco Pesenti Gritti
  *  Copyright (C) 2003, 2004 Christian Persch
+ *  Copyright (C) 2018       Germán Poo-Caamaño
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,8 +28,9 @@
 
 G_BEGIN_DECLS
 
-#define EV_TYPE_PAGE_ACTION_WIDGET (ev_page_action_widget_get_type ())
-#define EV_PAGE_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION_WIDGET, 
EvPageActionWidget))
+#define EV_TYPE_PAGE_ACTION_WIDGET    (ev_page_action_widget_get_type ())
+#define EV_PAGE_ACTION_WIDGET(obj)    (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PAGE_ACTION_WIDGET, 
EvPageActionWidget))
+#define EV_IS_PAGE_ACTION_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PAGE_ACTION_WIDGET))
 
 typedef struct _EvPageActionWidget EvPageActionWidget;
 typedef struct _EvPageActionWidgetClass EvPageActionWidgetClass;
@@ -41,14 +43,17 @@ struct _EvPageActionWidgetClass
                                EvLink             *link);
 };
 
-GType ev_page_action_widget_get_type          (void) G_GNUC_CONST;
+GType      ev_page_action_widget_get_type           (void) G_GNUC_CONST;
 
-void ev_page_action_widget_update_links_model (EvPageActionWidget *proxy,
-                                              GtkTreeModel       *model);
+void       ev_page_action_widget_update_links_model (EvPageActionWidget *proxy,
+                                                     GtkTreeModel       *model);
 
-void ev_page_action_widget_set_model          (EvPageActionWidget *action_widget,
-                                              EvDocumentModel    *doc_model);
-void ev_page_action_widget_grab_focus         (EvPageActionWidget *proxy);
+void       ev_page_action_widget_set_model          (EvPageActionWidget *action_widget,
+                                                     EvDocumentModel    *doc_model);
+void       ev_page_action_widget_grab_focus         (EvPageActionWidget *proxy);
+
+GtkWidget *ev_page_action_widget_new                (GMenu              *menu);
+gboolean   ev_page_action_widget_get_popup_shown    (EvPageActionWidget *action_widget);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]