2009-03-05 Alejandro G. Castro <alex@igalia.com>
authorAlejandro G. Castro <alex@igalia.com>
Thu, 5 Mar 2009 17:50:44 +0000 (17:50 +0000)
committerAlejandro G. Castro <alex@igalia.com>
Thu, 5 Mar 2009 17:50:44 +0000 (17:50 +0000)
Added a new example application that allows tuning the pannable
area and replaced defines with properties in order to simplify the
tuning: PROP_DRAG_INERTIA, PROP_PANNING_THRESHOLD,
PROP_SCROLLBAR_FADE_DELAY, PROP_BOUNCE_STEPS, PROP_FORCE and
PROP_DIRECTION_ERROR_MARGIN.

* examples/hildon-pannable-area-tuning-example.c: New example
application.
* src/hildon-pannable-area.c,
(hildon_pannable_area_class_init),
(hildon_pannable_area_init),
(hildon_pannable_area_get_property),
(hildon_pannable_area_set_property),
(hildon_pannable_area_launch_fade_timeout),
(hildon_pannable_area_adjust_value_changed),
(hildon_pannable_axis_scroll),
(hildon_pannable_area_motion_notify_cb),
(hildon_pannable_area_scroll_cb),
(hildon_pannable_area_button_release_cb): We have converted some
of the defines that control the widget to properties to simplify
the tuning.

ChangeLog
examples/Makefile.am
examples/hildon-pannable-area-tuning-example.c [new file with mode: 0644]
src/hildon-pannable-area.c

index 415aac6..3eaaabb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2009-03-05  Alejandro G. Castro  <alex@igalia.com>
+
+       Added a new example application that allows tuning the pannable
+       area and replaced defines with properties in order to simplify the
+       tuning: PROP_DRAG_INERTIA, PROP_PANNING_THRESHOLD,
+       PROP_SCROLLBAR_FADE_DELAY, PROP_BOUNCE_STEPS, PROP_FORCE and
+       PROP_DIRECTION_ERROR_MARGIN.
+
+       * examples/hildon-pannable-area-tuning-example.c: New example
+       application.
+       * src/hildon-pannable-area.c,
+       (hildon_pannable_area_class_init),
+       (hildon_pannable_area_init),
+       (hildon_pannable_area_get_property),
+       (hildon_pannable_area_set_property),
+       (hildon_pannable_area_launch_fade_timeout),
+       (hildon_pannable_area_adjust_value_changed),
+       (hildon_pannable_axis_scroll),
+       (hildon_pannable_area_motion_notify_cb),
+       (hildon_pannable_area_scroll_cb),
+       (hildon_pannable_area_button_release_cb): We have converted some
+       of the defines that control the widget to properties to simplify
+       the tuning.
+
 2009-03-05  Alberto Garcia  <agarcia@igalia.com>
 
        * src/hildon-app-menu.c (hildon_app_menu_map)
index efc840a..0368bdf 100644 (file)
@@ -17,6 +17,7 @@ EXAMPLES                              = hildon-window-example                         \
                                          hildon-edit-toolbar-example                   \
                                          hildon-wizard-dialog-example                  \
                                          hildon-pannable-area-tree-view-example        \
+                                         hildon-pannable-area-tuning-example           \
                                          hildon-pannable-area-scroll-jump-example      \
                                          hildon-pannable-area-buttons-scroll-example   \
                                          hildon-pannable-area-gesture-signals-example  \
@@ -331,6 +332,12 @@ hildon_pannable_area_tree_view_example_CFLAGS              = $(HILDON_OBJ_CFLAGS)                  \
                                                           $(EXTRA_CFLAGS)
 hildon_pannable_area_tree_view_example_SOURCES         = hildon-pannable-area-tree-view-example.c
 
+# Hildon pannable area tuning example
+hildon_pannable_area_tuning_example_LDADD              = $(HILDON_OBJ_LIBS)
+hildon_pannable_area_tuning_example_CFLAGS             = $(HILDON_OBJ_CFLAGS)                  \
+                                                          $(EXTRA_CFLAGS)
+hildon_pannable_area_tuning_example_SOURCES            = hildon-pannable-area-tuning-example.c
+
 # Hildon pannable area scroll jump example
 hildon_pannable_area_scroll_jump_example_LDADD         = $(HILDON_OBJ_LIBS)
 hildon_pannable_area_scroll_jump_example_CFLAGS                = $(HILDON_OBJ_CFLAGS)
