[libchamplain] Back to tidy
- From: Jiří Techet <jiritechet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libchamplain] Back to tidy
- Date: Sat, 26 Feb 2011 12:58:09 +0000 (UTC)
commit 0568e0215b6482903b1880da432d22f02d718c5b
Author: JiÅ?Ã Techet <techet gmail com>
Date: Thu Feb 24 20:57:55 2011 +0100
Back to tidy
Using Mx instead of tidy added too much extra stuff we don't need
at all. It will be easier to continue using tidy and backport the
fixes from Mx.
.gitignore | 12 +-
Makefile.am | 2 +-
champlain/Makefile.am | 6 +-
champlain/champlain-view.c | 32 +-
configure.ac | 2 +-
mx/Makefile.am | 64 -
mx/mx-adjustment.c | 1233 --------------------
mx/mx-adjustment.h | 149 ---
mx/mx-bin.c | 715 ------------
mx/mx-bin.h | 99 --
mx/mx-kinetic-scroll-view.c | 1232 -------------------
mx/mx-kinetic-scroll-view.h | 97 --
mx/mx-marshal.list | 8 -
mx/mx-scrollable.c | 99 --
mx/mx-scrollable.h | 71 --
mx/mx-types.h | 80 --
mx/mx-viewport.c | 678 -----------
mx/mx-viewport.h | 91 --
tidy/Makefile.am | 63 +
tidy/tidy-adjustment.c | 643 ++++++++++
tidy/tidy-adjustment.h | 119 ++
tidy/tidy-debug.h | 4 +
mx/mx-enum-types.c.in => tidy/tidy-enum-types.c.in | 2 +-
mx/mx-enum-types.h.in => tidy/tidy-enum-types.h.in | 8 +-
tidy/tidy-finger-scroll.c | 694 +++++++++++
tidy/tidy-finger-scroll.h | 64 +
tidy/tidy-marshal.list | 6 +
mx/mx-private.h => tidy/tidy-private.h | 14 +-
tidy/tidy-scroll-view.c | 339 ++++++
tidy/tidy-scroll-view.h | 65 +
tidy/tidy-scrollable.c | 87 ++
tidy/tidy-scrollable.h | 63 +
tidy/tidy-viewport.c | 596 ++++++++++
tidy/tidy-viewport.h | 72 ++
34 files changed, 2854 insertions(+), 4655 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index cd22249..6ad77d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,12 +84,12 @@ libtool
ltmain.sh
missing
stamp-h1
-mx/mx-enum-types.c
-mx/mx-enum-types.h
-mx/stamp-enum-types
-mx/mx-marshal.c
-mx/mx-marshal.h
-mx/stamp-marshal
+tidy/tidy-enum-types.c
+tidy/tidy-enum-types.h
+tidy/stamp-enum-types
+tidy/tidy-marshal.c
+tidy/tidy-marshal.h
+tidy/stamp-marshal
bindings/python/update-binding.sh
bindings/python/champlain-gtk/pychamplaingtk.c
bindings/python/champlain/pychamplain.c
diff --git a/Makefile.am b/Makefile.am
index bd3492e..6b9c72f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = build mx champlain
+SUBDIRS = build tidy champlain
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
diff --git a/champlain/Makefile.am b/champlain/Makefile.am
index af457c8..8934354 100644
--- a/champlain/Makefile.am
+++ b/champlain/Makefile.am
@@ -125,7 +125,7 @@ nodist_libchamplain_ CHAMPLAIN_API_VERSION@_la_SOURCES = \
$(libchamplain_headers_built) \
$(libchamplain_sources_built)
-libchamplain_ CHAMPLAIN_API_VERSION@_la_LIBADD = $(DEPS_LIBS) $(SOUP_LIBS) $(MEMPHIS_LIBS) $(top_builddir)/mx/libchamplainmx-1.0.la
+libchamplain_ CHAMPLAIN_API_VERSION@_la_LIBADD = $(DEPS_LIBS) $(SOUP_LIBS) $(MEMPHIS_LIBS) $(top_builddir)/tidy/libtidy-1.0.la
libchamplain_ CHAMPLAIN_API_VERSION@_la_LDFLAGS = \
-version-info $(LIBRARY_VERSION)\
@@ -137,7 +137,7 @@ AM_CPPFLAGS = \
$(SOUP_CFLAGS) \
$(MEMPHIS_CFLAGS) \
-DDATADIR=\""$(datadir)"\" \
- -I$(top_srcdir)/mx \
+ -I$(top_srcdir)/tidy \
-I$(top_srcdir) \
-DCHAMPLAIN_COMPILATION \
$(WARN_CFLAGS)
@@ -174,7 +174,7 @@ Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_FILES = $(introspection_sources)
Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_INCLUDES = Clutter-1.0 Gtk-3.0 $(memphis_gir_include)
Champlain_ CHAMPLAIN_API_VERSION_NORM@_gir_CFLAGS = \
$(DEPS_CFLAGS) $(SOUP_CFLAGS) $(MEMPHIS_CFLAGS) \
- -I$(top_srcdir)/mx -I$(top_srcdir) -I$(top_builddir) \
+ -I$(top_srcdir)/tidy -I$(top_srcdir) -I$(top_builddir) \
-DCHAMPLAIN_COMPILATION
INTROSPECTION_GIRS += Champlain- CHAMPLAIN_API_VERSION@.gir
diff --git a/champlain/champlain-view.c b/champlain/champlain-view.c
index 5937fba..bfeeb5a 100644
--- a/champlain/champlain-view.c
+++ b/champlain/champlain-view.c
@@ -67,10 +67,10 @@
#include <glib.h>
#include <glib-object.h>
#include <math.h>
-#include <mx-kinetic-scroll-view.h>
-#include <mx-viewport.h>
-#include <mx-adjustment.h>
-#include <mx-scrollable.h>
+#include <tidy-finger-scroll.h>
+#include <tidy-viewport.h>
+#include <tidy-adjustment.h>
+#include <tidy-scrollable.h>
//#define VIEW_LOG
#ifdef VIEW_LOG
@@ -265,7 +265,7 @@ update_viewport (ChamplainView *view,
if (relocate || force_relocate)
{
g_signal_handlers_block_by_func (priv->viewport, G_CALLBACK (viewport_pos_changed_cb), view);
- mx_viewport_set_origin (MX_VIEWPORT (priv->viewport),
+ tidy_viewport_set_origin (TIDY_VIEWPORT (priv->viewport),
priv->viewport_x,
priv->viewport_y,
0);
@@ -285,7 +285,7 @@ update_viewport (ChamplainView *view,
static void
-panning_completed (G_GNUC_UNUSED MxKineticScrollView *scroll,
+panning_completed (G_GNUC_UNUSED TidyFingerScroll *scroll,
ChamplainView *view)
{
DEBUG_LOG ()
@@ -294,7 +294,7 @@ panning_completed (G_GNUC_UNUSED MxKineticScrollView *scroll,
gfloat absolute_x, absolute_y;
gfloat x, y;
- mx_viewport_get_origin (MX_VIEWPORT (priv->viewport), &x, &y, NULL);
+ tidy_viewport_get_origin (TIDY_VIEWPORT (priv->viewport), &x, &y, NULL);
absolute_x = x + priv->anchor_x + priv->viewport_width / 2.0;
absolute_y = y + priv->anchor_y + priv->viewport_height / 2.0;
@@ -332,11 +332,11 @@ resize_viewport (ChamplainView *view)
gdouble lower_y = 0;
gdouble upper_x = G_MAXINT16;
gdouble upper_y = G_MAXINT16;
- MxAdjustment *hadjust, *vadjust;
+ TidyAdjustment *hadjust, *vadjust;
ChamplainViewPrivate *priv = view->priv;
- mx_scrollable_get_adjustments (MX_SCROLLABLE (priv->viewport), &hadjust,
+ tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (priv->viewport), &hadjust,
&vadjust);
if (priv->zoom_level < 8)
@@ -353,7 +353,7 @@ resize_viewport (ChamplainView *view)
/*
* block emmision of signal by priv->viewport with viewport_pos_changed_cb()
- * callback - the signal can be emitted by updating MxAdjustment, but
+ * callback - the signal can be emitted by updating TidyAdjustment, but
* calling the callback now would be a disaster since we don't have updated
* anchor yet
*/
@@ -527,7 +527,7 @@ champlain_view_dispose (GObject *object)
if (priv->kinetic_scroll != NULL)
{
- mx_kinetic_scroll_view_stop (MX_KINETIC_SCROLL_VIEW (priv->kinetic_scroll));
+ tidy_finger_scroll_stop (TIDY_FINGER_SCROLL (priv->kinetic_scroll));
g_object_unref (priv->kinetic_scroll);
priv->kinetic_scroll = NULL;
}
@@ -1019,8 +1019,8 @@ champlain_view_init (ChamplainView *view)
clutter_actor_show (priv->viewport_container);
/* Setup viewport */
- priv->viewport = g_object_ref (mx_viewport_new ());
- mx_bin_set_child (MX_BIN (priv->viewport), priv->viewport_container);
+ priv->viewport = g_object_ref (tidy_viewport_new ());
+ clutter_container_add_actor (CLUTTER_CONTAINER (priv->viewport), priv->viewport_container);
g_object_set (G_OBJECT (priv->viewport), "sync-adjustments", FALSE, NULL);
@@ -1032,7 +1032,7 @@ champlain_view_init (ChamplainView *view)
clutter_actor_raise (priv->user_layers, priv->map_layer);
/* Setup kinetic scroll */
- priv->kinetic_scroll = g_object_ref (mx_kinetic_scroll_view_new ());
+ priv->kinetic_scroll = g_object_ref (tidy_finger_scroll_new (FALSE));
g_signal_connect (priv->kinetic_scroll, "scroll-event",
G_CALLBACK (scroll_event), view);
@@ -1085,7 +1085,7 @@ viewport_pos_changed_cb (G_GNUC_UNUSED GObject *gobject,
ChamplainViewPrivate *priv = view->priv;
gfloat x, y;
- mx_viewport_get_origin (MX_VIEWPORT (priv->viewport), &x, &y, NULL);
+ tidy_viewport_get_origin (TIDY_VIEWPORT (priv->viewport), &x, &y, NULL);
if (fabs (x - priv->viewport_x) > 100 ||
fabs (y - priv->viewport_y) > 100 ||
@@ -2196,7 +2196,7 @@ champlain_view_set_kinetic_mode (ChamplainView *view,
ChamplainViewPrivate *priv = view->priv;
priv->kinetic_mode = kinetic;
- mx_kinetic_scroll_view_set_kinetic_mode (MX_KINETIC_SCROLL_VIEW (priv->kinetic_scroll), kinetic);
+ g_object_set (view->priv->kinetic_scroll, "mode", kinetic, NULL);
}
diff --git a/configure.ac b/configure.ac
index 2bf4f26..d8a9c84 100644
--- a/configure.ac
+++ b/configure.ac
@@ -214,7 +214,7 @@ AC_CONFIG_FILES([build/Makefile
champlain/Makefile
champlain/champlain-version.h
demos/Makefile
- mx/Makefile
+ tidy/Makefile
docs/Makefile
docs/reference/Makefile
docs/reference/version.xml
diff --git a/tidy/Makefile.am b/tidy/Makefile.am
new file mode 100644
index 0000000..b2f0592
--- /dev/null
+++ b/tidy/Makefile.am
@@ -0,0 +1,63 @@
+BUILT_SOURCES =
+CLEANFILES =
+DISTCLEANFILES =
+EXTRA_DIST =
+
+
+tidy_headers_public = \
+ $(srcdir)/tidy-adjustment.h \
+ $(srcdir)/tidy-finger-scroll.h \
+ $(srcdir)/tidy-scrollable.h \
+ $(srcdir)/tidy-scroll-view.h \
+ $(srcdir)/tidy-viewport.h \
+ $(srcdir)/tidy-private.h \
+ $(srcdir)/tidy-debug.h
+
+tidy_sources = \
+ $(srcdir)/tidy-adjustment.c \
+ $(srcdir)/tidy-finger-scroll.c \
+ $(srcdir)/tidy-scroll-view.c \
+ $(srcdir)/tidy-scrollable.c \
+ $(srcdir)/tidy-viewport.c
+
+
+# glib-genmarshal rules
+glib_marshal_list = tidy-marshal.list
+glib_marshal_prefix = _tidy_marshal
+include $(top_srcdir)/build/Makefile.am.marshal
+
+# glib-mkenums rules
+glib_enum_h = tidy-enum-types.h
+glib_enum_c = tidy-enum-types.c
+glib_enum_headers = $(tidy_headers_public)
+include $(top_srcdir)/build/Makefile.am.enums
+
+tidy_headers_built = \
+ tidy-enum-types.h \
+ tidy-marshal.h
+
+tidy_sources_built = \
+ tidy-enum-types.c \
+ tidy-marshal.c
+
+
+libtidy_1_0_la_SOURCES = \
+ $(tidy_headers_public) \
+ $(tidy_sources)
+
+nodist_libtidy_1_0_la_SOURCES = \
+ $(tidy_headers_built) \
+ $(tidy_sources_built)
+
+libtidy_1_0_la_LIBADD = $(DEPS_LIBS)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DPREFIX=\""$(prefix)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DG_LOG_DOMAIN=\"Tidy\" \
+ $(DEPS_CFLAGS) \
+ $(TIDY_DEBUG_CFLAGS)
+
+noinst_LTLIBRARIES = libtidy-1.0.la
diff --git a/tidy/tidy-adjustment.c b/tidy/tidy-adjustment.c
new file mode 100644
index 0000000..cd0417e
--- /dev/null
+++ b/tidy/tidy-adjustment.c
@@ -0,0 +1,643 @@
+/* tidy-adjustment.c: Adjustment object
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>, inspired by GtkAdjustment
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+#include "tidy-adjustment.h"
+#include "tidy-marshal.h"
+#include "tidy-private.h"
+
+G_DEFINE_TYPE (TidyAdjustment, tidy_adjustment, G_TYPE_OBJECT)
+
+#define ADJUSTMENT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentPrivate))
+
+struct _TidyAdjustmentPrivate
+{
+ gdouble lower;
+ gdouble upper;
+ gdouble value;
+ gdouble step_increment;
+ gdouble page_increment;
+ gdouble page_size;
+
+ /* For interpolation */
+ ClutterTimeline *interpolation;
+ gdouble dx;
+ gdouble old_position;
+ gdouble new_position;
+
+ /* For elasticity */
+ gboolean elastic;
+ ClutterAlpha *bounce_alpha;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_LOWER,
+ PROP_UPPER,
+ PROP_VALUE,
+ PROP_STEP_INC,
+ PROP_PAGE_INC,
+ PROP_PAGE_SIZE,
+
+ PROP_ELASTIC,
+};
+
+enum
+{
+ CHANGED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void tidy_adjustment_set_lower (TidyAdjustment *adjustment,
+ gdouble lower);
+static void tidy_adjustment_set_upper (TidyAdjustment *adjustment,
+ gdouble upper);
+static void tidy_adjustment_set_step_increment (TidyAdjustment *adjustment,
+ gdouble step);
+static void tidy_adjustment_set_page_increment (TidyAdjustment *adjustment,
+ gdouble page);
+static void tidy_adjustment_set_page_size (TidyAdjustment *adjustment,
+ gdouble size);
+
+static void
+tidy_adjustment_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyAdjustmentPrivate *priv = TIDY_ADJUSTMENT (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_LOWER:
+ g_value_set_double (value, priv->lower);
+ break;
+
+ case PROP_UPPER:
+ g_value_set_double (value, priv->upper);
+ break;
+
+ case PROP_VALUE:
+ g_value_set_double (value, priv->value);
+ break;
+
+ case PROP_STEP_INC:
+ g_value_set_double (value, priv->step_increment);
+ break;
+
+ case PROP_PAGE_INC:
+ g_value_set_double (value, priv->page_increment);
+ break;
+
+ case PROP_PAGE_SIZE:
+ g_value_set_double (value, priv->page_size);
+ break;
+
+ case PROP_ELASTIC:
+ g_value_set_boolean (value, priv->elastic);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_adjustment_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyAdjustment *adj = TIDY_ADJUSTMENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOWER:
+ tidy_adjustment_set_lower (adj, g_value_get_double (value));
+ break;
+
+ case PROP_UPPER:
+ tidy_adjustment_set_upper (adj, g_value_get_double (value));
+ break;
+
+ case PROP_VALUE:
+ tidy_adjustment_set_value (adj, g_value_get_double (value));
+ break;
+
+ case PROP_STEP_INC:
+ tidy_adjustment_set_step_increment (adj, g_value_get_double (value));
+ break;
+
+ case PROP_PAGE_INC:
+ tidy_adjustment_set_page_increment (adj, g_value_get_double (value));
+ break;
+
+ case PROP_PAGE_SIZE:
+ tidy_adjustment_set_page_size (adj, g_value_get_double (value));
+ break;
+
+ case PROP_ELASTIC:
+ tidy_adjustment_set_elastic (adj, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+stop_interpolation (TidyAdjustment *adjustment)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+ if (priv->interpolation)
+ {
+ clutter_timeline_stop (priv->interpolation);
+ g_object_unref (priv->interpolation);
+ priv->interpolation = NULL;
+
+ if (priv->bounce_alpha)
+ {
+ g_object_unref (priv->bounce_alpha);
+ priv->bounce_alpha = NULL;
+ }
+ }
+}
+
+void
+tidy_adjustment_interpolate_stop (TidyAdjustment *adjustment)
+{
+ stop_interpolation (adjustment);
+}
+
+static void
+tidy_adjustment_dispose (GObject *object)
+{
+ stop_interpolation (TIDY_ADJUSTMENT (object));
+
+ G_OBJECT_CLASS (tidy_adjustment_parent_class)->dispose (object);
+}
+
+static void
+tidy_adjustment_class_init (TidyAdjustmentClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyAdjustmentPrivate));
+
+ object_class->get_property = tidy_adjustment_get_property;
+ object_class->set_property = tidy_adjustment_set_property;
+ object_class->dispose = tidy_adjustment_dispose;
+
+ g_object_class_install_property (object_class,
+ PROP_LOWER,
+ g_param_spec_double ("lower",
+ "Lower",
+ "Lower bound",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_UPPER,
+ g_param_spec_double ("upper",
+ "Upper",
+ "Upper bound",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_VALUE,
+ g_param_spec_double ("value",
+ "Value",
+ "Current value",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_STEP_INC,
+ g_param_spec_double ("step-increment",
+ "Step Increment",
+ "Step increment",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_PAGE_INC,
+ g_param_spec_double ("page-increment",
+ "Page Increment",
+ "Page increment",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_PAGE_SIZE,
+ g_param_spec_double ("page-size",
+ "Page Size",
+ "Page size",
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ 0.0,
+ TIDY_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ELASTIC,
+ g_param_spec_boolean ("elastic",
+ "Elastic",
+ "Make interpolation "
+ "behave in an "
+ "'elastic' way and "
+ "stop clamping value.",
+ FALSE,
+ TIDY_PARAM_READWRITE));
+
+ signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TidyAdjustmentClass, changed),
+ NULL, NULL,
+ _tidy_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+tidy_adjustment_init (TidyAdjustment *self)
+{
+ self->priv = ADJUSTMENT_PRIVATE (self);
+}
+
+TidyAdjustment *
+tidy_adjustment_new (gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size)
+{
+ return g_object_new (TIDY_TYPE_ADJUSTMENT,
+ "value", value,
+ "lower", lower,
+ "upper", upper,
+ "step-increment", step_increment,
+ "page-increment", page_increment,
+ "page-size", page_size,
+ NULL);
+}
+
+gdouble
+tidy_adjustment_get_value (TidyAdjustment *adjustment)
+{
+ g_return_val_if_fail (TIDY_IS_ADJUSTMENT (adjustment), 0.0);
+
+ return adjustment->priv->value;
+}
+
+void
+tidy_adjustment_set_value (TidyAdjustment *adjustment,
+ double value)
+{
+ TidyAdjustmentPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+
+ priv = adjustment->priv;
+
+ stop_interpolation (adjustment);
+
+ if (!priv->elastic)
+ value = CLAMP (value, priv->lower, MAX (priv->lower,
+ priv->upper - priv->page_size));
+
+ if (priv->value != value)
+ {
+ priv->value = value;
+ g_object_notify (G_OBJECT (adjustment), "value");
+ }
+}
+
+void
+tidy_adjustment_clamp_page (TidyAdjustment *adjustment,
+ double lower,
+ double upper)
+{
+ gboolean changed;
+ TidyAdjustmentPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+
+ priv = adjustment->priv;
+
+ stop_interpolation (adjustment);
+
+ lower = CLAMP (lower, priv->lower, priv->upper - priv->page_size);
+ upper = CLAMP (upper, priv->lower + priv->page_size, priv->upper);
+
+ changed = FALSE;
+
+ if (priv->value + priv->page_size > upper)
+ {
+ priv->value = upper - priv->page_size;
+ changed = TRUE;
+ }
+
+ if (priv->value < lower)
+ {
+ priv->value = lower;
+ changed = TRUE;
+ }
+
+ if (changed)
+ g_object_notify (G_OBJECT (adjustment), "value");
+}
+
+static void
+tidy_adjustment_set_lower (TidyAdjustment *adjustment,
+ gdouble lower)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ if (priv->lower != lower)
+ {
+ priv->lower = lower;
+
+ g_signal_emit (adjustment, signals[CHANGED], 0);
+
+ g_object_notify (G_OBJECT (adjustment), "lower");
+
+ tidy_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+ }
+}
+
+static void
+tidy_adjustment_set_upper (TidyAdjustment *adjustment,
+ gdouble upper)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ if (priv->upper != upper)
+ {
+ priv->upper = upper;
+
+ g_signal_emit (adjustment, signals[CHANGED], 0);
+
+ g_object_notify (G_OBJECT (adjustment), "upper");
+
+ tidy_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+ }
+}
+
+static void
+tidy_adjustment_set_step_increment (TidyAdjustment *adjustment,
+ gdouble step)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ if (priv->step_increment != step)
+ {
+ priv->step_increment = step;
+
+ g_signal_emit (adjustment, signals[CHANGED], 0);
+
+ g_object_notify (G_OBJECT (adjustment), "step-increment");
+ }
+}
+
+static void
+tidy_adjustment_set_page_increment (TidyAdjustment *adjustment,
+ gdouble page)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ if (priv->page_increment != page)
+ {
+ priv->page_increment = page;
+
+ g_signal_emit (adjustment, signals[CHANGED], 0);
+
+ g_object_notify (G_OBJECT (adjustment), "page-increment");
+ }
+}
+
+static void
+tidy_adjustment_set_page_size (TidyAdjustment *adjustment,
+ gdouble size)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ if (priv->page_size != size)
+ {
+ priv->page_size = size;
+
+ g_signal_emit (adjustment, signals[CHANGED], 0);
+
+ g_object_notify (G_OBJECT (adjustment), "page_size");
+
+ tidy_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
+ }
+}
+
+void
+tidy_adjustment_get_values (TidyAdjustment *adjustment,
+ gdouble *value,
+ gdouble *lower,
+ gdouble *upper,
+ gdouble *step_increment,
+ gdouble *page_increment,
+ gdouble *page_size)
+{
+ TidyAdjustmentPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_ADJUSTMENT (adjustment));
+
+ priv = adjustment->priv;
+
+ if (lower)
+ *lower = priv->lower;
+
+ if (upper)
+ *upper = priv->upper;
+
+ if (value)
+ *value = tidy_adjustment_get_value (adjustment);
+
+ if (step_increment)
+ *step_increment = priv->step_increment;
+
+ if (page_increment)
+ *page_increment = priv->page_increment;
+
+ if (page_size)
+ *page_size = priv->page_size;
+}
+
+static void
+interpolation_new_frame_cb (ClutterTimeline *timeline,
+ gint frame_num,
+ TidyAdjustment *adjustment)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ priv->interpolation = NULL;
+ if (priv->elastic && priv->bounce_alpha)
+ {
+ gdouble progress = clutter_alpha_get_alpha (priv->bounce_alpha) / 1;
+ gdouble dx = priv->old_position +
+ (priv->new_position - priv->old_position) *
+ progress;
+ tidy_adjustment_set_value (adjustment, dx);
+ }
+ else
+ tidy_adjustment_set_value (adjustment,
+ priv->old_position +
+ frame_num * priv->dx);
+ priv->interpolation = timeline;
+}
+
+static void
+interpolation_completed_cb (ClutterTimeline *timeline,
+ TidyAdjustment *adjustment)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ stop_interpolation (adjustment);
+ tidy_adjustment_set_value (adjustment,
+ priv->new_position);
+}
+
+/* Note, there's super-optimal code that does a similar thing in
+ * clutter-alpha.c
+ *
+ * Tried this instead of CLUTTER_ALPHA_SINE_INC, but I think SINE_INC looks
+ * better. Leaving code here in case this is revisited.
+ */
+/*
+static guint32
+bounce_alpha_func (ClutterAlpha *alpha,
+ gpointer user_data)
+{
+ gdouble progress, angle;
+ ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
+
+ progress = clutter_timeline_get_progressx (timeline);
+ angle = clutter_qmulx (CFX_PI_2 + CFX_PI_4/2, progress);
+
+ return clutter_sinx (angle) +
+ (CFX_ONE - clutter_sinx (CFX_PI_2 + CFX_PI_4/2));
+}
+*/
+
+void
+tidy_adjustment_interpolate (TidyAdjustment *adjustment,
+ gdouble value,
+ guint n_frames,
+ guint fps)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+
+ stop_interpolation (adjustment);
+
+ if (n_frames <= 1)
+ {
+ tidy_adjustment_set_value (adjustment, value);
+ return;
+ }
+
+ priv->old_position = priv->value;
+ priv->new_position = value;
+
+ priv->dx = (priv->new_position - priv->old_position) * n_frames;
+ priv->interpolation = clutter_timeline_new (((float)n_frames / fps) * 1000);
+
+ if (priv->elastic)
+ priv->bounce_alpha = clutter_alpha_new_full (priv->interpolation,
+ CLUTTER_EASE_OUT_SINE);
+
+ g_signal_connect (priv->interpolation,
+ "new-frame",
+ G_CALLBACK (interpolation_new_frame_cb),
+ adjustment);
+ g_signal_connect (priv->interpolation,
+ "completed",
+ G_CALLBACK (interpolation_completed_cb),
+ adjustment);
+
+ clutter_timeline_start (priv->interpolation);
+}
+
+gboolean
+tidy_adjustment_get_elastic (TidyAdjustment *adjustment)
+{
+ return adjustment->priv->elastic;
+}
+
+void
+tidy_adjustment_set_elastic (TidyAdjustment *adjustment,
+ gboolean elastic)
+{
+ adjustment->priv->elastic = elastic;
+}
+
+gboolean
+tidy_adjustment_clamp (TidyAdjustment *adjustment,
+ gboolean interpolate,
+ guint n_frames,
+ guint fps)
+{
+ TidyAdjustmentPrivate *priv = adjustment->priv;
+ gdouble dest = priv->value;
+
+ if (priv->value < priv->lower)
+ dest = priv->lower;
+ if (priv->value > priv->upper - priv->page_size)
+ dest = priv->upper - priv->page_size;
+
+ if (dest != priv->value)
+ {
+ if (interpolate)
+ tidy_adjustment_interpolate (adjustment,
+ dest,
+ n_frames,
+ fps);
+ else
+ tidy_adjustment_set_value (adjustment, dest);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/tidy/tidy-adjustment.h b/tidy/tidy-adjustment.h
new file mode 100644
index 0000000..3215354
--- /dev/null
+++ b/tidy/tidy-adjustment.h
@@ -0,0 +1,119 @@
+/* tidy-adjustment.h: Adjustment object
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>, inspired by GtkAdjustment
+ */
+
+#ifndef __TIDY_ADJUSTMENT_H__
+#define __TIDY_ADJUSTMENT_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_ADJUSTMENT (tidy_adjustment_get_type())
+#define TIDY_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_ADJUSTMENT, TidyAdjustment))
+#define TIDY_IS_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_ADJUSTMENT))
+#define TIDY_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentClass))
+#define TIDY_IS_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_ADJUSTMENT))
+#define TIDY_ADJUSTMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_ADJUSTMENT, TidyAdjustmentClass))
+
+typedef struct _TidyAdjustment TidyAdjustment;
+typedef struct _TidyAdjustmentPrivate TidyAdjustmentPrivate;
+typedef struct _TidyAdjustmentClass TidyAdjustmentClass;
+
+/**
+ * TidyAdjustment:
+ *
+ * Class for handling an interval between to values. The contents of
+ * the #TidyAdjustment are private and should be accessed using the
+ * public API.
+ */
+struct _TidyAdjustment
+{
+ /*< private >*/
+ GObject parent_instance;
+
+ TidyAdjustmentPrivate *priv;
+};
+
+/**
+ * TidyAdjustmentClass
+ * @changed: Class handler for the ::changed signal.
+ *
+ * Base class for #TidyAdjustment.
+ */
+struct _TidyAdjustmentClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+ void (* changed) (TidyAdjustment *adjustment);
+};
+
+GType tidy_adjustment_get_type (void) G_GNUC_CONST;
+
+TidyAdjustment *tidy_adjustment_new (gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size);
+gdouble tidy_adjustment_get_value (TidyAdjustment *adjustment);
+void tidy_adjustment_set_value (TidyAdjustment *adjustment,
+ gdouble value);
+void tidy_adjustment_clamp_page (TidyAdjustment *adjustment,
+ gdouble lower,
+ gdouble upper);
+void tidy_adjustment_set_values (TidyAdjustment *adjustment,
+ gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size);
+void tidy_adjustment_get_values (TidyAdjustment *adjustment,
+ gdouble *value,
+ gdouble *lower,
+ gdouble *upper,
+ gdouble *step_increment,
+ gdouble *page_increment,
+ gdouble *page_size);
+
+void tidy_adjustment_interpolate (TidyAdjustment *adjustment,
+ gdouble value,
+ guint n_frames,
+ guint fps);
+
+gboolean tidy_adjustment_get_elastic (TidyAdjustment *adjustment);
+void tidy_adjustment_set_elastic (TidyAdjustment *adjustment,
+ gboolean elastic);
+
+gboolean tidy_adjustment_clamp (TidyAdjustment *adjustment,
+ gboolean interpolate,
+ guint n_frames,
+ guint fps);
+void tidy_adjustment_interpolate_stop (TidyAdjustment *adjustment);
+
+G_END_DECLS
+
+#endif /* __TIDY_ADJUSTMENT_H__ */
+
diff --git a/tidy/tidy-debug.h b/tidy/tidy-debug.h
new file mode 100644
index 0000000..0efb982
--- /dev/null
+++ b/tidy/tidy-debug.h
@@ -0,0 +1,4 @@
+#ifndef __TIDY_DEBUG_H__
+#define __TIDY_DEBUG_H__
+
+#endif /* __TIDY_DEBUG_H__ */
diff --git a/mx/mx-enum-types.c.in b/tidy/tidy-enum-types.c.in
similarity index 95%
rename from mx/mx-enum-types.c.in
rename to tidy/tidy-enum-types.c.in
index 7af6194..5f78912 100644
--- a/mx/mx-enum-types.c.in
+++ b/tidy/tidy-enum-types.c.in
@@ -1,5 +1,5 @@
/*** BEGIN file-header ***/
-#include "mx-enum-types.h"
+#include "tidy-enum-types.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
diff --git a/mx/mx-enum-types.h.in b/tidy/tidy-enum-types.h.in
similarity index 70%
rename from mx/mx-enum-types.h.in
rename to tidy/tidy-enum-types.h.in
index 49bce41..517cccb 100644
--- a/mx/mx-enum-types.h.in
+++ b/tidy/tidy-enum-types.h.in
@@ -1,6 +1,6 @@
/*** BEGIN file-header ***/
-#ifndef __MX_ENUM_TYPES_H__
-#define __MX_ENUM_TYPES_H__
+#ifndef __TIDY_ENUM_TYPES_H__
+#define __TIDY_ENUM_TYPES_H__
#include <glib-object.h>
@@ -15,11 +15,11 @@ G_BEGIN_DECLS
/*** BEGIN file-tail ***/
G_END_DECLS
-#endif /* !__MX_ENUM_TYPES_H__ */
+#endif /* !__TIDY_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name _get_type (void) G_GNUC_CONST;
-#define MX_TYPE_ ENUMSHORT@ (@enum_name _get_type())
+#define TIDY_TYPE_ ENUMSHORT@ (@enum_name _get_type())
/*** END value-header ***/
diff --git a/tidy/tidy-finger-scroll.c b/tidy/tidy-finger-scroll.c
new file mode 100644
index 0000000..8f2025f
--- /dev/null
+++ b/tidy/tidy-finger-scroll.c
@@ -0,0 +1,694 @@
+/* tidy-finger-scroll.c: Finger scrolling container actor
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#include "tidy-finger-scroll.h"
+#include "tidy-enum-types.h"
+#include "tidy-marshal.h"
+#include "tidy-scrollable.h"
+#include "tidy-scroll-view.h"
+#include <clutter/clutter.h>
+#include <math.h>
+
+G_DEFINE_TYPE (TidyFingerScroll, tidy_finger_scroll, TIDY_TYPE_SCROLL_VIEW)
+
+#define FINGER_SCROLL_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ TIDY_TYPE_FINGER_SCROLL, \
+ TidyFingerScrollPrivate))
+
+typedef struct {
+ /* Units to store the origin of a click when scrolling */
+ gfloat x;
+ gfloat y;
+ GTimeVal time;
+} TidyFingerScrollMotion;
+
+struct _TidyFingerScrollPrivate
+{
+ /* Scroll mode */
+ gboolean kinetic;
+
+ GArray *motion_buffer;
+ guint last_motion;
+
+ /* Variables for storing acceleration information for kinetic mode */
+ ClutterTimeline *deceleration_timeline;
+ gdouble dx;
+ gdouble dy;
+ gdouble decel_rate;
+
+};
+
+enum {
+ PROP_MODE = 1,
+ PROP_DECEL_RATE,
+ PROP_BUFFER,
+};
+
+enum
+{
+ /* normal signals */
+ PANNING_COMPLETED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static void
+tidy_finger_scroll_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+
+ switch (property_id)
+ {
+ case PROP_MODE :
+ g_value_set_boolean (value, priv->kinetic);
+ break;
+ case PROP_DECEL_RATE :
+ g_value_set_double (value, priv->decel_rate);
+ break;
+ case PROP_BUFFER :
+ g_value_set_uint (value, priv->motion_buffer->len);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+tidy_finger_scroll_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+
+ switch (property_id)
+ {
+ case PROP_MODE :
+ priv->kinetic = g_value_get_boolean (value);
+ g_object_notify (object, "mode");
+ break;
+ case PROP_DECEL_RATE :
+ priv->decel_rate = g_value_get_double (value);
+ g_object_notify (object, "decel-rate");
+ break;
+ case PROP_BUFFER :
+ g_array_set_size (priv->motion_buffer, g_value_get_uint (value));
+ g_object_notify (object, "motion-buffer");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+tidy_finger_scroll_dispose (GObject *object)
+{
+ TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+
+ if (priv->deceleration_timeline)
+ {
+ clutter_timeline_stop (priv->deceleration_timeline);
+ g_object_unref (priv->deceleration_timeline);
+ priv->deceleration_timeline = NULL;
+ }
+
+ G_OBJECT_CLASS (tidy_finger_scroll_parent_class)->dispose (object);
+}
+
+static void
+tidy_finger_scroll_finalize (GObject *object)
+{
+ TidyFingerScrollPrivate *priv = TIDY_FINGER_SCROLL (object)->priv;
+
+ g_array_free (priv->motion_buffer, TRUE);
+
+ G_OBJECT_CLASS (tidy_finger_scroll_parent_class)->finalize (object);
+}
+
+
+static void
+tidy_finger_scroll_class_init (TidyFingerScrollClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyFingerScrollPrivate));
+
+ object_class->get_property = tidy_finger_scroll_get_property;
+ object_class->set_property = tidy_finger_scroll_set_property;
+ object_class->dispose = tidy_finger_scroll_dispose;
+ object_class->finalize = tidy_finger_scroll_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_MODE,
+ g_param_spec_boolean ("mode",
+ "TidyFingerScrollMode",
+ "Scrolling mode",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_DECEL_RATE,
+ g_param_spec_double ("decel-rate",
+ "Deceleration rate",
+ "Rate at which the view "
+ "will decelerate in "
+ "kinetic mode.",
+ G_MINFLOAT + 1,
+ G_MAXFLOAT,
+ 1.1,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_BUFFER,
+ g_param_spec_uint ("motion-buffer",
+ "Motion buffer",
+ "Amount of motion "
+ "events to buffer",
+ 1, G_MAXUINT, 3,
+ G_PARAM_READWRITE));
+
+ signals[PANNING_COMPLETED] =
+ g_signal_new ("panning-completed", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+static gboolean
+motion_event_cb (ClutterActor *actor,
+ ClutterMotionEvent *event,
+ TidyFingerScroll *scroll)
+{
+ gfloat x, y;
+
+ TidyFingerScrollPrivate *priv = scroll->priv;
+
+ if (clutter_actor_transform_stage_point (actor,
+ event->x,
+ event->y,
+ &x, &y))
+ {
+ TidyFingerScrollMotion *motion;
+ ClutterActor *child =
+ tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+
+ if (child)
+ {
+ gdouble dx, dy;
+ TidyAdjustment *hadjust, *vadjust;
+
+ tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+ &hadjust,
+ &vadjust);
+
+ motion = &g_array_index (priv->motion_buffer,
+ TidyFingerScrollMotion, priv->last_motion);
+ dx = (motion->x - x) +
+ tidy_adjustment_get_value (hadjust);
+ dy = (motion->y - y) +
+ tidy_adjustment_get_value (vadjust);
+
+ tidy_adjustment_set_value (hadjust, dx);
+ tidy_adjustment_set_value (vadjust, dy);
+ }
+
+ priv->last_motion ++;
+ if (priv->last_motion == priv->motion_buffer->len)
+ {
+ priv->motion_buffer = g_array_remove_index (priv->motion_buffer, 0);
+ g_array_set_size (priv->motion_buffer, priv->last_motion);
+ priv->last_motion --;
+ }
+
+ motion = &g_array_index (priv->motion_buffer,
+ TidyFingerScrollMotion, priv->last_motion);
+ motion->x = x;
+ motion->y = y;
+ g_get_current_time (&motion->time);
+ }
+
+ return TRUE;
+}
+
+static void
+clamp_adjustments (TidyFingerScroll *scroll)
+{
+ ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW (scroll));
+
+ if (child)
+ {
+ guint fps, n_frames;
+ TidyAdjustment *hadj, *vadj;
+ gboolean snap;
+
+ tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+ &hadj, &vadj);
+
+ /* FIXME: Hard-coded value here */
+ fps = clutter_get_default_frame_rate ();
+ n_frames = fps / 6;
+
+ snap = TRUE;
+ if (tidy_adjustment_get_elastic (hadj))
+ snap = !tidy_adjustment_clamp (hadj, TRUE, n_frames, fps);
+
+ /* Snap to the nearest step increment on hadjustment */
+ if (snap)
+ {
+ gdouble d, value, lower, step_increment;
+
+ tidy_adjustment_get_values (hadj, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = (rint ((value - lower) / step_increment) *
+ step_increment) + lower;
+ tidy_adjustment_set_value (hadj, d);
+ }
+
+ snap = TRUE;
+ if (tidy_adjustment_get_elastic (vadj))
+ snap = !tidy_adjustment_clamp (vadj, TRUE, n_frames, fps);
+
+ /* Snap to the nearest step increment on vadjustment */
+ if (snap)
+ {
+ gdouble d, value, lower, step_increment;
+
+ tidy_adjustment_get_values (vadj, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = (rint ((value - lower) / step_increment) *
+ step_increment) + lower;
+ tidy_adjustment_set_value (vadj, d);
+ }
+ }
+}
+
+static void
+deceleration_completed_cb (ClutterTimeline *timeline,
+ TidyFingerScroll *scroll)
+{
+ clamp_adjustments (scroll);
+ g_object_unref (timeline);
+ scroll->priv->deceleration_timeline = NULL;
+
+ g_signal_emit_by_name (scroll, "panning-completed", NULL);
+}
+
+static void
+deceleration_new_frame_cb (ClutterTimeline *timeline,
+ gint frame_num,
+ TidyFingerScroll *scroll)
+{
+ TidyFingerScrollPrivate *priv = scroll->priv;
+ ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+
+ if (child)
+ {
+ gdouble value, lower, upper, page_size;
+ TidyAdjustment *hadjust, *vadjust;
+ gint i;
+ gboolean stop = TRUE;
+
+ tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+ &hadjust,
+ &vadjust);
+
+ for (i = 0; i < clutter_timeline_get_delta (timeline) / 15; i++)
+ {
+ tidy_adjustment_set_value (hadjust,
+ priv->dx +
+ tidy_adjustment_get_value (hadjust));
+ tidy_adjustment_set_value (vadjust,
+ priv->dy +
+ tidy_adjustment_get_value (vadjust));
+ priv->dx = (priv->dx / priv->decel_rate);
+ priv->dy = (priv->dy / priv->decel_rate);
+ }
+
+ /* Check if we've hit the upper or lower bounds and stop the timeline */
+ tidy_adjustment_get_values (hadjust, &value, &lower, &upper,
+ NULL, NULL, &page_size);
+ if (((priv->dx > 0) && (value < upper - page_size)) ||
+ ((priv->dx < 0) && (value > lower)))
+ stop = FALSE;
+
+ if (stop)
+ {
+ tidy_adjustment_get_values (vadjust, &value, &lower, &upper,
+ NULL, NULL, &page_size);
+ if (((priv->dy > 0) && (value < upper - page_size)) ||
+ ((priv->dy < 0) && (value > lower)))
+ stop = FALSE;
+ }
+
+ if (stop)
+ {
+ clutter_timeline_stop (timeline);
+ deceleration_completed_cb (timeline, scroll);
+ }
+ }
+}
+
+static gboolean
+button_release_event_cb (ClutterActor *actor,
+ ClutterButtonEvent *event,
+ TidyFingerScroll *scroll)
+{
+ TidyFingerScrollPrivate *priv = scroll->priv;
+ ClutterActor *child = tidy_scroll_view_get_child (TIDY_SCROLL_VIEW(scroll));
+ gboolean decelerating = FALSE;
+ gboolean moved = TRUE;
+
+ if (event->button != 1)
+ return FALSE;
+
+ g_signal_handlers_disconnect_by_func (actor,
+ motion_event_cb,
+ scroll);
+ g_signal_handlers_disconnect_by_func (actor,
+ button_release_event_cb,
+ scroll);
+
+ clutter_ungrab_pointer ();
+
+ if (priv->kinetic && child)
+ {
+ gfloat x, y;
+
+ if (clutter_actor_transform_stage_point (actor,
+ event->x,
+ event->y,
+ &x, &y))
+ {
+ double frac, x_origin, y_origin;
+ GTimeVal release_time, motion_time;
+ TidyAdjustment *hadjust, *vadjust;
+ glong time_diff;
+ gint i;
+
+ /* Get time delta */
+ g_get_current_time (&release_time);
+
+ /* Get average position/time of last x mouse events */
+ priv->last_motion ++;
+ x_origin = y_origin = 0;
+ motion_time = (GTimeVal){ 0, 0 };
+ for (i = 0; i < priv->last_motion; i++)
+ {
+ TidyFingerScrollMotion *motion =
+ &g_array_index (priv->motion_buffer, TidyFingerScrollMotion, i);
+
+ /* FIXME: This doesn't guard against overflows - Should
+ * either fix that, or calculate the correct maximum
+ * value for the buffer size
+ */
+
+ x_origin += motion->x;
+ y_origin += motion->y;
+ motion_time.tv_sec += motion->time.tv_sec;
+ motion_time.tv_usec += motion->time.tv_usec;
+ }
+ x_origin /= priv->last_motion;
+ y_origin /= priv->last_motion;
+ motion_time.tv_sec /= priv->last_motion;
+ motion_time.tv_usec /= priv->last_motion;
+
+ if (motion_time.tv_sec == release_time.tv_sec)
+ time_diff = release_time.tv_usec - motion_time.tv_usec;
+ else
+ time_diff = release_time.tv_usec +
+ (G_USEC_PER_SEC - motion_time.tv_usec);
+
+ /* On a macbook that's running Ubuntu 9.04 sometimes 'time_diff' is 0
+ and this causes a division by 0 when computing 'frac'. This check
+ avoids this error.
+ */
+ if (time_diff != 0)
+ {
+ /* Work out the fraction of 1/60th of a second that has elapsed */
+ frac = (time_diff/1000.0) / (1000.0/60.0);
+
+ /* See how many units to move in 1/60th of a second */
+ priv->dx = (x_origin - x) / frac;
+ priv->dy = (y_origin - y) / frac;
+
+ /* Get adjustments to do step-increment snapping */
+ tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (child),
+ &hadjust,
+ &vadjust);
+
+ if (ABS(priv->dx) > 1 ||
+ ABS(priv->dy) > 1)
+ {
+ gdouble value, lower, step_increment, d, a, x, y, n;
+
+ /* TODO: Convert this all to fixed point? */
+
+ /* We want n, where x / y n < z,
+ * x = Distance to move per frame
+ * y = Deceleration rate
+ * z = maximum distance from target
+ *
+ * Rearrange to n = log (x / z) / log (y)
+ * To simplify, z = 1, so n = log (x) / log (y)
+ *
+ * As z = 1, this will cause stops to be slightly abrupt -
+ * add a constant 15 frames to compensate.
+ */
+ x = MAX(ABS(priv->dx), ABS(priv->dy));
+ y = priv->decel_rate;
+ n = logf (x) / logf (y) + 15.0;
+
+ /* Now we have n, adjust dx/dy so that we finish on a step
+ * boundary.
+ *
+ * Distance moved, using the above variable names:
+ *
+ * d = x + x/y + x/y 2 + ... + x/y n
+ *
+ * Using geometric series,
+ *
+ * d = (1 - 1/y (n+1))/(1 - 1/y)*x
+ *
+ * Let a = (1 - 1/y (n+1))/(1 - 1/y),
+ *
+ * d = a * x
+ *
+ * Find d and find its nearest page boundary, then solve for x
+ *
+ * x = d / a
+ */
+
+ /* Get adjustments, work out y n */
+ a = (1.0 - 1.0 / pow (y, n + 1)) / (1.0 - 1.0 / y);
+
+ /* Solving for dx */
+ d = a * priv->dx;
+ tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = ((rint (((value + d) - lower) / step_increment) *
+ step_increment) + lower) - value;
+ priv->dx = (d / a);
+
+ /* Solving for dy */
+ d = a * (priv->dy);
+ tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = ((rint (((value + d) - lower) / step_increment) *
+ step_increment) + lower) - value;
+ priv->dy = (d / a);
+
+ priv->deceleration_timeline = clutter_timeline_new ((n / 60) * 1000.0);
+ }
+ else
+ {
+ gdouble value, lower, step_increment, d, a, y;
+
+ /* Start a short effects timeline to snap to the nearest step
+ * boundary (see equations above)
+ */
+ y = priv->decel_rate;
+ a = (1.0 - 1.0 / pow (y, 4 + 1)) / (1.0 - 1.0 / y);
+
+ tidy_adjustment_get_values (hadjust, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = ((rint ((value - lower) / step_increment) *
+ step_increment) + lower) - value;
+ priv->dx = (d / a);
+
+ tidy_adjustment_get_values (vadjust, &value, &lower, NULL,
+ &step_increment, NULL, NULL);
+ d = ((rint ((value - lower) / step_increment) *
+ step_increment) + lower) - value;
+ priv->dy = (d / a);
+
+ priv->deceleration_timeline = clutter_timeline_new (250);
+ }
+
+ g_signal_connect (priv->deceleration_timeline, "new_frame",
+ G_CALLBACK (deceleration_new_frame_cb), scroll);
+ g_signal_connect (priv->deceleration_timeline, "completed",
+ G_CALLBACK (deceleration_completed_cb), scroll);
+ clutter_timeline_start (priv->deceleration_timeline);
+ decelerating = TRUE;
+ }
+ }
+ }
+
+ /* Reset motion event buffer */
+ if (priv->last_motion <= 1)
+ moved = FALSE;
+ priv->last_motion = 0;
+
+ if (!decelerating)
+ {
+ clamp_adjustments (scroll);
+ g_signal_emit_by_name (scroll, "panning-completed", NULL);
+ }
+
+ /* Pass through events to children.
+ * FIXME: this probably breaks click-count.
+ */
+ if (!moved)
+ clutter_event_put ((ClutterEvent *)event);
+
+ return moved;
+}
+
+static gboolean
+after_event_cb (TidyFingerScroll *scroll)
+{
+ /* Check the pointer grab - if something else has grabbed it - for example,
+ * a scroll-bar or some such, don't do our funky stuff.
+ */
+ if (clutter_get_pointer_grab () != CLUTTER_ACTOR (scroll))
+ {
+ g_signal_handlers_disconnect_by_func (scroll,
+ motion_event_cb,
+ scroll);
+ g_signal_handlers_disconnect_by_func (scroll,
+ button_release_event_cb,
+ scroll);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+captured_event_cb (ClutterActor *actor,
+ ClutterEvent *event,
+ TidyFingerScroll *scroll)
+{
+ TidyFingerScrollPrivate *priv = scroll->priv;
+
+ if (event->type == CLUTTER_BUTTON_PRESS)
+ {
+ TidyFingerScrollMotion *motion;
+ ClutterButtonEvent *bevent = (ClutterButtonEvent *)event;
+
+ if (bevent->source != actor)
+ return FALSE;
+
+ /* Reset motion buffer */
+ priv->last_motion = 0;
+ motion = &g_array_index (priv->motion_buffer, TidyFingerScrollMotion, 0);
+
+ if ((bevent->button == 1) &&
+ (clutter_actor_transform_stage_point (actor,
+ bevent->x,
+ bevent->y,
+ &motion->x, &motion->y)))
+ {
+ g_get_current_time (&motion->time);
+
+ if (priv->deceleration_timeline)
+ {
+ clutter_timeline_stop (priv->deceleration_timeline);
+ g_object_unref (priv->deceleration_timeline);
+ priv->deceleration_timeline = NULL;
+ }
+
+ clutter_grab_pointer (actor);
+
+ /* Add a high priority idle to check the grab after the event
+ * emission is finished.
+ */
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+ (GSourceFunc)after_event_cb,
+ scroll,
+ NULL);
+
+ g_signal_connect (actor,
+ "motion-event",
+ G_CALLBACK (motion_event_cb),
+ scroll);
+ g_signal_connect (actor,
+ "button-release-event",
+ G_CALLBACK (button_release_event_cb),
+ scroll);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+tidy_finger_scroll_init (TidyFingerScroll *self)
+{
+ ClutterActor *scrollbar;
+ TidyFingerScrollPrivate *priv = self->priv = FINGER_SCROLL_PRIVATE (self);
+
+ priv->motion_buffer = g_array_sized_new (FALSE, TRUE,
+ sizeof (TidyFingerScrollMotion), 3);
+ g_array_set_size (priv->motion_buffer, 3);
+ priv->decel_rate = 1.1f;
+
+ clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
+ g_signal_connect (CLUTTER_ACTOR (self),
+ "captured-event",
+ G_CALLBACK (captured_event_cb),
+ self);
+
+
+}
+
+ClutterActor *
+tidy_finger_scroll_new (gboolean kinetic)
+{
+ return CLUTTER_ACTOR (g_object_new (TIDY_TYPE_FINGER_SCROLL,
+ "mode", kinetic, NULL));
+}
+
+void
+tidy_finger_scroll_stop (TidyFingerScroll *scroll)
+{
+ TidyFingerScrollPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_FINGER_SCROLL (scroll));
+
+ priv = scroll->priv;
+
+ if (priv->deceleration_timeline)
+ {
+ clutter_timeline_stop (priv->deceleration_timeline);
+ g_object_unref (priv->deceleration_timeline);
+ priv->deceleration_timeline = NULL;
+ }
+}
diff --git a/tidy/tidy-finger-scroll.h b/tidy/tidy-finger-scroll.h
new file mode 100644
index 0000000..6dd3cb9
--- /dev/null
+++ b/tidy/tidy-finger-scroll.h
@@ -0,0 +1,64 @@
+/* tidy-finger-scroll.h: Finger scrolling container actor
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#ifndef __TIDY_FINGER_SCROLL_H__
+#define __TIDY_FINGER_SCROLL_H__
+
+#include <glib-object.h>
+#include <tidy/tidy-scroll-view.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_FINGER_SCROLL (tidy_finger_scroll_get_type())
+#define TIDY_FINGER_SCROLL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_FINGER_SCROLL, TidyFingerScroll))
+#define TIDY_IS_FINGER_SCROLL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_FINGER_SCROLL))
+#define TIDY_FINGER_SCROLL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_FINGER_SCROLL, TidyFingerScrollClass))
+#define TIDY_IS_FINGER_SCROLL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_FINGER_SCROLL))
+#define TIDY_FINGER_SCROLL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_FINGER_SCROLL, TidyFingerScrollClass))
+
+
+typedef struct _TidyFingerScroll TidyFingerScroll;
+typedef struct _TidyFingerScrollPrivate TidyFingerScrollPrivate;
+typedef struct _TidyFingerScrollClass TidyFingerScrollClass;
+
+struct _TidyFingerScroll
+{
+ /*< private >*/
+ TidyScrollView parent_instance;
+
+ TidyFingerScrollPrivate *priv;
+};
+
+struct _TidyFingerScrollClass
+{
+ TidyScrollViewClass parent_class;
+};
+
+GType tidy_finger_scroll_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_finger_scroll_new (gboolean kinetic);
+
+void tidy_finger_scroll_stop (TidyFingerScroll *scroll);
+
+G_END_DECLS
+
+#endif /* __TIDY_FINGER_SCROLL_H__ */
diff --git a/tidy/tidy-marshal.list b/tidy/tidy-marshal.list
new file mode 100644
index 0000000..7a60e80
--- /dev/null
+++ b/tidy/tidy-marshal.list
@@ -0,0 +1,6 @@
+VOID:OBJECT
+VOID:VOID
+VOID:PARAM
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,OBJECT
diff --git a/mx/mx-private.h b/tidy/tidy-private.h
similarity index 82%
rename from mx/mx-private.h
rename to tidy/tidy-private.h
index b18eaf3..5f17d93 100644
--- a/mx/mx-private.h
+++ b/tidy/tidy-private.h
@@ -1,4 +1,4 @@
-/* mx-private.h: Private declarations
+/* tidy-private.h: Private declarations
*
* Copyright (C) 2007 OpenedHand
*
@@ -18,8 +18,8 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef __MX_PRIVATE_H__
-#define __MX_PRIVATE_H__
+#ifndef __TIDY_PRIVATE_H__
+#define __TIDY_PRIVATE_H__
#include <glib.h>
@@ -27,14 +27,14 @@ G_BEGIN_DECLS
#define I_(str) (g_intern_static_string ((str)))
-#define MX_PARAM_READWRITE \
- (G_PARAM_READABLE | G_PARAM_WRITABLE | \
+#define TIDY_PARAM_READABLE \
+ (G_PARAM_READABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
-#define MX_PARAM_READWRITE \
+#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 /* __MX_PRIVATE_H__ */
+#endif /* __TIDY_PRIVATE_H__ */
diff --git a/tidy/tidy-scroll-view.c b/tidy/tidy-scroll-view.c
new file mode 100644
index 0000000..82487b5
--- /dev/null
+++ b/tidy/tidy-scroll-view.c
@@ -0,0 +1,339 @@
+/* tidy-scroll-view.h: Container with scroll-bars
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#include "tidy-scroll-view.h"
+#include "tidy-marshal.h"
+#include "tidy-scrollable.h"
+#include <clutter/clutter.h>
+
+static void clutter_container_iface_init (ClutterContainerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (TidyScrollView, tidy_scroll_view, CLUTTER_TYPE_ACTOR,
+ G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
+ clutter_container_iface_init))
+
+#define SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+ TIDY_TYPE_SCROLL_VIEW, \
+ TidyScrollViewPrivate))
+
+struct _TidyScrollViewPrivate
+{
+ ClutterActor *child;
+};
+
+enum {
+ PROP_0,
+ PROP_CHILD,
+};
+
+static void
+tidy_scroll_view_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ TidyScrollViewPrivate *priv = ((TidyScrollView *)object)->priv;
+
+ switch (property_id)
+ {
+ case PROP_CHILD :
+ g_value_set_object (value, priv->child);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+tidy_scroll_view_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ switch (property_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+tidy_scroll_view_dispose (GObject *object)
+{
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (object)->priv;
+
+ if (priv->child)
+ clutter_container_remove_actor (CLUTTER_CONTAINER (object), priv->child);
+
+ G_OBJECT_CLASS (tidy_scroll_view_parent_class)->dispose (object);
+}
+
+static void
+tidy_scroll_view_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (tidy_scroll_view_parent_class)->finalize (object);
+}
+
+static void
+tidy_scroll_view_paint (ClutterActor *actor)
+{
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+
+ if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
+ clutter_actor_paint (priv->child);
+}
+
+static void
+tidy_scroll_view_pick (ClutterActor *actor, const ClutterColor *color)
+{
+ /* Chain up so we get a bounding box pained (if we are reactive) */
+ CLUTTER_ACTOR_CLASS (tidy_scroll_view_parent_class)->pick (actor, color);
+
+ /* Trigger pick on children */
+ tidy_scroll_view_paint (actor);
+}
+
+static void
+tidy_scroll_view_get_preferred_width (ClutterActor *actor,
+ gfloat for_height,
+ gfloat *min_width_p,
+ gfloat *natural_width_p)
+{
+
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+
+ if (!priv->child)
+ return;
+
+
+ /* Our natural width is the natural width of the child */
+ clutter_actor_get_preferred_width (priv->child,
+ for_height,
+ NULL,
+ natural_width_p);
+
+}
+
+static void
+tidy_scroll_view_get_preferred_height (ClutterActor *actor,
+ gfloat for_width,
+ gfloat *min_height_p,
+ gfloat *natural_height_p)
+{
+
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+
+ if (!priv->child)
+ return;
+
+
+ /* Our natural height is the natural height of the child */
+ clutter_actor_get_preferred_height (priv->child,
+ for_width,
+ NULL,
+ natural_height_p);
+}
+
+static void
+tidy_scroll_view_allocate (ClutterActor *actor,
+ const ClutterActorBox *box,
+ ClutterAllocationFlags flags)
+{
+ ClutterActorBox child_box;
+
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (actor)->priv;
+
+ /* Chain up */
+ CLUTTER_ACTOR_CLASS (tidy_scroll_view_parent_class)->
+ allocate (actor, box, flags);
+
+ /* Child */
+ child_box.x1 = 0;
+ child_box.x2 = box->x2 - box->x1;
+ child_box.y1 = 0;
+ child_box.y2 = box->y2 - box->y1;
+
+ if (priv->child)
+ {
+ clutter_actor_allocate (priv->child, &child_box, flags);
+ clutter_actor_set_clip (priv->child,
+ child_box.x1,
+ child_box.y1,
+ child_box.x2 - child_box.x1,
+ child_box.y2 - child_box.y1);
+ }
+
+}
+
+static void
+tidy_scroll_view_class_init (TidyScrollViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyScrollViewPrivate));
+
+ object_class->get_property = tidy_scroll_view_get_property;
+ object_class->set_property = tidy_scroll_view_set_property;
+ object_class->dispose= tidy_scroll_view_dispose;
+ object_class->finalize = tidy_scroll_view_finalize;
+
+ actor_class->paint = tidy_scroll_view_paint;
+ actor_class->pick = tidy_scroll_view_pick;
+ actor_class->get_preferred_width = tidy_scroll_view_get_preferred_width;
+ actor_class->get_preferred_height = tidy_scroll_view_get_preferred_height;
+ actor_class->allocate = tidy_scroll_view_allocate;
+
+ g_object_class_install_property (object_class,
+ PROP_CHILD,
+ g_param_spec_object ("child",
+ "ClutterActor",
+ "Child actor",
+ CLUTTER_TYPE_ACTOR,
+ G_PARAM_READABLE));
+}
+
+static void
+tidy_scroll_view_init (TidyScrollView *self)
+{
+ self->priv = SCROLL_VIEW_PRIVATE (self);
+}
+
+static void
+tidy_scroll_view_add_actor (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyScrollView *self = TIDY_SCROLL_VIEW (container);
+ TidyScrollViewPrivate *priv = self->priv;
+
+ if (priv->child)
+ {
+ g_warning ("Attempting to add an actor of type %s to "
+ "a TidyScrollView that already contains "
+ "an actor of type %s.",
+ g_type_name (G_OBJECT_TYPE (actor)),
+ g_type_name (G_OBJECT_TYPE (priv->child)));
+ }
+ else
+ {
+ if (TIDY_IS_SCROLLABLE(actor))
+ {
+ priv->child = actor;
+ clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
+
+ /* Notify that child has been set */
+ g_signal_emit_by_name (container, "actor-added", priv->child);
+ g_object_notify (G_OBJECT (container), "child");
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+ }
+ else
+ {
+ g_warning ("Attempting to add an actor to "
+ "a TidyScrollView, but the actor does "
+ "not implement TidyScrollable.");
+ }
+ }
+}
+
+static void
+tidy_scroll_view_remove_actor (ClutterContainer *container,
+ ClutterActor *actor)
+{
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (container)->priv;
+
+ if (actor == priv->child)
+ {
+ g_object_ref (priv->child);
+
+
+ clutter_actor_unparent (priv->child);
+
+ g_signal_emit_by_name (container, "actor-removed", priv->child);
+
+ g_object_unref (priv->child);
+ priv->child = NULL;
+
+ g_object_notify (G_OBJECT (container), "child");
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (container))
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
+ }
+}
+
+static void
+tidy_scroll_view_foreach (ClutterContainer *container,
+ ClutterCallback callback,
+ gpointer callback_data)
+{
+ TidyScrollViewPrivate *priv = TIDY_SCROLL_VIEW (container)->priv;
+
+ if (priv->child)
+ callback (priv->child, callback_data);
+}
+
+static void
+tidy_scroll_view_lower (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* single child */
+}
+
+static void
+tidy_scroll_view_raise (ClutterContainer *container,
+ ClutterActor *actor,
+ ClutterActor *sibling)
+{
+ /* single child */
+}
+
+static void
+tidy_scroll_view_sort_depth_order (ClutterContainer *container)
+{
+ /* single child */
+}
+
+static void
+clutter_container_iface_init (ClutterContainerIface *iface)
+{
+ iface->add = tidy_scroll_view_add_actor;
+ iface->remove = tidy_scroll_view_remove_actor;
+ iface->foreach = tidy_scroll_view_foreach;
+ iface->lower = tidy_scroll_view_lower;
+ iface->raise = tidy_scroll_view_raise;
+ iface->sort_depth_order = tidy_scroll_view_sort_depth_order;
+}
+
+ClutterActor *
+tidy_scroll_view_new (void)
+{
+ return CLUTTER_ACTOR (g_object_new (TIDY_TYPE_SCROLL_VIEW, NULL));
+}
+
+ClutterActor *
+tidy_scroll_view_get_child (TidyScrollView *scroll)
+{
+ TidyScrollViewPrivate *priv;
+
+ g_return_val_if_fail (TIDY_IS_SCROLL_VIEW (scroll), NULL);
+
+ priv = scroll->priv;
+
+ return priv->child;
+}
diff --git a/tidy/tidy-scroll-view.h b/tidy/tidy-scroll-view.h
new file mode 100644
index 0000000..aabc4d2
--- /dev/null
+++ b/tidy/tidy-scroll-view.h
@@ -0,0 +1,65 @@
+/* tidy-scroll-view.h: Container with scroll-bars
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#ifndef __TIDY_SCROLL_VIEW_H__
+#define __TIDY_SCROLL_VIEW_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_SCROLL_VIEW (tidy_scroll_view_get_type())
+#define TIDY_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_SCROLL_VIEW, TidyScrollView))
+#define TIDY_IS_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_SCROLL_VIEW))
+#define TIDY_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_SCROLL_VIEW, TidyScrollViewClass))
+#define TIDY_IS_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_SCROLL_VIEW))
+#define TIDY_SCROLL_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_SCROLL_VIEW, TidyScrollViewClass))
+
+typedef struct _TidyScrollView TidyScrollView;
+typedef struct _TidyScrollViewPrivate TidyScrollViewPrivate;
+typedef struct _TidyScrollViewClass TidyScrollViewClass;
+
+struct _TidyScrollView
+{
+ /*< private >*/
+ ClutterActor parent;
+
+ TidyScrollViewPrivate *priv;
+};
+
+struct _TidyScrollViewClass
+{
+ ClutterActorClass parent_class;
+};
+
+GType tidy_scroll_view_get_type (void) G_GNUC_CONST;
+
+ClutterActor *tidy_scroll_view_new (void);
+
+ClutterActor *tidy_scroll_view_get_hscroll_bar (TidyScrollView *scroll);
+ClutterActor *tidy_scroll_view_get_vscroll_bar (TidyScrollView *scroll);
+ClutterActor *tidy_scroll_view_get_child (TidyScrollView *scroll);
+
+G_END_DECLS
+
+#endif /* __TIDY_SCROLL_VIEW_H__ */
diff --git a/tidy/tidy-scrollable.c b/tidy/tidy-scrollable.c
new file mode 100644
index 0000000..6f6545f
--- /dev/null
+++ b/tidy/tidy-scrollable.c
@@ -0,0 +1,87 @@
+/* tidy-scrollable.c: Scrollable interface
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#include "tidy-scrollable.h"
+
+static void
+tidy_scrollable_base_init (gpointer g_iface)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized)
+ {
+ g_object_interface_install_property (g_iface,
+ g_param_spec_object ("hadjustment",
+ "TidyAdjustment",
+ "Horizontal adjustment",
+ TIDY_TYPE_ADJUSTMENT,
+ G_PARAM_READWRITE));
+
+ g_object_interface_install_property (g_iface,
+ g_param_spec_object ("vadjustment",
+ "TidyAdjustment",
+ "Vertical adjustment",
+ TIDY_TYPE_ADJUSTMENT,
+ G_PARAM_READWRITE));
+
+ initialized = TRUE;
+ }
+}
+
+GType
+tidy_scrollable_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (TidyScrollableInterface),
+ tidy_scrollable_base_init, /* base_init */
+ NULL,
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ "TidyScrollable", &info, 0);
+ }
+ return type;
+}
+
+void
+tidy_scrollable_set_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment *hadjustment,
+ TidyAdjustment *vadjustment)
+{
+ TIDY_SCROLLABLE_GET_INTERFACE (scrollable)->set_adjustments (scrollable,
+ hadjustment,
+ vadjustment);
+}
+
+void
+tidy_scrollable_get_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment **hadjustment,
+ TidyAdjustment **vadjustment)
+{
+ TIDY_SCROLLABLE_GET_INTERFACE (scrollable)->get_adjustments (scrollable,
+ hadjustment,
+ vadjustment);
+}
+
diff --git a/tidy/tidy-scrollable.h b/tidy/tidy-scrollable.h
new file mode 100644
index 0000000..367e589
--- /dev/null
+++ b/tidy/tidy-scrollable.h
@@ -0,0 +1,63 @@
+/* tidy-scrollable.h: Scrollable interface
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#ifndef __TIDY_SCROLLABLE_H__
+#define __TIDY_SCROLLABLE_H__
+
+#include <glib-object.h>
+#include "tidy-adjustment.h"
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_SCROLLABLE (tidy_scrollable_get_type ())
+#define TIDY_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_SCROLLABLE, TidyScrollable))
+#define TIDY_IS_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_SCROLLABLE))
+#define TIDY_SCROLLABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TIDY_TYPE_SCROLLABLE, TidyScrollableInterface))
+
+typedef struct _TidyScrollable TidyScrollable; /* Dummy object */
+typedef struct _TidyScrollableInterface TidyScrollableInterface;
+
+struct _TidyScrollableInterface
+{
+ GTypeInterface parent;
+
+ void (* set_adjustments) (TidyScrollable *scrollable,
+ TidyAdjustment *hadjustment,
+ TidyAdjustment *vadjustment);
+ void (* get_adjustments) (TidyScrollable *scrollable,
+ TidyAdjustment **hadjustment,
+ TidyAdjustment **vadjustment);
+};
+
+GType tidy_scrollable_get_type (void) G_GNUC_CONST;
+
+void tidy_scrollable_set_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment *hadjustment,
+ TidyAdjustment *vadjustment);
+void tidy_scrollable_get_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment **hadjustment,
+ TidyAdjustment **vadjustment);
+
+G_END_DECLS
+
+#endif /* __TIDY_SCROLLABLE_H__ */
+
diff --git a/tidy/tidy-viewport.c b/tidy/tidy-viewport.c
new file mode 100644
index 0000000..d30d1c5
--- /dev/null
+++ b/tidy/tidy-viewport.c
@@ -0,0 +1,596 @@
+/* tidy-viewport.c: Viewport actor
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+
+#include "tidy-viewport.h"
+#include "tidy-adjustment.h"
+#include "tidy-scrollable.h"
+#include "tidy-private.h"
+
+static void scrollable_interface_init (TidyScrollableInterface *iface);
+
+static void scrollable_set_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment *hadjustment,
+ TidyAdjustment *vadjustment);
+
+static void scrollable_get_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment **hadjustment,
+ TidyAdjustment **vadjustment);
+
+G_DEFINE_TYPE_WITH_CODE (TidyViewport, tidy_viewport, CLUTTER_TYPE_GROUP,
+ G_IMPLEMENT_INTERFACE (TIDY_TYPE_SCROLLABLE,
+ scrollable_interface_init))
+
+#define VIEWPORT_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TIDY_TYPE_VIEWPORT, \
+ TidyViewportPrivate))
+
+struct _TidyViewportPrivate
+{
+ gfloat x;
+ gfloat y;
+ gfloat z;
+
+ TidyAdjustment *hadjustment;
+ TidyAdjustment *vadjustment;
+
+ gboolean sync_adjustments;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_X_ORIGIN,
+ PROP_Y_ORIGIN,
+ PROP_Z_ORIGIN,
+ PROP_HADJUST,
+ PROP_VADJUST,
+ PROP_SYNC_ADJUST
+};
+
+static void
+tidy_viewport_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TidyAdjustment *adjustment;
+
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (object)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_X_ORIGIN:
+ g_value_set_int (value, priv->x);
+ break;
+
+ case PROP_Y_ORIGIN:
+ g_value_set_int (value, priv->y);
+ break;
+
+ case PROP_Z_ORIGIN:
+ g_value_set_int (value, priv->z);
+ break;
+
+ case PROP_HADJUST :
+ scrollable_get_adjustments (TIDY_SCROLLABLE (object), &adjustment, NULL);
+ g_value_set_object (value, adjustment);
+ break;
+
+ case PROP_VADJUST :
+ scrollable_get_adjustments (TIDY_SCROLLABLE (object), NULL, &adjustment);
+ g_value_set_object (value, adjustment);
+ break;
+
+ case PROP_SYNC_ADJUST :
+ g_value_set_boolean (value, priv->sync_adjustments);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+tidy_viewport_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TidyViewport *viewport = TIDY_VIEWPORT (object);
+ TidyViewportPrivate *priv = viewport->priv;
+
+ switch (prop_id)
+ {
+ case PROP_X_ORIGIN:
+ tidy_viewport_set_origin (viewport,
+ g_value_get_int (value),
+ priv->y,
+ priv->z);
+ break;
+
+ case PROP_Y_ORIGIN:
+ tidy_viewport_set_origin (viewport,
+ priv->x,
+ g_value_get_int (value),
+ priv->z);
+ break;
+
+ case PROP_Z_ORIGIN:
+ tidy_viewport_set_origin (viewport,
+ priv->x,
+ priv->y,
+ g_value_get_int (value));
+ break;
+
+ case PROP_HADJUST :
+ scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+ g_value_get_object (value),
+ priv->vadjustment);
+ break;
+
+ case PROP_VADJUST :
+ scrollable_set_adjustments (TIDY_SCROLLABLE (object),
+ priv->hadjustment,
+ g_value_get_object (value));
+ break;
+
+ case PROP_SYNC_ADJUST :
+ priv->sync_adjustments = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+tidy_viewport_stop (TidyViewport *viewport)
+{
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (viewport)->priv;
+
+ tidy_adjustment_interpolate_stop (priv->hadjustment);
+ tidy_adjustment_interpolate_stop (priv->vadjustment);
+}
+
+static void
+tidy_viewport_dispose (GObject *gobject)
+{
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (gobject)->priv;
+
+ if (priv->hadjustment)
+ {
+ tidy_adjustment_interpolate_stop (priv->hadjustment);
+ g_object_unref (priv->hadjustment);
+ priv->hadjustment = NULL;
+ }
+
+ if (priv->vadjustment)
+ {
+ tidy_adjustment_interpolate_stop (priv->vadjustment);
+ g_object_unref (priv->vadjustment);
+ priv->vadjustment = NULL;
+ }
+
+ G_OBJECT_CLASS (tidy_viewport_parent_class)->dispose (gobject);
+}
+
+static void
+tidy_viewport_paint (ClutterActor *self)
+{
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (self)->priv;
+
+ cogl_push_matrix ();
+
+ cogl_translate ((priv->x) * -1.0,
+ (priv->y) * -1.0,
+ (priv->z) * -1.0);
+
+ CLUTTER_ACTOR_CLASS (tidy_viewport_parent_class)->paint (self);
+
+ cogl_pop_matrix ();
+}
+
+static void
+tidy_viewport_pick (ClutterActor *self,
+ const ClutterColor *color)
+{
+ tidy_viewport_paint (self);
+}
+
+static void
+tidy_viewport_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ ClutterAllocationFlags flags)
+{
+ CoglFixed prev_value;
+
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (self)->priv;
+
+ /* Chain up */
+ CLUTTER_ACTOR_CLASS (tidy_viewport_parent_class)->
+ allocate (self, box, flags);
+
+ /* Refresh adjustments */
+ if (priv->sync_adjustments)
+ {
+ if (priv->hadjustment)
+ {
+ g_object_set (G_OBJECT (priv->hadjustment),
+ "lower", 0.0,
+ "upper", (box->x2 - box->x1),
+ NULL);
+
+ /* Make sure value is clamped */
+ prev_value = tidy_adjustment_get_value (priv->hadjustment);
+ tidy_adjustment_set_value (priv->hadjustment, prev_value);
+ }
+
+ if (priv->vadjustment)
+ {
+ g_object_set (G_OBJECT (priv->vadjustment),
+ "lower", 0.0,
+ "upper", (box->y2 - box->y1),
+ NULL);
+
+ prev_value = tidy_adjustment_get_value (priv->vadjustment);
+ tidy_adjustment_set_value (priv->vadjustment, prev_value);
+ }
+ }
+}
+
+static void
+tidy_viewport_class_init (TidyViewportClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (TidyViewportPrivate));
+
+ gobject_class->get_property = tidy_viewport_get_property;
+ gobject_class->set_property = tidy_viewport_set_property;
+ gobject_class->dispose = tidy_viewport_dispose;
+
+ actor_class->paint = tidy_viewport_paint;
+ actor_class->pick = tidy_viewport_pick;
+ actor_class->allocate = tidy_viewport_allocate;
+
+ g_object_class_install_property (gobject_class,
+ PROP_X_ORIGIN,
+ g_param_spec_int ("x-origin",
+ "X Origin",
+ "Origin's X coordinate in pixels",
+ -G_MAXINT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_Y_ORIGIN,
+ g_param_spec_int ("y-origin",
+ "Y Origin",
+ "Origin's Y coordinate in pixels",
+ -G_MAXINT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_Z_ORIGIN,
+ g_param_spec_int ("z-origin",
+ "Z Origin",
+ "Origin's Z coordinate in pixels",
+ -G_MAXINT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_SYNC_ADJUST,
+ g_param_spec_boolean ("sync-adjustments",
+ "Synchronise "
+ "adjustments",
+ "Whether to "
+ "synchronise "
+ "adjustments with "
+ "viewport size",
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_override_property (gobject_class,
+ PROP_HADJUST,
+ "hadjustment");
+
+ g_object_class_override_property (gobject_class,
+ PROP_VADJUST,
+ "vadjustment");
+}
+
+static void
+hadjustment_value_notify_cb (TidyAdjustment *adjustment,
+ GParamSpec *pspec,
+ TidyViewport *viewport)
+{
+ TidyViewportPrivate *priv = viewport->priv;
+ gdouble value;
+
+ value = tidy_adjustment_get_value (adjustment);
+
+ tidy_viewport_set_origin (viewport,
+ value,
+ priv->y,
+ priv->z);
+}
+
+static void
+vadjustment_value_notify_cb (TidyAdjustment *adjustment, GParamSpec *arg1,
+ TidyViewport *viewport)
+{
+ TidyViewportPrivate *priv = viewport->priv;
+ gdouble value;
+
+ value = tidy_adjustment_get_value (adjustment);
+
+ tidy_viewport_set_origin (viewport,
+ priv->x,
+ value,
+ priv->z);
+}
+
+static void
+scrollable_set_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment *hadjustment,
+ TidyAdjustment *vadjustment)
+{
+ TidyViewportPrivate *priv = TIDY_VIEWPORT (scrollable)->priv;
+
+ if (hadjustment != priv->hadjustment)
+ {
+ if (priv->hadjustment)
+ {
+ g_signal_handlers_disconnect_by_func (priv->hadjustment,
+ hadjustment_value_notify_cb,
+ scrollable);
+ g_object_unref (priv->hadjustment);
+ }
+
+ if (hadjustment)
+ {
+ g_object_ref (hadjustment);
+ g_signal_connect (hadjustment, "notify::value",
+ G_CALLBACK (hadjustment_value_notify_cb),
+ scrollable);
+ }
+
+ priv->hadjustment = hadjustment;
+ }
+
+ if (vadjustment != priv->vadjustment)
+ {
+ if (priv->vadjustment)
+ {
+ g_signal_handlers_disconnect_by_func (priv->vadjustment,
+ vadjustment_value_notify_cb,
+ scrollable);
+ g_object_unref (priv->vadjustment);
+ }
+
+ if (vadjustment)
+ {
+ g_object_ref (vadjustment);
+ g_signal_connect (vadjustment, "notify::value",
+ G_CALLBACK (vadjustment_value_notify_cb),
+ scrollable);
+ }
+
+ priv->vadjustment = vadjustment;
+ }
+}
+
+static void
+scrollable_get_adjustments (TidyScrollable *scrollable,
+ TidyAdjustment **hadjustment,
+ TidyAdjustment **vadjustment)
+{
+ TidyViewportPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_VIEWPORT (scrollable));
+
+ priv = ((TidyViewport *)scrollable)->priv;
+
+ if (hadjustment)
+ {
+ if (priv->hadjustment)
+ *hadjustment = priv->hadjustment;
+ else
+ {
+ TidyAdjustment *adjustment;
+ guint width, stage_width, increment;
+
+ width = clutter_actor_get_width (CLUTTER_ACTOR(scrollable));
+ stage_width = clutter_actor_get_width (clutter_stage_get_default ());
+ increment = MAX (1, MIN(stage_width, width));
+
+ adjustment = tidy_adjustment_new (priv->x,
+ 0,
+ width,
+ 1,
+ increment,
+ increment);
+ scrollable_set_adjustments (scrollable,
+ adjustment,
+ priv->vadjustment);
+ *hadjustment = adjustment;
+ }
+ }
+
+ if (vadjustment)
+ {
+ if (priv->vadjustment)
+ *vadjustment = priv->vadjustment;
+ else
+ {
+ TidyAdjustment *adjustment;
+ guint height, stage_height, increment;
+
+ height = clutter_actor_get_height (CLUTTER_ACTOR(scrollable));
+ stage_height = clutter_actor_get_height (clutter_stage_get_default ());
+ increment = MAX (1, MIN(stage_height, height));
+
+ adjustment = tidy_adjustment_new (priv->y,
+ 0,
+ height,
+ 1,
+ increment,
+ increment);
+ scrollable_set_adjustments (scrollable,
+ priv->hadjustment,
+ adjustment);
+ *vadjustment = adjustment;
+ }
+ }
+}
+
+static void
+scrollable_interface_init (TidyScrollableInterface *iface)
+{
+ iface->set_adjustments = scrollable_set_adjustments;
+ iface->get_adjustments = scrollable_get_adjustments;
+}
+
+static void
+clip_notify_cb (ClutterActor *actor,
+ GParamSpec *pspec,
+ TidyViewport *self)
+{
+ gfloat width, height;
+ TidyViewportPrivate *priv = self->priv;
+
+ if (!priv->sync_adjustments)
+ return;
+
+ if (!clutter_actor_has_clip (actor))
+ {
+ if (priv->hadjustment)
+ g_object_set (priv->hadjustment, "page-size", (gdouble)1.0, NULL);
+ if (priv->vadjustment)
+ g_object_set (priv->vadjustment, "page-size", (gdouble)1.0, NULL);
+ return;
+ }
+
+ clutter_actor_get_clip (actor, NULL, NULL, &width, &height);
+
+ if (priv->hadjustment)
+ g_object_set (priv->hadjustment, "page-size", (gdouble)width, NULL);
+
+ if (priv->vadjustment)
+ g_object_set (priv->vadjustment, "page-size", (gdouble)height, NULL);
+}
+
+static void
+tidy_viewport_init (TidyViewport *self)
+{
+ self->priv = VIEWPORT_PRIVATE (self);
+
+ self->priv->sync_adjustments = TRUE;
+
+ g_signal_connect (self, "notify::clip",
+ G_CALLBACK (clip_notify_cb), self);
+}
+
+ClutterActor *
+tidy_viewport_new (void)
+{
+ return g_object_new (TIDY_TYPE_VIEWPORT, NULL);
+}
+
+void
+tidy_viewport_set_origin (TidyViewport *viewport,
+ float x,
+ float y,
+ float z)
+{
+ TidyViewportPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_VIEWPORT (viewport));
+
+ priv = viewport->priv;
+
+ g_object_freeze_notify (G_OBJECT (viewport));
+
+ if (x != priv->x)
+ {
+ priv->x = x;
+ g_object_notify (G_OBJECT (viewport), "x-origin");
+
+ if (priv->hadjustment)
+ tidy_adjustment_set_value (priv->hadjustment,
+ x);
+ }
+
+ if (y != priv->y)
+ {
+ priv->y = y;
+ g_object_notify (G_OBJECT (viewport), "y-origin");
+
+ if (priv->vadjustment)
+ tidy_adjustment_set_value (priv->vadjustment,
+ y);
+ }
+
+ if (z != priv->z)
+ {
+ priv->z = z;
+ g_object_notify (G_OBJECT (viewport), "z-origin");
+ }
+
+ g_object_thaw_notify (G_OBJECT (viewport));
+
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (viewport));
+}
+
+void
+tidy_viewport_get_origin (TidyViewport *viewport,
+ float *x,
+ float *y,
+ float *z)
+{
+ TidyViewportPrivate *priv;
+
+ g_return_if_fail (TIDY_IS_VIEWPORT (viewport));
+
+ priv = viewport->priv;
+
+ if (x)
+ *x = priv->x;
+
+ if (y)
+ *y = priv->y;
+
+ if (z)
+ *z = priv->z;
+}
diff --git a/tidy/tidy-viewport.h b/tidy/tidy-viewport.h
new file mode 100644
index 0000000..1ee9b35
--- /dev/null
+++ b/tidy/tidy-viewport.h
@@ -0,0 +1,72 @@
+/* tidy-viewport.h: Viewport actor
+ *
+ * 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.
+ *
+ * Written by: Chris Lord <chris openedhand com>
+ */
+
+#ifndef __TIDY_VIEWPORT_H__
+#define __TIDY_VIEWPORT_H__
+
+#include <glib-object.h>
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define TIDY_TYPE_VIEWPORT (tidy_viewport_get_type())
+#define TIDY_VIEWPORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_VIEWPORT, TidyViewport))
+#define TIDY_IS_VIEWPORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_VIEWPORT))
+#define TIDY_VIEWPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_VIEWPORT, TidyViewportClass))
+#define TIDY_IS_VIEWPORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_VIEWPORT))
+#define TIDY_VIEWPORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_VIEWPORT, TidyViewportClass))
+
+typedef struct _TidyViewport TidyViewport;
+typedef struct _TidyViewportPrivate TidyViewportPrivate;
+typedef struct _TidyViewportClass TidyViewportClass;
+
+struct _TidyViewport
+{
+ ClutterGroup parent;
+
+ TidyViewportPrivate *priv;
+};
+
+struct _TidyViewportClass
+{
+ ClutterGroupClass parent_class;
+};
+
+GType tidy_viewport_get_type (void) G_GNUC_CONST;
+
+ClutterActor * tidy_viewport_new (void);
+
+void tidy_viewport_set_origin (TidyViewport *viewport,
+ float x,
+ float y,
+ float z);
+
+void tidy_viewport_get_origin (TidyViewport *viewport,
+ gfloat *x,
+ gfloat *y,
+ gfloat *z);
+void tidy_viewport_stop (TidyViewport *viewport);
+
+G_END_DECLS
+
+#endif /* __TIDY_VIEWPORT_H__ */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]