[evince] Use a GtkEntry with an arrow icon instead of a GtkComboBox for zoom selector



commit 1648495f1d82c4469b855907e61e446a134bf297
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Fri Jul 26 17:23:31 2013 +0200

    Use a GtkEntry with an arrow icon instead of a GtkComboBox for zoom selector
    
    This allows us to use our own custom menu with toggle and non-toggle
    menu items. Fit-page and fit-width options are toggle menu items, so
    that it's possible to know which mode is currently in use. The code is
    simpler now too and zoom selector actions are handled like all other
    chrome actions.

 po/POTFILES.in                |    1 -
 shell/ev-window.c             |  125 +++++++++++---
 shell/ev-window.h             |   41 +++---
 shell/ev-zoom-action-widget.c |  377 +++++++++++++++++++++++------------------
 shell/ev-zoom-action-widget.h |   14 +-
 shell/ev-zoom-action.c        |   43 +++---
 shell/ev-zoom-action.h        |   34 +++-
 shell/evince-ui.xml           |    7 +
 8 files changed, 396 insertions(+), 246 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 87cc0c2..e02c4f1 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -54,6 +54,5 @@ shell/ev-sidebar-thumbnails.c
 shell/ev-utils.c
 shell/ev-window.c
 shell/ev-window-title.c
-shell/ev-zoom-action-widget.c
 shell/main.c
 [type: gettext/glade]shell/evince-appmenu.ui
diff --git a/shell/ev-window.c b/shell/ev-window.c
index db25972..06ce072 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -173,6 +173,7 @@ struct _EvWindowPrivate {
        GtkActionGroup   *action_group;
        GtkActionGroup   *view_popup_action_group;
        GtkActionGroup   *attachment_popup_action_group;
+       GtkActionGroup   *zoom_selector_popup_action_group;
        GtkRecentManager *recent_manager;
        GtkActionGroup   *recent_action_group;
        guint             recent_ui_id;
@@ -474,8 +475,6 @@ ev_window_setup_action_sensitivity (EvWindow *ev_window)
        ev_window_set_action_sensitive (ev_window, "ViewContinuous", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewDual", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewDualOddLeft", has_pages);
-       ev_window_set_action_sensitive (ev_window, "ViewFitPage", has_pages);
-       ev_window_set_action_sensitive (ev_window, "ViewFitWidth", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewReload", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewAutoscroll", has_pages);
        ev_window_set_action_sensitive (ev_window, "ViewInvertedColors", has_pages);
@@ -597,7 +596,7 @@ update_chrome_flag (EvWindow *window, EvChrome flag, gboolean active)
 static void
 update_sizing_buttons (EvWindow *window)
 {
-       GtkActionGroup *action_group = window->priv->action_group;
+       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
        GtkAction *action;
        gboolean fit_page, fit_width;
 
@@ -3852,6 +3851,26 @@ ev_window_cmd_fit_width (GtkAction *action, EvWindow *ev_window)
        ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FIT_WIDTH);
 }
 
+static void
+ev_window_cmd_view_zoom_activate (GtkAction *action,
+                                 EvWindow  *ev_window)
+{
+       const char *action_name = gtk_action_get_name (action);
+       gdouble     zoom = 0;
+       guint       i;
+
+       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
+               if (strcmp (action_name, zoom_levels[i].name) == 0) {
+                       zoom = zoom_levels[i].level;
+                       break;
+               }
+       }
+       g_assert (zoom > 0);
+
+       ev_document_model_set_sizing_mode (ev_window->priv->model, EV_SIZING_FREE);
+       ev_document_model_set_scale (ev_window->priv->model,
+                                    zoom * get_screen_dpi (ev_window) / 72.0);
+}
 
 static void
 ev_window_cmd_edit_select_all (GtkAction *action, EvWindow *ev_window)
@@ -4766,15 +4785,24 @@ ev_window_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *
 }
 
 static void
-ev_window_max_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *window)
+ev_window_setup_zoom_actions_visibility (EvWindow *window,
+                                        gdouble   max_scale)
 {
-       GtkAction *action;
-       gdouble max_scale;
+       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
+       guint           i;
 
-       max_scale = ev_document_model_get_max_scale (model);
-       action = gtk_action_group_get_action (window->priv->action_group,
-                                             ZOOM_CONTROL_ACTION);
-       ev_zoom_action_set_max_zoom_level (EV_ZOOM_ACTION (action), max_scale);
+       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
+               GtkAction *action;
+
+               action = gtk_action_group_get_action (action_group, zoom_levels[i].name);
+               gtk_action_set_visible (action, zoom_levels[i].level <= max_scale);
+       }
+}
+
+static void
+ev_window_max_zoom_changed_cb (EvDocumentModel *model, GParamSpec *pspec, EvWindow *window)
+{
+       ev_window_setup_zoom_actions_visibility (window, ev_document_model_get_max_scale (model));
 }
 
 static void
@@ -5612,6 +5640,8 @@ ev_window_dispose (GObject *object)
                priv->attachment_popup_action_group = NULL;
        }
 