diff --git a/examples/hildon-pannable-area-tuning-example.c b/examples/hildon-pannable-area-tuning-example.c
new file mode 100644 (file)
index 0000000..bead8bb
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * This file is a part of hildon examples
+ *
+ * Copyright (C) 2009 Nokia Corporation, all rights reserved.
+ * Copyright (C) 2006 The Free Software Foundation
+ *
+ * Author: Claudio Saavedra <csaavedra@alumnos.utalca.cl>
+ *
+ * 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* This example is based on other example written by Claudio for
+   EOG */
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gprintf.h>
+#include "hildon.h"
+
+typedef struct {
+    GtkWidget *pannable;
+    GtkWidget *treeview;
+} ApplicationContext;
+
+enum {
+    PIXBUF_COLUMN,
+    TEXT_COLUMN,
+    N_COLUMNS};
+
+enum {
+    COLUMN_PROP_NAME = 0,
+    COLUMN_PROP_VALUE,
+    COLUMN_PROP_TYPE,
+    N_COLS
+};
+
+static GtkListStore *
+create_list_store (void)
+{
+    GtkListStore *store;
+
+    store = gtk_list_store_new (N_COLS,
+                                G_TYPE_STRING,
+                                G_TYPE_STRING,
+                                G_TYPE_GTYPE);
+
+    return store;
+}
+
+static void
+list_store_fill (GtkListStore *store,
+                 GObject *object)
+{
+    guint n_properties, i;
+    GParamSpec **param_specs;
+    GtkTreeIter iter;
+    GObjectClass *objectclass;
+    gdouble f_value;
+    gint i_value;
+    gchar *s_value = NULL;
+
+    objectclass = G_OBJECT_GET_CLASS (object);
+    param_specs = g_object_class_list_properties (objectclass,
+                                                  &n_properties);
+
+    for (i = 0; i < n_properties; i++) {
+        if (param_specs [i]->owner_type == G_TYPE_FROM_CLASS (objectclass)) {
+            switch (param_specs[i]->value_type) {
+            case G_TYPE_DOUBLE:
+                g_object_get (object,
+                              param_specs[i]->name, &f_value, NULL);
+                s_value = g_strdup_printf ("%f", f_value);
+                break;
+            case G_TYPE_OBJECT:
+                break;
+           case G_TYPE_BOOLEAN:
+           case G_TYPE_ENUM:
+           case G_TYPE_UINT:
+           case G_TYPE_INT:
+                g_object_get (object,
+                              param_specs[i]->name, &i_value, NULL);
+                s_value = g_strdup_printf ("%d", i_value);
+                break;
+            }
+
+            if (s_value) {
+                gtk_list_store_append (store, &iter);
+                gtk_list_store_set (store, &iter,
+                                    COLUMN_PROP_NAME, param_specs[i]->name,
+                                    COLUMN_PROP_VALUE, s_value,
+                                    COLUMN_PROP_TYPE, param_specs[i]->value_type,
+                                    -1);
+
+                g_free (s_value);
+                s_value = NULL;
+            }
+        }
+    }
+
+    g_free (param_specs);
+}
+
+static void
+cell_edited_cb (GtkCellRendererText *renderer,
+                gchar               *path_string,
+                gchar               *s_value,
+                gpointer             user_data)
+{
+    ApplicationContext *app_ctx;
+    GObjectClass *objectclass;
+    GParamSpec **param_specs;
+    gint column;
+    GtkTreePath *path;
+    GtkTreeModel *model;
+    gdouble f_value;
+    gint i_value;
+    gchar *p_name;
+    GtkTreeIter iter;
+    guint n_properties, i = 0;
+
+    app_ctx = (ApplicationContext *)user_data;
+
+    objectclass = G_OBJECT_GET_CLASS (app_ctx->pannable);
+
+    model = gtk_tree_view_get_model (GTK_TREE_VIEW (app_ctx->treeview));
+    path = gtk_tree_path_new_from_string (path_string);
+    gtk_tree_model_get_iter (model, &iter, path);
+    gtk_tree_path_free (path);
+
+    gtk_tree_model_get (model, &iter,
+                        COLUMN_PROP_NAME, &p_name,
+                        -1);
+
+    param_specs = g_object_class_list_properties (objectclass,
+                                                  &n_properties);
+
+    column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (renderer),
+                                                 "column"));
+
+    while (strcmp (param_specs[i]->name, p_name)) i++;
+
+    switch (param_specs[i]->value_type) {
+    case G_TYPE_DOUBLE:
+        f_value = g_ascii_strtod (s_value, NULL);
+        g_object_set (G_OBJECT (app_ctx->pannable),
+                      p_name, f_value, NULL);
+        break;
+    case G_TYPE_BOOLEAN:
+    case G_TYPE_ENUM:
+    case G_TYPE_UINT:
+    case G_TYPE_INT:
+        i_value = atoi (s_value);
+        g_object_set (G_OBJECT (app_ctx->pannable),
+                      p_name, i_value, NULL);
+        break;
+    }
+
+    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                        column, s_value,
+                        -1);
+
+    g_free (param_specs);
+
+    g_free (p_name);
+}
+
+static GtkWidget *
+create_attributes_treeview (ApplicationContext *app_ctx)
+{
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+    GtkTreeView *treeview;
+
+    treeview = GTK_TREE_VIEW (gtk_tree_view_new ());
+
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Property",
+                                                       renderer,
+                                                       "text",
+                                                       COLUMN_PROP_NAME,
+                                                       NULL);
+    gtk_tree_view_column_set_sort_column_id (column, COLUMN_PROP_NAME);
+    gtk_tree_view_append_column (treeview, column);
+
+    renderer = gtk_cell_renderer_text_new ();
+    g_object_set (renderer, "editable", TRUE, NULL);
+    column = gtk_tree_view_column_new_with_attributes ("Value",
+                                                       renderer,
+                                                       "text", COLUMN_PROP_VALUE,
+                                                       NULL);
+    gtk_tree_view_column_set_sort_column_id (column, COLUMN_PROP_VALUE);
+    gtk_tree_view_append_column (treeview, column);
+    g_signal_connect (renderer, "edited",
+                      G_CALLBACK (cell_edited_cb), app_ctx);
+    g_object_set_data (G_OBJECT (renderer), "column",
+                       GINT_TO_POINTER (COLUMN_PROP_VALUE));
+
+    return GTK_WIDGET (treeview);
+}
+
+static void
+on_notify_cb (GObject *object,
+              GParamSpec *param_spec,
+              gpointer user_data)
+{
+    GtkTreeModel *store;
+    GtkTreeIter iter;
+    gchar *par_name;
+    gfloat f_value;
+    gchar s_value[128];
+
+    store = GTK_TREE_MODEL (user_data);
+
+    gtk_tree_model_get_iter_first (store, &iter);
+
+    do {
+
+      gtk_tree_model_get (store, &iter,
+                          COLUMN_PROP_NAME, &par_name,
+                          -1);
+      if (strcmp (par_name, param_spec->name) == 0 &&
+          param_spec->value_type == G_TYPE_FLOAT) {
+        g_object_get (object,
+                      param_spec->name, &f_value,
+                      NULL);
+        g_sprintf (s_value, "%f", f_value);
+        gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+                            COLUMN_PROP_VALUE, s_value,
+                            -1);
+      }
+
+      g_free (par_name);
+
+    } while (gtk_tree_model_iter_next (store, &iter));
+}
+
+static GtkWidget*
+create_pannable_treeview (void)
+{
+    GtkWidget *tv;
+    GtkTreeViewColumn *col;
+    GtkCellRenderer *renderer;
+    GtkListStore *store;
+    GSList *stocks, *item;
+    gint i;
+
+    /* Create a treeview */
+    tv = gtk_tree_view_new ();
+
+    g_object_set (tv, "fixed-height-mode", TRUE, NULL);
+
+    col = gtk_tree_view_column_new ();
+    gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
+    gtk_tree_view_column_set_title (col, "Title");
+
+    g_object_set (tv, "fixed-height-mode", TRUE, NULL);
+    renderer = gtk_cell_renderer_pixbuf_new ();
+    gtk_cell_renderer_set_fixed_size (renderer, 48, 48);
+    gtk_tree_view_column_pack_start (col, renderer, FALSE);
+    gtk_tree_view_column_set_attributes (col, renderer, "stock-id", PIXBUF_COLUMN, NULL);
+
+    renderer = gtk_cell_renderer_text_new ();
+    gtk_tree_view_column_pack_start (col, renderer, FALSE);
+    gtk_tree_view_column_set_attributes (col, renderer, "text", TEXT_COLUMN, NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW(tv), col);
+
+    /* Add some rows to the treeview */
+    stocks = gtk_stock_list_ids ();
+    item = stocks;
+    store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
+    for (i = 0; i < 100; i++) {
+      GtkTreeIter iter;
+      GtkStockItem stock_item;
+      gchar *stock_id;
+
+      stock_id = (gchar *)item->data;
+      gtk_stock_lookup (stock_id, &stock_item);
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter, PIXBUF_COLUMN, stock_id, TEXT_COLUMN, stock_item.label, -1);
+
+      item = item->next? item->next : stocks;
+    }
+    gtk_tree_view_set_model (GTK_TREE_VIEW (tv), GTK_TREE_MODEL (store));
+    g_object_unref (store);
+
+    g_slist_foreach (stocks, (GFunc)g_free, NULL);
+    g_slist_free (stocks);
+
+    return tv;
+}
+gint
+main (gint argc, gchar **argv)
+{
+    HildonProgram *program;
+    GtkWidget *window;
+    GtkWidget *pannable;
+    GtkWidget *hbox, *vbox;
+    GtkWidget *treeview, *pannable_treeview;
+    GtkWidget *sw;
+    GtkListStore *store;
+    ApplicationContext *app_ctx = NULL;
+
+    hildon_gtk_init (&argc, &argv);
+
+    program = hildon_program_get_instance ();
+
+    /* Create the main window */
+    window = hildon_window_new ();
+    hildon_program_add_window (program, HILDON_WINDOW (window));
+
+    gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+
+    g_signal_connect (G_OBJECT (window), "delete-event",
+                      G_CALLBACK (gtk_main_quit), NULL);
+
+    pannable = hildon_pannable_area_new ();
+
+    app_ctx = g_new0 (ApplicationContext, 1);
+    app_ctx->pannable = pannable;
+
+    pannable_treeview = create_pannable_treeview();
+
+    gtk_container_add (GTK_CONTAINER (pannable),
+                       pannable_treeview);
+
+    treeview = create_attributes_treeview (app_ctx);
+
+    app_ctx->treeview = treeview;
+    store = create_list_store ();
+
+    gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
+                             GTK_TREE_MODEL (store));
+
+    list_store_fill (store, G_OBJECT (pannable));
+
+    sw = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+                                         GTK_SHADOW_ETCHED_IN);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+                                    GTK_POLICY_NEVER,
+                                    GTK_POLICY_AUTOMATIC);
+
+    gtk_container_add (GTK_CONTAINER (sw), treeview);
+
+    hbox = gtk_hbox_new (FALSE, 10);
+
+    vbox = gtk_vbox_new (FALSE, 10);
+    gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 10);
+
+    gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 10);
+
+/*     vbox = gtk_vbox_new (FALSE, 10); */
+/*     gtk_box_pack_start (GTK_BOX (vbox), pannable, TRUE, TRUE, 10); */
+    gtk_box_pack_start (GTK_BOX (hbox), pannable, TRUE, TRUE, 10);
+
+    g_signal_connect_after (pannable, "notify",
+                            G_CALLBACK (on_notify_cb), store);
+
+    gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+    gtk_container_add (GTK_CONTAINER (window), hbox);
+
+    gtk_widget_show_all (window);
+
+    gtk_main ();
+
+    g_free (app_ctx);
+
+    return 0;
+}
index 29f2c49..46d669e 100644 (file)
 
 #define USE_CAIRO_SCROLLBARS 0
 
