From 9ede3d1e6ae6c74044bb1cc56db4445620d5be4e Mon Sep 17 00:00:00 2001 From: "Alejandro G. Castro" Date: Thu, 5 Mar 2009 17:50:44 +0000 Subject: [PATCH] 2009-03-05 Alejandro G. Castro 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 | 24 ++ examples/Makefile.am | 7 + examples/hildon-pannable-area-tuning-example.c | 383 ++++++++++++++++++++++++ src/hildon-pannable-area.c | 201 ++++++++++--- 4 files changed, 577 insertions(+), 38 deletions(-) create mode 100644 examples/hildon-pannable-area-tuning-example.c diff --git a/ChangeLog b/ChangeLog index 415aac6..3eaaabb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2009-03-05 Alejandro G. Castro + + 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 * src/hildon-app-menu.c (hildon_app_menu_map) diff --git a/examples/Makefile.am b/examples/Makefile.am index efc840a..0368bdf 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -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 index 0000000..bead8bb --- /dev/null +++ b/examples/hildon-pannable-area-tuning-example.c @@ -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 + * + * 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 +#include +#include +#include +#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; +} diff --git a/src/hildon-pannable-area.c b/src/hildon-pannable-area.c index 29f2c49..46d669e 100644 --- a/src/hildon-pannable-area.c +++ b/src/hildon-pannable-area.c @@ -50,16 +50,11 @@ #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); -- 1.7.9.5