+       g_clear_object (&priv->zoom_selector_popup_action_group);
+
        if (priv->recent_action_group) {
                g_object_unref (priv->recent_action_group);
                priv->recent_action_group = NULL;
@@ -5982,12 +6012,6 @@ static const GtkToggleActionEntry toggle_entries[] = {
         { "ViewPresentation", EV_STOCK_RUN_PRESENTATION, N_("Pre_sentation"), "F5",
           N_("Run document as a presentation"),
           G_CALLBACK (ev_window_cmd_view_presentation) },
-        { "ViewFitPage", EV_STOCK_ZOOM_PAGE, N_("Fit Pa_ge"), NULL,
-          N_("Make the current document fill the window"),
-          G_CALLBACK (ev_window_cmd_view_fit_page) },
-        { "ViewFitWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit _Width"), NULL,
-          N_("Make the current document fill the window width"),
-          G_CALLBACK (ev_window_cmd_view_fit_width) },
        { "ViewInvertedColors", EV_STOCK_INVERTED_COLORS, N_("_Inverted Colors"), "<control>I",
          N_("Show page contents with the colors inverted"),
          G_CALLBACK (ev_window_cmd_view_inverted_colors) },
@@ -5995,7 +6019,6 @@ static const GtkToggleActionEntry toggle_entries[] = {
        { "EditFind", "edit-find-symbolic", N_("_Find…"), "<control>F",
          N_("Find a word or phrase in the document"),
          G_CALLBACK (ev_window_cmd_toggle_find) },
-
 };
 
 /* Popups specific items */
@@ -6024,6 +6047,15 @@ static const GtkActionEntry attachment_popup_entries [] = {
          NULL, G_CALLBACK (ev_attachment_popup_cmd_save_attachment_as) },
 };
 
+static const GtkToggleActionEntry zoom_selector_popup_actions[] = {
+       { "ViewFitPage", EV_STOCK_ZOOM_PAGE, N_("Fit Pa_ge"), NULL,
+         N_("Make the current document fill the window"),
+         G_CALLBACK (ev_window_cmd_view_fit_page) },
+       { "ViewFitWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit _Width"), NULL,
+         N_("Make the current document fill the window width"),
+         G_CALLBACK (ev_window_cmd_view_fit_width) }
+};
+
 static void
 sidebar_links_link_activated_cb (EvSidebarLinks *sidebar_links, EvLink *link, EvWindow *window)
 {
@@ -6091,6 +6123,36 @@ zoom_action_activated_cb (EvZoomAction *action,
 }
 
 static void
+ev_window_register_zoom_selector_popup_actions (EvWindow *window)
+{
+       GtkActionGroup *action_group = window->priv->zoom_selector_popup_action_group;
+       guint           i, new_ui_id;
+
+       new_ui_id = gtk_ui_manager_new_merge_id (window->priv->ui_manager);
+
+       for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
+               GtkAction *action;
+
+               action = gtk_action_new (zoom_levels[i].name,
+                                        _(zoom_levels[i].name),
+                                        NULL, NULL);
+               g_signal_connect (action, "activate",
+                                 G_CALLBACK (ev_window_cmd_view_zoom_activate),
+                                 window);
+               gtk_action_group_add_action (action_group, action);
+               g_object_unref (action);
+
+               gtk_ui_manager_add_ui (window->priv->ui_manager,
+                                      new_ui_id,
+                                      "/ZoomSelectorPopup/ViewZoomItems",
+                                      _(zoom_levels[i].name),
+                                      zoom_levels[i].name,
+                                      GTK_UI_MANAGER_MENUITEM,
+                                      FALSE);
+       }
+}
+
+static void
 register_custom_actions (EvWindow *window, GtkActionGroup *group)
 {
        GtkAction *action;
@@ -6117,6 +6179,8 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group)
                               NULL);
        ev_zoom_action_set_model (EV_ZOOM_ACTION (action),
                                  window->priv->model);
+       ev_zoom_action_set_window (EV_ZOOM_ACTION (action),
+                                  window);
        g_signal_connect (action, "activated",
                          G_CALLBACK (zoom_action_activated_cb), window);
        gtk_action_group_add_action (group, action);
@@ -6178,14 +6242,6 @@ set_action_properties (GtkActionGroup *action_group)
        /*translators: this is the label for toolbar button*/
        g_object_set (action, "short_label", _("Zoom Out"), NULL);
 
-       action = gtk_action_group_get_action (action_group, "ViewFitPage");
-       /*translators: this is the label for toolbar button*/
-       g_object_set (action, "short_label", _("Fit Page"), NULL);
-
-       action = gtk_action_group_get_action (action_group, "ViewFitWidth");
-       /*translators: this is the label for toolbar button*/
-       g_object_set (action, "short_label", _("Fit Width"), NULL);
-
        action = gtk_action_group_get_action (action_group, "LeaveFullscreen");
        g_object_set (action, "is-important", TRUE, NULL);
 }
@@ -7160,11 +7216,22 @@ ev_window_init (EvWindow *ev_window)
        gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
                                            action_group, 0);
 