-#define SMOOTH_FACTOR 0.85
-#define FORCE 5
-#define BOUNCE_STEPS 6
 #define SCROLL_BAR_MIN_SIZE 5
 #define RATIO_TOLERANCE 0.000001
-#define SCROLLBAR_FADE_DELAY 30
-#define SCROLL_FADE_TIMEOUT 10
+#define SCROLL_FADE_TIMEOUT 100
 #define MOTION_EVENTS_PER_SECOND 25
-#define PANNING_THRESHOLD 3
-#define DIRECTION_ERROR_MARGIN 10
+#define CURSOR_STOPPED_TIMEOUT 125
 
 G_DEFINE_TYPE (HildonPannableArea, hildon_pannable_area, GTK_TYPE_BIN)
 
@@ -84,9 +79,15 @@ struct _HildonPannableAreaPrivate {
   gdouble vmax;
   gdouble vfast_factor;
   gdouble decel;
+  gdouble drag_inertia;
   gdouble scroll_time;
   gdouble vel_factor;
   guint sps;
+  guint panning_threshold;
+  guint scrollbar_fade_delay;
+  guint bounce_steps;
+  guint force;
+  guint direction_error_margin;
   gdouble vel_x;
   gdouble vel_y;
   GdkWindow *child;
@@ -148,7 +149,13 @@ enum {
   PROP_VELOCITY_MAX,
   PROP_VELOCITY_FAST_FACTOR,
   PROP_DECELERATION,
+  PROP_DRAG_INERTIA,
   PROP_SPS,
+  PROP_PANNING_THRESHOLD,
+  PROP_SCROLLBAR_FADE_DELAY,
+  PROP_BOUNCE_STEPS,
+  PROP_FORCE,
+  PROP_DIRECTION_ERROR_MARGIN,
   PROP_VSCROLLBAR_POLICY,
   PROP_HSCROLLBAR_POLICY,
   PROP_VOVERSHOOT_MAX,
@@ -242,6 +249,8 @@ static void hildon_pannable_area_calculate_velocity (gdouble *vel,
                                                      gdouble delta,
                                                      gdouble dist,
                                                      gdouble vmax,
+                                                     gdouble drag_inertia,
+                                                     gdouble force,
                                                      guint sps);
 static gboolean hildon_pannable_area_motion_event_scroll_timeout (HildonPannableArea *area);
 static void hildon_pannable_area_motion_event_scroll (HildonPannableArea *area,
@@ -384,6 +393,17 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                                        G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (object_class,
+                                  PROP_DRAG_INERTIA,
+                                  g_param_spec_double ("drag_inertia",
+                                                       "Inertia of the cursor dragging",
+                                                       "Percentage of the calculated speed in each moment we are are going to use"
+                                                        "to calculate the launch speed, the other part would be the speed"
+                                                        "calculated previously",
+                                                       0, 1.0, 0.85,
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
                                   PROP_SPS,
                                   g_param_spec_uint ("sps",
                                                      "Scrolls per second",
@@ -393,10 +413,62 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                                      G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (object_class,
+                                  PROP_PANNING_THRESHOLD,
+                                  g_param_spec_uint ("panning_threshold",
+                                                     "Threshold to consider a motion event an scroll",
+                                                     "Amount of pixels to consider a motion event an scroll, if it is less"
+                                                      "it is a click detected incorrectly by the touch screen.",
+                                                     0, G_MAXUINT, 3,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                  PROP_SCROLLBAR_FADE_DELAY,
+                                  g_param_spec_uint ("scrollbar_fade_delay",
+                                                     "Time before starting to fade the scrollbar",
+                                                     "Time the scrollbar is going to be visible if the widget is not in"
+                                                      "action in miliseconds",
+                                                     0, G_MAXUINT, 3000,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                  PROP_BOUNCE_STEPS,
+                                  g_param_spec_uint ("bounce_steps",
+                                                     "Bounce steps",
+                                                     "Number of steps that is going to be used to bounce when hitting the"
+                                                      "edge, the rubberband effect depends on it",
+                                                     0, G_MAXUINT, 6,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                  PROP_FORCE,
+                                  g_param_spec_uint ("force",
+                                                     "Multiplier of the calculated speed",
+                                                     "Force applied to the movement, multiplies the calculated speed of the"
+                                                      "user movement the cursor in the screen",
+                                                     0, G_MAXUINT, 5,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                  PROP_DIRECTION_ERROR_MARGIN,
+                                  g_param_spec_uint ("direction_error_margin",
+                                                     "Margin in the direction detection",
+                                                     "After detecting the direction of the movement (horizontal or"
+                                                      "vertical), we can add this margin of error to allow the movement in"
+                                                      "the other direction even apparently it is not",
+                                                     0, G_MAXUINT, 10,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
                                   PROP_VOVERSHOOT_MAX,
                                   g_param_spec_int ("vovershoot_max",
                                                      "Vertical overshoot distance",
-                                                     "Space we allow the widget to pass over its vertical limits when hitting the edges, set 0 in order to deactivate overshooting.",
+                                                     "Space we allow the widget to pass over its vertical limits when"
+                                                     "hitting the edges, set 0 in order to deactivate overshooting.",
                                                      0, G_MAXINT, 150,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT));
@@ -405,7 +477,8 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                   PROP_HOVERSHOOT_MAX,
                                   g_param_spec_int ("hovershoot_max",
                                                      "Horizontal overshoot distance",
-                                                     "Space we allow the widget to pass over its horizontal limits when hitting the edges, set 0 in order to deactivate overshooting.",
+                                                     "Space we allow the widget to pass over its horizontal limits when"
+                                                     "hitting the edges, set 0 in order to deactivate overshooting.",
                                                      0, G_MAXINT, 150,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT));
@@ -414,8 +487,7 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                   PROP_SCROLL_TIME,
                                   g_param_spec_double ("scroll_time",
                                                        "Time to scroll to a position",
-                                                       "The time to scroll to a position when calling the hildon_pannable_scroll_to function"
-                                                       "acceleration scrolling mode.",
+                                                       "The time to scroll to a position when calling the hildon_pannable_scroll_to function",
                                                        1.0, 20.0, 10.0,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT));
@@ -433,7 +505,8 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                   PROP_LOW_FRICTION_MODE,
                                   g_param_spec_boolean ("low-friction-mode",
                                                         "Do not decelerate the initial velocity",
-                                                        "Avoid decelerating the panning movement, like no friction, the widget will stop in the edges or if the user clicks.",
+                                                        "Avoid decelerating the panning movement, like no friction, the widget"
+                                                         "will stop in the edges or if the user clicks.",
                                                         FALSE,
                                                         G_PARAM_READWRITE |
                                                         G_PARAM_CONSTRUCT));
@@ -525,7 +598,7 @@ hildon_pannable_area_init (HildonPannableArea * area)
   priv->scroll_indicator_timeout = 0;
   priv->motion_event_scroll_timeout = 0;
   priv->scroll_indicator_event_interrupt = 0;
-  priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
+  priv->scroll_delay_counter = priv->scrollbar_fade_delay;
   priv->scroll_to_x = -1;
   priv->scroll_to_y = -1;
   priv->first_drag = TRUE;
@@ -585,9 +658,28 @@ hildon_pannable_area_get_property (GObject * object,
   case PROP_DECELERATION:
     g_value_set_double (value, priv->decel);
     break;
+  case PROP_DRAG_INERTIA:
+    g_value_set_double (value, priv->drag_inertia);
+    break;
   case PROP_SPS:
     g_value_set_uint (value, priv->sps);
     break;
+  case PROP_PANNING_THRESHOLD:
+    g_value_set_uint (value, priv->panning_threshold);
+    break;
+  case PROP_SCROLLBAR_FADE_DELAY:
+    /* convert to miliseconds */
+    g_value_set_uint (value, priv->scrollbar_fade_delay * SCROLL_FADE_TIMEOUT);
+    break;
+  case PROP_BOUNCE_STEPS:
+    g_value_set_uint (value, priv->bounce_steps);
+    break;
+  case PROP_FORCE:
+    g_value_set_uint (value, priv->force);
+    break;
+  case PROP_DIRECTION_ERROR_MARGIN:
+    g_value_set_uint (value, priv->direction_error_margin);
+    break;
   case PROP_VSCROLLBAR_POLICY:
     g_value_set_enum (value, priv->vscrollbar_policy);
     break;
@@ -669,9 +761,28 @@ hildon_pannable_area_set_property (GObject * object,
 
     priv->decel = g_value_get_double (value);
     break;
+  case PROP_DRAG_INERTIA:
+    priv->drag_inertia = g_value_get_double (value);
+    break;
   case PROP_SPS:
     priv->sps = g_value_get_uint (value);
     break;
+  case PROP_PANNING_THRESHOLD:
+    priv->panning_threshold = g_value_get_uint (value);
+    break;
+  case PROP_SCROLLBAR_FADE_DELAY:
+    /* convert to miliseconds */
+    priv->scrollbar_fade_delay = g_value_get_uint (value)/(SCROLL_FADE_TIMEOUT);
+    break;
+  case PROP_BOUNCE_STEPS:
+    priv->bounce_steps = g_value_get_uint (value);
+    break;
+  case PROP_FORCE:
+    priv->force = g_value_get_uint (value);
+    break;
+  case PROP_DIRECTION_ERROR_MARGIN:
+    priv->direction_error_margin = g_value_get_uint (value);
+    break;
   case PROP_VSCROLLBAR_POLICY:
     priv->vscrollbar_policy = g_value_get_enum (value);
 
@@ -1037,7 +1148,7 @@ hildon_pannable_area_grab_notify (GtkWidget *widget,
     priv->scroll_indicator_event_interrupt = 0;
 
     if ((!priv->scroll_indicator_timeout)&&(priv->scroll_indicator_alpha)>0.1) {
-      priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
+      priv->scroll_delay_counter = priv->scrollbar_fade_delay;
 
       hildon_pannable_area_launch_fade_timeout (HILDON_PANNABLE_AREA (widget),
                                                 priv->scroll_indicator_alpha);
@@ -1342,7 +1453,7 @@ hildon_pannable_area_launch_fade_timeout (HildonPannableArea * area,
 
   if (!priv->scroll_indicator_timeout)
     priv->scroll_indicator_timeout =
-      gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) SCROLL_FADE_TIMEOUT),
+      gdk_threads_add_timeout (SCROLL_FADE_TIMEOUT,
                                (GSourceFunc) hildon_pannable_area_scroll_indicator_fade,
                                area);
 }
@@ -1366,7 +1477,7 @@ hildon_pannable_area_adjust_value_changed (HildonPannableArea * area,
 
     if ((priv->vscroll_visible) || (priv->hscroll_visible)) {
       priv->scroll_indicator_event_interrupt = 0;
-      priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
+      priv->scroll_delay_counter = priv->scrollbar_fade_delay;
 
       hildon_pannable_area_launch_fade_timeout (area, 1.0);
     }
@@ -1861,22 +1972,24 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
   } else {
     if (!priv->clicked) {
 
-      /* When the overshoot has started we continue for BOUNCE_STEPS more steps into the overshoot
-       * before we reverse direction. The deceleration factor is calculated based on
-       * the percentage distance from the first item with each iteration, therefore always
-       * returning us to the top/bottom most element
+      /* When the overshoot has started we continue for
+       * PROP_BOUNCE_STEPS more steps into the overshoot before we
+       * reverse direction. The deceleration factor is calculated
+       * based on the percentage distance from the first item with
+       * each iteration, therefore always returning us to the
+       * top/bottom most element
        */
       if (*overshot_dist > 0) {
 
-        if ((*overshooting < BOUNCE_STEPS) && (*vel > 0)) {
+        if ((*overshooting < priv->bounce_steps) && (*vel > 0)) {
           (*overshooting)++;
           *vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel);
-        } else if ((*overshooting >= BOUNCE_STEPS) && (*vel > 0)) {
+        } else if ((*overshooting >= priv->bounce_steps) && (*vel > 0)) {
           *vel *= -1;
           (*overshooting)--;
         } else if ((*overshooting > 1) && (*vel < 0)) {
           (*overshooting)--;
-          /* we add the MAX in order to avoid very small speeds */
+          /* we add the MIN in order to avoid very small speeds */
           *vel = MIN ((((gdouble)*overshot_dist)/overshoot_max) * (*vel), -10.0);
         }
 
@@ -1886,15 +1999,15 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
 
       } else if (*overshot_dist < 0) {
 
-        if ((*overshooting < BOUNCE_STEPS) && (*vel < 0)) {
+        if ((*overshooting < priv->bounce_steps) && (*vel < 0)) {
           (*overshooting)++;
           *vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1;
-        } else if ((*overshooting >= BOUNCE_STEPS) && (*vel < 0)) {
+        } else if ((*overshooting >= priv->bounce_steps) && (*vel < 0)) {
           *vel *= -1;
           (*overshooting)--;
         } else if ((*overshooting > 1) && (*vel > 0)) {
           (*overshooting)--;
-          /* we add the MIN in order to avoid very small speeds */
+          /* we add the MAX in order to avoid very small speeds */
           *vel = MAX ((((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1, 10.0);
         }
 
@@ -2039,15 +2152,17 @@ hildon_pannable_area_calculate_velocity (gdouble *vel,
                                          gdouble delta,
                                          gdouble dist,
                                          gdouble vmax,
+                                         gdouble drag_inertia,
+                                         gdouble force,
                                          guint sps)
 {
   gdouble rawvel;
 
   if (ABS (dist) >= RATIO_TOLERANCE) {
-    rawvel = ((dist / ABS (delta)) *
-              (gdouble) sps) * FORCE;
-    *vel = *vel * (1 - SMOOTH_FACTOR) +
-      rawvel * SMOOTH_FACTOR;
+    rawvel = (dist / ABS (delta)) *
+      ((gdouble) sps) * force;
+    *vel = *vel * (1 - drag_inertia) +
+      rawvel * drag_inertia;
     *vel = *vel > 0 ? MIN (*vel, vmax)
       : MAX (*vel, -1 * vmax);
   }
@@ -2117,8 +2232,8 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
   y = event->y - priv->y;
 
   if (priv->first_drag && (!priv->moved) &&
-      ((ABS (x) > (PANNING_THRESHOLD))
-       || (ABS (y) > (PANNING_THRESHOLD)))) {
+      ((ABS (x) > (priv->panning_threshold))
+       || (ABS (y) > (priv->panning_threshold)))) {
     priv->moved = TRUE;
     x = 0;
     y = 0;
@@ -2145,7 +2260,7 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
           /* even in case we do not have to move we check if this
              could be a fake horizontal movement */
           if (ABS (priv->iy - event->y) -
-              ABS (priv->ix - event->x) >= DIRECTION_ERROR_MARGIN)
+              ABS (priv->ix - event->x) >= priv->direction_error_margin)
             priv->moved = FALSE;
         }
       } else {
@@ -2167,7 +2282,7 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
           /* even in case we do not have to move we check if this
              could be a fake vertical movement */
           if (ABS (priv->ix - event->x) -
-              ABS (priv->iy - event->y) >= DIRECTION_ERROR_MARGIN)
+              ABS (priv->iy - event->y) >= priv->direction_error_margin)
             priv->moved = FALSE;
         }
       }
@@ -2220,6 +2335,8 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
                                                  delta,
                                                  dist,
                                                  priv->vmax,
+                                                 priv->drag_inertia,
+                                                 priv->force,
                                                  priv->sps);
       } else {
         y = 0;
@@ -2233,6 +2350,8 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
                                                  delta,
                                                  dist,
                                                  priv->vmax,
+                                                 priv->drag_inertia,
+                                                 priv->force,
                                                  priv->sps);
       } else {
         x = 0;
@@ -2285,7 +2404,13 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget,
     return TRUE;
 
   priv->scroll_indicator_event_interrupt = 0;
-  priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
+  priv->scroll_delay_counter = priv->scrollbar_fade_delay;
+
+  if ((priv->last_type == 2)&&
+      (event->time - priv->last_time > CURSOR_STOPPED_TIMEOUT)) {
+    priv->vel_y = 0.0;
+    priv->vel_x = 0.0;
+  }
 
   if ((ABS (priv->vel_y) > 1.0)||
       (ABS (priv->vel_x) > 1.0)) {
@@ -2308,12 +2433,12 @@ hildon_pannable_area_button_release_cb (GtkWidget * widget,
 
     /* If overshoot has been initiated with a finger down, on release set max speed */
     if (priv->overshot_dist_y != 0) {
-      priv->overshooting_y = BOUNCE_STEPS; /* Hack to stop a bounce in the finger down case */
+      priv->overshooting_y = priv->bounce_steps; /* Hack to stop a bounce in the finger down case */
       priv->vel_y = priv->vmax;
     }
 
     if (priv->overshot_dist_x != 0) {
-      priv->overshooting_x = BOUNCE_STEPS; /* Hack to stop a bounce in the finger down case */
+      priv->overshooting_x = priv->bounce_steps; /* Hack to stop a bounce in the finger down case */
       priv->vel_x = priv->vmax;
     }
 
@@ -2379,7 +2504,7 @@ hildon_pannable_area_scroll_cb (GtkWidget *widget,
     return TRUE;
 
   priv->scroll_indicator_event_interrupt = 0;
-  priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY + 20;
+  priv->scroll_delay_counter = priv->scrollbar_fade_delay + 20;
 
   hildon_pannable_area_launch_fade_timeout (HILDON_PANNABLE_AREA (widget), 1.0);