[gtk+/popover-menu-buttons] Improvements to display-hint handling



commit 4648e73f60b11000dcf0f96f8e120c687f79a56d
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Apr 22 07:39:26 2014 -0400

    Improvements to display-hint handling
    
    Reuse GtkModelButton for the iconic rendering. Once we have that,
    we can allow check and radio actions for iconic rendering. Add
    tests that show this.
    
    As a further refinement, iconic model buttons will fall back to
    showing the label if no icon is set.

 gtk/gtkmodelbutton.c |   96 +++++++++++++++++++++++++++++++++++++++-----------
 gtk/gtkpopover.c     |   33 +++++++----------
 tests/popover.ui     |   39 ++++++++++++++------
 tests/testpopover.c  |    9 +++--
 4 files changed, 120 insertions(+), 57 deletions(-)
---
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index 0787e04..3a7a738 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -41,6 +41,7 @@ struct _GtkModelButton
   gboolean has_submenu;
   gboolean center;
   gboolean inverted;
+  gboolean iconic;
   GtkMenuTrackerItemRole role;
 };
 
@@ -58,7 +59,8 @@ enum
   PROP_ACCEL,
   PROP_HAS_SUBMENU,
   PROP_INVERTED,
-  PROP_CENTERED
+  PROP_CENTERED,
+  PROP_ICONIC
 };
 
 static void
@@ -97,20 +99,32 @@ gtk_model_button_set_action_role (GtkModelButton         *button,
 }
 
 static void
+update_visibility (GtkModelButton *button)
+{
+  gboolean has_icon;
+  gboolean has_text;
+
+  has_icon = gtk_image_get_storage_type (GTK_IMAGE (button->image)) != GTK_IMAGE_EMPTY;
+  has_text = gtk_label_get_text (GTK_LABEL (button->label))[0] != '\0';
+
+  gtk_widget_set_visible (button->image, has_icon);
+  gtk_widget_set_visible (button->label, has_text && (!button->iconic || !has_icon));
+}
+
+static void
 gtk_model_button_set_icon (GtkModelButton *button,
                            GIcon          *icon)
 {
   gtk_image_set_from_gicon (GTK_IMAGE (button->image), icon, GTK_ICON_SIZE_MENU);
-  gtk_widget_set_visible (button->image, icon != NULL);
+  update_visibility (button);
 }
 
 static void
 gtk_model_button_set_text (GtkModelButton *button,
                            const gchar    *text)
 {
-  if (text != NULL)
-    gtk_label_set_text_with_mnemonic (GTK_LABEL (button->label), text);
-  gtk_widget_set_visible (button->label, text != NULL);
+  gtk_label_set_text_with_mnemonic (GTK_LABEL (button->label), text);
+  update_visibility (button);
 }
 
 static void
@@ -154,6 +168,26 @@ gtk_model_button_set_centered (GtkModelButton *button,
 }
 
 static void