+       action_group = gtk_action_group_new ("ZoomSelectorPopupActions");
+       ev_window->priv->zoom_selector_popup_action_group = action_group;
+       gtk_action_group_set_translation_domain (action_group, NULL);
+       gtk_action_group_add_toggle_actions (action_group, zoom_selector_popup_actions,
+                                            G_N_ELEMENTS (zoom_selector_popup_actions),
+                                            ev_window);
+       gtk_ui_manager_insert_action_group (ev_window->priv->ui_manager,
+                                           action_group, 0);
+
         gtk_ui_manager_add_ui_from_resource (ev_window->priv->ui_manager,
                                              "/org/gnome/evince/shell/ui/evince.xml",
                                              &error);
         g_assert_no_error (error);
 
+       ev_window_register_zoom_selector_popup_actions (ev_window);
+
        css_provider = gtk_css_provider_new ();
        _gtk_css_provider_load_from_resource (css_provider,
                                              "/org/gnome/evince/shell/ui/evince.css",
@@ -7547,3 +7614,11 @@ ev_window_get_main_action_group (EvWindow *ev_window)
 
        return ev_window->priv->action_group;
 }
+
+GtkActionGroup *
+ev_window_get_zoom_selector_action_group (EvWindow *ev_window)
+{
+       g_return_val_if_fail (EV_WINDOW (ev_window), NULL);
+
+       return ev_window->priv->zoom_selector_popup_action_group;
+}
diff --git a/shell/ev-window.h b/shell/ev-window.h
index 5c618e7..fd2d0b5 100644
--- a/shell/ev-window.h
+++ b/shell/ev-window.h
@@ -68,26 +68,27 @@ struct _EvWindowClass {
        GtkApplicationWindowClass base_class;
 };
 
-GType          ev_window_get_type              (void) G_GNUC_CONST;
-GtkWidget      *ev_window_new                   (void);
-const char     *ev_window_get_uri               (EvWindow       *ev_window);
-void           ev_window_open_uri              (EvWindow       *ev_window,
-                                                 const char     *uri,
-                                                 EvLinkDest     *dest,
-                                                 EvWindowRunMode mode,
-                                                 const gchar    *search_string);
-void           ev_window_open_document         (EvWindow       *ev_window,
-                                                 EvDocument     *document,
-                                                 EvLinkDest     *dest,
-                                                 EvWindowRunMode mode,
-                                                 const gchar    *search_string);
-gboolean       ev_window_is_empty              (const EvWindow *ev_window);
-void           ev_window_print_range           (EvWindow       *ev_window,
-                                                 int             first_page,
-                                                 int            last_page);
-const gchar    *ev_window_get_dbus_object_path  (EvWindow       *ev_window);
-GtkUIManager   *ev_window_get_ui_manager        (EvWindow       *ev_window);
-GtkActionGroup *ev_window_get_main_action_group (EvWindow       *ev_window);
+GType          ev_window_get_type                       (void) G_GNUC_CONST;
+GtkWidget      *ev_window_new                            (void);
+const char     *ev_window_get_uri                        (EvWindow       *ev_window);
+void           ev_window_open_uri                       (EvWindow       *ev_window,
+                                                          const char     *uri,
+                                                          EvLinkDest     *dest,
+                                                          EvWindowRunMode mode,
+                                                          const gchar    *search_string);
+void           ev_window_open_document                  (EvWindow       *ev_window,
+                                                          EvDocument     *document,
+                                                          EvLinkDest     *dest,
+                                                          EvWindowRunMode mode,
+                                                          const gchar    *search_string);
+gboolean       ev_window_is_empty                       (const EvWindow *ev_window);
+void           ev_window_print_range                    (EvWindow       *ev_window,
+                                                          int             first_page,
+                                                          int           last_page);
+const gchar    *ev_window_get_dbus_object_path           (EvWindow       *ev_window);
+GtkUIManager   *ev_window_get_ui_manager                 (EvWindow       *ev_window);
+GtkActionGroup *ev_window_get_main_action_group          (EvWindow       *ev_window);
+GtkActionGroup *ev_window_get_zoom_selector_action_group (EvWindow       *ev_window);
 
 
 G_END_DECLS
diff --git a/shell/ev-zoom-action-widget.c b/shell/ev-zoom-action-widget.c
index 379e43d..95a7f3b 100644
--- a/shell/ev-zoom-action-widget.c
+++ b/shell/ev-zoom-action-widget.c
@@ -21,48 +21,22 @@
 #include "config.h"
 
 #include "ev-zoom-action-widget.h"
+#include "ev-zoom-action.h"
 
 #include <glib/gi18n.h>
 
