gnome-shell r42 - in trunk/src: . tidy
- From: otaylor svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-shell r42 - in trunk/src: . tidy
- Date: Wed, 12 Nov 2008 21:09:27 +0000 (UTC)
Author: otaylor
Date: Wed Nov 12 21:09:27 2008
New Revision: 42
URL: http://svn.gnome.org/viewvc/gnome-shell?rev=42&view=rev
Log:
Experimentally add build infrastructure and a few Tidy widgets
For experimenting with using tidy, import TidyButton and TidyGrid
(+ dependencies) into our source tree and set up build machinery
to build them and build a typelib for them.
The sources are build right into libgnome-shell.so, so the Shell.gir
and Tidy.gir actually point to the same shared library.
src/Makefile-tidy.am: Build libtidy-1.0.la
src/Makefile.am: Include built tidy into gnome-shell.la and
build Tidy-1.0.typelib
src/tidy/*: Add some source files from Tidy
Added:
trunk/src/Makefile-tidy.am
trunk/src/tidy/
trunk/src/tidy/tidy-actor.c
trunk/src/tidy/tidy-actor.h
trunk/src/tidy/tidy-button.c
trunk/src/tidy/tidy-button.h
trunk/src/tidy/tidy-debug.h
trunk/src/tidy/tidy-enum-types.c.in
trunk/src/tidy/tidy-enum-types.h.in
trunk/src/tidy/tidy-frame.c
trunk/src/tidy/tidy-frame.h
trunk/src/tidy/tidy-grid.c
trunk/src/tidy/tidy-grid.h
trunk/src/tidy/tidy-marshal.list
trunk/src/tidy/tidy-private.h
trunk/src/tidy/tidy-stylable.c
trunk/src/tidy/tidy-stylable.h
trunk/src/tidy/tidy-style.c
trunk/src/tidy/tidy-style.h
trunk/src/tidy/tidy-types.h
trunk/src/tidy/tidy-util.c
trunk/src/tidy/tidy-util.h
Modified:
trunk/src/ (props changed)
trunk/src/Makefile.am
Added: trunk/src/Makefile-tidy.am
==============================================================================
--- (empty file)
+++ trunk/src/Makefile-tidy.am Wed Nov 12 21:09:27 2008
@@ -0,0 +1,109 @@
+NULL =
+
+GLIB_GENMARSHAL = `pkg-config --variable=glib_genmarshal glib-2.0`
+GLIB_MKENUMS = `pkg-config --variable=glib_mkenums glib-2.0`
+
+tidy_cflags = \
+ -I$(top_srcdir)/src \
+ -DPREFIX=\""$(prefix)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DG_LOG_DOMAIN=\"Tidy\" \
+ $(MUTTER_PLUGIN_CFLAGS) \
+ $(NULL)
+
+tidy_built_sources = \
+ tidy-enum-types.h \
+ tidy-enum-types.c \
+ tidy-marshal.h \
+ tidy-marshal.c
+
+BUILT_SOURCES += $(tidy_built_sources)
+
+STAMP_FILES = stamp-tidy-marshal.h stamp-tidy-enum-types.h
+
+# please, keep this sorted alphabetically
+tidy_source_h = \
+ tidy/tidy-actor.h \
+ tidy/tidy-button.h \
+ tidy/tidy-frame.h \
+ tidy/tidy-grid.h \
+ tidy/tidy-stylable.h \
+ tidy/tidy-style.h \
+ tidy/tidy-types.h \
+ tidy/tidy-util.h \
+ $(NULL)
+
+tidy_source_h_private = \
+ tidy/tidy-debug.h \
+ $(NULL)
+
+# please, keep this sorted alphabetically
+tidy_source_c = \
+ tidy/tidy-actor.c \
+ tidy/tidy-button.c \
+ tidy/tidy-frame.c \
+ tidy/tidy-grid.c \
+ tidy/tidy-stylable.c \
+ tidy/tidy-style.c \
+ tidy/tidy-util.c \
+ $(NULL)
+
+tidy-marshal.h: stamp-tidy-marshal.h
+ @true
+stamp-tidy-marshal.h: Makefile tidy/tidy-marshal.list
+ $(GLIB_GENMARSHAL) \
+ --prefix=_tidy_marshal \
+ --header \
+ $(srcdir)/tidy/tidy-marshal.list > xgen-tmh && \
+ (cmp -s xgen-tmh tidy-marshal.h || cp -f xgen-tmh tidy-marshal.h) && \
+ rm -f xgen-tmh && \
+ echo timestamp > $(@F)
+
+tidy-marshal.c: Makefile tidy/tidy-marshal.list
+ (echo "#include \"tidy-marshal.h\"" ; \
+ $(GLIB_GENMARSHAL) \
+ --prefix=_tidy_marshal \
+ --body \
+ $(srcdir)/tidy/tidy-marshal.list ) > xgen-tmc && \
+ cp -f xgen-tmc tidy-marshal.c && \
+ rm -f xgen-tmc
+
+tidy-enum-types.h: stamp-tidy-enum-types.h Makefile
+ @true
+stamp-tidy-enum-types.h: $(tidy_source_h) tidy/tidy-enum-types.h.in
+ ( cd $(srcdir) && \
+ $(GLIB_MKENUMS) \
+ --template $(srcdir)/tidy/tidy-enum-types.h.in \
+ $(tidy_source_h) ) >> xgen-teth && \
+ (cmp xgen-teth tidy-enum-types.h || cp xgen-teth tidy-enum-types.h) && \
+ rm -f xgen-teth && \
+ echo timestamp > $(@F)
+
+tidy-enum-types.c: stamp-tidy-enum-types.h tidy/tidy-enum-types.c.in
+ ( cd $(srcdir) && \
+ $(GLIB_MKENUMS) \
+ --template $(srcdir)/tidy/tidy-enum-types.c.in \
+ $(tidy_source_h) ) >> xgen-tetc && \
+ cp xgen-tetc tidy-enum-types.c && \
+ rm -f xgen-tetc
+
+lib_LTLIBRARIES = libtidy-1.0.la
+
+libtidy_1_0_la_LIBADD = $(TIDY_LIBS)
+libtidy_1_0_la_SOURCES = \
+ $(tidy_source_c) \
+ $(tidy_source_h) \
+ $(tidy_source_h_priv) \
+ $(tidy_built_sources) \
+ $(NULL)
+libtidy_1_0_la_CPPFLAGS = $(tidy_cflags)
+libtidy_1_0_la_LDFLAGS = $(LDADD)
+
+CLEANFILES += $(STAMP_FILES) $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ tidy/tidy-enum-types.h.in \
+ tidy/tidy-enum-types.c.in \
+ tidy/tidy-private.h \
+ tidy/tidy-marshal.list
Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am (original)
+++ trunk/src/Makefile.am Wed Nov 12 21:09:27 2008
@@ -1,4 +1,9 @@
-INCLUDES = \
+BUILT_SOURCES =
+CLEANFILES =
+
+include Makefile-tidy.am
+
+gnome_shell_cflags = \
$(MUTTER_PLUGIN_CFLAGS) \
-DGETTEXT_PACKAGE=gnome-shell \
-DJSDIR=\"$(pkgdatadir)/js\"
@@ -14,7 +19,8 @@
shell-global.h
libgnome_shell_la_LDFLAGS = -avoid-version -module
-libgnome_shell_la_LIBADD = $(MUTTER_PLUGIN_LIBS)
+libgnome_shell_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libtidy-1.0.la
+libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
# We can't have any undefined symbols when g-ir-scanner dlopens the library
# to introspect it, so we link everything a _second_ time, including a
@@ -27,14 +33,15 @@
# The dummy -rpath here is needed to convince libtool to build a
# noinst_LTLIBRARY shared
libgnome_shell_introspect_la_LDFLAGS = -avoid-version -module -rpath $(libdir)
-libgnome_shell_introspect_la_LIBADD = $(MUTTER_PLUGIN_LIBS)
+libgnome_shell_introspect_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libtidy-1.0.la
+libgnome_shell_introspect_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)/girepository
-typelib_DATA = Shell-0.1.typelib
+typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib
# After we run g-ir-scanner, we need to change the library name written in
# the .gir file from the "fake" second copy of the library to the real name
-Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES)
+Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES) Makefile
g-ir-scanner \
--namespace=Shell \
--nsversion=0.1 \
@@ -42,8 +49,8 @@
--include=Clutter-0.8 \
--include=Meta-2.25 \
--library=gnome-shell-introspect \
- $(libgnome_shell_la_SOURCES) \
- $(INCLUDES) \
+- $(libgnome_shell_la_SOURCES) \
+ $(libgnome_shell_la_CPPFLAGS) \
-o $ tmp
sed 's/gnome-shell-introspect/gnome-shell/' < $ tmp > $@ && rm $ tmp
@@ -51,3 +58,23 @@
# (not the fake library, since we've already done the rewriting)
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Shell-0.1.gir -o $@
+
+# After we run g-ir-scanner, we need to change the library name written in
+# the .gir file from the "fake" second copy of the library to the real name
+Tidy-1.0.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES) Makefile
+ g-ir-scanner \
+ --namespace=Tidy \
+ --nsversion=1.0 \
+ --include=GObject-2.0 \
+ --include=Clutter-0.8 \
+ --library=gnome-shell-introspect \
+ $(tidy_source_h) \
+ $(tidy_source_c) \
+ $(tidy_cflags) \
+ -o $ tmp
+ sed 's/gnome-shell-introspect/gnome-shell/' < $ tmp > $@ && rm $ tmp
+
+# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
+# (not the fake library, since we've already done the rewriting)
+Tidy-1.0.typelib: libgnome-shell.la Tidy-1.0.gir
+ LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
Added: trunk/src/tidy/tidy-actor.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-actor.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,529 @@
+/* tidy-actor.c: Base class for Tidy actors
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:tidy-actor
+ * @short_description: Base class for stylable actors
+ *
+ * #TidyActor is a simple abstract class on top of #ClutterActor. It
+ * provides basic themeing properties, support for padding and alignment.
+ *
+ * Actors in the Tidy library should subclass #TidyActor if they plan
+ * to obey to a certain #TidyStyle or if they implement #ClutterContainer
+ * and want to offer basic layout capabilities.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "tidy-actor.h"
+
+#include "tidy-debug.h"
+#include "tidy-marshal.h"
+#include "tidy-private.h"
+#include "tidy-stylable.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_STYLE,
+ PROP_PADDING,
+ PROP_X_ALIGN,
+ PROP_Y_ALIGN
+};
+
+enum
+{
+ LAST_SIGNAL
+};
+
+static void tidy_stylable_iface_init (TidyStylableIface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TidyActor, tidy_actor, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (TIDY_TYPE_STYLABLE,
+ tidy_stylable_iface_init));
+
+#define TIDY_ACTOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_ACTOR, TidyActorPrivate))
+
+struct _TidyActorPrivate
+{
+ TidyStyle *style;
+
+ TidyPadding padding;
+
+ ClutterFixed x_align;
+ ClutterFixed y_align;
+};
+
+static void
+tidy_actor_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyActor *actor = TIDY_ACTOR (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_PADDING:
+ tidy_actor_set_padding (actor, g_value_get_boxed (value));
+ break;
+
+ case PROP_X_ALIGN:
+ actor->priv->x_align =
+ CLUTTER_FIXED_TO_FLOAT (g_value_get_double (value));
+ break;
+
+ case PROP_Y_ALIGN:
+ actor->priv->y_align =
+ CLUTTER_FIXED_TO_FLOAT (g_value_get_double (value));
+ break;
+
+ case PROP_STYLE:
+ tidy_stylable_set_style (TIDY_STYLABLE (actor),
+ g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_actor_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyActor *actor = TIDY_ACTOR (gobject);
+ TidyActorPrivate *priv = actor->priv;
+
+ switch (prop_id)
+ {
+ case PROP_PADDING:
+ {
+ TidyPadding padding = { 0, };
+
+ tidy_actor_get_padding (actor, &padding);
+ g_value_set_boxed (value, &padding);
+ }
+ break;
+
+ case PROP_X_ALIGN:
+ g_value_set_double (value, CLUTTER_FIXED_TO_FLOAT (priv->x_align));
+ break;
+
+ case PROP_Y_ALIGN:
+ g_value_set_double (value, CLUTTER_FIXED_TO_FLOAT (priv->y_align));
+ break;
+
+ case PROP_STYLE:
+ g_value_set_object (value, priv->style);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_actor_dispose (GObject *gobject)
+{
+ TidyActor *actor = TIDY_ACTOR (gobject);
+
+ if (actor->priv->style)
+ {
+ g_object_unref (actor->priv->style);
+ actor->priv->style = NULL;
+ }
+
+ G_OBJECT_CLASS (tidy_actor_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_actor_class_init (TidyActorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyActorPrivate));
+
+ gobject_class->set_property = tidy_actor_set_property;
+ gobject_class->get_property = tidy_actor_get_property;
+ gobject_class->dispose = tidy_actor_dispose;
+
+ /**
+ * TidyActor:padding:
+ *
+ * Padding around an actor, expressed in #ClutterUnit<!-- -->s. Padding
+ * is the internal space between an actors bounding box and its internal
+ * children.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PADDING,
+ g_param_spec_boxed ("padding",
+ "Padding",
+ "Units of padding around an actor",
+ TIDY_TYPE_PADDING,
+ TIDY_PARAM_READWRITE));
+ /**
+ * TidyActor:x-align:
+ *
+ * Alignment of internal children along the X axis, relative to the
+ * actor's bounding box origin, and in relative units (1.0 is the
+ * current width of the actor).
+ *
+ * A value of 0.0 will left-align the children; 0.5 will align them at
+ * the middle of the actor's width; 1.0 will right align the children.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_X_ALIGN,
+ g_param_spec_double ("x-align",
+ "X Alignment",
+ "Alignment (between 0.0 and 1.0) on the X axis",
+ 0.0, 1.0, 0.5,
+ TIDY_PARAM_READWRITE));
+ /**
+ * TidyActor:y-align:
+ *
+ * Alignment of internal children along the Y axis, relative to the
+ * actor's bounding box origin, and in relative units (1.0 is the
+ * current height of the actor).
+ *
+ * A value of 0.0 will top-align the children; 0.5 will align them at
+ * the middle of the actor's height; 1.0 will bottom align the children.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_Y_ALIGN,
+ g_param_spec_double ("y-align",
+ "Y Alignement",
+ "Alignment (between 0.0 and 1.0) on the Y axis",
+ 0.0, 1.0, 0.5,
+ TIDY_PARAM_READWRITE));
+ g_object_class_override_property (gobject_class, PROP_STYLE, "style");
+}
+
+static TidyStyle *
+tidy_actor_get_style (TidyStylable *stylable)
+{
+ TidyActorPrivate *priv = TIDY_ACTOR (stylable)->priv;
+
+ if (!priv->style)
+ priv->style = g_object_ref (tidy_style_get_default ());
+
+ return priv->style;
+}
+
+static void
+tidy_actor_set_style (TidyStylable *stylable,
+ TidyStyle *style)
+{
+ TidyActorPrivate *priv = TIDY_ACTOR (stylable)->priv;
+
+ if (priv->style)
+ g_object_unref (priv->style);
+
+ priv->style = g_object_ref_sink (style);
+}
+
+static void
+tidy_stylable_iface_init (TidyStylableIface *iface)
+{
+ static gboolean is_initialized = FALSE;
+
+ if (!is_initialized)
+ {
+ GParamSpec *pspec;
+
+ pspec = g_param_spec_string ("font-name",
+ "Font Name",
+ "The font to use for displaying text",
+ "Sans 12px",
+ G_PARAM_READWRITE);
+ tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
+
+ pspec = g_param_spec_boxed ("bg-color",
+ "Background Color",
+ "The background color of an actor",
+ CLUTTER_TYPE_COLOR,
+ G_PARAM_READWRITE);
+ tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
+
+ pspec = g_param_spec_boxed ("active-color",
+ "Active Color",
+ "The color of an active actor",
+ CLUTTER_TYPE_COLOR,
+ G_PARAM_READWRITE);
+ tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
+
+ pspec = g_param_spec_boxed ("text-color",
+ "Text Color",
+ "The color of the text of an actor",
+ CLUTTER_TYPE_COLOR,
+ G_PARAM_READWRITE);
+ tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
+
+ iface->get_style = tidy_actor_get_style;
+ iface->set_style = tidy_actor_set_style;
+ }
+}
+
+static void
+tidy_actor_init (TidyActor *actor)
+{
+ TidyActorPrivate *priv;
+
+ actor->priv = priv = TIDY_ACTOR_GET_PRIVATE (actor);
+
+ /* no padding */
+ priv->padding.top = priv->padding.bottom = 0;
+ priv->padding.right = priv->padding.left = 0;
+
+ /* middle align */
+ priv->x_align = priv->y_align = CLUTTER_FLOAT_TO_FIXED (0.5);
+
+ clutter_actor_set_reactive (CLUTTER_ACTOR (actor), TRUE);
+}
+
+/**
+ * tidy_actor_set_padding:
+ * @actor: a #TidyActor
+ * @padding: padding for internal children
+ *
+ * Sets @padding around @actor.
+ */
+void
+tidy_actor_set_padding (TidyActor *actor,
+ const TidyPadding *padding)
+{
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+ g_return_if_fail (padding != NULL);
+
+ actor->priv->padding = *padding;
+
+ g_object_notify (G_OBJECT (actor), "padding");
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
+}
+
+/**
+ * tidy_actor_get_padding:
+ * @actor: a #TidyActor
+ * @padding: return location for the padding
+ *
+ * Retrieves the padding aound @actor.
+ */
+void
+tidy_actor_get_padding (TidyActor *actor,
+ TidyPadding *padding)
+{
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+ g_return_if_fail (padding != NULL);
+
+ *padding = actor->priv->padding;
+}
+
+/**
+ * tidy_actor_set_alignment:
+ * @actor: a #TidyActor
+ * @x_align: relative alignment on the X axis
+ * @y_align: relative alignment on the Y axis
+ *
+ * Sets the alignment, relative to the @actor's width and height, of
+ * the internal children.
+ */
+void
+tidy_actor_set_alignment (TidyActor *actor,
+ gdouble x_align,
+ gdouble y_align)
+{
+ TidyActorPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+
+ g_object_ref (actor);
+ g_object_freeze_notify (G_OBJECT (actor));
+
+ priv = actor->priv;
+
+ x_align = CLAMP (x_align, 0.0, 1.0);
+ y_align = CLAMP (y_align, 0.0, 1.0);
+
+ priv->x_align = CLUTTER_FLOAT_TO_FIXED (x_align);
+ g_object_notify (G_OBJECT (actor), "x-align");
+
+ priv->y_align = CLUTTER_FLOAT_TO_FIXED (y_align);
+ g_object_notify (G_OBJECT (actor), "y-align");
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
+
+ g_object_thaw_notify (G_OBJECT (actor));
+ g_object_unref (actor);
+}
+
+/**
+ * tidy_actor_get_alignment:
+ * @actor: a #TidyActor
+ * @x_align: return location for the relative alignment on the X axis,
+ * or %NULL
+ * @y_align: return location for the relative alignment on the Y axis,
+ * or %NULL
+ *
+ * Retrieves the alignment, relative to the @actor's width and height, of
+ * the internal children.
+ */
+void
+tidy_actor_get_alignment (TidyActor *actor,
+ gdouble *x_align,
+ gdouble *y_align)
+{
+ TidyActorPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+
+ priv = actor->priv;
+
+ if (x_align)
+ *x_align = CLUTTER_FIXED_TO_FLOAT (priv->x_align);
+
+ if (y_align)
+ *y_align = CLUTTER_FIXED_TO_FLOAT (priv->y_align);
+}
+
+/**
+ * tidy_actor_set_alignmentx:
+ * @actor: a #TidyActor
+ * @x_align: relative alignment on the X axis
+ * @y_align: relative alignment on the Y axis
+ *
+ * Fixed point version of tidy_actor_set_alignment().
+ *
+ * Sets the alignment, relative to the @actor's width and height, of
+ * the internal children.
+ */
+void
+tidy_actor_set_alignmentx (TidyActor *actor,
+ ClutterFixed x_align,
+ ClutterFixed y_align)
+{
+ TidyActorPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+
+ g_object_ref (actor);
+ g_object_freeze_notify (G_OBJECT (actor));
+
+ priv = actor->priv;
+
+ x_align = CLAMP (x_align, 0, CFX_ONE);
+ y_align = CLAMP (y_align, 0, CFX_ONE);
+
+ if (priv->x_align != x_align)
+ {
+ priv->x_align = x_align;
+ g_object_notify (G_OBJECT (actor), "x-align");
+ }
+
+ if (priv->y_align != y_align)
+ {
+ priv->y_align = y_align;
+ g_object_notify (G_OBJECT (actor), "y-align");
+ }
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
+
+ g_object_thaw_notify (G_OBJECT (actor));
+ g_object_unref (actor);
+}
+
+/**
+ * tidy_actor_get_alignmentx:
+ * @actor: a #TidyActor
+ * @x_align: return location for the relative alignment on the X axis,
+ * or %NULL
+ * @y_align: return location for the relative alignment on the Y axis,
+ * or %NULL
+ *
+ * Fixed point version of tidy_actor_get_alignment().
+ *
+ * Retrieves the alignment, relative to the @actor's width and height, of
+ * the internal children.
+ */
+void
+tidy_actor_get_alignmentx (TidyActor *actor,
+ ClutterFixed *x_align,
+ ClutterFixed *y_align)
+{
+ TidyActorPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ACTOR (actor));
+
+ priv = actor->priv;
+
+ if (x_align)
+ *x_align = priv->x_align;
+
+ if (y_align)
+ *y_align = priv->y_align;
+}
+
+static TidyPadding *
+tidy_padding_copy (const TidyPadding *padding)
+{
+ TidyPadding *copy;
+
+ g_return_val_if_fail (padding != NULL, NULL);
+
+ copy = g_slice_new (TidyPadding);
+ *copy = *padding;
+
+ return copy;
+}
+
+static void
+tidy_padding_free (TidyPadding *padding)
+{
+ if (G_LIKELY (padding))
+ g_slice_free (TidyPadding, padding);
+}
+
+GType
+tidy_padding_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (G_UNLIKELY (our_type == 0))
+ our_type =
+ g_boxed_type_register_static (I_("TidyPadding"),
+ (GBoxedCopyFunc) tidy_padding_copy,
+ (GBoxedFreeFunc) tidy_padding_free);
+
+ return our_type;
+}
Added: trunk/src/tidy/tidy-actor.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-actor.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,88 @@
+/* tidy-actor.h: Base class for Tidy actors
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TIDY_ACTOR_H__
+#define __TIDY_ACTOR_H__
+
+#include <clutter/clutter-actor.h>
+#include <tidy/tidy-types.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_ACTOR (tidy_actor_get_type ())
+#define TIDY_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_ACTOR, TidyActor))
+#define TIDY_IS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_ACTOR))
+#define TIDY_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_ACTOR, TidyActorClass))
+#define TIDY_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_ACTOR))
+#define TIDY_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_ACTOR, TidyActorClass))
+
+typedef struct _TidyActor TidyActor;
+typedef struct _TidyActorPrivate TidyActorPrivate;
+typedef struct _TidyActorClass TidyActorClass;
+
+/**
+ * TidyActor:
+ *
+ * Base class for stylable actors. The contents of the #TidyActor
+ * structure are private and should only be accessed through the
+ * public API.
+ */
+struct _TidyActor
+{
+ /*< private >*/
+ ClutterActor parent_instance;
+
+ TidyActorPrivate *priv;
+};
+
+/**
+ * TidyActorClass:
+ *
+ * Base class for stylable actors.
+ */
+struct _TidyActorClass
+{
+ /*< private >*/
+ ClutterActorClass parent_class;
+};
+
+GType tidy_actor_get_type (void) G_GNUC_CONST;
+
+void tidy_actor_set_padding (TidyActor *actor,
+ const TidyPadding *padding);
+void tidy_actor_get_padding (TidyActor *actor,
+ TidyPadding *padding);
+
+void tidy_actor_set_alignment (TidyActor *actor,
+ gdouble x_align,
+ gdouble y_align);
+void tidy_actor_get_alignment (TidyActor *actor,
+ gdouble *x_align,
+ gdouble *y_align);
+void tidy_actor_set_alignmentx (TidyActor *actor,
+ ClutterFixed x_align,
+ ClutterFixed y_align);
+void tidy_actor_get_alignmentx (TidyActor *actor,
+ ClutterFixed *x_align,
+ ClutterFixed *y_align);
+
+G_END_DECLS
+
+#endif /* __TIDY_ACTOR_H__ */
Added: trunk/src/tidy/tidy-button.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-button.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,374 @@
+/* tidy-button.c: Plain button actor
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <clutter/clutter.h>
+
+#include "tidy-button.h"
+
+#include "tidy-debug.h"
+#include "tidy-marshal.h"
+#include "tidy-stylable.h"
+
+enum
+{
+ PROP_0,
+
+ PROP_LABEL
+};
+
+enum
+{
+ CLICKED,
+
+ LAST_SIGNAL
+};
+
+#define TIDY_BUTTON_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_BUTTON, TidyButtonPrivate))
+
+struct _TidyButtonPrivate
+{
+ gchar *text;
+
+ ClutterTimeline *timeline;
+ ClutterEffectTemplate *press_tmpl;
+
+ guint8 old_opacity;
+
+ guint is_pressed : 1;
+};
+
+static guint button_signals[LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (TidyButton, tidy_button, TIDY_TYPE_FRAME);
+
+static void
+tidy_button_real_pressed (TidyButton *button)
+{
+ TidyButtonPrivate *priv = button->priv;
+ ClutterActor *actor = CLUTTER_ACTOR (button);
+
+ if (G_UNLIKELY (!priv->press_tmpl))
+ {
+ priv->timeline = clutter_timeline_new_for_duration (250);
+ priv->press_tmpl = clutter_effect_template_new (priv->timeline,
+ clutter_sine_inc_func);
+ clutter_effect_template_set_timeline_clone (priv->press_tmpl, FALSE);
+ }
+
+ if (clutter_timeline_is_playing (priv->timeline))
+ {
+ clutter_timeline_stop (priv->timeline);
+ clutter_actor_set_opacity (actor, priv->old_opacity);
+ }
+
+ priv->old_opacity = clutter_actor_get_opacity (actor);
+
+ clutter_effect_fade (priv->press_tmpl, actor,
+ 0x44,
+ NULL, NULL);
+}
+
+static void
+tidy_button_real_released (TidyButton *button)
+{
+ TidyButtonPrivate *priv = button->priv;
+ ClutterActor *actor = CLUTTER_ACTOR (button);
+
+ if (G_UNLIKELY (!priv->press_tmpl))
+ {
+ priv->timeline = clutter_timeline_new_for_duration (250);
+ priv->press_tmpl = clutter_effect_template_new (priv->timeline,
+ clutter_sine_inc_func);
+ clutter_effect_template_set_timeline_clone (priv->press_tmpl, FALSE);
+ }
+
+ if (clutter_timeline_is_playing (priv->timeline))
+ clutter_timeline_stop (priv->timeline);
+
+ clutter_effect_fade (priv->press_tmpl, actor,
+ priv->old_opacity,
+ NULL, NULL);
+}
+
+static void
+tidy_button_construct_child (TidyButton *button)
+{
+ TidyButtonPrivate *priv = button->priv;
+ gchar *font_name;
+ ClutterColor *text_color;
+ ClutterActor *label;
+
+ if (!priv->text)
+ return;
+
+ tidy_stylable_get (TIDY_STYLABLE (button),
+ "font-name", &font_name,
+ "text-color", &text_color,
+ NULL);
+
+ label = g_object_new (CLUTTER_TYPE_LABEL,
+ "font-name", font_name,
+ "text", priv->text,
+ "color", text_color,
+ "alignment", PANGO_ALIGN_CENTER,
+ "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
+ "use-markup", TRUE,
+ "wrap", FALSE,
+ NULL);
+
+ clutter_actor_show (label);
+ clutter_container_add_actor (CLUTTER_CONTAINER (button), label);
+
+ clutter_color_free (text_color);
+ g_free (font_name);
+}
+
+static gboolean
+tidy_button_button_press (ClutterActor *actor,
+ ClutterButtonEvent *event)
+{
+ if (event->button == 1 &&
+ event->click_count == 1)
+ {
+ TidyButton *button = TIDY_BUTTON (actor);
+ TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
+
+ button->priv->is_pressed = TRUE;
+
+ clutter_grab_pointer (actor);
+
+ if (klass->pressed)
+ klass->pressed (button);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+tidy_button_button_release (ClutterActor *actor,
+ ClutterButtonEvent *event)
+{
+ if (event->button == 1)
+ {
+ TidyButton *button = TIDY_BUTTON (actor);
+ TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
+
+ if (!button->priv->is_pressed)
+ return FALSE;
+
+ clutter_ungrab_pointer ();
+
+ button->priv->is_pressed = FALSE;
+
+ if (klass->released)
+ klass->released (button);
+
+ g_signal_emit (button, button_signals[CLICKED], 0);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+tidy_button_leave (ClutterActor *actor,
+ ClutterCrossingEvent *event)
+{
+ TidyButton *button = TIDY_BUTTON (actor);
+
+ if (button->priv->is_pressed)
+ {
+ TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
+
+ clutter_ungrab_pointer ();
+
+ button->priv->is_pressed = FALSE;
+
+ if (klass->released)
+ klass->released (button);
+ }
+
+ return FALSE;
+}
+
+static void
+tidy_button_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyButton *button = TIDY_BUTTON (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_LABEL:
+ tidy_button_set_label (button, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_button_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_LABEL:
+ g_value_set_string (value, priv->text);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_button_finalize (GObject *gobject)
+{
+ TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
+
+ g_free (priv->text);
+
+ G_OBJECT_CLASS (tidy_button_parent_class)->finalize (gobject);
+}
+
+static void
+tidy_button_dispose (GObject *gobject)
+{
+ TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
+
+ if (priv->press_tmpl)
+ {
+ g_object_unref (priv->press_tmpl);
+ g_object_unref (priv->timeline);
+
+ priv->press_tmpl = NULL;
+ priv->timeline = NULL;
+ }
+
+ G_OBJECT_CLASS (tidy_button_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_button_class_init (TidyButtonClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyButtonPrivate));
+
+ klass->pressed = tidy_button_real_pressed;
+ klass->released = tidy_button_real_released;
+
+ gobject_class->set_property = tidy_button_set_property;
+ gobject_class->get_property = tidy_button_get_property;
+ gobject_class->dispose = tidy_button_dispose;
+ gobject_class->finalize = tidy_button_finalize;
+
+ actor_class->button_press_event = tidy_button_button_press;
+ actor_class->button_release_event = tidy_button_button_release;
+ actor_class->leave_event = tidy_button_leave;
+
+ g_object_class_install_property (gobject_class,
+ PROP_LABEL,
+ g_param_spec_string ("label",
+ "Label",
+ "Label of the button",
+ NULL,
+ G_PARAM_READWRITE));
+
+ button_signals[CLICKED] =
+ g_signal_new ("clicked",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TidyButtonClass, clicked),
+ NULL, NULL,
+ _tidy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+tidy_button_init (TidyButton *button)
+{
+ button->priv = TIDY_BUTTON_GET_PRIVATE (button);
+}
+
+ClutterActor *
+tidy_button_new (void)
+{
+ return g_object_new (TIDY_TYPE_BUTTON, NULL);
+}
+
+ClutterActor *
+tidy_button_new_with_label (const gchar *text)
+{
+ return g_object_new (TIDY_TYPE_BUTTON, "label", text, NULL);
+}
+
+G_CONST_RETURN gchar *
+tidy_button_get_label (TidyButton *button)
+{
+ g_return_val_if_fail (TIDY_IS_BUTTON (button), NULL);
+
+ return button->priv->text;
+}
+
+void
+tidy_button_set_label (TidyButton *button,
+ const gchar *text)
+{
+ TidyButtonPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_BUTTON (button));
+
+ priv = button->priv;
+
+ g_free (priv->text);
+ priv->text = g_strdup (text);
+
+ tidy_button_construct_child (button);
+
+ g_object_notify (G_OBJECT (button), "label");
+}
Added: trunk/src/tidy/tidy-button.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-button.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,70 @@
+/* tidy-button.h: Plain button actor
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ */
+
+#ifndef __TIDY_BUTTON_H__
+#define __TIDY_BUTTON_H__
+
+#include <tidy/tidy-frame.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_BUTTON (tidy_button_get_type ())
+#define TIDY_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_BUTTON, TidyButton))
+#define TIDY_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_BUTTON))
+#define TIDY_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_BUTTON, TidyButtonClass))
+#define TIDY_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_BUTTON))
+#define TIDY_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_BUTTON, TidyButtonClass))
+
+typedef struct _TidyButton TidyButton;
+typedef struct _TidyButtonPrivate TidyButtonPrivate;
+typedef struct _TidyButtonClass TidyButtonClass;
+
+struct _TidyButton
+{
+ TidyFrame parent_instance;
+
+ TidyButtonPrivate *priv;
+};
+
+struct _TidyButtonClass
+{
+ TidyFrameClass parent_class;
+
+ /* vfuncs, not signals */
+ void (* pressed) (TidyButton *button);
+ void (* released) (TidyButton *button);
+
+ /* signals */
+ void (* clicked) (TidyButton *button);
+};
+
+GType tidy_button_get_type (void) G_GNUC_CONST;
+
+ClutterActor * tidy_button_new (void);
+ClutterActor * tidy_button_new_with_label (const gchar *text);
+G_CONST_RETURN gchar *tidy_button_get_label (TidyButton *button);
+void tidy_button_set_label (TidyButton *button,
+ const gchar *text);
+
+G_END_DECLS
+
+#endif /* __TIDY_BUTTON_H__ */
Added: trunk/src/tidy/tidy-debug.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-debug.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,4 @@
+#ifndef __TIDY_DEBUG_H__
+#define __TIDY_DEBUG_H__
+
+#endif /* __TIDY_DEBUG_H__ */
Added: trunk/src/tidy/tidy-enum-types.c.in
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-enum-types.c.in Wed Nov 12 21:09:27 2008
@@ -0,0 +1,30 @@
+/*** BEGIN file-header ***/
+#include "tidy-enum-types.h"
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@filename@"
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ enum_name@_get_type(void) {
+ static GType enum_type_id = 0;
+ if (G_UNLIKELY (!enum_type_id))
+ {
+ static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ enum_type_id = g_ type@_register_static("@EnumName@", values);
+ }
+ return enum_type_id;
+}
+/*** END value-tail ***/
Added: trunk/src/tidy/tidy-enum-types.h.in
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-enum-types.h.in Wed Nov 12 21:09:27 2008
@@ -0,0 +1,25 @@
+/*** BEGIN file-header ***/
+#ifndef __TIDY_ENUM_TYPES_H__
+#define __TIDY_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* !__TIDY_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+#define TIDY_TYPE_ ENUMSHORT@ (@enum_name _get_type())
+
+/*** END value-header ***/
Added: trunk/src/tidy/tidy-frame.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-frame.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,515 @@
+/* tidy-frame.c: Simple container with a background
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib-object.h>
+
+#include <cogl/cogl.h>
+#include <clutter/clutter.h>
+
+#include "tidy-frame.h"
+#include "tidy-private.h"
+#include "tidy-stylable.h"
+
+#define TIDY_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_FRAME, TidyFramePrivate))
+
+enum
+{
+ PROP_0,
+
+ PROP_CHILD,
+ PROP_TEXTURE
+};
+
+struct _TidyFramePrivate
+{
+ ClutterActor *child;
+ ClutterActor *texture;
+};
+
+static ClutterColor default_bg_color = { 0xcc, 0xcc, 0xcc, 0xff };
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TidyFrame, tidy_frame, TIDY_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+ clutter_container_iface_init));
+
+static void
+tidy_frame_get_preferred_width (ClutterActor *actor,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
+ TidyPadding padding = { 0, };
+ ClutterUnit min_width, natural_width;
+
+ tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
+
+ min_width = 0;
+ natural_width = padding.left + padding.right;
+
+ if (priv->child)
+ {
+ ClutterUnit child_min, child_natural;
+
+ clutter_actor_get_preferred_width (priv->child, for_height,
+ &child_min,
+ &child_natural);
+
+ min_width += child_min;
+ natural_width += child_natural;
+ }
+
+ if (min_width_p)
+ *min_width_p = min_width;
+
+ if (natural_width_p)
+ *natural_width_p = natural_width;
+}
+
+static void
+tidy_frame_get_preferred_height (ClutterActor *actor,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
+ TidyPadding padding = { 0, };
+ ClutterUnit min_height, natural_height;
+
+ tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
+
+ min_height = 0;
+ natural_height = padding.top + padding.bottom;
+
+ if (priv->child)
+ {
+ ClutterUnit child_min, child_natural;
+
+ clutter_actor_get_preferred_height (priv->child, for_width,
+ &child_min,
+ &child_natural);
+
+ min_height += child_min;
+ natural_height += child_natural;
+ }
+
+ if (min_height_p)
+ *min_height_p = min_height;
+
+ if (natural_height_p)
+ *natural_height_p = natural_height;
+}
+
+static void
+tidy_frame_allocate (ClutterActor *actor,
+ const ClutterActorBox *box,
+ gboolean origin_changed)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
+ ClutterActorClass *klass;
+
+ klass = CLUTTER_ACTOR_CLASS (tidy_frame_parent_class);
+ klass->allocate (actor, box, origin_changed);
+
+ if (priv->texture)
+ {
+ ClutterActorBox texture_box = { 0, };
+
+ texture_box.x1 = 0;
+ texture_box.y1 = 0;
+ texture_box.x2 = box->x2 - box->x1;
+ texture_box.y2 = box->y2 - box->y1;
+
+ clutter_actor_allocate (priv->texture, &texture_box, origin_changed);
+ }
+
+ if (priv->child)
+ {
+ TidyPadding padding = { 0, };
+ ClutterFixed x_align, y_align;
+ ClutterUnit available_width, available_height;
+ ClutterUnit child_width, child_height;
+ ClutterActorBox child_box = { 0, };
+
+ tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
+ tidy_actor_get_alignmentx (TIDY_ACTOR (actor), &x_align, &y_align);
+
+ available_width = box->x2 - box->x1
+ - padding.left
+ - padding.right;
+ available_height = box->y2 - box->y1
+ - padding.top
+ - padding.bottom;
+
+ if (available_width < 0)
+ available_width = 0;
+
+ if (available_height < 0)
+ available_height = 0;
+
+ clutter_actor_get_preferred_size (priv->child,
+ NULL, NULL,
+ &child_width,
+ &child_height);
+
+ if (child_width > available_width)
+ child_width = available_width;
+
+ if (child_height > available_height)
+ child_height = available_height;
+
+ child_box.x1 = CLUTTER_FIXED_MUL ((available_width - child_width),
+ x_align)
+ + padding.left;
+ child_box.y1 = CLUTTER_FIXED_MUL ((available_height - child_height),
+ y_align)
+ + padding.top;
+
+ child_box.x2 = child_box.x1 + child_width;
+ child_box.y2 = child_box.y1 + child_height;
+
+ clutter_actor_allocate (priv->child, &child_box, origin_changed);
+ }
+}
+
+static void
+tidy_frame_paint (ClutterActor *actor)
+{
+ TidyFrame *frame = TIDY_FRAME (actor);
+ TidyFramePrivate *priv = frame->priv;
+
+ cogl_push_matrix ();
+
+ if (priv->texture)
+ clutter_actor_paint (priv->texture);
+ else
+ {
+ ClutterActorBox allocation = { 0, };
+ ClutterColor *bg_color;
+ guint w, h;
+
+ tidy_stylable_get (TIDY_STYLABLE (frame), "bg-color", &bg_color, NULL);
+ if (!bg_color)
+ bg_color = &default_bg_color;
+
+ bg_color->alpha = clutter_actor_get_paint_opacity (actor)
+ * bg_color->alpha
+ / 255;
+
+ clutter_actor_get_allocation_box (actor, &allocation);
+
+ w = CLUTTER_UNITS_TO_DEVICE (allocation.x2 - allocation.x1);
+ h = CLUTTER_UNITS_TO_DEVICE (allocation.y2 - allocation.y1);
+
+ cogl_color (bg_color);
+ cogl_rectangle (0, 0, w, h);
+
+ if (bg_color != &default_bg_color)
+ clutter_color_free (bg_color);
+ }
+
+ if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
+ clutter_actor_paint (priv->child);
+
+ cogl_pop_matrix ();
+}
+
+static void
+tidy_frame_pick (ClutterActor *actor,
+ const ClutterColor *pick_color)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
+
+ /* chain up, so we get a box with our coordinates */
+ CLUTTER_ACTOR_CLASS (tidy_frame_parent_class)->pick (actor, pick_color);
+
+ if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
+ clutter_actor_paint (priv->child);
+}
+
+static void
+tidy_frame_dispose (GObject *gobject)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (gobject)->priv;
+
+ if (priv->child)
+ {
+ clutter_actor_unparent (priv->child);
+ priv->child = NULL;
+ }
+
+ if (priv->texture)
+ {
+ clutter_actor_unparent (priv->texture);
+ priv->texture = NULL;
+ }
+
+ G_OBJECT_CLASS (tidy_frame_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_frame_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_CHILD:
+ clutter_container_add_actor (CLUTTER_CONTAINER (gobject),
+ g_value_get_object (value));
+ break;
+
+ case PROP_TEXTURE:
+ tidy_frame_set_texture (TIDY_FRAME (gobject),
+ g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_frame_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_CHILD:
+ g_value_set_object (value, priv->child);
+ break;
+
+ case PROP_TEXTURE:
+ g_value_set_object (value, priv->texture);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_frame_class_init (TidyFrameClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyFramePrivate));
+
+ gobject_class->set_property = tidy_frame_set_property;
+ gobject_class->get_property = tidy_frame_get_property;
+ gobject_class->dispose = tidy_frame_dispose;
+
+ actor_class->pick = tidy_frame_pick;
+ actor_class->paint = tidy_frame_paint;
+ actor_class->allocate = tidy_frame_allocate;
+ actor_class->get_preferred_width = tidy_frame_get_preferred_width;
+ actor_class->get_preferred_height = tidy_frame_get_preferred_height;
+
+ g_object_class_install_property (gobject_class,
+ PROP_CHILD,
+ g_param_spec_object ("child",
+ "Child",
+ "The child of the frame",
+ CLUTTER_TYPE_ACTOR,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_TEXTURE,
+ g_param_spec_object ("texture",
+ "Texture",
+ "The background texture of the frame",
+ CLUTTER_TYPE_ACTOR,
+ TIDY_PARAM_READWRITE));
+}
+
+static void
+tidy_frame_init (TidyFrame *frame)
+{
+ frame->priv = TIDY_FRAME_GET_PRIVATE (frame);
+}
+
+static void
+tidy_frame_add_actor (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
+
+ if (priv->child)
+ clutter_actor_unparent (priv->child);
+
+ clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+ priv->child = actor;
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+ g_signal_emit_by_name (container, "actor-added", actor);
+
+ g_object_notify (G_OBJECT (container), "child");
+}
+
+static void
+tidy_frame_remove_actor (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
+
+ if (priv->child == actor)
+ {
+ g_object_ref (priv->child);
+
+ clutter_actor_unparent (priv->child);
+ priv->child = NULL;
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+ g_signal_emit_by_name (container, "actor-removed", priv->child);
+
+ g_object_unref (priv->child);
+ }
+}
+
+static void
+tidy_frame_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer callback_data)
+{
+ TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
+
+ if (priv->texture)
+ callback (priv->texture, callback_data);
+
+ if (priv->child)
+ callback (priv->child, callback_data);
+}
+
+static void
+tidy_frame_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* single child */
+}
+
+static void
+tidy_frame_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* single child */
+}
+
+static void
+tidy_frame_sort_depth_order (ClutterContainer *container)
+{
+ /* single child */
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+ iface->add = tidy_frame_add_actor;
+ iface->remove = tidy_frame_remove_actor;
+ iface->foreach = tidy_frame_foreach;
+ iface->lower = tidy_frame_lower;
+ iface->raise = tidy_frame_raise;
+ iface->sort_depth_order = tidy_frame_sort_depth_order;
+}
+
+ClutterActor *
+tidy_frame_new (void)
+{
+ return g_object_new (TIDY_TYPE_FRAME, NULL);
+}
+
+ClutterActor *
+tidy_frame_get_child (TidyFrame *frame)
+{
+ g_return_val_if_fail (TIDY_IS_FRAME (frame), NULL);
+
+ return frame->priv->child;
+}
+
+void
+tidy_frame_set_texture (TidyFrame *frame,
+ ClutterActor *texture)
+{
+ TidyFramePrivate *priv;
+
+ g_return_if_fail (TIDY_IS_FRAME (frame));
+ g_return_if_fail (CLUTTER_IS_ACTOR (texture));
+
+ priv = frame->priv;
+
+ if (priv->texture == texture)
+ return;
+
+ if (priv->texture)
+ {
+ clutter_actor_unparent (priv->texture);
+ priv->texture = NULL;
+ }
+
+ if (texture)
+ {
+ ClutterActor *parent = clutter_actor_get_parent (texture);
+
+ if (G_UNLIKELY (parent != NULL))
+ {
+ g_warning ("Unable to set the background texture of type `%s' for "
+ "the frame of type `%s': the texture actor is already "
+ "a child of a container of type `%s'",
+ g_type_name (G_OBJECT_TYPE (texture)),
+ g_type_name (G_OBJECT_TYPE (frame)),
+ g_type_name (G_OBJECT_TYPE (parent)));
+ return;
+ }
+
+ priv->texture = texture;
+ clutter_actor_set_parent (texture, CLUTTER_ACTOR (frame));
+ }
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
+
+ g_object_notify (G_OBJECT (frame), "texture");
+}
+
+ClutterActor *
+tidy_frame_get_texture (TidyFrame *frame)
+{
+ g_return_val_if_fail (TIDY_IS_FRAME (frame), NULL);
+
+ return frame->priv->texture;
+}
+
Added: trunk/src/tidy/tidy-frame.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-frame.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,64 @@
+/* tidy-frame.h: Simple container with a background
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ */
+
+#ifndef __TIDY_FRAME_H__
+#define __TIDY_FRAME_H__
+
+#include <clutter/clutter-actor.h>
+#include <tidy/tidy-actor.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_FRAME (tidy_frame_get_type ())
+#define TIDY_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_FRAME, TidyFrame))
+#define TIDY_IS_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_FRAME))
+#define TIDY_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_FRAME, TidyFrameClass))
+#define TIDY_IS_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_FRAME))
+#define TIDY_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_FRAME, TidyFrameClass))
+
+typedef struct _TidyFrame TidyFrame;
+typedef struct _TidyFramePrivate TidyFramePrivate;
+typedef struct _TidyFrameClass TidyFrameClass;
+
+struct _TidyFrame
+{
+ TidyActor parent_instance;
+
+ TidyFramePrivate *priv;
+};
+
+struct _TidyFrameClass
+{
+ TidyActorClass parent_class;
+};
+
+GType tidy_frame_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_frame_new (void);
+ClutterActor *tidy_frame_get_child (TidyFrame *frame);
+void tidy_frame_set_texture (TidyFrame *frame,
+ ClutterActor *actor);
+ClutterActor *tidy_frame_get_texture (TidyFrame *frame);
+
+G_END_DECLS
+
+#endif /* __TIDY_FRAME_H__ */
Added: trunk/src/tidy/tidy-grid.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-grid.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,1005 @@
+/* tidy-grid.h: Reflowing grid layout container for clutter.
+ *
+ * Copyright (C) 2008 Intel Corporation
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ãyvind KolÃs <pippin linux intel com>
+ */
+
+/* TODO:
+ *
+ * - Better names for properties.
+ * - Caching layouted positions? (perhaps needed for huge collections)
+ * - More comments / overall concept on how the layouting is done.
+ * - Allow more layout directions than just row major / column major.
+ */
+
+#include <clutter/clutter-actor.h>
+#include <clutter/clutter-container.h>
+#include <string.h>
+
+#include "tidy-grid.h"
+
+typedef struct _TidyGridActorData TidyGridActorData;
+
+static void tidy_grid_dispose (GObject *object);
+static void tidy_grid_finalize (GObject *object);
+
+static void tidy_grid_finalize (GObject *object);
+
+static void tidy_grid_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void tidy_grid_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+static void tidy_grid_real_add (ClutterContainer *container,
+ ClutterActor *actor);
+static void tidy_grid_real_remove (ClutterContainer *container,
+ ClutterActor *actor);
+static void tidy_grid_real_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer user_data);
+static void tidy_grid_real_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling);
+static void tidy_grid_real_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling);
+static void
+tidy_grid_real_sort_depth_order (ClutterContainer *container);
+
+static void
+tidy_grid_free_actor_data (gpointer data);
+
+static void tidy_grid_paint (ClutterActor *actor);
+
+static void tidy_grid_pick (ClutterActor *actor,
+ const ClutterColor *color);
+
+static void
+tidy_grid_get_preferred_width (ClutterActor *self,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p);
+
+static void
+tidy_grid_get_preferred_height (ClutterActor *self,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p);
+
+static void tidy_grid_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ gboolean absolute_origin_changed);
+
+G_DEFINE_TYPE_WITH_CODE (TidyGrid, tidy_grid,
+ CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+ clutter_container_iface_init));
+
+#define TIDY_GRID_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_GRID, \
+ TidyGridPrivate))
+
+struct _TidyGridPrivate
+{
+ ClutterUnit for_height, for_width;
+ ClutterUnit pref_width, pref_height;
+ ClutterUnit alloc_width, alloc_height;
+
+ gboolean absolute_origin_changed;
+ GHashTable *hash_table;
+ GList *list;
+
+ gboolean homogenous_rows;
+ gboolean homogenous_columns;
+ gboolean end_align;
+ ClutterUnit column_gap, row_gap;
+ gdouble valign, halign;
+
+ gboolean column_major;
+
+ gboolean first_of_batch;
+ ClutterUnit a_current_sum, a_wrap;
+ ClutterUnit max_extent_a;
+ ClutterUnit max_extent_b;
+};
+
+enum
+{
+ PROP_0,
+ PROP_HOMOGENOUS_ROWS,
+ PROP_HOMOGENOUS_COLUMNS,
+ PROP_ROW_GAP,
+ PROP_COLUMN_GAP,
+ PROP_VALIGN,
+ PROP_HALIGN,
+ PROP_END_ALIGN,
+ PROP_COLUMN_MAJOR,
+};
+
+struct _TidyGridActorData
+{
+ gboolean xpos_set, ypos_set;
+ ClutterUnit xpos, ypos;
+ ClutterUnit pref_width, pref_height;
+};
+
+static void
+tidy_grid_class_init (TidyGridClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ ClutterActorClass *actor_class = (ClutterActorClass *) klass;
+
+ gobject_class->dispose = tidy_grid_dispose;
+ gobject_class->finalize = tidy_grid_finalize;
+
+ gobject_class->set_property = tidy_grid_set_property;
+ gobject_class->get_property = tidy_grid_get_property;
+
+ actor_class->paint = tidy_grid_paint;
+ actor_class->pick = tidy_grid_pick;
+ actor_class->get_preferred_width = tidy_grid_get_preferred_width;
+ actor_class->get_preferred_height = tidy_grid_get_preferred_height;
+ actor_class->allocate = tidy_grid_allocate;
+
+ g_type_class_add_private (klass, sizeof (TidyGridPrivate));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ROW_GAP,
+ clutter_param_spec_unit ("row-gap",
+ "Row gap",
+ "gap between rows in the layout",
+ 0, CLUTTER_MAXUNIT,
+ 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_COLUMN_GAP,
+ clutter_param_spec_unit ("column-gap",
+ "Column gap",
+ "gap between columns in the layout",
+ 0, CLUTTER_MAXUNIT,
+ 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HOMOGENOUS_ROWS,
+ g_param_spec_boolean ("homogenous-rows",
+ "homogenous rows",
+ "Should all rows have the same height?",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HOMOGENOUS_COLUMNS,
+ g_param_spec_boolean ("homogenous-columns",
+ "homogenous columns",
+ "Should all columns have the same height?",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_COLUMN_MAJOR,
+ g_param_spec_boolean ("column-major",
+ "column-major",
+ "Do a column filling first instead of row filling first",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_END_ALIGN,
+ g_param_spec_boolean ("end-align",
+ "end-align",
+ "Right/bottom aligned rows/columns",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_VALIGN,
+ g_param_spec_double ("valign",
+ "Vertical align",
+ "Vertical alignment of items within cells",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HALIGN,
+ g_param_spec_double ("halign",
+ "Horizontal align",
+ "Horizontal alignment of items within cells",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+ iface->add = tidy_grid_real_add;
+ iface->remove = tidy_grid_real_remove;
+ iface->foreach = tidy_grid_real_foreach;
+ iface->raise = tidy_grid_real_raise;
+ iface->lower = tidy_grid_real_lower;
+ iface->sort_depth_order = tidy_grid_real_sort_depth_order;
+}
+
+static void
+tidy_grid_init (TidyGrid *self)
+{
+ TidyGridPrivate *priv;
+
+ self->priv = priv = TIDY_GRID_GET_PRIVATE (self);
+
+ /* do not unref in the hashtable, the reference is for now kept by the list
+ * (double bookkeeping sucks)
+ */
+ priv->hash_table
+ = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ tidy_grid_free_actor_data);
+}
+
+static void
+tidy_grid_dispose (GObject *object)
+{
+ TidyGrid *self = (TidyGrid *) object;
+ TidyGridPrivate *priv;
+
+ priv = self->priv;
+
+ /* Destroy all of the children. This will cause them to be removed
+ from the container and unparented */
+ clutter_container_foreach (CLUTTER_CONTAINER (object),
+ (ClutterCallback) clutter_actor_destroy,
+ NULL);
+
+ G_OBJECT_CLASS (tidy_grid_parent_class)->dispose (object);
+}
+
+static void
+tidy_grid_finalize (GObject *object)
+{
+ TidyGrid *self = (TidyGrid *) object;
+ TidyGridPrivate *priv = self->priv;
+
+ g_hash_table_destroy (priv->hash_table);
+
+ G_OBJECT_CLASS (tidy_grid_parent_class)->finalize (object);
+}
+
+
+void
+tidy_grid_set_end_align (TidyGrid *self,
+ gboolean value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->end_align = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+tidy_grid_get_end_align (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->end_align;
+}
+
+void
+tidy_grid_set_homogenous_rows (TidyGrid *self,
+ gboolean value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->homogenous_rows = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+tidy_grid_get_homogenous_rows (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->homogenous_rows;
+}
+
+
+void
+tidy_grid_set_homogenous_columns (TidyGrid *self,
+ gboolean value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->homogenous_columns = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+
+gboolean
+tidy_grid_get_homogenous_columns (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->homogenous_columns;
+}
+
+
+void
+tidy_grid_set_column_major (TidyGrid *self,
+ gboolean value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->column_major = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gboolean
+tidy_grid_get_column_major (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->column_major;
+}
+
+void
+tidy_grid_set_column_gap (TidyGrid *self,
+ ClutterUnit value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->column_gap = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+ClutterUnit
+tidy_grid_get_column_gap (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->column_gap;
+}
+
+
+
+void
+tidy_grid_set_row_gap (TidyGrid *self,
+ ClutterUnit value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->row_gap = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+ClutterUnit
+tidy_grid_get_row_gap (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->row_gap;
+}
+
+
+void
+tidy_grid_set_valign (TidyGrid *self,
+ gdouble value)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->valign = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gdouble
+tidy_grid_get_valign (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->valign;
+}
+
+
+
+void
+tidy_grid_set_halign (TidyGrid *self,
+ gdouble value)
+
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ priv->halign = value;
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+gdouble
+tidy_grid_get_halign (TidyGrid *self)
+{
+ TidyGridPrivate *priv = TIDY_GRID_GET_PRIVATE (self);
+ return priv->halign;
+}
+
+
+static void
+tidy_grid_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyGrid *grid = TIDY_GRID (object);
+
+ TidyGridPrivate *priv;
+
+ priv = TIDY_GRID_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_END_ALIGN:
+ tidy_grid_set_end_align (grid, g_value_get_boolean (value));
+ break;
+ case PROP_HOMOGENOUS_ROWS:
+ tidy_grid_set_homogenous_rows (grid, g_value_get_boolean (value));
+ break;
+ case PROP_HOMOGENOUS_COLUMNS:
+ tidy_grid_set_homogenous_columns (grid, g_value_get_boolean (value));
+ break;
+ case PROP_COLUMN_MAJOR:
+ tidy_grid_set_column_major (grid, g_value_get_boolean (value));
+ break;
+ case PROP_COLUMN_GAP:
+ tidy_grid_set_column_gap (grid, clutter_value_get_unit (value));
+ break;
+ case PROP_ROW_GAP:
+ tidy_grid_set_row_gap (grid, clutter_value_get_unit (value));
+ break;
+ case PROP_VALIGN:
+ tidy_grid_set_valign (grid, g_value_get_double (value));
+ break;
+ case PROP_HALIGN:
+ tidy_grid_set_halign (grid, g_value_get_double (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_grid_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyGrid *grid = TIDY_GRID (object);
+
+ TidyGridPrivate *priv;
+
+ priv = TIDY_GRID_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_HOMOGENOUS_ROWS:
+ g_value_set_boolean (value, tidy_grid_get_homogenous_rows (grid));
+ break;
+ case PROP_HOMOGENOUS_COLUMNS:
+ g_value_set_boolean (value, tidy_grid_get_homogenous_columns (grid));
+ break;
+ case PROP_END_ALIGN:
+ g_value_set_boolean (value, tidy_grid_get_end_align (grid));
+ break;
+ case PROP_COLUMN_MAJOR:
+ g_value_set_boolean (value, tidy_grid_get_column_major (grid));
+ break;
+ case PROP_COLUMN_GAP:
+ clutter_value_set_unit (value, tidy_grid_get_column_gap (grid));
+ break;
+ case PROP_ROW_GAP:
+ clutter_value_set_unit (value, tidy_grid_get_row_gap (grid));
+ break;
+ case PROP_VALIGN:
+ g_value_set_double (value, tidy_grid_get_valign (grid));
+ break;
+ case PROP_HALIGN:
+ g_value_set_double (value, tidy_grid_get_halign (grid));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static void
+tidy_grid_free_actor_data (gpointer data)
+{
+ g_slice_free (TidyGridActorData, data);
+}
+
+ClutterActor *
+tidy_grid_new (void)
+{
+ ClutterActor *self = g_object_new (TIDY_TYPE_GRID, NULL);
+
+ return self;
+}
+
+static void
+tidy_grid_real_add (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyGridPrivate *priv;
+ TidyGridActorData *data;
+
+ g_return_if_fail (TIDY_IS_GRID (container));
+
+ priv = TIDY_GRID (container)->priv;
+
+ g_object_ref (actor);
+
+ clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+
+ data = g_slice_alloc0 (sizeof (TidyGridActorData));
+
+ priv->list = g_list_append (priv->list, actor);
+ g_hash_table_insert (priv->hash_table, actor, data);
+
+ g_signal_emit_by_name (container, "actor-added", actor);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+
+ g_object_unref (actor);
+}
+
+static void
+tidy_grid_real_remove (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyGrid *layout = TIDY_GRID (container);
+ TidyGridPrivate *priv = layout->priv;
+
+ g_object_ref (actor);
+
+ if (g_hash_table_remove (priv->hash_table, actor))
+ {
+ clutter_actor_unparent (actor);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (layout));
+
+ g_signal_emit_by_name (container, "actor-removed", actor);
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (layout)))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (layout));
+ }
+ priv->list = g_list_remove (priv->list, actor);
+
+ g_object_unref (actor);
+}
+
+static void
+tidy_grid_real_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer user_data)
+{
+ TidyGrid *layout = TIDY_GRID (container);
+ TidyGridPrivate *priv = layout->priv;
+
+ g_list_foreach (priv->list, (GFunc) callback, user_data);
+}
+
+static void
+tidy_grid_real_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* STUB */
+}
+
+static void
+tidy_grid_real_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* STUB */
+}
+
+static void
+tidy_grid_real_sort_depth_order (ClutterContainer *container)
+{
+ /* STUB */
+}
+
+static void
+tidy_grid_paint (ClutterActor *actor)
+{
+ TidyGrid *layout = (TidyGrid *) actor;
+ TidyGridPrivate *priv = layout->priv;
+ GList *child_item;
+
+ for (child_item = priv->list;
+ child_item != NULL;
+ child_item = child_item->next)
+ {
+ ClutterActor *child = child_item->data;
+
+ g_assert (child != NULL);
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (child))
+ clutter_actor_paint (child);
+ }
+
+}
+
+static void
+tidy_grid_pick (ClutterActor *actor,
+ const ClutterColor *color)
+{
+ /* Chain up so we get a bounding box pained (if we are reactive) */
+ CLUTTER_ACTOR_CLASS (tidy_grid_parent_class)->pick (actor, color);
+
+ /* Just forward to the paint call which in turn will trigger
+ * the child actors also getting 'picked'.
+ */
+ if (CLUTTER_ACTOR_IS_VISIBLE (actor))
+ tidy_grid_paint (actor);
+}
+
+static void
+tidy_grid_get_preferred_width (ClutterActor *self,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p)
+{
+ TidyGrid *layout = (TidyGrid *) self;
+ TidyGridPrivate *priv = layout->priv;
+ ClutterUnit natural_width;
+
+ natural_width = CLUTTER_UNITS_FROM_INT (200);
+ if (min_width_p)
+ *min_width_p = natural_width;
+ if (natural_width_p)
+ *natural_width_p = natural_width;
+
+ priv->pref_width = natural_width;
+}
+
+static void
+tidy_grid_get_preferred_height (ClutterActor *self,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p)
+{
+ TidyGrid *layout = (TidyGrid *) self;
+ TidyGridPrivate *priv = layout->priv;
+ ClutterUnit natural_height;
+
+ natural_height = CLUTTER_UNITS_FROM_INT (200);
+
+ priv->for_width = for_width;
+ priv->pref_height = natural_height;
+
+ if (min_height_p)
+ *min_height_p = natural_height;
+ if (natural_height_p)
+ *natural_height_p = natural_height;
+}
+
+static ClutterUnit
+compute_row_height (GList *siblings,
+ ClutterUnit best_yet,
+ ClutterUnit current_a,
+ TidyGridPrivate *priv)
+{
+ GList *l;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ ClutterUnit gap;
+
+ if (priv->column_major)
+ {
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ gap = priv->row_gap;
+ }
+ else
+ {
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ gap = priv->column_gap;
+ }
+
+ for (l = siblings; l != NULL; l = l->next)
+ {
+ ClutterActor *child = l->data;
+ ClutterUnit natural_width, natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = natural_height;
+ natural_height = natural_width;
+ natural_width = temp;
+ }
+
+ /* if the primary axis is homogenous, each additional item is the same
+ * width */
+ if (homogenous_a)
+ natural_width = priv->max_extent_a;
+
+ if (natural_height > best_yet)
+ best_yet = natural_height;
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_width + gap > priv->a_wrap)
+ {
+ return best_yet;
+ }
+ current_a += natural_width + gap;
+ }
+ return best_yet;
+}
+
+
+
+
+static ClutterUnit
+compute_row_start (GList *siblings,
+ ClutterUnit start_x,
+ TidyGridPrivate *priv)
+{
+ ClutterUnit current_a = start_x;
+ GList *l;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ ClutterUnit gap;
+
+ if (priv->column_major)
+ {
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ gap = priv->row_gap;
+ }
+ else
+ {
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ gap = priv->column_gap;
+ }
+
+ for (l = siblings; l != NULL; l = l->next)
+ {
+ ClutterActor *child = l->data;
+ ClutterUnit natural_width, natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+
+
+ if (priv->column_major)
+ natural_width = natural_height;
+
+ /* if the primary axis is homogenous, each additional item is the same width */
+ if (homogenous_a)
+ natural_width = priv->max_extent_a;
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_width + gap > priv->a_wrap)
+ {
+ if (current_a == start_x)
+ return start_x;
+ return (priv->a_wrap - current_a);
+ }
+ current_a += natural_width + gap;
+ }
+ return (priv->a_wrap - current_a);
+}
+
+static void
+tidy_grid_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ gboolean absolute_origin_changed)
+{
+ TidyGrid *layout = (TidyGrid *) self;
+ TidyGridPrivate *priv = layout->priv;
+
+ ClutterUnit current_a;
+ ClutterUnit current_b;
+ ClutterUnit next_b;
+ ClutterUnit agap;
+ ClutterUnit bgap;
+
+ gboolean homogenous_a;
+ gboolean homogenous_b;
+ gdouble aalign;
+ gdouble balign;
+
+ current_a = current_b = next_b = 0;
+
+ GList *iter;
+
+ /* chain up to set actor->allocation */
+ CLUTTER_ACTOR_CLASS (tidy_grid_parent_class)
+ ->allocate (self, box, absolute_origin_changed);
+
+ priv->alloc_width = box->x2 - box->x1;
+ priv->alloc_height = box->y2 - box->y1;
+ priv->absolute_origin_changed = absolute_origin_changed;
+
+ /* Make sure we have calculated the preferred size */
+ /* what does this do? */
+ clutter_actor_get_preferred_size (self, NULL, NULL, NULL, NULL);
+
+
+ if (priv->column_major)
+ {
+ priv->a_wrap = priv->alloc_height;
+ homogenous_b = priv->homogenous_columns;
+ homogenous_a = priv->homogenous_rows;
+ aalign = priv->valign;
+ balign = priv->halign;
+ agap = priv->row_gap;
+ bgap = priv->column_gap;
+ }
+ else
+ {
+ priv->a_wrap = priv->alloc_width;
+ homogenous_a = priv->homogenous_columns;
+ homogenous_b = priv->homogenous_rows;
+ aalign = priv->halign;
+ balign = priv->valign;
+ agap = priv->column_gap;
+ bgap = priv->row_gap;
+ }
+
+ priv->max_extent_a = 0;
+ priv->max_extent_b = 0;
+
+ priv->first_of_batch = TRUE;
+
+ if (homogenous_a ||
+ homogenous_b)
+ {
+ for (iter = priv->list; iter; iter = iter->next)
+ {
+ ClutterActor *child = iter->data;
+ ClutterUnit natural_width;
+ ClutterUnit natural_height;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_width, &natural_height);
+ if (natural_width > priv->max_extent_a)
+ priv->max_extent_a = natural_width;
+ if (natural_height > priv->max_extent_b)
+ priv->max_extent_b = natural_width;
+ }
+ }
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = priv->max_extent_a;
+ priv->max_extent_a = priv->max_extent_b;
+ priv->max_extent_b = temp;
+ }
+
+ for (iter = priv->list; iter; iter=iter->next)
+ {
+ ClutterActor *child = iter->data;
+ ClutterUnit natural_a;
+ ClutterUnit natural_b;
+
+ /* each child will get as much space as they require */
+ clutter_actor_get_preferred_size (CLUTTER_ACTOR (child),
+ NULL, NULL,
+ &natural_a, &natural_b);
+
+ if (priv->column_major) /* swap axes around if column is major */
+ {
+ ClutterUnit temp = natural_a;
+ natural_a = natural_b;
+ natural_b = temp;
+ }
+
+ /* if the child is overflowing, we wrap to next line */
+ if (current_a + natural_a > priv->a_wrap ||
+ (homogenous_a && current_a + priv->max_extent_a > priv->a_wrap))
+ {
+ current_b = next_b + bgap;
+ current_a = 0;
+ next_b = current_b + bgap;
+ priv->first_of_batch = TRUE;
+ }
+
+ if (priv->end_align &&
+ priv->first_of_batch)
+ {
+ current_a = compute_row_start (iter, current_a, priv);
+ priv->first_of_batch = FALSE;
+ }
+
+ if (next_b-current_b < natural_b)
+ next_b = current_b + natural_b;
+
+ {
+ ClutterUnit row_height;
+ ClutterActorBox child_box;
+
+ if (homogenous_b)
+ {
+ row_height = priv->max_extent_b;
+ }
+ else
+ {
+ row_height = compute_row_height (iter, next_b-current_b,
+ current_a, priv);
+ }
+
+ if (homogenous_a)
+ {
+ child_box.x1 = current_a + (priv->max_extent_a-natural_a) * aalign;
+ child_box.x2 = child_box.x1 + natural_a;
+
+ }
+ else
+ {
+ child_box.x1 = current_a;
+ child_box.x2 = child_box.x1 + natural_a;
+ }
+
+ child_box.y1 = current_b + (row_height-natural_b) * balign;
+ child_box.y2 = child_box.y1 + natural_b;
+
+
+ if (priv->column_major)
+ {
+ ClutterUnit temp = child_box.x1;
+ child_box.x1 = child_box.y1;
+ child_box.y1 = temp;
+
+ temp = child_box.x2;
+ child_box.x2 = child_box.y2;
+ child_box.y2 = temp;
+ }
+
+ /* update the allocation */
+ clutter_actor_allocate (CLUTTER_ACTOR (child),
+ &child_box,
+ absolute_origin_changed);
+
+ if (homogenous_a)
+ {
+ current_a += priv->max_extent_a + agap;
+ }
+ else
+ {
+ current_a += natural_a + agap;
+ }
+ }
+ }
+}
Added: trunk/src/tidy/tidy-grid.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-grid.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,99 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum <mallum openedhand com>
+ *
+ * Copyright (C) 2008 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TIDY_GRID_H__
+#define __TIDY_GRID_H__
+
+#include <clutter/clutter-actor.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_GRID (tidy_grid_get_type())
+#define TIDY_GRID(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ TIDY_TYPE_GRID, \
+ TidyGrid))
+#define TIDY_GRID_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ TIDY_TYPE_GRID, \
+ TidyGridClass))
+#define TIDY_IS_GRID(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ TIDY_TYPE_GRID))
+#define TIDY_IS_GRID_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ TIDY_TYPE_GRID))
+#define TIDY_GRID_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ TIDY_TYPE_GRID, \
+ TidyGridClass))
+
+typedef struct _TidyGrid TidyGrid;
+typedef struct _TidyGridClass TidyGridClass;
+typedef struct _TidyGridPrivate TidyGridPrivate;
+
+struct _TidyGridClass
+{
+ ClutterActorClass parent_class;
+};
+
+struct _TidyGrid
+{
+ ClutterActor parent;
+
+ TidyGridPrivate *priv;
+};
+
+GType tidy_grid_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_grid_new (void);
+void tidy_grid_set_end_align (TidyGrid *self,
+ gboolean value);
+gboolean tidy_grid_get_end_align (TidyGrid *self);
+void tidy_grid_set_homogenous_rows (TidyGrid *self,
+ gboolean value);
+gboolean tidy_grid_get_homogenous_rows (TidyGrid *self);
+void tidy_grid_set_homogenous_columns (TidyGrid *self,
+ gboolean value);
+gboolean tidy_grid_get_homogenous_columns (TidyGrid *self);
+void tidy_grid_set_column_major (TidyGrid *self,
+ gboolean value);
+gboolean tidy_grid_get_column_major (TidyGrid *self);
+void tidy_grid_set_row_gap (TidyGrid *self,
+ ClutterUnit value);
+ClutterUnit tidy_grid_get_row_gap (TidyGrid *self);
+void tidy_grid_set_column_gap (TidyGrid *self,
+ ClutterUnit value);
+ClutterUnit tidy_grid_get_column_gap (TidyGrid *self);
+void tidy_grid_set_valign (TidyGrid *self,
+ gdouble value);
+gdouble tidy_grid_get_valign (TidyGrid *self);
+void tidy_grid_set_halign (TidyGrid *self,
+ gdouble value);
+gdouble tidy_grid_get_halign (TidyGrid *self);
+
+G_END_DECLS
+
+#endif /* __TIDY_GRID_H__ */
Added: trunk/src/tidy/tidy-marshal.list
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-marshal.list Wed Nov 12 21:09:27 2008
@@ -0,0 +1,8 @@
+VOID:OBJECT
+VOID:VOID
+VOID:PARAM
+VOID:POINTER
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,OBJECT
+VOID:STRING,OBJECT
Added: trunk/src/tidy/tidy-private.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-private.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,40 @@
+/* tidy-private.h: Private declarations
+ *
+ * Copyright (C) 2007 OpenedHand
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TIDY_PRIVATE_H__
+#define __TIDY_PRIVATE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define I_(str) (g_intern_static_string ((str)))
+
+#define TIDY_PARAM_READABLE \
+ (G_PARAM_READABLE | \
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+#define TIDY_PARAM_READWRITE \
+ (G_PARAM_READABLE | G_PARAM_WRITABLE | \
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
+
+G_END_DECLS
+
+#endif /* __TIDY_PRIVATE_H__ */
Added: trunk/src/tidy/tidy-stylable.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-stylable.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,789 @@
+/* tidy-stylable.c: Interface for stylable objects
+ */
+
+/**
+ * SECTION:tidy-stylable
+ * @short_description: Interface for stylable objects
+ *
+ * Stylable objects are classes that can have "style properties", that is
+ * properties that can be changed by attaching a #TidyStyle to them.
+ *
+ * Objects can choose to subclass #TidyActor, and thus inherit all the
+ * #TidyActor style properties; or they can subclass #TidyActor and
+ * reimplement the #TidyStylable interface to add new style properties
+ * specific for them (and their subclasses); or, finally, they can simply
+ * subclass #GObject and implement #TidyStylable to install new properties.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
+#include <gobject/gobjectnotifyqueue.c>
+
+#include "tidy-marshal.h"
+#include "tidy-private.h"
+#include "tidy-stylable.h"
+
+enum
+{
+ STYLE_SET,
+ STYLE_NOTIFY,
+
+ LAST_SIGNAL
+};
+
+static GObjectNotifyContext property_notify_context = { 0, };
+
+static GParamSpecPool *style_property_spec_pool = NULL;
+
+static GQuark quark_real_owner = 0;
+static GQuark quark_style = 0;
+
+static guint stylable_signals[LAST_SIGNAL] = { 0, };
+
+static void
+tidy_stylable_notify_dispatcher (GObject *gobject,
+ guint n_pspecs,
+ GParamSpec **pspecs)
+{
+ guint i;
+
+ for (i = 0; i < n_pspecs; i++)
+ g_signal_emit (gobject, stylable_signals[STYLE_NOTIFY],
+ g_quark_from_string (pspecs[i]->name),
+ pspecs[i]);
+}
+
+static void
+tidy_stylable_base_finalize (gpointer g_iface)
+{
+ GList *list, *node;
+
+ list = g_param_spec_pool_list_owned (style_property_spec_pool,
+ G_TYPE_FROM_INTERFACE (g_iface));
+
+ for (node = list; node; node = node->next)
+ {
+ GParamSpec *pspec = node->data;
+
+ g_param_spec_pool_remove (style_property_spec_pool, pspec);
+ g_param_spec_unref (pspec);
+ }
+
+ g_list_free (list);
+}
+
+static void
+tidy_stylable_base_init (gpointer g_iface)
+{
+ static gboolean initialised = FALSE;
+
+ if (G_UNLIKELY (!initialised))
+ {
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ initialised = TRUE;
+
+ quark_real_owner = g_quark_from_static_string ("tidy-stylable-real-owner-quark");
+ quark_style = g_quark_from_static_string ("tidy-stylable-style-quark");
+
+ style_property_spec_pool = g_param_spec_pool_new (FALSE);
+
+ property_notify_context.quark_notify_queue = g_quark_from_static_string ("TidyStylable-style-property-notify-queue");
+ property_notify_context.dispatcher = tidy_stylable_notify_dispatcher;
+
+ /**
+ * TidyStylable:style:
+ *
+ * The #TidyStyle attached to a stylable object.
+ */
+ g_object_interface_install_property (g_iface,
+ g_param_spec_object ("style",
+ "Style",
+ "A style object",
+ TIDY_TYPE_STYLE,
+ TIDY_PARAM_READWRITE));
+
+ /**
+ * TidyStylable::style-set:
+ * @stylable: the #TidyStylable that received the signal
+ * @old_style: the previously set #TidyStyle for @stylable
+ *
+ * The ::style-set signal is emitted each time the #TidyStyle attached
+ * to @stylable has been changed.
+ */
+ stylable_signals[STYLE_SET] =
+ g_signal_new (I_("style-set"),
+ iface_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TidyStylableIface, style_set),
+ NULL, NULL,
+ _tidy_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ TIDY_TYPE_STYLE);
+ stylable_signals[STYLE_NOTIFY] =
+ g_signal_new (I_("style-notify"),
+ iface_type,
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (TidyStylableIface, style_notify),
+ NULL, NULL,
+ _tidy_marshal_VOID__PARAM,
+ G_TYPE_NONE, 1,
+ G_TYPE_PARAM);
+ }
+}
+
+GType
+tidy_stylable_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (G_UNLIKELY (our_type == 0))
+ {
+ GTypeInfo stylable_info = {
+ sizeof (TidyStylableIface),
+ tidy_stylable_base_init,
+ tidy_stylable_base_finalize
+ };
+
+ our_type = g_type_register_static (G_TYPE_INTERFACE,
+ I_("TidyStylable"),
+ &stylable_info, 0);
+ }
+
+ return our_type;
+}
+
+void
+tidy_stylable_freeze_notify (TidyStylable *stylable)
+{
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+
+ g_object_ref (stylable);
+ g_object_notify_queue_freeze (G_OBJECT (stylable), &property_notify_context);
+ g_object_unref (stylable);
+}
+
+void
+tidy_stylable_thaw_notify (TidyStylable *stylable)
+{
+ GObjectNotifyQueue *nqueue;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+
+ g_object_ref (stylable);
+
+ nqueue = g_object_notify_queue_from_object (G_OBJECT (stylable),
+ &property_notify_context);
+
+ if (!nqueue || !nqueue->freeze_count)
+ g_warning ("%s: property-changed notification for %s(%p) is not frozen",
+ G_STRFUNC, G_OBJECT_TYPE_NAME (stylable), stylable);
+ else
+ g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+
+ g_object_unref (stylable);
+}
+
+void
+tidy_stylable_notify (TidyStylable *stylable,
+ const gchar *property_name)
+{
+ GParamSpec *pspec;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (property_name != NULL);
+
+ g_object_ref (stylable);
+
+ pspec = g_param_spec_pool_lookup (style_property_spec_pool,
+ property_name,
+ G_OBJECT_TYPE (stylable),
+ TRUE);
+
+ if (!pspec)
+ g_warning ("%s: object class `%s' has no style property named `%s'",
+ G_STRFUNC,
+ G_OBJECT_TYPE_NAME (stylable),
+ property_name);
+ else
+ {
+ GObjectNotifyQueue *nqueue;
+
+ nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
+ &property_notify_context);
+ g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec);
+ g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+ }
+
+ g_object_unref (stylable);
+}
+
+/**
+ * tidy_stylable_iface_install_property:
+ * @iface: a #TidyStylableIface
+ * @owner_type: #GType of the style property owner
+ * @pspec: a #GParamSpec
+ *
+ * Installs a property for @owner_type using @pspec as the property
+ * description.
+ *
+ * This function should be used inside the #TidyStylableIface initialization
+ * function of a class, for instance:
+ *
+ * <informalexample><programlisting>
+ * G_DEFINE_TYPE_WITH_CODE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR,
+ * G_IMPLEMENT_INTERFACE (TIDY_TYPE_STYLABLE,
+ * tidy_stylable_init));
+ * ...
+ * static void
+ * tidy_stylable_init (TidyStylableIface *iface)
+ * {
+ * static gboolean is_initialized = FALSE;
+ *
+ * if (!is_initialized)
+ * {
+ * ...
+ * tidy_stylable_iface_install_property (stylable,
+ * FOO_TYPE_ACTOR,
+ * g_param_spec_int ("x-spacing",
+ * "X Spacing",
+ * "Horizontal spacing",
+ * -1, G_MAXINT,
+ * 2,
+ * G_PARAM_READWRITE));
+ * ...
+ * }
+ * }
+ * </programlisting></informalexample>
+ */
+void
+tidy_stylable_iface_install_property (TidyStylableIface *iface,
+ GType owner_type,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (TIDY_IS_STYLABLE_IFACE (iface));
+ g_return_if_fail (owner_type != G_TYPE_INVALID);
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+ g_return_if_fail (pspec->flags & G_PARAM_READABLE);
+ g_return_if_fail (!(pspec->flags & (G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT
+)));
+
+ if (g_param_spec_pool_lookup (style_property_spec_pool, pspec->name,
+ owner_type,
+ FALSE))
+ {
+ g_warning ("%s: class `%s' already contains a style property named `%s'",
+ G_STRLOC,
+ g_type_name (owner_type),
+ pspec->name);
+ return;
+ }
+
+ g_param_spec_ref_sink (pspec);
+ g_param_spec_set_qdata_full (pspec, quark_real_owner,
+ g_strdup (g_type_name (owner_type)),
+ g_free);
+
+ g_param_spec_pool_insert (style_property_spec_pool,
+ pspec,
+ owner_type);
+}
+
+/**
+ * tidy_stylable_list_properties:
+ * @stylable: a #TidyStylable
+ * @n_props: return location for the number of properties, or %NULL
+ *
+ * Retrieves all the #GParamSpec<!-- -->s installed by @stylable.
+ *
+ * Return value: an array of #GParamSpec<!-- -->s. Free it with
+ * g_free() when done.
+ */
+GParamSpec **
+tidy_stylable_list_properties (TidyStylable *stylable,
+ guint *n_props)
+{
+ GParamSpec **pspecs = NULL;
+ guint n;
+
+ g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
+
+ pspecs = g_param_spec_pool_list (style_property_spec_pool,
+ G_OBJECT_TYPE (stylable),
+ &n);
+ if (n_props)
+ *n_props = n;
+
+ return pspecs;
+}
+
+/**
+ * tidy_stylable_find_property:
+ * @stylable: a #TidyStylable
+ * @property_name: the name of the property to find
+ *
+ * Finds the #GParamSpec installed by @stylable for the property
+ * with @property_name.
+ *
+ * Return value: a #GParamSpec for the given property, or %NULL if
+ * no property with that name was found
+ */
+GParamSpec *
+tidy_stylable_find_property (TidyStylable *stylable,
+ const gchar *property_name)
+{
+ g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ return g_param_spec_pool_lookup (style_property_spec_pool,
+ property_name,
+ G_OBJECT_TYPE (stylable),
+ TRUE);
+}
+
+static inline void
+tidy_stylable_set_property_internal (TidyStylable *stylable,
+ GParamSpec *pspec,
+ const GValue *value,
+ GObjectNotifyQueue *nqueue)
+{
+ GValue tmp_value = { 0, };
+
+ g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (!g_value_transform (value, &tmp_value))
+ g_warning ("unable to set property `%s' of type `%s' from value of type `%s'",
+ pspec->name,
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+ G_VALUE_TYPE_NAME (value));
+ else if (g_param_value_validate (pspec, &tmp_value) &&
+ !(pspec->flags & G_PARAM_LAX_VALIDATION))
+ {
+ gchar *contents = g_strdup_value_contents (value);
+
+ g_warning ("value \"%s\" of type `%s' is invalid or out of range for property `%s' of type `%s'",
+ contents,
+ G_VALUE_TYPE_NAME (value),
+ pspec->name,
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
+ g_free (contents);
+ }
+ else
+ {
+ TidyStyle *style = tidy_stylable_get_style (stylable);
+ gchar *real_name;
+
+ real_name = g_strconcat (g_param_spec_get_qdata (pspec, quark_real_owner),
+ "::",
+ pspec->name,
+ NULL);
+
+ if (!tidy_style_has_property (style, real_name))
+ tidy_style_add_property (style, real_name,
+ G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ tidy_style_set_property (style, real_name, &tmp_value);
+ g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec);
+
+ g_free (real_name);
+ }
+
+ g_value_unset (&tmp_value);
+}
+
+static inline void
+tidy_stylable_get_property_internal (TidyStylable *stylable,
+ GParamSpec *pspec,
+ GValue *value)
+{
+ TidyStyle *style;
+ GValue real_value = { 0, };
+ gchar *real_name;
+
+ real_name = g_strconcat (g_param_spec_get_qdata (pspec, quark_real_owner),
+ "::",
+ pspec->name,
+ NULL);
+
+ style = tidy_stylable_get_style (stylable);
+ if (!tidy_style_has_property (style, real_name))
+ {
+ /* the style has no property set, use the default value
+ * from the GParamSpec
+ */
+ g_param_value_set_default (pspec, value);
+ g_free (real_name);
+ return;
+ }
+
+ tidy_style_get_property (style, real_name, &real_value);
+
+ g_value_copy (&real_value, value);
+ g_value_unset (&real_value);
+
+ g_free (real_name);
+}
+
+/**
+ * tidy_stylable_get_property:
+ * @stylable: a #TidyStylable
+ * @property_name: the name of the property
+ * @value: return location for an empty #GValue
+ *
+ * Retrieves the value of @property_name for @stylable, and puts it
+ * into @value.
+ */
+void
+tidy_stylable_get_property (TidyStylable *stylable,
+ const gchar *property_name,
+ GValue *value)
+{
+ GParamSpec *pspec;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (value != NULL);
+
+ pspec = tidy_stylable_find_property (stylable, property_name);
+ if (!pspec)
+ {
+ g_warning ("Stylable class `%s' doesn't have a property named `%s'",
+ g_type_name (G_OBJECT_TYPE (stylable)),
+ property_name);
+ return;
+ }
+
+ if (!(pspec->flags & G_PARAM_READABLE))
+ {
+ g_warning ("Style property `%s' of class `%s' is not readable",
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ return;
+ }
+
+ if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec))
+ {
+ g_warning ("Passed value is not of the requested type `%s' for "
+ "the style property `%s' of class `%s'",
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ return;
+ }
+
+ tidy_stylable_get_property_internal (stylable, pspec, value);
+}
+
+/**
+ * tidy_stylable_set_property:
+ * @stylable: a #TidyStylable
+ * @property_name: the name of the property to set
+ * @value: an initialized #GValue
+ *
+ * Sets the property @property_name with @value.
+ */
+void
+tidy_stylable_set_property (TidyStylable *stylable,
+ const gchar *property_name,
+ const GValue *value)
+{
+ GObjectNotifyQueue *nqueue;
+ GParamSpec *pspec;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (value != NULL);
+
+ g_object_ref (stylable);
+
+ nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
+ &property_notify_context);
+
+ pspec = tidy_stylable_find_property (stylable, property_name);
+ if (!pspec)
+ {
+ g_warning ("Stylable class `%s' doesn't have a property named `%s'",
+ g_type_name (G_OBJECT_TYPE (stylable)),
+ property_name);
+ }
+ else if (!(pspec->flags & G_PARAM_WRITABLE))
+ {
+ g_warning ("Style property `%s' of class `%s' is not readable",
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ }
+ else if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec))
+ {
+ g_warning ("Passed value is not of the requested type `%s' for "
+ "the style property `%s' of class `%s'",
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ }
+ else
+ tidy_stylable_set_property_internal (stylable, pspec, value, nqueue);
+
+ g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+ g_object_unref (stylable);
+}
+
+static void
+tidy_stylable_get_valist (TidyStylable *stylable,
+ const gchar *first_property_name,
+ va_list varargs)
+{
+ const gchar *name;
+
+ g_object_ref (stylable);
+
+ name = first_property_name;
+
+ while (name)
+ {
+ GParamSpec *pspec;
+ GValue value = { 0, };
+ gchar *error;
+
+ pspec = tidy_stylable_find_property (stylable, name);
+ if (!pspec)
+ {
+ g_warning ("%s: no style property named `%s' found for class `%s'",
+ G_STRLOC,
+ name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ break;
+ }
+
+ if (!(pspec->flags & G_PARAM_READABLE))
+ {
+ g_warning ("Style property `%s' of class `%s' is not readable",
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ break;
+ }
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+ tidy_stylable_get_property_internal (stylable, pspec, &value);
+
+ G_VALUE_LCOPY (&value, varargs, 0, &error);
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+ g_value_unset (&value);
+ break;
+ }
+
+ g_value_unset (&value);
+
+ name = va_arg (varargs, gchar*);
+ }
+
+ g_object_unref (stylable);
+}
+
+static void
+tidy_stylable_set_valist (TidyStylable *stylable,
+ const gchar *first_property_name,
+ va_list varargs)
+{
+ GObjectNotifyQueue *nqueue;
+ const gchar *name;
+
+ g_object_ref (stylable);
+
+ nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
+ &property_notify_context);
+
+ name = first_property_name;
+
+ while (name)
+ {
+ GParamSpec *pspec;
+ GValue value = { 0, };
+ gchar *error;
+
+ pspec = tidy_stylable_find_property (stylable, name);
+ if (!pspec)
+ {
+ g_warning ("%s: no style property named `%s' found for class `%s'",
+ G_STRLOC,
+ name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ break;
+ }
+
+ if (!(pspec->flags & G_PARAM_WRITABLE) ||
+ (pspec->flags & G_PARAM_CONSTRUCT_ONLY))
+ {
+ g_warning ("Style property `%s' of class `%s' is not writable",
+ pspec->name,
+ g_type_name (G_OBJECT_TYPE (stylable)));
+ break;
+ }
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ G_VALUE_COLLECT (&value, varargs, 0, &error);
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+ g_value_unset (&value);
+ break;
+ }
+
+ tidy_stylable_set_property_internal (stylable, pspec, &value, nqueue);
+ g_value_unset (&value);
+
+ name = va_arg (varargs, gchar*);
+ }
+
+ g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+ g_object_unref (stylable);
+}
+
+/**
+ * tidy_stylable_get:
+ * @stylable: a #TidyStylable
+ * @first_property_name: name of the first property to get
+ * @Varargs: return location for the first property, followed optionally
+ * by more name/return location pairs, followed by %NULL
+ *
+ * Gets the style properties for @stylable.
+ *
+ * In general, a copy is made of the property contents and the called
+ * is responsible for freeing the memory in the appropriate manner for
+ * the property type.
+ *
+ * <example>
+ * <title>Using tidy_stylable_get(<!-- -->)</title>
+ * <para>An example of using tidy_stylable_get() to get the contents of
+ * two style properties - one of type #G_TYPE_INT and one of type
+ * #CLUTTER_TYPE_COLOR:</para>
+ * <programlisting>
+ * gint x_spacing;
+ * ClutterColor *bg_color;
+ *
+ * tidy_stylable_get (stylable,
+ * "x-spacing", &x_spacing,
+ * "bg-color", &bg_color,
+ * NULL);
+ *
+ * /<!-- -->* do something with x_spacing and bg_color *<!-- -->/
+ *
+ * clutter_color_free (bg_color);
+ * </programlisting>
+ * </example>
+ */
+void
+tidy_stylable_get (TidyStylable *stylable,
+ const gchar *first_property_name,
+ ...)
+{
+ va_list args;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (first_property_name != NULL);
+
+ va_start (args, first_property_name);
+ tidy_stylable_get_valist (stylable, first_property_name, args);
+ va_end (args);
+}
+
+/**
+ * tidy_stylable_set:
+ * @stylable: a #TidyStylable
+ * @first_property_name: name of the first property to set
+ * @Varargs: value for the first property, followed optionally by
+ * more name/value pairs, followed by %NULL
+ *
+ * Sets the style properties of @stylable.
+ */
+void
+tidy_stylable_set (TidyStylable *stylable,
+ const gchar *first_property_name,
+ ...)
+{
+ va_list args;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (first_property_name != NULL);
+
+ va_start (args, first_property_name);
+ tidy_stylable_set_valist (stylable, first_property_name, args);
+ va_end (args);
+}
+
+/**
+ * tidy_stylable_get_style:
+ * @stylable: a #TidyStylable
+ *
+ * Retrieves the #TidyStyle used by @stylable. This function does not
+ * alter the reference count of the returned object.
+ *
+ * Return value: a #TidyStyle
+ */
+TidyStyle *
+tidy_stylable_get_style (TidyStylable *stylable)
+{
+ TidyStylableIface *iface;
+
+ g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
+
+ iface = TIDY_STYLABLE_GET_IFACE (stylable);
+ if (iface->get_style)
+ return iface->get_style (stylable);
+
+ return g_object_get_data (G_OBJECT (stylable), "tidy-stylable-style");
+}
+
+/**
+ * tidy_stylable_set_style:
+ * @stylable: a #TidyStylable
+ * @style: a #TidyStyle
+ *
+ * Sets @style as the new #TidyStyle to be used by @stylable.
+ *
+ * The #TidyStylable will take ownership of the passed #TidyStyle.
+ *
+ * After the #TidyStle has been set, the TidyStylable::style-set signal
+ * will be emitted.
+ */
+void
+tidy_stylable_set_style (TidyStylable *stylable,
+ TidyStyle *style)
+{
+ TidyStylableIface *iface;
+ TidyStyle *old_style;
+
+ g_return_if_fail (TIDY_IS_STYLABLE (stylable));
+ g_return_if_fail (TIDY_IS_STYLE (style));
+
+ iface = TIDY_STYLABLE_GET_IFACE (stylable);
+
+ old_style = tidy_stylable_get_style (stylable);
+ g_object_ref (old_style);
+
+ if (iface->set_style)
+ iface->set_style (stylable, style);
+ else
+ {
+ g_object_set_qdata_full (G_OBJECT (stylable),
+ quark_style,
+ g_object_ref_sink (style),
+ g_object_unref);
+ }
+
+ g_signal_emit (stylable, stylable_signals[STYLE_SET], 0, old_style);
+ g_object_unref (old_style);
+
+ g_object_notify (G_OBJECT (stylable), "style");
+}
Added: trunk/src/tidy/tidy-stylable.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-stylable.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,69 @@
+#ifndef __TIDY_STYLABLE_H__
+#define __TIDY_STYLABLE_H__
+
+#include <glib-object.h>
+#include <tidy/tidy-style.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_STYLABLE (tidy_stylable_get_type ())
+#define TIDY_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_STYLABLE, TidyStylable))
+#define TIDY_IS_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_STYLABLE))
+#define TIDY_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_CAST ((iface), TIDY_TYPE_STYLABLE, TidyStylableIface))
+#define TIDY_IS_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_TYPE ((iface), TIDY_TYPE_STYLABLE))
+#define TIDY_STYLABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TIDY_TYPE_STYLABLE, TidyStylableIface))
+
+typedef struct _TidyStylable TidyStylable; /* dummy typedef */
+typedef struct _TidyStylableIface TidyStylableIface;
+
+struct _TidyStylableIface
+{
+ GTypeInterface g_iface;
+
+ /* virtual functions */
+ TidyStyle *(* get_style) (TidyStylable *stylable);
+ void (* set_style) (TidyStylable *stylable,
+ TidyStyle *style);
+
+ /* signals, not vfuncs */
+ void (* style_notify) (TidyStylable *stylable,
+ GParamSpec *pspec);
+
+ void (* style_set) (TidyStylable *stylable,
+ TidyStyle *old_style);
+};
+
+GType tidy_stylable_get_type (void) G_GNUC_CONST;
+
+void tidy_stylable_iface_install_property (TidyStylableIface *iface,
+ GType owner_type,
+ GParamSpec *pspec);
+
+void tidy_stylable_freeze_notify (TidyStylable *stylable);
+void tidy_stylable_notify (TidyStylable *stylable,
+ const gchar *property_name);
+void tidy_stylable_thaw_notify (TidyStylable *stylable);
+GParamSpec **tidy_stylable_list_properties (TidyStylable *stylable,
+ guint *n_props);
+GParamSpec * tidy_stylable_find_property (TidyStylable *stylable,
+ const gchar *property_name);
+void tidy_stylable_set_style (TidyStylable *stylable,
+ TidyStyle *style);
+TidyStyle * tidy_stylable_get_style (TidyStylable *stylable);
+
+void tidy_stylable_set (TidyStylable *stylable,
+ const gchar *first_property_name,
+ ...) G_GNUC_NULL_TERMINATED;
+void tidy_stylable_get (TidyStylable *stylable,
+ const gchar *first_property_name,
+ ...) G_GNUC_NULL_TERMINATED;
+void tidy_stylable_set_property (TidyStylable *stylable,
+ const gchar *property_name,
+ const GValue *value);
+void tidy_stylable_get_property (TidyStylable *stylable,
+ const gchar *property_name,
+ GValue *value);
+
+G_END_DECLS
+
+#endif /* __TIDY_STYLABLE_H__ */
Added: trunk/src/tidy/tidy-style.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-style.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,653 @@
+#ifndef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
+
+#include <clutter/clutter-behaviour.h>
+#include <clutter/clutter-color.h>
+
+#include "tidy-style.h"
+#include "tidy-marshal.h"
+#include "tidy-debug.h"
+
+enum
+{
+ CHANGED,
+
+ LAST_SIGNAL
+};
+
+#define TIDY_STYLE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_STYLE, TidyStylePrivate))
+
+typedef struct {
+ GType value_type;
+ gchar *value_name;
+ GValue value;
+} StyleProperty;
+
+typedef struct {
+ gchar *name;
+ GType behaviour_type;
+ GArray *parameters;
+ guint duration;
+ ClutterAlphaFunc alpha_func;
+} StyleEffect;
+
+struct _TidyStylePrivate
+{
+ GHashTable *properties;
+ GHashTable *effects;
+};
+
+static guint style_signals[LAST_SIGNAL] = { 0, };
+
+static const gchar *tidy_default_font_name = "Sans 12px";
+static const ClutterColor tidy_default_text_color = { 0x00, 0x00, 0x00, 0xff };
+static const ClutterColor tidy_default_bg_color = { 0xcc, 0xcc, 0xcc, 0xff };
+static const ClutterColor tidy_default_active_color = { 0xf5, 0x79, 0x00, 0xff };
+
+static TidyStyle *default_style = NULL;
+
+G_DEFINE_TYPE (TidyStyle, tidy_style, G_TYPE_OBJECT);
+
+static StyleProperty *
+style_property_new (const gchar *value_name,
+ GType value_type)
+{
+ StyleProperty *retval;
+
+ retval = g_slice_new0 (StyleProperty);
+ retval->value_type = value_type;
+ retval->value_name = g_strdup (value_name);
+ g_value_init (&retval->value, value_type);
+
+ return retval;
+}
+
+static void
+style_property_free (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ StyleProperty *sp = data;
+
+ g_free (sp->value_name);
+ g_value_unset (&sp->value);
+ }
+}
+
+static StyleEffect *
+style_effect_new (const gchar *name)
+{
+ StyleEffect *retval;
+
+ retval = g_slice_new0 (StyleEffect);
+ retval->name = g_strdup (name);
+ retval->behaviour_type = G_TYPE_INVALID;
+
+ return retval;
+}
+
+static void
+style_effect_free (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ StyleEffect *effect = data;
+
+ g_free (effect->name);
+
+ if (effect->parameters)
+ {
+ gint i;
+
+ for (i = 0; i < effect->parameters->len; i++)
+ {
+ GParameter *param;
+
+ param = &g_array_index (effect->parameters, GParameter, i);
+
+ g_free ((gchar *) param->name);
+ g_value_unset (¶m->value);
+ }
+
+ g_array_free (effect->parameters, TRUE);
+ effect->parameters = NULL;
+ }
+
+ g_slice_free (StyleEffect, effect);
+ }
+}
+
+static void
+init_defaults (TidyStyle *style)
+{
+ TidyStylePrivate *priv = style->priv;
+
+ {
+ StyleProperty *sp;
+
+ sp = style_property_new (TIDY_FONT_NAME, G_TYPE_STRING);
+ g_value_set_string (&sp->value, tidy_default_font_name);
+
+ g_hash_table_insert (priv->properties, sp->value_name, sp);
+ }
+
+ {
+ StyleProperty *sp;
+
+ sp = style_property_new (TIDY_BACKGROUND_COLOR, CLUTTER_TYPE_COLOR);
+ g_value_set_boxed (&sp->value, &tidy_default_bg_color);
+
+ g_hash_table_insert (priv->properties, sp->value_name, sp);
+ }
+
+ {
+ StyleProperty *sp;
+
+ sp = style_property_new (TIDY_ACTIVE_COLOR, CLUTTER_TYPE_COLOR);
+ g_value_set_boxed (&sp->value, &tidy_default_active_color);
+
+ g_hash_table_insert (priv->properties, sp->value_name, sp);
+ }
+
+ {
+ StyleProperty *sp;
+
+ sp = style_property_new (TIDY_TEXT_COLOR, CLUTTER_TYPE_COLOR);
+ g_value_set_boxed (&sp->value, &tidy_default_text_color);
+
+ g_hash_table_insert (priv->properties, sp->value_name, sp);
+ }
+}
+
+static gboolean
+tidy_style_load_from_file (TidyStyle *style,
+ const gchar *filename,
+ GError **error)
+{
+ GKeyFile *rc_file;
+ GError *internal_error;
+
+ rc_file = g_key_file_new ();
+
+ internal_error = NULL;
+ g_key_file_load_from_file (rc_file, filename, 0, &internal_error);
+ if (internal_error)
+ {
+ g_key_file_free (rc_file);
+ /* if the specified files does not exist then just ignore it
+ * and fall back to the default values; if, instead, the file
+ * is not accessible or is malformed, propagate the error
+ */
+ if (internal_error->domain == G_FILE_ERROR &&
+ internal_error->code == G_FILE_ERROR_NOENT)
+ {
+ g_error_free (internal_error);
+ return TRUE;
+ }
+
+ g_propagate_error (error, internal_error);
+ return FALSE;
+ }
+
+ g_key_file_free (rc_file);
+
+ return TRUE;
+}
+
+static void
+tidy_style_load (TidyStyle *style)
+{
+ const gchar *env_var;
+ gchar *rc_file = NULL;
+ GError *error;
+
+ init_defaults (style);
+
+ env_var = g_getenv ("TIDY_RC_FILE");
+ if (env_var && *env_var)
+ rc_file = g_strdup (env_var);
+
+ if (!rc_file)
+ rc_file = g_build_filename (g_get_user_config_dir (),
+ "tidy",
+ "tidyrc",
+ NULL);
+
+ error = NULL;
+ if (!tidy_style_load_from_file (style, rc_file, &error))
+ {
+ g_critical ("Unable to load resource file `%s': %s",
+ rc_file,
+ error->message);
+ g_error_free (error);
+ }
+
+ g_free (rc_file);
+}
+
+static void
+tidy_style_finalize (GObject *gobject)
+{
+ TidyStylePrivate *priv = TIDY_STYLE (gobject)->priv;
+
+ g_hash_table_destroy (priv->properties);
+ g_hash_table_destroy (priv->effects);
+
+ G_OBJECT_CLASS (tidy_style_parent_class)->finalize (gobject);
+}
+
+static void
+tidy_style_class_init (TidyStyleClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyStylePrivate));
+
+ gobject_class->finalize = tidy_style_finalize;
+
+ style_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TidyStyleClass, changed),
+ NULL, NULL,
+ _tidy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+tidy_style_init (TidyStyle *style)
+{
+ TidyStylePrivate *priv;
+
+ style->priv = priv = TIDY_STYLE_GET_PRIVATE (style);
+
+ priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL,
+ style_property_free);
+ priv->effects = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL,
+ style_effect_free);
+
+ tidy_style_load (style);
+}
+
+/* need to unref */
+TidyStyle *
+tidy_style_new (void)
+{
+ return g_object_new (TIDY_TYPE_STYLE, NULL);
+}
+
+/* never ref/unref */
+TidyStyle *
+tidy_style_get_default (void)
+{
+ if (G_LIKELY (default_style))
+ return default_style;
+
+ default_style = g_object_new (TIDY_TYPE_STYLE, NULL);
+
+ return default_style;
+}
+
+static StyleProperty *
+tidy_style_find_property (TidyStyle *style,
+ const gchar *property_name)
+{
+ return g_hash_table_lookup (style->priv->properties, property_name);
+}
+
+gboolean
+tidy_style_has_property (TidyStyle *style,
+ const gchar *property_name)
+{
+ g_return_val_if_fail (TIDY_IS_STYLE (style), FALSE);
+ g_return_val_if_fail (property_name != NULL, FALSE);
+
+ return (tidy_style_find_property (style, property_name) != NULL);
+}
+
+void
+tidy_style_add_property (TidyStyle *style,
+ const gchar *property_name,
+ GType property_type)
+{
+ StyleProperty *property;
+
+ g_return_if_fail (TIDY_IS_STYLE (style));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (property_type != G_TYPE_INVALID);
+
+ property = tidy_style_find_property (style, property_name);
+ if (G_UNLIKELY (property))
+ {
+ g_warning ("A property named `%s', with type %s already exists.",
+ property->value_name,
+ g_type_name (property->value_type));
+ return;
+ }
+
+ property = style_property_new (property_name, property_type);
+ g_hash_table_insert (style->priv->properties, property->value_name, property);
+
+ g_signal_emit (style, style_signals[CHANGED], 0);
+}
+
+void
+tidy_style_get_property (TidyStyle *style,
+ const gchar *property_name,
+ GValue *value)
+{
+ StyleProperty *property;
+
+ g_return_if_fail (TIDY_IS_STYLE (style));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (value != NULL);
+
+ property = tidy_style_find_property (style, property_name);
+ if (!property)
+ {
+ g_warning ("No style property named `%s' found.", property_name);
+ return;
+ }
+
+ g_value_init (value, property->value_type);
+ g_value_copy (&property->value, value);
+}
+
+void
+tidy_style_set_property (TidyStyle *style,
+ const gchar *property_name,
+ const GValue *value)
+{
+ StyleProperty *property;
+
+ g_return_if_fail (TIDY_IS_STYLE (style));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (value != NULL);
+
+ property = tidy_style_find_property (style, property_name);
+ if (!property)
+ {
+ g_warning ("No style property named `%s' found.", property_name);
+ return;
+ }
+
+ g_value_copy (value, &property->value);
+
+ g_signal_emit (style, style_signals[CHANGED], 0);
+}
+
+static StyleEffect *
+tidy_style_find_effect (TidyStyle *style,
+ const gchar *effect_name)
+{
+ return g_hash_table_lookup (style->priv->effects, effect_name);
+}
+
+void
+tidy_style_add_effect (TidyStyle *style,
+ const gchar *effect_name)
+{
+ StyleEffect *effect;
+
+ effect = tidy_style_find_effect (style, effect_name);
+ if (G_UNLIKELY (effect))
+ {
+ g_warning ("An effect named `%s', with type %s already exists.",
+ effect->name,
+ g_type_name (effect->behaviour_type));
+ return;
+ }
+
+ effect = style_effect_new (effect_name);
+ g_hash_table_replace (style->priv->effects,
+ effect->name,
+ effect);
+}
+
+gboolean
+tidy_style_has_effect (TidyStyle *style,
+ const gchar *effect_name)
+{
+ g_return_val_if_fail (TIDY_IS_STYLE (style), FALSE);
+ g_return_val_if_fail (effect_name != NULL, FALSE);
+
+ return (tidy_style_find_effect (style, effect_name) != NULL);
+}
+
+static void
+tidy_style_set_effect_valist (TidyStyle *style,
+ StyleEffect *effect,
+ const gchar *first_property_name,
+ va_list varargs)
+{
+ GObjectClass *klass;
+ const gchar *name;
+
+ klass = g_type_class_ref (effect->behaviour_type);
+ if (G_UNLIKELY (!klass))
+ return;
+
+ name = first_property_name;
+ while (name)
+ {
+ GParamSpec *pspec;
+ GParameter param = { 0, };
+ GValue value = { 0, };
+ gchar *error = NULL;
+
+ pspec = g_object_class_find_property (klass, name);
+ if (!pspec)
+ {
+ g_warning ("Unable to find the property `%s' for the "
+ "behaviour of type `%s'",
+ name,
+ g_type_name (effect->behaviour_type));
+ break;
+ }
+
+ if (!(pspec->flags & G_PARAM_WRITABLE))
+ {
+ g_warning ("The property `%s' for the behaviour of type "
+ "`%s' is not writable",
+ pspec->name,
+ g_type_name (effect->behaviour_type));
+ break;
+ }
+
+ param.name = g_strdup (pspec->name);
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ G_VALUE_COLLECT (&value, varargs, 0, &error);
+ if (error)
+ {
+ g_warning ("%s: %s", G_STRLOC, error);
+ g_free (error);
+ g_value_unset (&value);
+ break;
+ }
+
+ g_value_init (&(param.value), G_PARAM_SPEC_VALUE_TYPE (pspec));
+ g_value_copy (&value, &(param.value));
+ g_value_unset (&value);
+
+ name = va_arg (varargs, gchar*);
+ }
+
+ g_type_class_unref (klass);
+}
+
+void
+tidy_style_set_effect (TidyStyle *style,
+ const gchar *effect_name,
+ guint duration,
+ GType behaviour_type,
+ ClutterAlphaFunc alpha_func,
+ const gchar *first_property_name,
+ ...)
+{
+ StyleEffect *effect;
+ va_list args;
+
+ effect = tidy_style_find_effect (style, effect_name);
+ if (!effect)
+ {
+ g_warning ("No effect named `%s' found.", effect_name);
+ return;
+ }
+
+ if (effect->parameters)
+ {
+ gint i;
+
+ for (i = 0; i < effect->parameters->len; i++)
+ {
+ GParameter *param;
+
+ param = &g_array_index (effect->parameters, GParameter, i);
+
+ g_free ((gchar *) param->name);
+ g_value_unset (¶m->value);
+ }
+
+ g_array_free (effect->parameters, TRUE);
+ effect->parameters = NULL;
+ }
+
+ effect->duration = duration;
+ effect->behaviour_type = behaviour_type;
+ effect->alpha_func = alpha_func;
+ effect->parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
+
+ va_start (args, first_property_name);
+ tidy_style_set_effect_valist (style, effect, first_property_name, args);
+ va_end (args);
+}
+
+void
+tidy_style_set_effectv (TidyStyle *style,
+ const gchar *effect_name,
+ guint duration,
+ GType behaviour_type,
+ ClutterAlphaFunc alpha_func,
+ guint n_parameters,
+ GParameter *parameters)
+{
+ StyleEffect *effect;
+ gint i;
+
+ effect = tidy_style_find_effect (style, effect_name);
+ if (!effect)
+ {
+ g_warning ("No effect named `%s' found.", effect_name);
+ return;
+ }
+
+ if (effect->parameters)
+ {
+ gint i;
+
+ for (i = 0; i < effect->parameters->len; i++)
+ {
+ GParameter *param;
+
+ param = &g_array_index (effect->parameters, GParameter, i);
+
+ g_free ((gchar *) param->name);
+ g_value_unset (¶m->value);
+ }
+
+ g_array_free (effect->parameters, TRUE);
+ effect->parameters = NULL;
+ }
+
+ effect->duration = duration;
+ effect->behaviour_type = behaviour_type;
+ effect->alpha_func = alpha_func;
+ effect->parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
+
+ for (i = 0; i < n_parameters; i++)
+ {
+ GParameter param = { NULL, };
+
+ param.name = g_strdup (parameters[i].name);
+
+ g_value_init (¶m.value, G_VALUE_TYPE (¶meters[i].value));
+ g_value_copy (¶meters[i].value, ¶m.value);
+
+ g_array_append_val (effect->parameters, param);
+ }
+}
+
+static ClutterBehaviour *
+tidy_style_construct_effect (TidyStyle *style,
+ const gchar *effect_name)
+{
+ ClutterTimeline *timeline;
+ ClutterAlpha *alpha;
+ ClutterBehaviour *behaviour;
+ StyleEffect *effect;
+
+ effect = tidy_style_find_effect (style, effect_name);
+ if (!effect)
+ {
+ g_warning ("No effect named `%s' found.", effect_name);
+ return NULL;
+ }
+
+ timeline = clutter_timeline_new_for_duration (effect->duration);
+
+ alpha = clutter_alpha_new_full (timeline, effect->alpha_func, NULL, NULL);
+ g_object_unref (timeline);
+
+ behaviour = g_object_newv (effect->behaviour_type,
+ effect->parameters->len,
+ (GParameter *) effect->parameters->data);
+
+ clutter_behaviour_set_alpha (behaviour, alpha);
+
+ /* we just unref the behaviour, which will take care of cleaning
+ * up everything (alpha+timeline)
+ */
+ g_signal_connect_swapped (timeline,
+ "completed", G_CALLBACK (g_object_unref),
+ behaviour);
+
+ return behaviour;
+}
+
+ClutterTimeline *
+tidy_style_get_effect (TidyStyle *style,
+ const gchar *effect_name,
+ ClutterActor *actor)
+{
+ ClutterBehaviour *behaviour;
+ ClutterAlpha *alpha;
+ ClutterTimeline *timeline;
+
+ g_return_val_if_fail (TIDY_IS_STYLE (style), NULL);
+ g_return_val_if_fail (effect_name != NULL, NULL);
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
+
+ behaviour = tidy_style_construct_effect (style, effect_name);
+ if (!behaviour)
+ return NULL;
+
+ clutter_behaviour_apply (behaviour, actor);
+
+ alpha = clutter_behaviour_get_alpha (behaviour);
+ timeline = clutter_alpha_get_timeline (alpha);
+
+ return timeline;
+}
Added: trunk/src/tidy/tidy-style.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-style.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,85 @@
+#ifndef __TIDY_STYLE_H__
+#define __TIDY_STYLE_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-actor.h>
+#include <clutter/clutter-alpha.h>
+#include <clutter/clutter-timeline.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_STYLE (tidy_style_get_type ())
+#define TIDY_STYLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_STYLE, TidyStyle))
+#define TIDY_IS_STYLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_STYLE))
+#define TIDY_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_STYLE, TidyStyleClass))
+#define TIDY_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_STYLE))
+#define TIDY_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_STYLE, TidyStyleClass))
+
+/* Default properties */
+#define TIDY_FONT_NAME "TidyActor::font-name"
+#define TIDY_BACKGROUND_COLOR "TidyActor::bg-color"
+#define TIDY_ACTIVE_COLOR "TidyActor::active-color"
+#define TIDY_TEXT_COLOR "TidyActor::text-color"
+
+typedef struct _TidyStyle TidyStyle;
+typedef struct _TidyStylePrivate TidyStylePrivate;
+typedef struct _TidyStyleClass TidyStyleClass;
+
+struct _TidyStyle
+{
+ GObject parent_instance;
+
+ TidyStylePrivate *priv;
+};
+
+struct _TidyStyleClass
+{
+ GObjectClass parent_class;
+
+ void (* changed) (TidyStyle *style);
+};
+
+GType tidy_style_get_type (void) G_GNUC_CONST;
+
+TidyStyle * tidy_style_get_default (void);
+TidyStyle * tidy_style_new (void);
+
+gboolean tidy_style_has_property (TidyStyle *style,
+ const gchar *property_name);
+gboolean tidy_style_has_effect (TidyStyle *style,
+ const gchar *effect_name);
+void tidy_style_add_property (TidyStyle *style,
+ const gchar *property_name,
+ GType property_type);
+void tidy_style_add_effect (TidyStyle *style,
+ const gchar *effect_name);
+
+void tidy_style_get_property (TidyStyle *style,
+ const gchar *property_name,
+ GValue *value);
+void tidy_style_set_property (TidyStyle *style,
+ const gchar *property_name,
+ const GValue *value);
+
+ClutterTimeline *tidy_style_get_effect (TidyStyle *style,
+ const gchar *effect_name,
+ ClutterActor *actor);
+void tidy_style_set_effectv (TidyStyle *style,
+ const gchar *effect_name,
+ guint duration,
+ GType behaviour_type,
+ ClutterAlphaFunc alpha_func,
+ guint n_parameters,
+ GParameter *parameters);
+void tidy_style_set_effect (TidyStyle *style,
+ const gchar *effect_name,
+ guint duration,
+ GType behaviour_type,
+ ClutterAlphaFunc alpha_func,
+ const gchar *first_property_name,
+ ...) G_GNUC_NULL_TERMINATED;
+
+
+G_END_DECLS
+
+#endif /* __TIDY_STYLE_H__ */
Added: trunk/src/tidy/tidy-types.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-types.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,25 @@
+#ifndef __TIDY_TYPES_H__
+#define __TIDY_TYPES_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-units.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_PADDING (tidy_padding_get_type ())
+
+typedef struct _TidyPadding TidyPadding;
+
+struct _TidyPadding
+{
+ ClutterUnit top;
+ ClutterUnit right;
+ ClutterUnit bottom;
+ ClutterUnit left;
+};
+
+GType tidy_padding_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __TIDY_TYPES_H__ */
Added: trunk/src/tidy/tidy-util.c
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-util.c Wed Nov 12 21:09:27 2008
@@ -0,0 +1,37 @@
+#include "tidy-util.h"
+
+/* Hack to (mostly) fill glyph cache, useful on MBX.
+ *
+ * FIXME: untested
+*/
+void
+tidy_util_preload_glyphs (char *font, ...)
+{
+ va_list args;
+
+ va_start (args, font);
+
+ while (font)
+ {
+ /* Hold on to your hat.. */
+ ClutterActor *foo;
+ ClutterColor text_color = { 0xff, 0xff, 0xff, 0xff };
+
+ foo = clutter_label_new_full
+ (font,
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "1234567890&()*.,';:-_+=[]{}# ?><\"!`%\\|/ ",
+ &text_color);
+ if (foo)
+ {
+ clutter_actor_realize(foo);
+ clutter_actor_paint(foo);
+ g_object_unref (foo);
+ }
+
+ font = va_arg (args, char*);
+ }
+
+ va_end (args);
+}
Added: trunk/src/tidy/tidy-util.h
==============================================================================
--- (empty file)
+++ trunk/src/tidy/tidy-util.h Wed Nov 12 21:09:27 2008
@@ -0,0 +1,9 @@
+#ifndef _TIDY_UTIL
+#define _TIDY_UTIL
+
+#include <clutter/clutter.h>
+
+void
+tidy_util_preload_glyphs (char *font, ...);
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]