[libadwaita/wip/exalm/menu-split-buttons: 7/19] Add AdwButtonContent




commit 6d2621f14c1034293319e61865f943da9ddc0e8e
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Fri Sep 3 15:28:46 2021 +0500

    Add AdwButtonContent
    
    We're going to use buttons that use icon+label more commonly, so we need
    a nice way to create them.
    
    Unfortunately for technical reasons we can't reuse .icon-button.text-button
    style classes, so we'll have to roll our own .image-text-button. We also
    still have to add a style class on a button so that later we can know to
    flatten these buttons.
    
    Update the existing .icon-button.text-button style as well.

 src/adw-button-content.c             | 433 +++++++++++++++++++++++++++++++++++
 src/adw-button-content.h             |  47 ++++
 src/adwaita.h                        |   1 +
 src/meson.build                      |   2 +
 src/stylesheet/widgets/_buttons.scss |  46 +++-
 tests/meson.build                    |   1 +
 tests/test-button-content.c          | 165 +++++++++++++
 7 files changed, 686 insertions(+), 9 deletions(-)
---
diff --git a/src/adw-button-content.c b/src/adw-button-content.c
new file mode 100644
index 00000000..828992ea
--- /dev/null
+++ b/src/adw-button-content.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include "config.h"
+#include "adw-button-content.h"
+
+#include "adw-split-button.h"
+
+/**
+ * AdwButtonContent:
+ *
+ * A helper widget for creating buttons.
+ *
+ * `AdwButtonContent` is a box-like widget with an icon and a label.
+ *
+ * It's intended to be used as a direct child of [class@Gtk.Button],
+ * [class@Gtk.MenuButton] or [class@Adw.SplitButton], when they need to habe
+ * both an icon and a label, as follows:
+ *
+ * ```xml
+ * <object class="GtkButton">
+ *   <property name="child">
+ *     <object class="AdwButtonContent">
+ *       <property name="icon-name">document-open-symbolic</property>
+ *       <property name="label" translatable="yes">_Open</property>
+ *       <property name="use-underline">True</property>
+ *     </object>
+ *   </property>
+ * </object>
+ * ```
+ *
+ * `AdwButtonContent` handles style classes and connecting the mnemonic to the
+ * button automatically.
+ *
+ * ## CSS nodes
+ *
+ * ```
+ * buttoncontent
+ * ├── image
+ * ╰── label
+ * ```
+ *
+ * `AdwSplitButton`'s CSS node is called `buttoncontent`. It contains the
+ * subnodes `image` and `label`.
+ *
+ * When inside a `GtkButton` or `AdwSplitButton`, the button will receive the
+ * `.image-text-button` style class. When inside a `GtkMenuButton`, the
+ * internal `GtkButton` will receive it instead.
+ *
+ * ## Accessibility
+ *
+ * `AdwSplitButton` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ *
+ * Since: 1.0
+ */
+
+struct _AdwButtonContent {
+  GtkWidget parent_instance;
+
+  GtkWidget *icon;
+  GtkWidget *label;
+
+  char *icon_name;
+
+  GtkWidget *button;
+};
+
+G_DEFINE_TYPE (AdwButtonContent, adw_button_content, GTK_TYPE_WIDGET)
+
+enum {
+  PROP_0,
+  PROP_ICON_NAME,
+  PROP_LABEL,
+  PROP_USE_UNDERLINE,
+  LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static inline GtkWidget *
+find_parent_button (AdwButtonContent *self)
+{
+  return gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_BUTTON);
+}
+
+static void
+adw_button_content_root (GtkWidget *widget)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (widget);
+
+  GTK_WIDGET_CLASS (adw_button_content_parent_class)->root (widget);
+
+  gtk_label_set_mnemonic_widget (GTK_LABEL (self->label),
+                                 find_parent_button (self));
+
+  self->button = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_BUTTON);
+
+  /* For AdwSplitButton we want to style the split button widget and not the
+   * button inside. */
+  if (ADW_IS_SPLIT_BUTTON (gtk_widget_get_parent (self->button)))
+    self->button = gtk_widget_get_parent (self->button);
+
+  gtk_widget_add_css_class (self->button, "image-text-button");
+}
+
+static void
+adw_button_content_unroot (GtkWidget *widget)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (widget);
+
+  gtk_label_set_mnemonic_widget (GTK_LABEL (self->label), NULL);
+
+  if (self->button) {
+    gtk_widget_remove_css_class (self->button, "image-text-button");
+
+    self->button = NULL;
+  }
+
+  GTK_WIDGET_CLASS (adw_button_content_parent_class)->unroot (widget);
+}
+
+static void
+adw_button_content_dispose (GObject *object)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (object);
+
+  g_clear_pointer (&self->icon, gtk_widget_unparent);
+  g_clear_pointer (&self->label, gtk_widget_unparent);
+
+  G_OBJECT_CLASS (adw_button_content_parent_class)->dispose (object);
+}
+
+static void
+adw_button_content_finalize (GObject *object)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (object);
+
+  g_clear_pointer (&self->icon_name, g_free);
+
+  G_OBJECT_CLASS (adw_button_content_parent_class)->finalize (object);
+}
+
+static void
+adw_button_content_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (object);
+
+  switch (prop_id) {
+  case PROP_ICON_NAME:
+    g_value_set_string (value, adw_button_content_get_icon_name (self));
+    break;
+  case PROP_LABEL:
+    g_value_set_string (value, adw_button_content_get_label (self));
+    break;
+  case PROP_USE_UNDERLINE:
+    g_value_set_boolean (value, adw_button_content_get_use_underline (self));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_button_content_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  AdwButtonContent *self = ADW_BUTTON_CONTENT (object);
+
+  switch (prop_id) {
+  case PROP_ICON_NAME:
+    adw_button_content_set_icon_name (self, g_value_get_string (value));
+    break;
+  case PROP_LABEL:
+    adw_button_content_set_label (self, g_value_get_string (value));
+    break;
+  case PROP_USE_UNDERLINE:
+    adw_button_content_set_use_underline (self, g_value_get_boolean (value));
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+adw_button_content_class_init (AdwButtonContentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = adw_button_content_dispose;
+  object_class->finalize = adw_button_content_finalize;
+  object_class->get_property = adw_button_content_get_property;
+  object_class->set_property = adw_button_content_set_property;
+
+  widget_class->root = adw_button_content_root;
+  widget_class->unroot = adw_button_content_unroot;
+
+  /**
+   * AdwButtonContent:icon-name: (attributes org.gtk.Property.get=adw_button_content_get_icon_name 
org.gtk.Property.set=adw_button_content_set_icon_name)
+   *
+   * The name of the displayed icon.
+   *
+   * If empty, the icon is not shown.
+   *
+   * Since: 1.0
+   */
+  props[PROP_ICON_NAME] =
+      g_param_spec_string ("icon-name",
+                           "Icon name",
+                           "The name of the displayed icon",
+                           "",
+                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * AdwButtonContent:label: (attributes org.gtk.Property.get=adw_button_content_get_label 
org.gtk.Property.set=adw_button_content_set_label)
+   *
+   * The displayed label.
+   *
+   * Since: 1.0
+   */
+  props[PROP_LABEL] =
+      g_param_spec_string ("label",
+                           "Label",
+                           "The displayed label",
+                           "",
+                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * AdwButtonContent:use-underline: (attributes org.gtk.Property.get=adw_button_content_get_use_underline 
org.gtk.Property.set=adw_button_content_set_use_underline)
+   *
+   * Whether an underline in the text indicates a mnemonic.
+   *
+   * The mnemonic can be used to activate the parent button.
+   *
+   * See [property@Adw.ButtonContent:label].
+   *
+   * Since: 1.0
+   */
+  props[PROP_USE_UNDERLINE] =
+    g_param_spec_boolean ("use-underline",
+                          "Use underline",
+                          "Whether an underline in the text indicates a mnemonic",
+                          FALSE,
+                          G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (object_class, LAST_PROP, props);
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
+  gtk_widget_class_set_css_name (widget_class, "buttoncontent");
+  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
+}
+
+static void
+adw_button_content_init (AdwButtonContent *self)
+{
+  self->icon_name = g_strdup ("");
+
+  gtk_widget_set_hexpand (GTK_WIDGET (self), FALSE);
+
+  self->icon = g_object_new (GTK_TYPE_IMAGE,
+                             "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
+                             NULL);
+  gtk_image_set_from_icon_name (GTK_IMAGE (self->icon), "image-missing");
+  gtk_widget_set_valign (self->icon, GTK_ALIGN_CENTER);
+  gtk_widget_set_hexpand (self->icon, TRUE);
+
+  self->label = gtk_label_new (NULL);
+  gtk_widget_set_hexpand (self->label, TRUE);
+  gtk_widget_hide (self->label);
+
+  gtk_widget_set_parent (self->icon, GTK_WIDGET (self));
+  gtk_widget_set_parent (self->label, GTK_WIDGET (self));
+}
+
+/**
+ * adw_button_content_new:
+ *
+ * Creates a new `AdwButtonContent`.
+ *
+ * Returns: the new created `AdwButtonContent`
+ *
+ * Since: 1.0
+ */
+GtkWidget *
+adw_button_content_new (void)
+{
+  return g_object_new (ADW_TYPE_BUTTON_CONTENT, NULL);
+}
+
+/**
+ * adw_button_content_get_icon_name: (attributes org.gtk.Method.get_property=icon-name)
+ * @self: a `AdwButtonContent`
+ *
+ * Gets the name of the displayed icon.
+ *
+ * Returns: the icon name
+ *
+ * Since: 1.0
+ */
+const char *
+adw_button_content_get_icon_name (AdwButtonContent *self)
+{
+  g_return_val_if_fail (ADW_IS_BUTTON_CONTENT (self), NULL);
+
+  return self->icon_name;
+}
+
+/**
+ * adw_button_content_set_icon_name: (attributes org.gtk.Method.set_property=icon-name)
+ * @self: a `AdwButtonContent`
+ * @icon_name: the new icon name
+ *
+ * Sets the name of the displayed icon.
+ *
+ * Since: 1.0
+ */
+void
+adw_button_content_set_icon_name (AdwButtonContent *self,
+                                  const char       *icon_name)
+{
+  g_return_if_fail (ADW_IS_BUTTON_CONTENT (self));
+  g_return_if_fail (icon_name != NULL);
+
+  if (!g_strcmp0 (icon_name, adw_button_content_get_icon_name (self)))
+    return;
+
+  g_free (self->icon_name);
+  icon_name = g_strdup (icon_name);
+
+  if (!icon_name[0])
+    icon_name = "image-missing";
+
+  gtk_image_set_from_icon_name (GTK_IMAGE (self->icon), icon_name);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]);
+}
+
+/**
+ * adw_button_content_get_label: (attributes org.gtk.Method.get_property=label)
+ * @self: a `AdwButtonContent`
+ *
+ * Gets the displayed label.
+ *
+ * Returns: the label
+ *
+ * Since: 1.0
+ */
+const char *
+adw_button_content_get_label (AdwButtonContent *self)
+{
+  g_return_val_if_fail (ADW_IS_BUTTON_CONTENT (self), NULL);
+
+  return gtk_label_get_label (GTK_LABEL (self->label));
+}
+
+/**
+ * adw_button_content_set_label: (attributes org.gtk.Method.set_property=label)
+ * @self: a `AdwButtonContent`
+ * @label: the new label
+ *
+ * Sets the displayed label.
+ *
+ * Since: 1.0
+ */
+void
+adw_button_content_set_label (AdwButtonContent *self,
+                              const char       *label)
+{
+  g_return_if_fail (ADW_IS_BUTTON_CONTENT (self));
+  g_return_if_fail (label != NULL);
+
+  if (!g_strcmp0 (label, adw_button_content_get_label (self)))
+    return;
+
+  gtk_label_set_label (GTK_LABEL (self->label), label);
+
+  gtk_widget_set_visible (self->label, label[0]);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]);
+}
+
+/**
+ * adw_button_content_get_use_underline: (attributes org.gtk.Method.get_property=use-underline)
+ * @self: a `AdwButtonContent`
+ *
+ * Gets whether an underline in the text indicates a mnemonic.
+ *
+ * Returns: whether an underline in the text indicates a mnemonic
+ *
+ * Since: 1.0
+ */
+gboolean
+adw_button_content_get_use_underline (AdwButtonContent *self)
+{
+  g_return_val_if_fail (ADW_IS_BUTTON_CONTENT (self), FALSE);
+
+  return gtk_label_get_use_underline (GTK_LABEL (self->label));
+}
+
+/**
+ * adw_button_content_set_use_underline: (attributes org.gtk.Method.set_property=use-underline)
+ * @self: a `AdwButtonContent`
+ * @use_underline: whether an underline in the text indicates a mnemonic
+ *
+ * Sets whether an underline in the text indicates a mnemonic.
+ *
+ * Since: 1.0
+ */
+void
+adw_button_content_set_use_underline (AdwButtonContent *self,
+                                      gboolean          use_underline)
+{
+  g_return_if_fail (ADW_IS_BUTTON_CONTENT (self));
+
+  use_underline = !!use_underline;
+
+  if (use_underline == adw_button_content_get_use_underline (self))
+    return;
+
+  gtk_label_set_use_underline (GTK_LABEL (self->label), use_underline);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USE_UNDERLINE]);
+}
diff --git a/src/adw-button-content.h b/src/adw-button-content.h
new file mode 100644
index 00000000..639c2c14
--- /dev/null
+++ b/src/adw-button-content.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#pragma once
+
+#if !defined(_ADWAITA_INSIDE) && !defined(ADWAITA_COMPILATION)
+#error "Only <adwaita.h> can be included directly."
+#endif
+
+#include "adw-version.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_BUTTON_CONTENT (adw_button_content_get_type())
+
+ADW_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (AdwButtonContent, adw_button_content, ADW, BUTTON_CONTENT, GtkWidget)
+
+ADW_AVAILABLE_IN_ALL
+GtkWidget *adw_button_content_new (void) G_GNUC_WARN_UNUSED_RESULT;
+
+ADW_AVAILABLE_IN_ALL
+const char *adw_button_content_get_label (AdwButtonContent  *self);
+ADW_AVAILABLE_IN_ALL
+void        adw_button_content_set_label (AdwButtonContent *self,
+                                          const char       *label);
+
+ADW_AVAILABLE_IN_ALL
+const char *adw_button_content_get_icon_name (AdwButtonContent  *self);
+ADW_AVAILABLE_IN_ALL
+void        adw_button_content_set_icon_name (AdwButtonContent *self,
+                                              const char       *icon_name);
+
+ADW_AVAILABLE_IN_ALL
+gboolean adw_button_content_get_use_underline (AdwButtonContent *self);
+ADW_AVAILABLE_IN_ALL
+void     adw_button_content_set_use_underline (AdwButtonContent *self,
+                                               gboolean          use_underline);
+
+G_END_DECLS
diff --git a/src/adwaita.h b/src/adwaita.h
index 82a55c48..2de16a19 100644
--- a/src/adwaita.h
+++ b/src/adwaita.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 #include "adw-application-window.h"
 #include "adw-avatar.h"
 #include "adw-bin.h"