+gtk_model_button_set_iconic (GtkModelButton *button,
+                             gboolean        iconic)
+{
+  button->iconic = iconic;
+  if (iconic)
+    {
+      gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (button)), "modelbutton");
+      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NORMAL);
+    }
+  else
+    {
+      gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (button)), "modelbutton");
+      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+    }
+
+  update_visibility (button);
+  gtk_widget_queue_resize (GTK_WIDGET (button));
+}
+
+static void
 gtk_model_button_set_property (GObject      *object,
                                guint         prop_id,
                                const GValue *value,
@@ -195,6 +229,10 @@ gtk_model_button_set_property (GObject      *object,
       gtk_model_button_set_centered (button, g_value_get_boolean (value));
       break;
 
+    case PROP_ICONIC:
+      gtk_model_button_set_iconic (button, g_value_get_boolean (value));
+      break;
+
     default:
       g_assert_not_reached ();
     }
@@ -223,7 +261,10 @@ gtk_model_button_get_full_border (GtkModelButton *button,
   border->top = border_width + focus_width + focus_pad;
   border->bottom = border_width + focus_width + focus_pad;
 
-  *indicator = indicator_size + 2 * indicator_spacing;
+  if (button->iconic)
+    *indicator = 0;
+  else
+    *indicator = indicator_size + 2 * indicator_spacing;
 }
 
 static void
@@ -448,12 +489,22 @@ gtk_model_button_draw (GtkWidget *widget,
   gint focus_width, focus_pad;
   gint baseline;
 
+  state = get_button_state (model_button);
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save (context);
+  gtk_style_context_set_state (context, state);
+
+  if (model_button->iconic)
+    {
+      GTK_WIDGET_CLASS (gtk_model_button_parent_class)->draw (widget, cr);
+      goto out;
+    }
+
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-  context = gtk_widget_get_style_context (widget);
   baseline = gtk_widget_get_allocated_baseline (widget);
-  state = get_button_state (model_button);
 
   gtk_widget_style_get (widget, 
                         "focus-line-width", &focus_width, 
@@ -474,9 +525,6 @@ gtk_model_button_draw (GtkWidget *widget,
     y = CLAMP (baseline - indicator_size * button->priv->baseline_align,
                0, height - indicator_size);
 
-  gtk_style_context_save (context);
-  gtk_style_context_set_state (context, state);
-
   gtk_render_background (context, cr,
                          border_width, border_width,
                          width - 2 * border_width,
@@ -522,12 +570,13 @@ gtk_model_button_draw (GtkWidget *widget,
                         height - 2 * (border_width + focus_pad) - border.top - border.bottom);
     }
 
-  gtk_style_context_restore (context);
-
   child = gtk_bin_get_child (GTK_BIN (widget));
   if (child)
     gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);
 
+out:
+  gtk_style_context_restore (context);
+
   return FALSE;
 }
 
@@ -548,30 +597,34 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
   widget_class->draw = gtk_model_button_draw;
 
   g_object_class_install_property (object_class, PROP_ACTION_ROLE,
-                                   g_param_spec_enum ("action-role", "action role", "action role",
+                                   g_param_spec_enum ("action-role", "", "",
                                                       GTK_TYPE_MENU_TRACKER_ITEM_ROLE,
                                                       GTK_MENU_TRACKER_ITEM_ROLE_NORMAL,
                                                       G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_ICON,
-                                   g_param_spec_object ("icon", "icon", "icon", G_TYPE_ICON,
+                                   g_param_spec_object ("icon", "", "", G_TYPE_ICON,
                                                         G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_TEXT,
-                                   g_param_spec_string ("text", "text", "text", NULL,
+                                   g_param_spec_string ("text", "", "", NULL,
                                                         G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_TOGGLED,
-                                   g_param_spec_boolean ("toggled", "toggled", "toggled", FALSE,
+                                   g_param_spec_boolean ("toggled", "", "", FALSE,
                                                          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_ACCEL,
-                                   g_param_spec_string ("accel", "accel", "accel", NULL,
+                                   g_param_spec_string ("accel", "", "", NULL,
                                                         G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_HAS_SUBMENU,
-                                   g_param_spec_boolean ("has-submenu", "has-submenu", "has-submenu", FALSE,
+                                   g_param_spec_boolean ("has-submenu", "", "", FALSE,
                                                          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_INVERTED,
-                                   g_param_spec_boolean ("inverted", "inverted", "inverted", FALSE,
+                                   g_param_spec_boolean ("inverted", "", "", FALSE,
+
                                                          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_CENTERED,
-                                   g_param_spec_boolean ("centered", "centered", "centered", FALSE,
+                                   g_param_spec_boolean ("centered", "", "", FALSE,
+                                                         G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_ICONIC,
+                                   g_param_spec_boolean ("iconic", "", "", TRUE,
                                                          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
 
   gtk_widget_class_set_accessible_role (GTK_WIDGET_CLASS (class), ATK_ROLE_PUSH_BUTTON);
@@ -595,6 +648,7 @@ gtk_model_button_init (GtkModelButton *button)
   gtk_container_add (GTK_CONTAINER (button->box), button->image);
   gtk_container_add (GTK_CONTAINER (button->box), button->label);
   gtk_container_add (GTK_CONTAINER (button), button->box);
+  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (button)), "modelbutton");
 }
 
 GtkWidget *
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 82c3880..9a4f458 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -2095,6 +2095,7 @@ gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
     {
       const gchar *hint;
       GtkWidget *icon_box = NULL;
+      GtkWidget *button;
 
       hint = gtk_menu_tracker_item_get_display_hint (item);
       if (g_strcmp0 (hint, "iconic") == 0)
@@ -2123,33 +2124,25 @@ gtk_popover_tracker_insert_func (GtkMenuTrackerItem *item,
             }
         }
 
+      button = gtk_model_button_new ();
+      g_object_bind_property (item, "label", button, "text", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "icon", button, "icon", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "sensitive", button, "sensitive", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "visible", button, "visible", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "role", button, "action-role", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "toggled", button, "toggled", G_BINDING_SYNC_CREATE);
+      g_object_bind_property (item, "accel", button, "accel", G_BINDING_SYNC_CREATE);
+      g_signal_connect (button, "clicked", G_CALLBACK (gtk_popover_item_activate), item);
       if (icon_box)
         {
-          GtkWidget *button;
-        
-          if (gtk_menu_tracker_item_get_role (item) != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
-            g_warning ("Only normal actions supported in icon section");
-
-          button = gtk_button_new_from_icon_name ("process-stop-symbolic", GTK_ICON_SIZE_MENU);
-          g_object_bind_property (item, "icon", gtk_button_get_image (GTK_BUTTON (button)), "gicon", 
G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "sensitive", button, "sensitive", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "visible", button, "visible", G_BINDING_SYNC_CREATE);
-          g_signal_connect (button, "clicked", G_CALLBACK (gtk_popover_item_activate), item);
+          g_object_set (button, "iconic", TRUE, "centered", TRUE, NULL);
           g_object_set_data_full (G_OBJECT (button), "GtkMenuTrackerItem", g_object_ref (item), 
g_object_unref);
+
           gtk_box_pack_end (GTK_BOX (icon_box), button, TRUE, TRUE, 0);
         }
       else
         {
-          widget = gtk_model_button_new ();
-          g_object_bind_property (item, "label", widget, "text", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "icon", widget, "icon", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "sensitive", widget, "sensitive", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "visible", widget, "visible", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "role", widget, "action-role", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "toggled", widget, "toggled", G_BINDING_SYNC_CREATE);
-          g_object_bind_property (item, "accel", widget, "accel", G_BINDING_SYNC_CREATE);
-
-          g_signal_connect (widget, "clicked", G_CALLBACK (gtk_popover_item_activate), item);
+          widget = button;
         }
     }
   g_object_set_data_full (G_OBJECT (widget), "GtkMenuTrackerItem", g_object_ref (item), g_object_unref);
diff --git a/tests/popover.ui b/tests/popover.ui
index 5bc154d..5f0a6c5 100644
--- a/tests/popover.ui
+++ b/tests/popover.ui
@@ -62,6 +62,21 @@
           <attribute name="label">Item 5b</attribute>
           <attribute name="action">top.action5</attribute>
         </item>
+        <section>
+          <attribute name="display-hint">iconic</attribute>
+          <item>
+            <attribute name="label">List</attribute>
+            <attribute name="action">top.set-view</attribute>
+            <attribute name="target">list</attribute>
+            <attribute name="icon">view-list-symbolic</attribute>
+          </item>
+          <item>
+            <attribute name="label">Grid</attribute>
+            <attribute name="action">top.set-view</attribute>
+            <attribute name="target">grid</attribute>
+            <attribute name="icon">view-grid-symbolic</attribute>
+          </item>
+        </section>
         <item>
           <attribute name="label">Item 5c</attribute>
           <attribute name="action">top.action5</attribute>
@@ -73,25 +88,25 @@
       </section>
       <section>
         <attribute name="display-hint">iconic</attribute>
+        <attribute name="label">Edit</attribute>
       <item>
-        <attribute name="label">Left</attribute>
-        <attribute name="action">top.justify-left</attribute>
-        <attribute name="icon">format-justify-left-symbolic</attribute>
+        <attribute name="label">Bold</attribute>
+        <attribute name="action">top.bold</attribute>
       </item>
       <item>
-        <attribute name="label">Center</attribute>
-        <attribute name="action">top.justify-center</attribute>
-        <attribute name="icon">format-justify-center-symbolic</attribute>
+        <attribute name="label">Italic</attribute>
+        <attribute name="action">top.italic</attribute>
+        <attribute name="icon">format-text-italic-symbolic</attribute>
       </item>
       <item>
-        <attribute name="label">Right</attribute>
-        <attribute name="action">top.justify-right</attribute>
-        <attribute name="icon">format-justify-right-symbolic</attribute>
+        <attribute name="label">Strikethrough</attribute>
+        <attribute name="action">top.strikethrough</attribute>
+        <attribute name="icon">format-text-strikethrough-symbolic</attribute>
       </item>
       <item>
-        <attribute name="label">Fill</attribute>
-        <attribute name="action">top.justify-fill</attribute>
-        <attribute name="icon">format-justify-fill-symbolic</attribute>
+        <attribute name="label">Underline</attribute>
+        <attribute name="action">top.underline</attribute>
+        <attribute name="icon">format-text-underline-symbolic</attribute>
       </item>
       </section>
       <section>
diff --git a/tests/testpopover.c b/tests/testpopover.c
index b33e042..2f80e31 100644
--- a/tests/testpopover.c
+++ b/tests/testpopover.c
@@ -12,10 +12,11 @@ static GActionEntry entries[] = {
   { "cut", activate, NULL, NULL, NULL },
   { "copy", activate, NULL, NULL, NULL },
   { "paste", activate, NULL, NULL, NULL },
-  { "justify-left", activate, NULL, NULL, NULL },
-  { "justify-center", activate, NULL, NULL, NULL },
-  { "justify-right", activate, NULL, NULL, NULL },
-  { "justify-fill", activate, NULL, NULL, NULL },
+  { "bold", NULL, NULL, "false", NULL },
+  { "italic", NULL, NULL, "false", NULL },
+  { "strikethrough", NULL, NULL, "false", NULL },
+  { "underline", NULL, NULL, "false", NULL },
+  { "set-view", NULL, "s", "'list'", NULL },
   { "action1", activate, NULL, NULL, NULL },
   { "action2", NULL, NULL, "true", NULL },
   { "action2a", NULL, NULL, "false", NULL },


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