summaryrefslogtreecommitdiff
path: root/gtk/gtkmenubutton.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-05-18 04:56:30 +0000
committerMatthias Clasen <mclasen@redhat.com>2019-05-18 13:06:32 +0000
commit6a7d70cc9f677fb8628c769e9f4f6bb688ac7f82 (patch)
tree1946d4801d0e43c1d39fbccaeb5d7bfbe7dfac29 /gtk/gtkmenubutton.c
parent7cec5323d13db5f64dfee7758d83faa6ef3da3d5 (diff)
downloadgtk+-6a7d70cc9f677fb8628c769e9f4f6bb688ac7f82.tar.gz
menubutton: Don't derive from GtkToggleButton
Make GtkMenuButton a widget that has a toggle button, instead of deriving from it. We give it icon-name and label properties, to let people do what they expect to do with menu buttons.
Diffstat (limited to 'gtk/gtkmenubutton.c')
-rw-r--r--gtk/gtkmenubutton.c209
1 files changed, 168 insertions, 41 deletions
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index 60b5a2b034..687a9c6850 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -27,9 +27,9 @@
* This popup can be provided either as a #GtkMenu, a #GtkPopover or an
* abstract #GMenuModel.
*
- * The #GtkMenuButton widget can hold any valid child widget. That is, it
- * can hold almost any other standard #GtkWidget. The most commonly used
- * child is #GtkImage. If no widget is explicitely added to the #GtkMenuButton,
+ * The #GtkMenuButton widget can show either an icon (set with the
+ * #GtkMenuButton:icon-name property) or a label (set with the
+ * #GtkMenuButton:label property). If neither is explicitly set,
* a #GtkImage is automatically created, using an arrow image oriented
* according to #GtkMenuButton:direction or the generic “open-menu-symbolic”
* icon if the direction is not set.
@@ -121,11 +121,14 @@
#include "gtkprivate.h"
#include "gtkstylecontext.h"
#include "gtktypebuiltins.h"
+#include "gtklabel.h"
+#include "gtkbox.h"
#include "a11y/gtkmenubuttonaccessible.h"
struct _GtkMenuButtonPrivate
{
+ GtkWidget *button;
GtkWidget *menu; /* The menu and the popover are mutually exclusive */
GtkWidget *popover; /* Only one at a time can be set */
GMenuModel *model;
@@ -136,7 +139,8 @@ struct _GtkMenuButtonPrivate
GtkWidget *align_widget;
GtkWidget *arrow_widget;
GtkArrowType arrow_type;
- gboolean use_popover;
+
+ guint use_popover : 1;
guint press_handled : 1;
};
@@ -149,12 +153,14 @@ enum
PROP_DIRECTION,
PROP_USE_POPOVER,
PROP_POPOVER,
+ PROP_ICON_NAME,
+ PROP_LABEL,
LAST_PROP
};
static GParamSpec *menu_button_props[LAST_PROP];
-G_DEFINE_TYPE_WITH_PRIVATE (GtkMenuButton, gtk_menu_button, GTK_TYPE_TOGGLE_BUTTON)
+G_DEFINE_TYPE_WITH_PRIVATE (GtkMenuButton, gtk_menu_button, GTK_TYPE_WIDGET)
static void gtk_menu_button_dispose (GObject *object);
@@ -186,6 +192,12 @@ gtk_menu_button_set_property (GObject *object,
case PROP_POPOVER:
gtk_menu_button_set_popover (self, g_value_get_object (value));
break;
+ case PROP_ICON_NAME:
+ gtk_menu_button_set_icon_name (self, g_value_get_string (value));
+ break;
+ case PROP_LABEL:
+ gtk_menu_button_set_label (self, g_value_get_string (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -219,6 +231,12 @@ gtk_menu_button_get_property (GObject *object,
case PROP_POPOVER:
g_value_set_object (value, priv->popover);
break;
+ case PROP_ICON_NAME:
+ g_value_set_string (value, gtk_menu_button_get_icon_name (GTK_MENU_BUTTON (object)));
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, gtk_menu_button_get_label (GTK_MENU_BUTTON (object)));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -402,11 +420,10 @@ popup_menu (GtkMenuButton *menu_button,
}
static void
-gtk_menu_button_toggled (GtkToggleButton *button)
+gtk_menu_button_toggled (GtkMenuButton *menu_button)
{
- GtkMenuButton *menu_button = GTK_MENU_BUTTON (button);
GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
- gboolean active = gtk_toggle_button_get_active (button);
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
if (priv->menu)
{
@@ -434,35 +451,39 @@ gtk_menu_button_toggled (GtkToggleButton *button)
else
gtk_popover_popdown (GTK_POPOVER (priv->popover));
}
-
- if (GTK_TOGGLE_BUTTON_CLASS (gtk_menu_button_parent_class)->toggled)
- GTK_TOGGLE_BUTTON_CLASS (gtk_menu_button_parent_class)->toggled (button);
}
static void
-gtk_menu_button_add (GtkContainer *container,
- GtkWidget *child)
+gtk_menu_button_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
{
- GtkMenuButton *button = GTK_MENU_BUTTON (container);
- GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (button);
-
- if (priv->arrow_widget)
- gtk_container_remove (container, priv->arrow_widget);
+ GtkMenuButton *menu_button = GTK_MENU_BUTTON (widget);
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
- GTK_CONTAINER_CLASS (gtk_menu_button_parent_class)->add (container, child);
+ gtk_widget_measure (priv->button,
+ orientation,
+ for_size,
+ minimum, natural,
+ minimum_baseline, natural_baseline);
}
static void
-gtk_menu_button_remove (GtkContainer *container,
- GtkWidget *child)
+gtk_menu_button_size_allocate (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline)
{
- GtkMenuButton *button = GTK_MENU_BUTTON (container);
- GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (button);
-
- if (child == priv->arrow_widget)
- priv->arrow_widget = NULL;
+ GtkMenuButton *menu_button = GTK_MENU_BUTTON (widget);
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
- GTK_CONTAINER_CLASS (gtk_menu_button_parent_class)->remove (container, child);
+ gtk_widget_size_allocate (priv->button,
+ &(GtkAllocation) { 0, 0, width, height },
+ baseline);
}
static void
@@ -470,19 +491,14 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
- GtkToggleButtonClass *toggle_button_class = GTK_TOGGLE_BUTTON_CLASS (klass);
gobject_class->set_property = gtk_menu_button_set_property;
gobject_class->get_property = gtk_menu_button_get_property;
gobject_class->dispose = gtk_menu_button_dispose;
widget_class->state_flags_changed = gtk_menu_button_state_flags_changed;
-
- container_class->add = gtk_menu_button_add;
- container_class->remove = gtk_menu_button_remove;
-
- toggle_button_class->toggled = gtk_menu_button_toggled;
+ widget_class->measure = gtk_menu_button_measure;
+ widget_class->size_allocate = gtk_menu_button_size_allocate;
/**
* GtkMenuButton:popup:
@@ -564,10 +580,24 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
GTK_TYPE_POPOVER,
G_PARAM_READWRITE);
+ menu_button_props[PROP_ICON_NAME] =
+ g_param_spec_string ("icon-name",
+ P_("Icon Name"),
+ P_("The name of the icon used to automatically populate the button"),
+ NULL,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
+ menu_button_props[PROP_LABEL] =
+ g_param_spec_string ("label",
+ P_("Label"),
+ P_("The label for the button"),
+ NULL,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
g_object_class_install_properties (gobject_class, LAST_PROP, menu_button_props);
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_BUTTON_ACCESSIBLE);
- gtk_widget_class_set_css_name (widget_class, I_("button"));
+ gtk_widget_class_set_css_name (widget_class, I_("menubutton"));
}
static void
@@ -604,7 +634,7 @@ add_arrow (GtkMenuButton *menu_button)
arrow = gtk_image_new ();
set_arrow_type (GTK_IMAGE (arrow), priv->arrow_type);
- gtk_container_add (GTK_CONTAINER (menu_button), arrow);
+ gtk_container_add (GTK_CONTAINER (priv->button), arrow);
priv->arrow_widget = arrow;
}
@@ -614,9 +644,14 @@ gtk_menu_button_init (GtkMenuButton *menu_button)
GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
GtkStyleContext *context;
+ gtk_widget_set_has_surface (GTK_WIDGET (menu_button), FALSE);
+
priv->arrow_type = GTK_ARROW_DOWN;
priv->use_popover = TRUE;
+ priv->button = gtk_toggle_button_new ();
+ gtk_widget_set_parent (priv->button, GTK_WIDGET (menu_button));
+ g_signal_connect_swapped (priv->button, "toggled", G_CALLBACK (gtk_menu_button_toggled), menu_button);
add_arrow (menu_button);
gtk_widget_set_sensitive (GTK_WIDGET (menu_button), FALSE);
@@ -648,7 +683,9 @@ gtk_menu_button_new (void)
static gboolean
menu_deactivate_cb (GtkMenuButton *menu_button)
{
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_button), FALSE);
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->button), FALSE);
return TRUE;
}
@@ -669,9 +706,6 @@ update_sensitivity (GtkMenuButton *menu_button)
{
GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
- if (gtk_actionable_get_action_name (GTK_ACTIONABLE (menu_button)) != NULL)
- return;
-
gtk_widget_set_sensitive (GTK_WIDGET (menu_button),
priv->menu != NULL || priv->popover != NULL);
}
@@ -990,7 +1024,7 @@ gtk_menu_button_set_direction (GtkMenuButton *menu_button,
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_DIRECTION]);
/* Is it custom content? We don't change that */
- child = gtk_bin_get_child (GTK_BIN (menu_button));
+ child = gtk_bin_get_child (GTK_BIN (priv->button));
if (priv->arrow_widget != child)
return;
@@ -1045,6 +1079,7 @@ gtk_menu_button_dispose (GObject *object)
set_align_widget_pointer (GTK_MENU_BUTTON (object), NULL);
g_clear_object (&priv->model);
+ g_clear_pointer (&priv->button, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_menu_button_parent_class)->dispose (object);
}
@@ -1182,3 +1217,95 @@ gtk_menu_button_get_popover (GtkMenuButton *menu_button)
return GTK_POPOVER (priv->popover);
}
+
+/**
+ * gtk_menu_button_set_icon_name:
+ * @menu_button: a #GtkMenuButton
+ * @icon_name: the icon name
+ *
+ * Sets the name of an icon to show inside the menu button.
+ */
+void
+gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
+ const char *icon_name)
+{
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+
+ g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
+
+ gtk_button_set_icon_name (GTK_BUTTON (priv->button), icon_name);
+ g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
+}
+
+/**
+ * gtk_menu_button_get_icon_name:
+ * @menu_button: a #GtkMenuButton
+ *
+ * Gets the name of the icon shown in the button.
+ *
+ * Returns: the name of the icon shown in the button
+ */
+const char *
+gtk_menu_button_get_icon_name (GtkMenuButton *menu_button)
+{
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+
+ g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), NULL);
+
+ return gtk_button_get_icon_name (GTK_BUTTON (priv->button));
+}
+
+/**
+ * gtk_menu_button_set_label:
+ * @menu_button: a #GtkMenuButton
+ * @icon_name: the label
+ *
+ * Sets the label to show inside the menu button.
+ */
+void
+gtk_menu_button_set_label (GtkMenuButton *menu_button,
+ const char *label)
+{
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+ GtkWidget *child;
+ GtkWidget *box;
+
+ g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
+
+ child = gtk_bin_get_child (GTK_BIN (priv->button));
+ if (child)
+ gtk_container_remove (GTK_CONTAINER (priv->button), child);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add (GTK_CONTAINER (box), gtk_label_new (label));
+ gtk_container_add (GTK_CONTAINER (box), gtk_image_new_from_icon_name ("pan-down-symbolic"));
+ gtk_container_add (GTK_CONTAINER (priv->button), box);
+
+ g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
+}
+
+/**
+ * gtk_menu_button_get_label:
+ * @menu_button: a #GtkMenuButton
+ *
+ * Gets the label shown in the button
+ *
+ * Returns: the label shown in the button
+ */
+const char *
+gtk_menu_button_get_label (GtkMenuButton *menu_button)
+{
+ GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+ GtkWidget *child;
+
+ g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), NULL);
+
+ child = gtk_bin_get_child (GTK_BIN (priv->button));
+ if (GTK_IS_BOX (child))
+ {
+ child = gtk_widget_get_first_child (child);
+ return gtk_label_get_label (GTK_LABEL (child));
+ }
+
+ return NULL;
+}