[gtk/wip/exalm/buttons: 4/4] menu-button: Allow label and icon-name to be set together




commit b036179b1f5aa9cd2be618d9fd663a4da4832ed0
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Tue Aug 31 02:58:56 2021 +0500

    menu-button: Allow label and icon-name to be set together
    
    Same as for GtkButton. Rework when .arrow-button is added as it makes less
    sense when the button can contain text, icon, arrow and all combinations
    thereof. Keep .image-button instead of .arrow-button when the button only
    has an arrow and arrow-type=none, as it's styled as a menu open icon and is
    an image button for the styling purposes.
    
    Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/4205

 gtk/gtkmenubutton.c            | 159 ++++++++++++++++++++---------------------
 gtk/theme/Default/_common.scss |  12 ++++
 2 files changed, 91 insertions(+), 80 deletions(-)
---
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index e1d8209ddc..9231e5e33d 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -66,9 +66,9 @@
  * `GtkMenuButton` has a single CSS node with name `menubutton`
  * which contains a `button` node with a `.toggle` style class.
  *
- * If the button contains only an icon or an arrow, it will have the
- * `.image-button` style class, if it contains both, it will have the
- * `.arrow-button` style class.
+ * If the button contains an icon and/or a label, it will have the
+ * `.image-button` and/or `.text-button` style classes. If it contains an arrow,
+ * it will additionally have the `.arrow-button` style class.
  *
  * Inside the toggle button content, there is an `arrow` node for
  * the indicator, which will carry one of the `.none`, `.up`, `.down`,
@@ -119,6 +119,7 @@ struct _GtkMenuButton
   gpointer create_popup_user_data;
   GDestroyNotify create_popup_destroy_notify;
 
+  GtkWidget *child;
   GtkWidget *label_widget;
   GtkWidget *image_widget;
   GtkWidget *arrow_widget;
@@ -575,48 +576,65 @@ set_arrow_type (GtkWidget    *arrow,
 static void
 update_style_classes (GtkMenuButton *menu_button)
 {
-  if (menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button)) ||
-      (menu_button->image_widget && !menu_button->always_show_arrow))
+  gboolean has_image, has_text, has_arrow;
+
+  has_image = gtk_widget_get_visible (menu_button->image_widget);
+  has_text = gtk_widget_get_visible (menu_button->label_widget);
+  has_arrow = menu_button->arrow_type != GTK_ARROW_NONE;
+
+  if (has_text)
+    gtk_widget_add_css_class (menu_button->button, "text-button");
+  else
+    gtk_widget_remove_css_class (menu_button->button, "text-button");
+
+  if (has_image || (!has_text && !has_arrow))
     gtk_widget_add_css_class (menu_button->button, "image-button");
   else
     gtk_widget_remove_css_class (menu_button->button, "image-button");
 
-  if (menu_button->image_widget && menu_button->always_show_arrow)
+  if (has_arrow && (!has_image || has_text || menu_button->always_show_arrow))
     gtk_widget_add_css_class (menu_button->button, "arrow-button");
   else
     gtk_widget_remove_css_class (menu_button->button, "arrow-button");
 }
 
 static void
-update_arrow (GtkMenuButton *menu_button)
+update_alignment (GtkMenuButton *menu_button)
 {
-  gboolean has_only_arrow, is_text_button;
-
-  if (menu_button->arrow_widget == NULL)
-    return;
+  gboolean has_image, has_text;
 
-  has_only_arrow = menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button));
-  is_text_button = menu_button->label_widget != NULL;
+  has_image = gtk_widget_get_visible (menu_button->image_widget);
+  has_text = gtk_widget_get_visible (menu_button->label_widget);
 
-  set_arrow_type (menu_button->arrow_widget,
-                  menu_button->arrow_type,
-                  has_only_arrow ||
-                  ((is_text_button || menu_button->always_show_arrow) &&
-                   (menu_button->arrow_type != GTK_ARROW_NONE)));
+  if (has_text && has_image)
+    {
+      gtk_widget_set_halign (menu_button->image_widget, GTK_ALIGN_END);
+      gtk_widget_set_halign (menu_button->label_widget, GTK_ALIGN_START);
+    }
+  else
+    {
+      gtk_widget_set_halign (menu_button->image_widget, GTK_ALIGN_CENTER);
+      gtk_widget_set_halign (menu_button->label_widget, GTK_ALIGN_CENTER);
+    }
 
-  update_style_classes (menu_button);
+  gtk_widget_set_hexpand (menu_button->arrow_widget, !has_text && !has_image);
 }
 
 static void
-add_arrow (GtkMenuButton *self)
+update_arrow (GtkMenuButton *menu_button)
 {
-  GtkWidget *arrow;
+  gboolean has_image, has_text;
+
+  has_image = gtk_widget_get_visible (menu_button->image_widget);
+  has_text = gtk_widget_get_visible (menu_button->label_widget);
 
-  arrow = gtk_builtin_icon_new ("arrow");
-  gtk_widget_set_halign (arrow, GTK_ALIGN_CENTER);
-  set_arrow_type (arrow, self->arrow_type, TRUE);
-  gtk_button_set_child (GTK_BUTTON (self->button), arrow);
-  self->arrow_widget = arrow;
+  set_arrow_type (menu_button->arrow_widget,
+                  menu_button->arrow_type,
+                  (!has_image && !has_text) ||
+                  ((has_text || menu_button->always_show_arrow) &&
+                   (menu_button->arrow_type != GTK_ARROW_NONE)));
+
+  update_style_classes (menu_button);
 }
 
 static void