+#include "adw-button-content.h"
 #include "adw-carousel.h"
 #include "adw-carousel-indicator-dots.h"
 #include "adw-carousel-indicator-lines.h"
diff --git a/src/meson.build b/src/meson.build
index f32a00d8..9feba8bf 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -74,6 +74,7 @@ src_headers = [
   'adw-application-window.h',
   'adw-avatar.h',
   'adw-bin.h',
+  'adw-button-content.h',
   'adw-carousel.h',
   'adw-carousel-indicator-dots.h',
   'adw-carousel-indicator-lines.h',
@@ -129,6 +130,7 @@ src_sources = [
   'adw-avatar.c',
   'adw-bidi.c',
   'adw-bin.c',
+  'adw-button-content.c',
   'adw-carousel.c',
   'adw-carousel-indicator-dots.c',
   'adw-carousel-indicator-lines.c',
diff --git a/src/stylesheet/widgets/_buttons.scss b/src/stylesheet/widgets/_buttons.scss
index 251caf02..6fbcac1d 100644
--- a/src/stylesheet/widgets/_buttons.scss
+++ b/src/stylesheet/widgets/_buttons.scss
@@ -69,13 +69,19 @@ button {
       padding-right: 17px;
     }
 
-    &.text-button.image-button {
-      padding-left: 9px;
-      padding-right: 9px;
+    &.text-button.image-button,
+    &.image-text-button {
+      padding-left: 10px;
+      padding-right: 10px;
 
-      label {
-        padding-left: 8px;
-        padding-right: 8px;
+      > box,
+      > box > box {
+        border-spacing: 4px;
+
+        > label {
+          padding-left: 2px;
+          padding-right: 2px;
+        }
       }
     }
 
@@ -83,8 +89,10 @@ button {
       padding-left: 10px;
       padding-right: 10px;
 
-      > box {
-        border-spacing: 4px;
+      > box { border-spacing: 4px; }
+
+      &.text-button {
+        > box { border-spacing: 4px; }
       }
     }
 
@@ -415,7 +423,8 @@ splitbutton {
     padding-right: 5px;
   }
 
-  &.text-button.image-button > button {
+  &.text-button.image-button > button,
+  &.image-text-button > button {
     padding-left: 10px;
     padding-right: 10px;
 
@@ -510,3 +519,22 @@ splitbutton {
     -gtk-icon-source: -gtk-icontheme('pan-down-symbolic');
   }
 }
+
+buttoncontent {
+  border-spacing: 6px;
+
+  > label {
+    font-weight: bold;
+
+    &:dir(ltr) { padding-right: 2px; }
+    &:dir(rtl) { padding-left: 2px; }
+  }
+
+  .arrow-button > box > &,
+  splitbutton > button > & {
+    > label {
+      &:dir(ltr) { padding-right: 0; }
+      &:dir(rtl) { padding-left: 0; }
+    }
+  }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 895d13a0..43f908b8 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -24,6 +24,7 @@ test_names = [
   'test-application-window',
   'test-avatar',
   'test-bin',
+  'test-button-content',
   'test-carousel',
   'test-carousel-indicator-dots',
   'test-carousel-indicator-lines',
diff --git a/tests/test-button-content.c b/tests/test-button-content.c
new file mode 100644
index 00000000..0a8fecad
--- /dev/null
+++ b/tests/test-button-content.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * Author: Alexander Mikhaylenko <alexander mikhaylenko puri sm>
+ */
+
+#include <adwaita.h>
+
+int notified;
+
+static void
+notify_cb (GtkWidget *widget, gpointer data)
+{
+  notified++;
+}
+
+static void
+test_adw_button_content_icon_name (void)
+{
+  g_autoptr (AdwButtonContent) content = NULL;
+  const char *icon_name;
+
+  content = g_object_ref_sink (ADW_BUTTON_CONTENT (adw_button_content_new ()));
+  g_assert_nonnull (content);
+
+  notified = 0;
+  g_signal_connect (content, "notify::icon-name", G_CALLBACK (notify_cb), NULL);
+
+  g_object_get (content, "icon-name", &icon_name, NULL);
+  g_assert_cmpstr (icon_name, ==, "");
+
+  adw_button_content_set_icon_name (content, "");
+  g_assert_cmpint (notified, ==, 0);
+
+
+  adw_button_content_set_icon_name (content, "document-open-symbolic");
+  g_assert_cmpstr (adw_button_content_get_icon_name (content), ==, "document-open-symbolic");
+  g_assert_cmpint (notified, ==, 1);
+
+  g_object_set (content, "icon-name", "", NULL);
+  g_assert_cmpstr (adw_button_content_get_icon_name (content), ==, "");
+  g_assert_cmpint (notified, ==, 2);
+}
+
+static void
+test_adw_button_content_label (void)
+{
+  g_autoptr (AdwButtonContent) content = NULL;
+  const char *label;
+
+  content = g_object_ref_sink (ADW_BUTTON_CONTENT (adw_button_content_new ()));
+  g_assert_nonnull (content);
+
+  notified = 0;
+  g_signal_connect (content, "notify::label", G_CALLBACK (notify_cb), NULL);
+
+  g_object_get (content, "label", &label, NULL);
+  g_assert_cmpstr (label, ==, "");
+
+  adw_button_content_set_label (content, "");
+  g_assert_cmpint (notified, ==, 0);
+
+
+  adw_button_content_set_label (content, "Open");
+  g_assert_cmpstr (adw_button_content_get_label (content), ==, "Open");
+  g_assert_cmpint (notified, ==, 1);
+
+  g_object_set (content, "label", "", NULL);
+  g_assert_cmpstr (adw_button_content_get_label (content), ==, "");
+  g_assert_cmpint (notified, ==, 2);
+}
+
+static void
+test_adw_button_content_use_underline (void)
+{
+  g_autoptr (AdwButtonContent) content = NULL;
+  gboolean use_underline;
+
+  content = g_object_ref_sink (ADW_BUTTON_CONTENT (adw_button_content_new ()));
+  g_assert_nonnull (content);
+
+  notified = 0;
+  g_signal_connect (content, "notify::use-underline", G_CALLBACK (notify_cb), NULL);
+
+  g_object_get (content, "use-underline", &use_underline, NULL);
+  g_assert_false (use_underline);
+
+  adw_button_content_set_use_underline (content, FALSE);
+  g_assert_cmpint (notified, ==, 0);
+
+
+  adw_button_content_set_use_underline (content, TRUE);
+  g_assert_true (adw_button_content_get_use_underline (content));
+  g_assert_cmpint (notified, ==, 1);
+
+  g_object_set (content, "use-underline", FALSE, NULL);
+  g_assert_false (adw_button_content_get_use_underline (content));
+  g_assert_cmpint (notified, ==, 2);
+}
+
+static void
+test_adw_button_content_style_class_button (void)
+{
+  g_autoptr (GtkWidget) window = NULL;
+  GtkWidget *button;
+  AdwButtonContent *content;
+
+  window = g_object_ref_sink (gtk_window_new ());
+
+  button = gtk_button_new ();
+  gtk_window_set_child (GTK_WINDOW (window), button);
+
+  gtk_window_present (GTK_WINDOW (window));
+
+  content = ADW_BUTTON_CONTENT (adw_button_content_new ());
+  g_assert_nonnull (content);
+
+  gtk_button_set_child (GTK_BUTTON (button), GTK_WIDGET (content));
+  g_assert_true (gtk_widget_has_css_class (button, "image-text-button"));
+
+  gtk_button_set_child (GTK_BUTTON (button), NULL);
+  g_assert_false (gtk_widget_has_css_class (button, "image-text-button"));
+}
+
+static void
+test_adw_button_content_style_class_split_button (void)
+{
+  g_autoptr (GtkWidget) window = NULL;
+  GtkWidget *button;
+  AdwButtonContent *content;
+
+  window = g_object_ref_sink (gtk_window_new ());
+
+  button = adw_split_button_new ();
+  gtk_window_set_child (GTK_WINDOW (window), button);
+
+  gtk_window_present (GTK_WINDOW (window));
+
+  content = ADW_BUTTON_CONTENT (adw_button_content_new ());
+  g_assert_nonnull (content);
+
+  adw_split_button_set_child (ADW_SPLIT_BUTTON (button), GTK_WIDGET (content));
+  g_assert_true (gtk_widget_has_css_class (button, "image-text-button"));
+
+  adw_split_button_set_child (ADW_SPLIT_BUTTON (button), NULL);
+  g_assert_false (gtk_widget_has_css_class (button, "image-text-button"));
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  gtk_test_init (&argc, &argv, NULL);
+  adw_init ();
+
+  g_test_add_func ("/Adwaita/ButtonContent/icon_name", test_adw_button_content_icon_name);
+  g_test_add_func ("/Adwaita/ButtonContent/label", test_adw_button_content_label);
+  g_test_add_func ("/Adwaita/ButtonContent/use_underline", test_adw_button_content_use_underline);
+  g_test_add_func ("/Adwaita/ButtonContent/style_class_button", test_adw_button_content_style_class_button);
+  g_test_add_func ("/Adwaita/ButtonContent/style_class_split_button", 
test_adw_button_content_style_class_split_button);
+
+  return g_test_run ();
+}


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