[gtk+/wip/actor: 12/42] xxx: css box



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]