@@ -627,12 +645,39 @@ gtk_menu_button_init (GtkMenuButton *self)
   self->button = gtk_toggle_button_new ();
   gtk_widget_set_parent (self->button, GTK_WIDGET (self));
   g_signal_connect_swapped (self->button, "toggled", G_CALLBACK (gtk_menu_button_toggled), self);
-  add_arrow (self);
-  update_style_classes (self);
+
+  self->child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_widget_set_hexpand (self->child, FALSE);
+  gtk_button_set_child (GTK_BUTTON (self->button), self->child);
+
+  self->image_widget = g_object_new (GTK_TYPE_IMAGE,
+                                     "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
+                                     NULL);
+  gtk_widget_set_hexpand (self->image_widget, TRUE);
+  gtk_widget_hide (self->image_widget);
+
+  self->label_widget = gtk_label_new (NULL);
+  gtk_widget_hide (self->label_widget);
+  gtk_widget_set_hexpand (self->label_widget, TRUE);
+  gtk_label_set_xalign (GTK_LABEL (self->label_widget), 0);
+  gtk_label_set_use_underline (GTK_LABEL (self->label_widget),
+                               gtk_button_get_use_underline (GTK_BUTTON (self->button)));
+  gtk_label_set_mnemonic_widget (GTK_LABEL (self->label_widget), self->button);
+
+  self->arrow_widget = gtk_builtin_icon_new ("arrow");
+  gtk_widget_set_halign (self->arrow_widget, GTK_ALIGN_CENTER);
+  set_arrow_type (self->arrow_widget, self->arrow_type, TRUE);
+
+  gtk_box_append (GTK_BOX (self->child), self->image_widget);
+  gtk_box_append (GTK_BOX (self->child), self->label_widget);
+  gtk_box_append (GTK_BOX (self->child), self->arrow_widget);
 
   gtk_widget_set_sensitive (self->button, FALSE);
 
   gtk_widget_add_css_class (GTK_WIDGET (self), "popup");
+
+  update_alignment (self);
+  update_arrow (self);
 }
 
 /**
@@ -937,38 +982,15 @@ void
 gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
                                const char    *icon_name)
 {
-  GtkWidget *box, *image_widget, *arrow;
-
   g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
 
-  g_object_freeze_notify (G_OBJECT (menu_button));
-
-  if (gtk_menu_button_get_label (menu_button))
-    g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
-
-  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-  gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
-
-  image_widget = g_object_new (GTK_TYPE_IMAGE,
-                               "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
-                               "icon-name", icon_name,
-                               NULL);
-  menu_button->image_widget = image_widget;
-
-  arrow = gtk_builtin_icon_new ("arrow");
-  menu_button->arrow_widget = arrow;
-
-  gtk_box_append (GTK_BOX (box), image_widget);
-  gtk_box_append (GTK_BOX (box), arrow);
-  gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
-
-  menu_button->label_widget = NULL;
+  gtk_image_set_from_icon_name (GTK_IMAGE (menu_button->image_widget), icon_name);
+  gtk_widget_set_visible (menu_button->image_widget, icon_name && icon_name[0]);
 
+  update_alignment (menu_button);
   update_arrow (menu_button);
 
   g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
-
-  g_object_thaw_notify (G_OBJECT (menu_button));
 }
 
 /**
@@ -1046,38 +1068,15 @@ void
 gtk_menu_button_set_label (GtkMenuButton *menu_button,
                            const char    *label)
 {
-  GtkWidget *box;
-  GtkWidget *label_widget;
-  GtkWidget *arrow;
-
   g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
 
-  g_object_freeze_notify (G_OBJECT (menu_button));
-
-  if (gtk_menu_button_get_icon_name (menu_button))
-    g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
-
-  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-  label_widget = gtk_label_new (label);
-  gtk_label_set_xalign (GTK_LABEL (label_widget), 0);
-  gtk_label_set_use_underline (GTK_LABEL (label_widget),
-                               gtk_button_get_use_underline (GTK_BUTTON (menu_button->button)));
-  gtk_widget_set_hexpand (label_widget, TRUE);
-  gtk_widget_set_halign (label_widget, GTK_ALIGN_CENTER);
-  arrow = gtk_builtin_icon_new ("arrow");
-  menu_button->arrow_widget = arrow;
-  gtk_box_append (GTK_BOX (box), label_widget);
-  gtk_box_append (GTK_BOX (box), arrow);
-  gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
-  menu_button->label_widget = label_widget;
-
-  menu_button->image_widget = NULL;
+  gtk_label_set_label (GTK_LABEL (menu_button->label_widget), label);
+  gtk_widget_set_visible (menu_button->label_widget, label && label[0]);
 
+  update_alignment (menu_button);
   update_arrow (menu_button);
 
   g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
-
-  g_object_thaw_notify (G_OBJECT (menu_button));
 }
 
 /**
diff --git a/gtk/theme/Default/_common.scss b/gtk/theme/Default/_common.scss
index 344af26831..47e47c1a59 100644
--- a/gtk/theme/Default/_common.scss
+++ b/gtk/theme/Default/_common.scss
@@ -570,6 +570,18 @@ button {
       }
     }
 
+    &.arrow-button {
+      padding-left: 10px;
+      padding-right: 10px;
+
+      > box {
+        border-spacing: 4px;
+
+        > label:dir(ltr) { padding-right: 0px; }
+        > label:dir(rtl) { padding-left: 0px; }
+      }
+    }
+
     @at-root %button_basic_drop_active,
     &:drop(active) {
       color: $drop_target_color;


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