-struct _EvZoomActionWidgetPrivate {
-        GtkWidget       *combo;
-
-        EvDocumentModel *model;
-        gulong           combo_changed_handler;
-};
-
-#define EV_ZOOM_FIT_PAGE  (-3.0)
-#define EV_ZOOM_FIT_WIDTH (-4.0)
-#define EV_ZOOM_SEPARATOR (-5.0)
-
-static const struct {
-        const gchar *name;
-        float        level;
-} zoom_levels[] = {
-        { N_("Fit Page"),  EV_ZOOM_FIT_PAGE  },
-        { N_("Fit Width"), EV_ZOOM_FIT_WIDTH },
-        { NULL,            EV_ZOOM_SEPARATOR },
-        { N_("50%"), 0.5 },
-        { N_("70%"), 0.7071067811 },
-        { N_("85%"), 0.8408964152 },
-        { N_("100%"), 1.0 },
-        { N_("125%"), 1.1892071149 },
-        { N_("150%"), 1.4142135623 },
-        { N_("175%"), 1.6817928304 },
-        { N_("200%"), 2.0 },
-        { N_("300%"), 2.8284271247 },
-        { N_("400%"), 4.0 },
-        { N_("800%"), 8.0 },
-        { N_("1600%"), 16.0 },
-        { N_("3200%"), 32.0 },
-        { N_("6400%"), 64.0 }
+enum {
+        PROP_0,
+        PROP_POPUP_SHOWN
 };
 
-enum {
-        TEXT_COLUMN,
-        IS_SEPARATOR_COLUMN,
+struct _EvZoomActionWidgetPrivate {
+        GtkWidget       *entry;
 
-        N_COLUMNS
+        EvDocumentModel *model;
+        EvWindow        *window;
+        GtkWidget       *popup;
+        gboolean         popup_shown;
 };
 
 G_DEFINE_TYPE (EvZoomActionWidget, ev_zoom_action_widget, GTK_TYPE_TOOL_ITEM)
@@ -73,14 +47,14 @@ static void
 ev_zoom_action_widget_set_zoom_level (EvZoomActionWidget *control,
                                       float               zoom)
 {
-        GtkWidget *entry = gtk_bin_get_child (GTK_BIN (control->priv->combo));
-        gchar     *zoom_str;
-        float      zoom_perc;
-        guint      i;
+        gchar *zoom_str;
+        float  zoom_perc;
+        guint  i;
 
         for (i = 3; i < G_N_ELEMENTS (zoom_levels); i++) {
                 if (ABS (zoom - zoom_levels[i].level) < EPSILON) {
-                        gtk_entry_set_text (GTK_ENTRY (entry), zoom_levels[i].name);
+                        gtk_entry_set_text (GTK_ENTRY (control->priv->entry),
+                                            zoom_levels[i].name);
                         return;
                 }
         }
@@ -90,7 +64,7 @@ ev_zoom_action_widget_set_zoom_level (EvZoomActionWidget *control,
                 zoom_str = g_strdup_printf ("%d%%", (gint)zoom_perc);
         else
                 zoom_str = g_strdup_printf ("%.2f%%", zoom_perc);
-        gtk_entry_set_text (GTK_ENTRY (entry), zoom_str);
+        gtk_entry_set_text (GTK_ENTRY (control->priv->entry), zoom_str);
         g_free (zoom_str);
 }
 
@@ -124,36 +98,7 @@ document_changed_cb (EvDocumentModel    *model,
 }
 
 static void
-combo_changed_cb (GtkComboBox        *combo,
-                  EvZoomActionWidget *control)
-{
-        gint         index;
-        float        zoom;
-        EvSizingMode mode;
-
-        index = gtk_combo_box_get_active (combo);
-        if (index == -1)
-                return;
-
-        zoom = zoom_levels[index].level;
-        if (zoom == EV_ZOOM_FIT_PAGE)
-                mode = EV_SIZING_FIT_PAGE;
-        else if (zoom == EV_ZOOM_FIT_WIDTH)
-                mode = EV_SIZING_FIT_WIDTH;
-        else
-                mode = EV_SIZING_FREE;
-
-        ev_document_model_set_sizing_mode (control->priv->model, mode);
-        if (mode == EV_SIZING_FREE) {
-                GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (control));
-
-                ev_document_model_set_scale (control->priv->model,
-                                             zoom * ev_document_misc_get_screen_dpi (screen) / 72.0);
-        }
-}
-
-static void
-combo_activated_cb (GtkEntry           *entry,
+entry_activated_cb (GtkEntry           *entry,
                     EvZoomActionWidget *control)
 {
         GdkScreen   *screen;
@@ -181,124 +126,233 @@ combo_activated_cb (GtkEntry           *entry,
 }
 
 static gboolean
-combo_focus_out_cb (EvZoomActionWidget *control)
+focus_out_cb (EvZoomActionWidget *control)
 {
         ev_zoom_action_widget_update_zoom_level (control);
 
         return FALSE;
 }
 
-static gchar *
-combo_format_entry_text (GtkComboBox        *combo,
-                         const gchar        *path,
-                         EvZoomActionWidget *control)
+static gint
+get_max_zoom_level_label (EvZoomActionWidget *control)
 {
-        GtkWidget *entry = gtk_bin_get_child (GTK_BIN (combo));
+        GList *actions, *l;
+        gint   width = 0;
 
-        return g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
+        actions = gtk_action_group_list_actions (ev_window_get_zoom_selector_action_group 
(control->priv->window));
+
+        for (l = actions; l; l = g_list_next (l)) {
+                GtkAction *action = (GtkAction *)l->data;
+                int        length;
+
+                length = g_utf8_strlen (gtk_action_get_label (action), -1);
+                if (length > width)
+                        width = length;
+        }
+
+        g_list_free (actions);
+
+        /* Count the toggle size as one character more */
+        return width + 1;
 }
 
-static gboolean
-row_is_separator (GtkTreeModel *model,
-                  GtkTreeIter  *iter,
-                  gpointer      data)
+static void
+popup_menu_show_cb (GtkWidget          *widget,
+                    EvZoomActionWidget *control)
 {
-        gboolean is_sep;
-
-        gtk_tree_model_get (model, iter, IS_SEPARATOR_COLUMN, &is_sep, -1);
+        control->priv->popup_shown = TRUE;
+        g_object_notify (G_OBJECT (control), "popup-shown");
+}
 
-        return is_sep;
+static void
+popup_menu_hide_cb (GtkWidget          *widget,
+                    EvZoomActionWidget *control)
+{
+        control->priv->popup_shown = FALSE;
+        g_object_notify (G_OBJECT (control), "popup-shown");
 }
 
 static void
-ev_zoom_action_widget_finalize (GObject *object)
+popup_menu_detached (EvZoomActionWidget *control,
+                     GtkWidget          *popup)
 {
-        EvZoomActionWidget *control = EV_ZOOM_ACTION_WIDGET (object);
+        GtkWidget *toplevel;
 
-        ev_zoom_action_widget_set_model (control, NULL);
+        if (control->priv->popup != popup)
+                return;
+
+        toplevel = gtk_widget_get_toplevel (control->priv->popup);
+        g_signal_handlers_disconnect_by_func (toplevel,
+                                              popup_menu_show_cb,
+                                              control);
+        g_signal_handlers_disconnect_by_func (toplevel,
+                                              popup_menu_hide_cb,
+                                              control);
 
-        G_OBJECT_CLASS (ev_zoom_action_widget_parent_class)->finalize (object);
+        control->priv->popup = NULL;
 }
 
-static void
-fill_combo_model (GtkListStore *model,
-                  guint         max_level)
+static GtkWidget *
+get_popup (EvZoomActionWidget *control)
 {
-        guint i;
+        GtkUIManager *ui_manager;
+        GtkWidget    *toplevel;
+
+        if (control->priv->popup)
+                return control->priv->popup;
+
+        ui_manager = ev_window_get_ui_manager (control->priv->window);
+        control->priv->popup = gtk_ui_manager_get_widget (ui_manager, "/ZoomSelectorPopup");
+        gtk_menu_attach_to_widget (GTK_MENU (control->priv->popup), GTK_WIDGET (control),
+                                   (GtkMenuDetachFunc)popup_menu_detached);
+        toplevel = gtk_widget_get_toplevel (control->priv->popup);
+        g_signal_connect (toplevel, "show",
+                          G_CALLBACK (popup_menu_show_cb),
+                          control);
+        g_signal_connect (toplevel, "hide",
+                          G_CALLBACK (popup_menu_hide_cb),
+                          control);
 
-        for (i = 0; i < max_level; i++) {
-                GtkTreeIter iter;
+        return control->priv->popup;
+}
 
-                gtk_list_store_append (model, &iter);
-                gtk_list_store_set (model, &iter,
-                                    TEXT_COLUMN, _(zoom_levels[i].name),
-                                    IS_SEPARATOR_COLUMN, zoom_levels[i].name == NULL,
-                                    -1);
+static void
+menu_position_below (GtkMenu  *menu,
+                     gint     *x,
+                     gint     *y,
+                     gint     *push_in,
+                     gpointer  user_data)
+{
+        EvZoomActionWidget *control;
+        GtkWidget          *widget;
+        GtkAllocation       child_allocation;
+        GtkRequisition      req;
+        GdkScreen          *screen;
+        gint                monitor_num;
+        GdkRectangle        monitor;
+        gint                sx = 0, sy = 0;
+
+        control = EV_ZOOM_ACTION_WIDGET (user_data);
+        widget = GTK_WIDGET (control);
+
+        gtk_widget_get_allocation (control->priv->entry, &child_allocation);
+
+        if (!gtk_widget_get_has_window (control->priv->entry)) {
+                sx += child_allocation.x;
+                sy += child_allocation.y;
         }
+
+        gdk_window_get_root_coords (gtk_widget_get_window (control->priv->entry),
+                                    sx, sy, &sx, &sy);
+
+        gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
+
+        if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
+                *x = sx;
+        else
+                *x = sx + child_allocation.width - req.width;
+        *y = sy;
+
+        screen = gtk_widget_get_screen (widget);
+        monitor_num = gdk_screen_get_monitor_at_window (screen,
+                                                        gtk_widget_get_window (widget));
+        gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+        if (*x < monitor.x)
+                *x = monitor.x;
+        else if (*x + req.width > monitor.x + monitor.width)
+                *x = monitor.x + monitor.width - req.width;
+
+        if (monitor.y + monitor.height - *y - child_allocation.height >= req.height)
+                *y += child_allocation.height;
+        else if (*y - monitor.y >= req.height)
+                *y -= req.height;
+        else if (monitor.y + monitor.height - *y - child_allocation.height > *y - monitor.y)
+                *y += child_allocation.height;
+        else
+                *y -= req.height;
+
+        *push_in = FALSE;
 }
 
-static gint
-get_max_zoom_level_label (void)
+static void
+entry_icon_press_callback (GtkEntry            *entry,
+                           GtkEntryIconPosition icon_pos,
+                           GdkEventButton      *event,
+                           EvZoomActionWidget  *control)
 {
-        gint i;
-        gint width = 0;
+        GtkWidget *menu;
 
-        for (i = 0; i < G_N_ELEMENTS (zoom_levels); i++) {
-                int length;
+        if (!control->priv->window || event->button != GDK_BUTTON_PRIMARY)
+                return;
 
-                length = zoom_levels[i].name ? strlen (_(zoom_levels[i].name)) : 0;
-                if (length > width)
-                        width = length;
-        }
+        menu = get_popup (control);
+        gtk_widget_set_size_request (menu,
+                                     gtk_widget_get_allocated_width (GTK_WIDGET (control)),
+                                     -1);
 
-        return width;
+        gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                        menu_position_below, control,
+                        event->button, event->time);
+}
+
+static gboolean
+setup_initial_entry_size (EvZoomActionWidget *control)
+{
+        gtk_entry_set_width_chars (GTK_ENTRY (control->priv->entry),
+                                   get_max_zoom_level_label (control));
+        return FALSE;
 }
 
 static void
 ev_zoom_action_widget_init (EvZoomActionWidget *control)
 {
         EvZoomActionWidgetPrivate *priv;
-        GtkWidget                 *entry;
         GtkWidget                 *vbox;
-        GtkListStore              *store;
 
         control->priv = G_TYPE_INSTANCE_GET_PRIVATE (control, EV_TYPE_ZOOM_ACTION_WIDGET, 
EvZoomActionWidgetPrivate);
         priv = control->priv;
 
-        store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN);
-        fill_combo_model (store, G_N_ELEMENTS (zoom_levels));
-
-        priv->combo = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (store));
-        gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (priv->combo), FALSE);
-        gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->combo), TEXT_COLUMN);
-        gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (priv->combo),
-                                              (GtkTreeViewRowSeparatorFunc)row_is_separator,
-                                              NULL, NULL);
-        g_object_unref (store);
-
-        entry = gtk_bin_get_child (GTK_BIN (priv->combo));
-        gtk_entry_set_width_chars (GTK_ENTRY (entry), get_max_zoom_level_label ());
-
         vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-        gtk_box_pack_start (GTK_BOX (vbox), priv->combo, TRUE, FALSE, 0);
