diff options
author | Timm Bäder <mail@baedert.org> | 2017-04-22 20:18:17 +0200 |
---|---|---|
committer | Timm Bäder <mail@baedert.org> | 2017-04-25 20:30:37 +0200 |
commit | 066c1983ba2c6f1f891e600c561ab03eac2074a6 (patch) | |
tree | b3bd68d270eb6ade9f463f615ab7c4e92c59df2d | |
parent | c92b7d4224b9cef1d08373fcc28f7fbd96c64e6d (diff) | |
download | gtk+-066c1983ba2c6f1f891e600c561ab03eac2074a6.tar.gz |
actionbar: Add explicit center widget
The center widget in GtkBox was only introduced to use it in
GtkActionBar. However, the implementation there is much more complex
than it needs to be, so move the center widget into GtkActionBar instead
and later remove it from GtkBox.
-rw-r--r-- | gtk/Makefile.am | 6 | ||||
-rw-r--r-- | gtk/gtkactionbar.c | 195 | ||||
-rw-r--r-- | gtk/gtkcenterbox.c | 226 | ||||
-rw-r--r-- | gtk/gtkcenterboxprivate.h | 43 | ||||
-rw-r--r-- | tests/testactionbar.c | 4 |
5 files changed, 441 insertions, 33 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index f66e20b4c5..df660307e8 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -576,7 +576,8 @@ gtk_private_h_sources = \ gtkwindowprivate.h \ gtktreemenu.h \ gdkpixbufutilsprivate.h \ - gtkgizmoprivate.h + gtkgizmoprivate.h \ + gtkcenterboxprivate.h # GTK+ C sources to build the library from gtk_base_c_sources = \ @@ -939,7 +940,8 @@ gtk_base_c_sources = \ gtkwin32draw.c \ gtkwin32theme.c \ gdkpixbufutils.c \ - gtkgizmo.c + gtkgizmo.c \ + gtkcenterbox.c if USE_QUARTZ gtk_base_c_sources += \ diff --git a/gtk/gtkactionbar.c b/gtk/gtkactionbar.c index bc06fbd623..85506eaefd 100644 --- a/gtk/gtkactionbar.c +++ b/gtk/gtkactionbar.c @@ -30,6 +30,7 @@ #include "gtkwidgetprivate.h" #include "gtkcontainerprivate.h" #include "gtkprivate.h" +#include "gtkcenterboxprivate.h" #include <string.h> @@ -55,8 +56,11 @@ struct _GtkActionBarPrivate { - GtkWidget *box; + GtkWidget *center_box; + GtkWidget *start_box; + GtkWidget *end_box; GtkWidget *revealer; + GtkCssGadget *gadget; }; @@ -85,7 +89,8 @@ gtk_action_bar_add (GtkContainer *container, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (container)); - gtk_container_add (GTK_CONTAINER (priv->box), child); + /* Default for pack-type is start */ + gtk_container_add (GTK_CONTAINER (priv->start_box), child); } static void @@ -94,7 +99,15 @@ gtk_action_bar_remove (GtkContainer *container, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (container)); - gtk_container_remove (GTK_CONTAINER (priv->box), child); + if (gtk_widget_get_parent (child) == priv->start_box) + gtk_container_remove (GTK_CONTAINER (priv->start_box), child); + else if (gtk_widget_get_parent (child) == priv->end_box) + gtk_container_remove (GTK_CONTAINER (priv->end_box), child); + else if (child == gtk_center_box_get_center_widget (GTK_CENTER_BOX (priv->center_box))) + gtk_center_box_set_center_widget (GTK_CENTER_BOX (priv->center_box), NULL); + else + g_warning ("Can't remove non-child %s %p from GtkActionBar %p", + G_OBJECT_TYPE_NAME (child), child, container); } static void @@ -106,9 +119,20 @@ gtk_action_bar_forall (GtkContainer *container, GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (container)); if (include_internals) - (* callback) (priv->revealer, callback_data); - else if (priv->box) - gtk_container_forall (GTK_CONTAINER (priv->box), callback, callback_data); + { + (*callback) (priv->revealer, callback_data); + } + else + { + if (priv->start_box != NULL) + gtk_container_forall (GTK_CONTAINER (priv->start_box), callback, callback_data); + + if (gtk_center_box_get_center_widget (GTK_CENTER_BOX (priv->center_box)) != NULL) + (*callback) (gtk_center_box_get_center_widget (GTK_CENTER_BOX (priv->center_box)), callback_data); + + if (priv->end_box != NULL) + gtk_container_forall (GTK_CONTAINER (priv->end_box), callback, callback_data); + } } static void @@ -116,9 +140,10 @@ gtk_action_bar_finalize (GObject *object) { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (object)); - g_clear_object (&priv->gadget); gtk_widget_unparent (priv->revealer); + g_clear_object (&priv->gadget); + G_OBJECT_CLASS (gtk_action_bar_parent_class)->finalize (object); } @@ -137,13 +162,47 @@ gtk_action_bar_get_child_property (GtkContainer *container, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (container)); - if (child == priv->revealer) - g_param_value_set_default (pspec, value); - else - gtk_container_child_get_property (GTK_CONTAINER (priv->box), - child, - pspec->name, - value); + switch (property_id) + { + case CHILD_PROP_PACK_TYPE: + if (gtk_widget_get_parent (child) == priv->start_box) + g_value_set_enum (value, GTK_PACK_START); + else if (gtk_widget_get_parent (child) == priv->end_box) + g_value_set_enum (value, GTK_PACK_END); + else /* Center widget */ + g_value_set_enum (value, GTK_PACK_START); + + break; + + case CHILD_PROP_POSITION: + if (gtk_widget_get_parent (child) == priv->start_box) + { + int n; + gtk_container_child_get (GTK_CONTAINER (priv->start_box), + child, + "position", &n, + NULL); + g_value_set_int (value, n); + } + else if (gtk_widget_get_parent (child) == priv->end_box) + { + int n; + gtk_container_child_get (GTK_CONTAINER (priv->end_box), + child, + "position", &n, + NULL); + g_value_set_int (value, n); + } + else /* Center widget */ + { + g_value_set_int (value, 0); + } + break; + + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + break; + } } static void @@ -155,11 +214,61 @@ gtk_action_bar_set_child_property (GtkContainer *container, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (container)); - if (child != priv->revealer) - gtk_container_child_set_property (GTK_CONTAINER (priv->box), - child, - pspec->name, - value); + switch (property_id) + { + case CHILD_PROP_PACK_TYPE: + if (gtk_widget_get_parent (child) == priv->start_box) + { + if (g_value_get_enum (value) == GTK_PACK_END) + { + g_object_ref (child); + gtk_container_remove (GTK_CONTAINER (priv->start_box), child); + gtk_box_pack_end (GTK_BOX (priv->end_box), child); + g_object_unref (child); + } + } + else if (gtk_widget_get_parent (child) == priv->end_box) + { + if (g_value_get_enum (value) == GTK_PACK_START) + { + g_object_ref (child); + gtk_container_remove (GTK_CONTAINER (priv->end_box), child); + gtk_container_add (GTK_CONTAINER (priv->start_box), child); + g_object_unref (child); + } + } + else + { + /* Ignore the center widget */ + } + + break; + + case CHILD_PROP_POSITION: + if (gtk_widget_get_parent (child) == priv->start_box) + { + gtk_container_child_set (GTK_CONTAINER (priv->start_box), + child, + "position", g_value_get_int (value), + NULL); + } + else if (gtk_widget_get_parent (child) == priv->end_box) + { + gtk_container_child_set (GTK_CONTAINER (priv->end_box), + child, + "position", g_value_get_int (value), + NULL); + } + else + { + /* Ignore center widget */ + } + break; + + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + break; + } } static gboolean @@ -171,7 +280,10 @@ gtk_action_bar_render (GtkCssGadget *gadget, int height, gpointer data) { - GTK_WIDGET_CLASS (gtk_action_bar_parent_class)->snapshot (gtk_css_gadget_get_owner (gadget), snapshot); + GtkActionBar *self = GTK_ACTION_BAR (gtk_css_gadget_get_owner (gadget)); + GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (self)); + + gtk_widget_snapshot_child (GTK_WIDGET (self), priv->revealer, snapshot); return FALSE; } @@ -196,8 +308,7 @@ gtk_action_bar_allocate (GtkCssGadget *gadget, GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (GTK_ACTION_BAR (widget)); gtk_widget_size_allocate (priv->revealer, (GtkAllocation *)allocation); - - gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip); + gtk_widget_get_clip (priv->revealer, out_clip); } static void @@ -291,6 +402,22 @@ gtk_action_bar_get_property (GObject *object, } static void +gtk_action_bar_destroy (GtkWidget *widget) +{ + GtkActionBar *self = GTK_ACTION_BAR (widget); + GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (self); + + gtk_center_box_set_start_widget (GTK_CENTER_BOX (priv->center_box), NULL); + gtk_center_box_set_center_widget (GTK_CENTER_BOX (priv->center_box), NULL); + gtk_center_box_set_end_widget (GTK_CENTER_BOX (priv->center_box), NULL); + + priv->start_box = NULL; + priv->end_box = NULL; + + GTK_WIDGET_CLASS (gtk_action_bar_parent_class)->destroy (widget); +} + +static void gtk_action_bar_class_init (GtkActionBarClass *klass) { GObjectClass *object_class; @@ -308,6 +435,7 @@ gtk_action_bar_class_init (GtkActionBarClass *klass) widget_class->snapshot = gtk_action_bar_snapshot; widget_class->size_allocate = gtk_action_bar_size_allocate; widget_class->measure = gtk_action_bar_measure_; + widget_class->destroy = gtk_action_bar_destroy; container_class->add = gtk_action_bar_add; container_class->remove = gtk_action_bar_remove; @@ -354,12 +482,18 @@ gtk_action_bar_init (GtkActionBar *action_bar) priv->revealer = gtk_revealer_new (); gtk_widget_set_parent (priv->revealer, widget); - priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_container_add (GTK_CONTAINER (priv->revealer), priv->box); - gtk_revealer_set_reveal_child (GTK_REVEALER (priv->revealer), TRUE); gtk_revealer_set_transition_type (GTK_REVEALER (priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP); + priv->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + priv->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + priv->center_box = gtk_center_box_new (); + gtk_center_box_set_start_widget (GTK_CENTER_BOX (priv->center_box), priv->start_box); + gtk_center_box_set_end_widget (GTK_CENTER_BOX (priv->center_box), priv->end_box); + + gtk_container_add (GTK_CONTAINER (priv->revealer), priv->center_box); + widget_node = gtk_widget_get_css_node (GTK_WIDGET (action_bar)); priv->gadget = gtk_css_custom_gadget_new_for_node (widget_node, GTK_WIDGET (action_bar), @@ -377,10 +511,9 @@ gtk_action_bar_buildable_add_child (GtkBuildable *buildable, const gchar *type) { GtkActionBar *action_bar = GTK_ACTION_BAR (buildable); - GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (action_bar); if (type && strcmp (type, "center") == 0) - gtk_box_set_center_widget (GTK_BOX (priv->box), GTK_WIDGET (child)); + gtk_action_bar_set_center_widget (action_bar, GTK_WIDGET (child)); else if (!type) gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child)); else @@ -412,7 +545,7 @@ gtk_action_bar_pack_start (GtkActionBar *action_bar, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (action_bar); - gtk_box_pack_start (GTK_BOX (priv->box), child); + gtk_container_add (GTK_CONTAINER (priv->start_box), child); } /** @@ -431,7 +564,7 @@ gtk_action_bar_pack_end (GtkActionBar *action_bar, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (action_bar); - gtk_box_pack_end (GTK_BOX (priv->box), child); + gtk_box_pack_end (GTK_BOX (priv->end_box), child); } /** @@ -449,7 +582,7 @@ gtk_action_bar_set_center_widget (GtkActionBar *action_bar, { GtkActionBarPrivate *priv = gtk_action_bar_get_instance_private (action_bar); - gtk_box_set_center_widget (GTK_BOX (priv->box), center_widget); + gtk_center_box_set_center_widget (GTK_CENTER_BOX (priv->center_box), center_widget); } /** @@ -469,7 +602,7 @@ gtk_action_bar_get_center_widget (GtkActionBar *action_bar) g_return_val_if_fail (GTK_IS_ACTION_BAR (action_bar), NULL); - return gtk_box_get_center_widget (GTK_BOX (priv->box)); + return gtk_center_box_get_center_widget (GTK_CENTER_BOX (priv->center_box)); } /** diff --git a/gtk/gtkcenterbox.c b/gtk/gtkcenterbox.c new file mode 100644 index 0000000000..316126c2ac --- /dev/null +++ b/gtk/gtkcenterbox.c @@ -0,0 +1,226 @@ + +#include "gtkcenterboxprivate.h" + +G_DEFINE_TYPE (GtkCenterBox, gtk_center_box, GTK_TYPE_WIDGET); + + +static void +gtk_center_box_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkCenterBox *self = GTK_CENTER_BOX (widget); + int min, nat, min_baseline, nat_baseline; + + gtk_widget_measure (self->start_widget, + orientation, + for_size, + minimum, natural, + minimum_baseline, natural_baseline); + + if (self->center_widget) + { + gtk_widget_measure (self->center_widget, + orientation, + for_size, + &min, &nat, + &min_baseline, &nat_baseline); + + /* XXX How are baselines even handled? */ + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + *minimum = *minimum + min; + *natural = *natural + nat; + } + else /* GTK_ORIENTATION_VERTICAL */ + { + *minimum = MAX (*minimum, min); + *natural = MAX (*minimum, nat); + } + } + + gtk_widget_measure (self->end_widget, + orientation, + for_size, + &min, &nat, + &min_baseline, &nat_baseline); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + *minimum = *minimum + min; + *natural = *natural + nat; + } + else /* GTK_ORIENTATION_VERTICAL */ + { + *minimum = MAX (*minimum, min); + *natural = MAX (*minimum, nat); + } + +} + +static void +gtk_center_box_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkCenterBox *self = GTK_CENTER_BOX (widget); + GtkAllocation child_allocation; + GtkAllocation clip = *allocation; + GtkAllocation child_clip; + int start_size, end_size; + int min, nat; + + GTK_WIDGET_CLASS (gtk_center_box_parent_class)->size_allocate (widget, allocation); + + + // TODO: Allocate natural sizes if possible? + + /* Start Box */ + gtk_widget_measure (self->start_widget, GTK_ORIENTATION_HORIZONTAL, + allocation->height, + &min, &nat, NULL, NULL); + child_allocation.x = allocation->x; + child_allocation.y = allocation->y; + child_allocation.width = min; + child_allocation.height = allocation->height; + + gtk_widget_size_allocate (self->start_widget, &child_allocation); + gtk_widget_get_clip (self->start_widget, &child_clip); + gdk_rectangle_union (&clip, &clip, &child_clip); + start_size = child_allocation.width; + + + /* End Box */ + gtk_widget_measure (self->end_widget, GTK_ORIENTATION_HORIZONTAL, + allocation->height, + &min, &nat, NULL, NULL); + child_allocation.x = allocation->x + allocation->width - min; + child_allocation.width = min; + + gtk_widget_size_allocate (self->end_widget, &child_allocation); + gtk_widget_get_clip (self->end_widget, &child_clip); + gdk_rectangle_union (&clip, &clip, &child_clip); + end_size = child_allocation.width; + + /* Center Widget */ + if (self->center_widget) + { + gtk_widget_measure (self->center_widget, GTK_ORIENTATION_HORIZONTAL, + allocation->height, + &min, &nat, NULL, NULL); + + child_allocation.x = (allocation->width / 2) - (min / 2); + + /* Push in from start/end */ + if (start_size > child_allocation.x) + child_allocation.x = start_size; + else if (allocation->width - end_size < child_allocation.x + min) + child_allocation.x = allocation->width - min - end_size; + + child_allocation.x += allocation->x; + child_allocation.width = min; + gtk_widget_size_allocate (self->center_widget, &child_allocation); + gtk_widget_get_clip (self->center_widget, &child_clip); + gdk_rectangle_union (&clip, &clip, &child_clip); + } + + gtk_widget_set_clip (widget, &clip); +} + +static void +gtk_center_box_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + GtkCenterBox *self = GTK_CENTER_BOX (widget); + + gtk_widget_snapshot_child (widget, self->start_widget, snapshot); + + if (self->center_widget) + gtk_widget_snapshot_child (widget, self->center_widget, snapshot); + + gtk_widget_snapshot_child (widget, self->end_widget, snapshot); +} + +static void +gtk_center_box_class_init (GtkCenterBoxClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + widget_class->measure = gtk_center_box_measure; + widget_class->size_allocate = gtk_center_box_size_allocate; + widget_class->snapshot = gtk_center_box_snapshot; +} + +static void +gtk_center_box_init (GtkCenterBox *self) +{ + gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); + + self->start_widget = NULL; + self->center_widget = NULL; + self->end_widget = NULL; +} + +GtkWidget * +gtk_center_box_new (void) +{ + return GTK_WIDGET (g_object_new (GTK_TYPE_CENTER_BOX, NULL)); +} + +void +gtk_center_box_set_start_widget (GtkCenterBox *self, + GtkWidget *child) +{ + if (self->start_widget) + gtk_widget_unparent (self->start_widget); + + self->start_widget = child; + if (child) + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} + +void +gtk_center_box_set_center_widget (GtkCenterBox *self, + GtkWidget *child) +{ + if (self->center_widget) + gtk_widget_unparent (self->center_widget); + + self->center_widget = child; + if (child) + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} + +void +gtk_center_box_set_end_widget (GtkCenterBox *self, + GtkWidget *child) +{ + if (self->end_widget) + gtk_widget_unparent (self->end_widget); + + self->end_widget = child; + if (child) + gtk_widget_set_parent (child, GTK_WIDGET (self)); +} + +GtkWidget * +gtk_center_box_get_start_widget (GtkCenterBox *self) +{ + return self->start_widget; +} + +GtkWidget * +gtk_center_box_get_center_widget (GtkCenterBox *self) +{ + return self->center_widget; +} + +GtkWidget * +gtk_center_box_get_end_widget (GtkCenterBox *self) +{ + return self->end_widget; +} diff --git a/gtk/gtkcenterboxprivate.h b/gtk/gtkcenterboxprivate.h new file mode 100644 index 0000000000..445d462b83 --- /dev/null +++ b/gtk/gtkcenterboxprivate.h @@ -0,0 +1,43 @@ + +#ifndef __GTK_CENTER_BOX_H__ +#define __GTK_CENTER_BOX_H__ + +#include "gtkwidget.h" + +#define GTK_TYPE_CENTER_BOX (gtk_center_box_get_type ()) +#define GTK_CENTER_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CENTER_BOX, GtkCenterBox)) +#define GTK_CENTER_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CENTER_BOX, GtkCenterBoxClass)) +#define GTK_IS_CENTER_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CENTER_BOX)) +#define GTK_IS_CENTER_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CENTER_BOX)) +#define GTK_CENTER_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CENTER_BOX, GtkCenterBoxClass)) + +typedef struct _GtkCenterBox GtkCenterBox; +typedef struct _GtkCenterBoxClass GtkCenterBoxClass; + +struct _GtkCenterBox +{ + GtkWidget parent_instance; + + GtkWidget *start_widget; + GtkWidget *center_widget; + GtkWidget *end_widget; +}; + +struct _GtkCenterBoxClass +{ + GtkWidgetClass parent_class; +}; + +GType gtk_center_box_get_type (void) G_GNUC_CONST; + +GtkWidget *gtk_center_box_new (void); +void gtk_center_box_set_start_widget (GtkCenterBox *self, GtkWidget *child); +void gtk_center_box_set_center_widget (GtkCenterBox *self, GtkWidget *child); +void gtk_center_box_set_end_widget (GtkCenterBox *self, GtkWidget *child); + +GtkWidget * gtk_center_box_get_start_widget (GtkCenterBox *self); +GtkWidget * gtk_center_box_get_center_widget (GtkCenterBox *self); +GtkWidget * gtk_center_box_get_end_widget (GtkCenterBox *self); + + +#endif diff --git a/tests/testactionbar.c b/tests/testactionbar.c index 00ff9c58ce..bd34bef129 100644 --- a/tests/testactionbar.c +++ b/tests/testactionbar.c @@ -46,6 +46,10 @@ create_widgets (GtkActionBar *bar, GtkPackType type; child = l->data; + + if (child == gtk_action_bar_get_center_widget (bar)) + continue; + gtk_container_child_get (GTK_CONTAINER (bar), child, "pack-type", &type, NULL); if (type == pack_type) gtk_container_remove (GTK_CONTAINER (bar), child); |