[gtk+/wip/actor: 12/42] xxx: css box
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/actor: 12/42] xxx: css box
- Date: Tue, 18 Dec 2012 13:27:02 +0000 (UTC)
commit ecc08809679385dca7db4270586568740a64895d
Author: Benjamin Otte <otte redhat com>
Date: Mon Dec 10 02:58:22 2012 +0100
xxx: css box
gtk/actors/gtkcssbox.c | 518 +++++++++++++++++++++++++++++++++++++++++
gtk/actors/gtkcssboxprivate.h | 60 +++++
2 files changed, 578 insertions(+), 0 deletions(-)
---
diff --git a/gtk/actors/gtkcssbox.c b/gtk/actors/gtkcssbox.c
new file mode 100644
index 0000000..0cb82bf
--- /dev/null
+++ b/gtk/actors/gtkcssbox.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright  2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gtkcssboxprivate.h"
+
+#include "gtkcssenumvalueprivate.h"
+#include "gtkcssnumbervalueprivate.h"
+#include "gtkcsstypesprivate.h"
+#include "gtkdebug.h"
+#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtkstylecontext.h"
+#include "gtkstylecontextprivate.h"
+#include "gtktypebuiltins.h"
+
+/* state flags that when set will automatically be set on all parents */
+#define GTK_STATE_FLAGS_PROPAGATE_TO_PARENT (GTK_STATE_FLAG_PRELIGHT)
+
+/* state flags that when set will automatically propagate to all children */
+#define GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN (GTK_STATE_FLAG_INSENSITIVE | GTK_STATE_FLAG_BACKDROP)
+
+G_STATIC_ASSERT((GTK_STATE_FLAGS_PROPAGATE_TO_PARENT & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN) == 0);
+
+#define GTK_STATE_FLAGS_NO_PROPAGATE (~(GTK_STATE_FLAGS_PROPAGATE_TO_PARENT | GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN))
+
+struct _GtkCssBoxPrivate {
+ GtkStyleContext *context;
+
+ GtkStateFlags state;
+
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_EFFECTIVE_STATE,
+ PROP_STATE,
+
+ PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST];
+
+G_DEFINE_TYPE (GtkCssBox, _gtk_css_box, GTK_TYPE_ACTOR)
+
+static void
+gtk_css_box_set_effective_state (GtkCssBox *box,
+ GtkStateFlags state)
+{
+ gtk_style_context_set_state (box->priv->context, state);
+ g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_EFFECTIVE_STATE]);
+}
+
+GtkStateFlags
+_gtk_css_box_get_effective_state (GtkCssBox *box)
+{
+ g_return_val_if_fail (GTK_IS_CSS_BOX (box), 0);
+
+ return gtk_style_context_get_state (box->priv->context);
+}
+
+static void
+gtk_css_box_update_state_on_parent (GtkCssBox *box,
+ GtkStateFlags state_to_set,
+ GtkStateFlags state_to_unset)
+{
+ GtkStateFlags effective;
+ GtkActor *iter, *parent;
+
+ effective = _gtk_css_box_get_effective_state (box);
+ state_to_set = ~effective & state_to_set;
+ state_to_unset = effective & state_to_unset;
+
+ for (iter = _gtk_actor_get_first_child (GTK_ACTOR (box));
+ iter && state_to_unset != 0;
+ iter = _gtk_actor_get_next_sibling (iter))
+ {
+ if (!GTK_IS_CSS_BOX (iter))
+ continue;
+
+ state_to_unset &= ~_gtk_css_box_get_effective_state (GTK_CSS_BOX (iter));
+ }
+
+ if (state_to_set == 0 && state_to_unset == 0)
+ return;
+
+ gtk_css_box_set_effective_state (box, (effective | state_to_set) & ~state_to_unset);
+
+ parent = _gtk_actor_get_parent (GTK_ACTOR (box));
+ if (GTK_IS_CSS_BOX (parent))
+ gtk_css_box_update_state_on_parent (GTK_CSS_BOX (parent), state_to_set, state_to_unset);
+}
+
+static void
+gtk_css_box_update_state_on_children (GtkCssBox *box,
+ GtkStateFlags state_to_set,
+ GtkStateFlags state_to_unset)
+{
+ GtkStateFlags effective;
+ GtkActor *iter;
+
+ effective = _gtk_css_box_get_effective_state (box);
+ state_to_set = ~effective & state_to_set;
+ state_to_unset = effective & state_to_unset;
+
+ gtk_css_box_set_effective_state (box, (effective | state_to_set) & ~state_to_unset);
+
+ if (state_to_set == 0 && state_to_unset == 0)
+ return;
+
+ for (iter = _gtk_actor_get_first_child (GTK_ACTOR (box));
+ iter;
+ iter = _gtk_actor_get_next_sibling (iter))
+ {
+ if (!GTK_IS_CSS_BOX (iter))
+ continue;
+
+ gtk_css_box_update_state_on_children (GTK_CSS_BOX (iter), state_to_set, state_to_unset);
+ }
+}
+
+static void
+gtk_css_box_finalize (GObject *object)
+{
+ GtkCssBox *self = GTK_CSS_BOX (object);
+ GtkCssBoxPrivate *priv = self->priv;
+
+ g_object_unref (priv->context);
+ priv->context = NULL;
+
+ G_OBJECT_CLASS (_gtk_css_box_parent_class)->finalize (object);
+}
+
+static void
+gtk_css_box_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCssBox *css_box = GTK_CSS_BOX (object);
+
+ switch (prop_id)
+ {
+ case PROP_STATE:
+ _gtk_css_box_set_state (css_box, g_value_get_enum (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_css_box_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCssBox *css_box = GTK_CSS_BOX (object);
+
+ switch (prop_id)
+ {
+ case PROP_EFFECTIVE_STATE:
+ g_value_set_enum (value, _gtk_css_box_get_effective_state (css_box));
+ break;
+
+ case PROP_STATE:
+ g_value_set_enum (value, _gtk_css_box_get_state (css_box));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_css_box_queue_restyle (GtkCssBox *self,
+ GtkCssChange change)
+{
+ _gtk_style_context_queue_invalidate (self->priv->context, change);
+}
+
+static void
+gtk_css_box_queue_restyle_siblings (GtkCssBox *self,
+ GtkCssChange change)
+{
+ GtkActor *iter;
+
+ for (iter = _gtk_actor_get_previous_sibling (GTK_ACTOR (self));
+ iter;
+ iter = _gtk_actor_get_previous_sibling (iter))
+ {
+ if (GTK_IS_CSS_BOX (iter))
+ gtk_css_box_queue_restyle (GTK_CSS_BOX (iter), change);
+ }
+
+ for (iter = _gtk_actor_get_next_sibling (GTK_ACTOR (self));
+ iter;
+ iter = _gtk_actor_get_next_sibling (iter))
+ {
+ if (GTK_IS_CSS_BOX (iter))
+ gtk_css_box_queue_restyle (GTK_CSS_BOX (iter), change);
+ }
+}
+
+static void
+gtk_css_box_real_show (GtkActor *self)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->show (self);
+
+ gtk_css_box_queue_restyle_siblings (box, GTK_CSS_CHANGE_ANY_SIBLING);
+}
+
+static void
+gtk_css_box_real_hide (GtkActor *self)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+
+ gtk_css_box_queue_restyle_siblings (box, GTK_CSS_CHANGE_ANY_SIBLING);
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->hide (self);
+}
+
+static void
+gtk_css_box_real_map (GtkActor *self)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+ GtkCssBoxPrivate *priv = box->priv;
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->map (self);
+
+ _gtk_style_context_update_animating (priv->context);
+}
+
+static void
+gtk_css_box_real_unmap (GtkActor *self)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+ GtkCssBoxPrivate *priv = box->priv;
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->map (self);
+
+ _gtk_style_context_update_animating (priv->context);
+}
+
+static void
+gtk_css_box_real_parent_set (GtkActor *self,
+ GtkActor *old_parent)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+ GtkCssBoxPrivate *priv = box->priv;
+ GtkActor *parent;
+
+ parent = _gtk_actor_get_parent (self);
+
+ if (old_parent == NULL)
+ {
+ g_warn_if_fail (GTK_IS_CSS_BOX (parent));
+ }
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->parent_set (self, old_parent);
+
+ gtk_style_context_set_parent (priv->context, parent ? GTK_CSS_BOX (parent)->priv->context : NULL);
+
+ if (parent)
+ {
+ gtk_css_box_update_state_on_children (box,
+ _gtk_css_box_get_effective_state (GTK_CSS_BOX (parent)) & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN,
+ 0);
+ gtk_css_box_update_state_on_parent (GTK_CSS_BOX (parent),
+ _gtk_css_box_get_effective_state (box) & GTK_STATE_FLAGS_PROPAGATE_TO_PARENT,
+ 0);
+ }
+ else
+ {
+ gtk_css_box_update_state_on_children (box,
+ 0,
+ _gtk_css_box_get_effective_state (GTK_CSS_BOX (old_parent)) & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN);
+ gtk_css_box_update_state_on_parent (GTK_CSS_BOX (old_parent),
+ 0,
+ _gtk_css_box_get_effective_state (box) & GTK_STATE_FLAGS_PROPAGATE_TO_PARENT);
+ }
+}
+
+static double
+gtk_css_box_get_edge (GtkCssBox *box,
+ GtkCssSide side)
+{
+ const struct {
+ guint margin;
+ guint border;
+ guint border_style;
+ guint padding;
+ } properties[] = {
+ /* [GTK_CSS_TOP] = */ { GTK_CSS_PROPERTY_MARGIN_TOP,
+ GTK_CSS_PROPERTY_BORDER_TOP_WIDTH,
+ GTK_CSS_PROPERTY_BORDER_TOP_STYLE,
+ GTK_CSS_PROPERTY_PADDING_TOP },
+ /* [GTK_CSS_RIGHT] = */ { GTK_CSS_PROPERTY_MARGIN_RIGHT,
+ GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH,
+ GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE,
+ GTK_CSS_PROPERTY_PADDING_RIGHT },
+ /* [GTK_CSS_BOTTOM] = */ { GTK_CSS_PROPERTY_MARGIN_BOTTOM,
+ GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
+ GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE,
+ GTK_CSS_PROPERTY_PADDING_BOTTOM },
+ /* [GTK_CSS_LEFT] = */ { GTK_CSS_PROPERTY_MARGIN_LEFT,
+ GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH,
+ GTK_CSS_PROPERTY_BORDER_LEFT_STYLE,
+ GTK_CSS_PROPERTY_PADDING_LEFT }
+ };
+ GtkStyleContext *context;
+ GtkBorderStyle border_style;
+ double result;
+
+ context = box->priv->context;
+
+ result = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, properties[side].margin), 100);
+ + _gtk_css_number_value_get (_gtk_style_context_peek_property (context, properties[side].padding), 100);
+
+ border_style = _gtk_css_border_style_value_get (_gtk_style_context_peek_property (context, properties[side].border_style));
+ if (border_style != GTK_BORDER_STYLE_NONE && border_style != GTK_BORDER_STYLE_HIDDEN)
+ result = _gtk_css_number_value_get (_gtk_style_context_peek_property (context, properties[side].border), 100);
+
+ if (result < 0.0)
+ return 0.0;
+
+ return result;
+}
+
+static void
+gtk_css_box_real_get_preferred_size (GtkActor *self,
+ GtkOrientation orientation,
+ gfloat for_size,
+ gfloat *min_size_p,
+ gfloat *natural_size_p)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+ float extra_size;
+
+ *min_size_p = 0;
+ *natural_size_p = 0;
+ if (for_size >= 0)
+ {
+ if (orientation == GTK_ORIENTATION_VERTICAL)
+ extra_size = gtk_css_box_get_edge (box, GTK_CSS_LEFT) + gtk_css_box_get_edge (box, GTK_CSS_RIGHT);
+ else
+ extra_size = gtk_css_box_get_edge (box, GTK_CSS_TOP) + gtk_css_box_get_edge (box, GTK_CSS_BOTTOM);
+
+ for_size = MAX (0, for_size - extra_size);
+ }
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ extra_size = gtk_css_box_get_edge (box, GTK_CSS_LEFT) + gtk_css_box_get_edge (box, GTK_CSS_RIGHT);
+ else
+ extra_size = gtk_css_box_get_edge (box, GTK_CSS_TOP) + gtk_css_box_get_edge (box, GTK_CSS_BOTTOM);
+
+ *min_size_p = MAX (0, *min_size_p + extra_size);
+ *natural_size_p = MAX (0, *natural_size_p + extra_size);
+}
+
+static void
+gtk_css_box_real_draw (GtkActor *self,
+ cairo_t *cr)
+{
+ GtkCssBox *box = GTK_CSS_BOX (self);
+ GtkCssBoxPrivate *priv = box->priv;
+
+ gtk_render_background (priv->context,
+ cr,
+ 0, 0,
+ _gtk_actor_get_width (self),
+ _gtk_actor_get_height (self));
+ gtk_render_frame (priv->context,
+ cr,
+ 0, 0,
+ _gtk_actor_get_width (self),
+ _gtk_actor_get_height (self));
+
+ GTK_ACTOR_CLASS (_gtk_css_box_parent_class)->draw (self, cr);
+}
+
+static void
+_gtk_css_box_class_init (GtkCssBoxClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkActorClass *actor_class = GTK_ACTOR_CLASS (klass);
+
+ object_class->finalize = gtk_css_box_finalize;
+ object_class->set_property = gtk_css_box_set_property;
+ object_class->get_property = gtk_css_box_get_property;
+
+ actor_class->show = gtk_css_box_real_show;
+ actor_class->hide = gtk_css_box_real_hide;
+ actor_class->map = gtk_css_box_real_map;
+ actor_class->unmap = gtk_css_box_real_unmap;
+ actor_class->draw = gtk_css_box_real_draw;
+ actor_class->parent_set = gtk_css_box_real_parent_set;
+ actor_class->get_preferred_size = gtk_css_box_real_get_preferred_size;
+
+ /**
+ * GtkCssBox:state:
+ *
+ * The state flags explicitly set on the box.
+ *
+ * See also GtkCssBox:effective-state.
+ */
+ obj_props[PROP_STATE] =
+ g_param_spec_flags ("state",
+ P_("State"),
+ P_("State flags set on the box"),
+ GTK_TYPE_STATE_FLAGS,
+ 0,
+ GTK_PARAM_READWRITE);
+
+ /**
+ * GtkCssBox:effective-state:
+ *
+ * The state flags explicitly set on the box. These are the flags cpomputed
+ * from the box's own state and propagated state from parent or children boxes.
+ *
+ * See also GtkCssBox:state.
+ */
+ obj_props[PROP_EFFECTIVE_STATE] =
+ g_param_spec_flags ("effective-state",
+ P_("Effective State"),
+ P_("Effective state computed for the box"),
+ GTK_TYPE_STATE_FLAGS,
+ 0,
+ GTK_PARAM_READWRITE);
+
+ g_type_class_add_private (klass, sizeof (GtkCssBoxPrivate));
+}
+
+static void
+_gtk_css_box_init (GtkCssBox *box)
+{
+ GtkCssBoxPrivate *priv;
+ GtkActor *actor = GTK_ACTOR (box);
+
+ box->priv = G_TYPE_INSTANCE_GET_PRIVATE (box,
+ GTK_TYPE_CSS_BOX,
+ GtkCssBoxPrivate);
+ priv = box->priv;
+
+ priv->context = gtk_style_context_new ();
+ gtk_style_context_set_direction (priv->context, _gtk_actor_get_text_direction (actor));
+ gtk_style_context_set_screen (priv->context, _gtk_actor_get_screen (actor));
+ //_gtk_style_context_set_actor (priv->context, actor);
+}
+
+void
+_gtk_css_box_set_state (GtkCssBox *box,
+ GtkStateFlags state)
+{
+ GtkCssBoxPrivate *priv;
+ GtkStateFlags changed;
+
+ g_return_if_fail (GTK_IS_CSS_BOX (box));
+
+ priv = box->priv;
+
+ if (priv->state == state)
+ return;
+
+ g_object_freeze_notify (G_OBJECT (box));
+
+ changed = priv->state ^ state;
+
+ priv->state = state;
+ g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_STATE]);
+
+ if (changed & GTK_STATE_FLAGS_PROPAGATE_TO_PARENT)
+ gtk_css_box_update_state_on_parent (box,
+ state & changed & GTK_STATE_FLAGS_PROPAGATE_TO_PARENT,
+ ~state & changed & GTK_STATE_FLAGS_PROPAGATE_TO_PARENT);
+ if (changed & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN)
+ gtk_css_box_update_state_on_children (box,
+ state & changed & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN,
+ ~state & changed & GTK_STATE_FLAGS_PROPAGATE_TO_CHILDREN);
+
+ gtk_css_box_set_effective_state (box,
+ (_gtk_css_box_get_effective_state (box) & GTK_STATE_FLAGS_NO_PROPAGATE)
+ | (state & ~GTK_STATE_FLAGS_NO_PROPAGATE));
+
+ g_object_thaw_notify (G_OBJECT (box));
+}
+
+GtkStateFlags
+_gtk_css_box_get_state (GtkCssBox *box)
+{
+ g_return_val_if_fail (GTK_IS_CSS_BOX (box), 0);
+
+ return box->priv->state;
+}
diff --git a/gtk/actors/gtkcssboxprivate.h b/gtk/actors/gtkcssboxprivate.h
new file mode 100644
index 0000000..46619a6
--- /dev/null
+++ b/gtk/actors/gtkcssboxprivate.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright  2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GTK_CSS_BOX_PRIVATE_H__
+#define __GTK_CSS_BOX_PRIVATE_H__
+
+#include <gtk/actors/gtkactorprivate.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CSS_BOX (_gtk_css_box_get_type ())
+#define GTK_CSS_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_BOX, GtkCssBox))
+#define GTK_CSS_BOX_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_BOX, GtkCssBoxClass))
+#define GTK_IS_CSS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_BOX))
+#define GTK_IS_CSS_BOX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_BOX))
+#define GTK_CSS_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_BOX, GtkCssBoxClass))
+
+typedef struct _GtkCssBox GtkCssBox;
+typedef struct _GtkCssBoxPrivate GtkCssBoxPrivate;
+typedef struct _GtkCssBoxClass GtkCssBoxClass;
+typedef struct _GtkCssBoxIter GtkCssBoxIter;
+
+struct _GtkCssBox
+{
+ GtkActor parent;
+
+ GtkCssBoxPrivate *priv;
+};
+
+struct _GtkCssBoxClass
+{
+ GtkActorClass parent_class;
+};
+
+GType _gtk_css_box_get_type (void) G_GNUC_CONST;
+
+void _gtk_css_box_set_state (GtkCssBox *box,
+ GtkStateFlags state);
+GtkStateFlags _gtk_css_box_get_state (GtkCssBox *box);
+GtkStateFlags _gtk_css_box_get_effective_state (GtkCssBox *box);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_BOX_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]