-        gtk_widget_show (priv->combo);
+
+        priv->entry = gtk_entry_new ();
+        gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->entry),
+                                           GTK_ENTRY_ICON_SECONDARY,
+                                           "go-down-symbolic");
+        gtk_box_pack_start (GTK_BOX (vbox), priv->entry, TRUE, FALSE, 0);
+        gtk_widget_show (priv->entry);
 
         gtk_container_add (GTK_CONTAINER (control), vbox);
         gtk_widget_show (vbox);
 
-        priv->combo_changed_handler =
-                g_signal_connect (priv->combo, "changed",
-                                  G_CALLBACK (combo_changed_cb),
-                                  control);
-        g_signal_connect (priv->combo, "format-entry-text",
-                          G_CALLBACK (combo_format_entry_text),
+        g_signal_connect (priv->entry, "icon-press",
+                          G_CALLBACK (entry_icon_press_callback),
                           control);
-        g_signal_connect (entry, "activate",
-                          G_CALLBACK (combo_activated_cb),
+        g_signal_connect (priv->entry, "activate",
+                          G_CALLBACK (entry_activated_cb),
                           control);
-        g_signal_connect_swapped (entry, "focus-out-event",
-                                  G_CALLBACK (combo_focus_out_cb),
+        g_signal_connect_swapped (priv->entry, "focus-out-event",
+                                  G_CALLBACK (focus_out_cb),
                                   control);
+
+        g_idle_add ((GSourceFunc)setup_initial_entry_size, control);
+}
+
+static void
+ev_zoom_action_widget_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+        EvZoomActionWidget *control = EV_ZOOM_ACTION_WIDGET (object);
+
+        switch (prop_id) {
+        case PROP_POPUP_SHOWN:
+                g_value_set_boolean (value, control->priv->popup_shown);
+                break;
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+         }
 }
 
 static void
@@ -306,7 +360,15 @@ ev_zoom_action_widget_class_init (EvZoomActionWidgetClass *klass)
 {
         GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-        object_class->finalize = ev_zoom_action_widget_finalize;
+        object_class->get_property = ev_zoom_action_widget_get_property;
+
+        g_object_class_install_property (object_class,
+                                         PROP_POPUP_SHOWN,
+                                         g_param_spec_boolean ("popup-shown",
+                                                               "Popup shown",
+                                                               "Whether the zoom control's dropdown is 
shown",
+                                                               FALSE,
+                                                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 
         g_type_class_add_private (object_class, sizeof (EvZoomActionWidgetPrivate));
 }
@@ -349,36 +411,19 @@ ev_zoom_action_widget_set_model (EvZoomActionWidget *control,
 }
 
 void
-ev_zoom_action_widget_set_max_zoom_level (EvZoomActionWidget *control,
-                                          float               max_zoom)
+ev_zoom_action_widget_set_window (EvZoomActionWidget *control,
+                                  EvWindow           *window)
 {
-        EvZoomActionWidgetPrivate *priv;
-        GtkListStore              *model;
-        guint                      max_level_index = 3;
-        guint                      i;
-
-        g_return_if_fail (EV_IS_ZOOM_ACTION_WIDGET (control));
-
-        priv = control->priv;
-
-        for (i = 3; i < G_N_ELEMENTS (zoom_levels); i++, max_level_index++) {
-                if (zoom_levels[i].level > max_zoom)
-                        break;
-        }
-
-        g_signal_handler_block (priv->combo, priv->combo_changed_handler);
-
-        model = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (priv->combo)));
-        gtk_list_store_clear (model);
-        fill_combo_model (model, max_level_index);
+        if (control->priv->window == window)
+                return;
 
-        g_signal_handler_unblock (priv->combo, priv->combo_changed_handler);
+        control->priv->window = window;
 }
 
 GtkWidget *
-ev_zoom_action_widget_get_combo_box (EvZoomActionWidget *control)
+ev_zoom_action_widget_get_entry (EvZoomActionWidget *control)
 {
         g_return_val_if_fail (EV_IS_ZOOM_ACTION_WIDGET (control), NULL);
 
-        return control->priv->combo;
+        return control->priv->entry;
 }
diff --git a/shell/ev-zoom-action-widget.h b/shell/ev-zoom-action-widget.h
index c42c7d3..a2dc293 100644
--- a/shell/ev-zoom-action-widget.h
+++ b/shell/ev-zoom-action-widget.h
@@ -25,6 +25,8 @@
 #include <evince-document.h>
 #include <evince-view.h>
 
+#include "ev-window.h"
+
 G_BEGIN_DECLS
 
 #define EV_TYPE_ZOOM_ACTION_WIDGET            (ev_zoom_action_widget_get_type())
@@ -48,13 +50,13 @@ struct _EvZoomActionWidgetClass {
         GtkToolItemClass parent_class;
 };
 
-GType      ev_zoom_action_widget_get_type           (void);
+GType      ev_zoom_action_widget_get_type   (void);
 
-void       ev_zoom_action_widget_set_model          (EvZoomActionWidget *control,
-                                                     EvDocumentModel    *model);
-GtkWidget *ev_zoom_action_widget_get_combo_box      (EvZoomActionWidget *control);
-void       ev_zoom_action_widget_set_max_zoom_level (EvZoomActionWidget *control,
-                                                     float               max_zoom);
+void       ev_zoom_action_widget_set_model  (EvZoomActionWidget *control,
+                                             EvDocumentModel    *model);
+GtkWidget *ev_zoom_action_widget_get_entry  (EvZoomActionWidget *control);
+void       ev_zoom_action_widget_set_window (EvZoomActionWidget *control,
+                                             EvWindow           *window);
 
 G_END_DECLS
 
diff --git a/shell/ev-zoom-action.c b/shell/ev-zoom-action.c
index f75d853..920fb9c 100644
--- a/shell/ev-zoom-action.c
+++ b/shell/ev-zoom-action.c
@@ -31,8 +31,8 @@ enum {
 
 struct _EvZoomActionPrivate {
         EvDocumentModel *model;
+        EvWindow        *window;
         gboolean         popup_shown;
-        float            max_zoom;
 };
 
 G_DEFINE_TYPE (EvZoomAction, ev_zoom_action, GTK_TYPE_ACTION)
@@ -40,11 +40,11 @@ G_DEFINE_TYPE (EvZoomAction, ev_zoom_action, GTK_TYPE_ACTION)
 static guint signals[LAST_SIGNAL] = { 0 };
 
 static void
-popup_shown_cb (GObject      *combo,
+popup_shown_cb (GObject      *zoom_widget,
                 GParamSpec   *pspec,
                 EvZoomAction *zoom_action)
 {
-        g_object_get (combo, "popup-shown", &zoom_action->priv->popup_shown, NULL);
+        g_object_get (zoom_widget, "popup-shown", &zoom_action->priv->popup_shown, NULL);
 }
 
 static void
@@ -61,16 +61,13 @@ connect_proxy (GtkAction *action,
         if (EV_IS_ZOOM_ACTION_WIDGET (proxy))   {
                 EvZoomAction *zoom_action = EV_ZOOM_ACTION (action);
                 EvZoomActionWidget* zoom_widget = EV_ZOOM_ACTION_WIDGET (proxy);
-                GtkWidget *combo;
 
                 ev_zoom_action_widget_set_model (zoom_widget, zoom_action->priv->model);
-                ev_zoom_action_widget_set_max_zoom_level (zoom_widget, zoom_action->priv->max_zoom);
-
-                combo = ev_zoom_action_widget_get_combo_box (zoom_widget);
-                g_signal_connect (combo, "notify::popup-shown",
+                ev_zoom_action_widget_set_window (zoom_widget, zoom_action->priv->window);
+                g_signal_connect (zoom_widget, "notify::popup-shown",
                                   G_CALLBACK (popup_shown_cb),
                                   action);
-                g_signal_connect (gtk_bin_get_child (GTK_BIN (combo)), "activate",
+                g_signal_connect (ev_zoom_action_widget_get_entry (zoom_widget), "activate",
                                   G_CALLBACK (zoom_widget_activated_cb),
                                   action);
         }
@@ -124,29 +121,31 @@ ev_zoom_action_set_model (EvZoomAction    *action,
         }
 }
 
-gboolean
-ev_zoom_action_get_popup_shown (EvZoomAction *action)
-{
-        g_return_val_if_fail (EV_IS_ZOOM_ACTION (action), FALSE);
-
-        return action->priv->popup_shown;
-}
-
 void
-ev_zoom_action_set_max_zoom_level (EvZoomAction *action,
-                                   float         max_zoom)
+ev_zoom_action_set_window (EvZoomAction *action,
+                           EvWindow     *window)
 {
+
         GSList *proxies, *l;
 
         g_return_if_fail (EV_IS_ZOOM_ACTION (action));
+        g_return_if_fail (EV_IS_WINDOW (window));
 
-        if (action->priv->max_zoom == max_zoom)
+        if (action->priv->window == window)
                 return;
 
-        action->priv->max_zoom = max_zoom;
+        action->priv->window = window;
         proxies = gtk_action_get_proxies (GTK_ACTION (action));
         for (l = proxies; l && l->data; l = g_slist_next (l)) {
                 if (EV_IS_ZOOM_ACTION_WIDGET (l->data))
-                        ev_zoom_action_widget_set_max_zoom_level (EV_ZOOM_ACTION_WIDGET (l->data), max_zoom);
+                        ev_zoom_action_widget_set_window (EV_ZOOM_ACTION_WIDGET (l->data), window);
         }
 }
+
+gboolean
+ev_zoom_action_get_popup_shown (EvZoomAction *action)
+{
+        g_return_val_if_fail (EV_IS_ZOOM_ACTION (action), FALSE);
+
+        return action->priv->popup_shown;
+}
diff --git a/shell/ev-zoom-action.h b/shell/ev-zoom-action.h
index 4ef66fe..6cb92c5 100644
--- a/shell/ev-zoom-action.h
+++ b/shell/ev-zoom-action.h
@@ -25,6 +25,8 @@
 #include <evince-document.h>
 #include <evince-view.h>
 
+#include "ev-window.h"
+
 G_BEGIN_DECLS
 
 #define EV_TYPE_ZOOM_ACTION            (ev_zoom_action_get_type ())
@@ -48,13 +50,33 @@ struct _EvZoomActionClass {
         GtkActionClass parent_class;
 };
 
-GType    ev_zoom_action_get_type           (void);
+static const struct {
+        const gchar *name;
+        float        level;
+} zoom_levels[] = {
+        { "50%", 0.5 },
+        { "70%", 0.7071067811 },
+        { "85%", 0.8408964152 },
+        { "100%", 1.0 },
+        { "125%", 1.1892071149 },
+        { "150%", 1.4142135623 },
+        { "175%", 1.6817928304 },
+        { "200%", 2.0 },
+        { "300%", 2.8284271247 },
+        { "400%", 4.0 },
+        { "800%", 8.0 },
+        { "1600%", 16.0 },
+        { "3200%", 32.0 },
+        { "6400%", 64.0 }
+};
+
+GType    ev_zoom_action_get_type        (void);
 
-void     ev_zoom_action_set_model          (EvZoomAction    *action,
-                                            EvDocumentModel *model);
-gboolean ev_zoom_action_get_popup_shown    (EvZoomAction    *action);
-void     ev_zoom_action_set_max_zoom_level (EvZoomAction    *action,
-                                            float            max_zoom);
+void     ev_zoom_action_set_model       (EvZoomAction    *action,
+                                         EvDocumentModel *model);
+gboolean ev_zoom_action_get_popup_shown (EvZoomAction    *action);
+void     ev_zoom_action_set_window      (EvZoomAction    *action,
+                                         EvWindow        *window);
 
 G_END_DECLS
 
diff --git a/shell/evince-ui.xml b/shell/evince-ui.xml
index 39e61db..db23f9c 100644
--- a/shell/evince-ui.xml
+++ b/shell/evince-ui.xml
@@ -81,6 +81,13 @@
     <menuitem name="SaveAttachmentAs" action="SaveAttachmentAs"/>
   </popup>
 
+  <popup name="ZoomSelectorPopup">
+    <menuitem name="ViewFitPage" action="ViewFitPage"/>
+    <menuitem name="ViewFitWidth" action="ViewFitWidth"/>
+    <separator/>
+    <placeholder name="ViewZoomItems"/>
+  </popup>
+
   <accelerator name="PageDownAccel" action="PageDown"/>
   <accelerator name="PageUpAccel" action="PageUp"/>
   <accelerator name="GoBackwardFastAccel" action="GoBackwardFast"/>



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