Added the movement modes to the hildon-pannable-area, with this modes the developers...
authorAlejandro G. Castro <alex@igalia.com>
Thu, 17 Jul 2008 18:52:43 +0000 (18:52 +0000)
committerAlejandro G. Castro <alex@igalia.com>
Thu, 17 Jul 2008 18:52:43 +0000 (18:52 +0000)
* examples/Makefile.am:
* examples/hildon-pannable-area-example-4.c: Added this example of
an application using the modes.

* src/hildon-marshalers.list: Added a new marshaller for the new
signals.

* src/hildon-pannable-area.h: Added new enumerations and flags in
order to control the movement modes and the new signals to warn
about the movements in the area.

* src/hildon-pannable-area.c:
(hildon_pannable_axis_scroll),
(hildon_pannable_area_scroll),
(hildon_pannable_area_motion_notify_cb),
(hildon_pannable_area_get_property),
(hildon_pannable_area_set_property),
(hildon_pannable_area_map),
(hildon_pannable_area_class_init),
(hildon_pannable_area_init),
(hildon_pannable_area_jump_to): Added the modes to control the
movement in the widget. We have added properties to control it,
signals to warn about the movements and refactored some code.

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

index 739549d..1f1d58e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2008-07-17  Alejandro G. Castro         <alex@igalia.com>
+
+       Added the movement modes to the hildon-pannable-area, with this
+       modes the developers can control in which directions the widget
+       can scroll. They can also connect to signals in order to do
+       something when that happens, allowing applications scroll. There
+       is an example uploaded showing how to use it.
+
+       * examples/Makefile.am:
+       * examples/hildon-pannable-area-example-4.c: Added this example of
+       an application using the modes.
+
+       * src/hildon-marshalers.list: Added a new marshaller for the new
+       signals.
+
+       * src/hildon-pannable-area.h: Added new enumerations and flags in
+       order to control the movement modes and the new signals to warn
+       about the movements in the area.
+
+       * src/hildon-pannable-area.c:
+       (hildon_pannable_axis_scroll),
+       (hildon_pannable_area_scroll),
+       (hildon_pannable_area_motion_notify_cb),
+       (hildon_pannable_area_get_property),
+       (hildon_pannable_area_set_property),
+       (hildon_pannable_area_map),
+       (hildon_pannable_area_class_init),
+       (hildon_pannable_area_init),
+       (hildon_pannable_area_jump_to): Added the modes to control the
+       movement in the widget. We have added properties to control it,
+       signals to warn about the movements and refactored some code.
+
 2008-07-15  Alejandro G. Castro         <alex@igalia.com>
 
        Changes required in order to allow vfast_factor set to zero to
index 22e1022..bce963a 100644 (file)
@@ -42,6 +42,7 @@ noinst_PROGRAMS                               = hildon-window-example                         \
                                          hildon-pannable-area-example                  \
                                          hildon-pannable-area-example-2                \
                                          hildon-pannable-area-example-3                \
+                                         hildon-pannable-area-example-4                \
                                          hildon-pannable-area-touch-list-example       \
                                          hildon-pannable-area-touch-grid-example       \
                                          hildon-logical-color-example                  \
@@ -264,6 +265,11 @@ hildon_pannable_area_example_3_LDADD               = $(HILDON_OBJ_LIBS)
 hildon_pannable_area_example_3_CFLAGS          = $(HILDON_OBJ_CFLAGS)
 hildon_pannable_area_example_3_SOURCES         = hildon-pannable-area-example-3.c
 
+# Hildon pannable area 4
+hildon_pannable_area_example_4_LDADD           = $(HILDON_OBJ_LIBS)
+hildon_pannable_area_example_4_CFLAGS          = $(HILDON_OBJ_CFLAGS)
+hildon_pannable_area_example_4_SOURCES         = hildon-pannable-area-example-4.c
+
 # Hildon pannable area touch list
 hildon_pannable_area_touch_list_example_LDADD  = $(HILDON_OBJ_LIBS)
 hildon_pannable_area_touch_list_example_CFLAGS = $(HILDON_OBJ_CFLAGS)
diff --git a/examples/hildon-pannable-area-example-4.c b/examples/hildon-pannable-area-example-4.c
new file mode 100644 (file)
index 0000000..6b365e1
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * This file is a part of hildon examples
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * Author: Karl Lattimer <karl.lattimer@nokia.com>
+ *
+ * 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
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include "hildon.h"
+
+enum { TEXT_COLUMN, OPTIONAL_COLUMN, N_COLUMNS };
+
+typedef struct {
+  GtkWidget *treeview;
+} HiddenColContext;
+
+HiddenColContext *ctx;
+
+static void
+horizontal_movement (HildonPannableArea *area,
+                     HildonPannableAreaMovDirection direction,
+                    GtkWidget *widget, gdouble x, gdouble y,
+                     gpointer user_data)
+{
+  GtkTreePath *path;
+  GdkRectangle rect;
+  gint col_x;
+  GtkTreeViewColumn *col = GTK_TREE_VIEW_COLUMN (user_data);
+
+  g_print ("widget %p treeview %p\n", widget, ctx->treeview);
+
+  if (direction == HILDON_PANNABLE_AREA_MOV_LEFT) {
+
+    path = gtk_tree_path_new_first ();
+
+    gtk_tree_view_get_background_area (GTK_TREE_VIEW (ctx->treeview),
+                                       path, col, &rect);
+
+    gtk_tree_view_convert_bin_window_to_tree_coords (GTK_TREE_VIEW (ctx->treeview),
+                                                     rect.x, 0, &col_x, NULL);
+
+    gtk_tree_path_free (path);
+
+    hildon_pannable_area_scroll_to (area, col_x, -1);
+  }
+  else {
+    hildon_pannable_area_scroll_to (area, 0, -1);
+  }
+
+  g_print ("horizontal_movement %lf, %lf\n", x, y);
+}
+
+static void
+vertical_movement (HildonPannableArea *area,
+                   HildonPannableAreaMovDirection direction,
+                  gdouble x, gdouble y,
+                   gpointer user_data)
+{
+  g_print ("vertical_movement: %lf, %lf\n", x, y);
+}
+
+static void
+get_sawtooth_label (gchar **label, guint num)
+{
+  static gchar *sawtooth = NULL;
+  gchar *label_aux, *sawtooth_aux;
+
+  if (num % 5 != 0) {
+    sawtooth_aux = g_strconcat (" ", sawtooth, NULL);
+    g_free (sawtooth);
+
+    sawtooth = sawtooth_aux;
+  } else {
+    sawtooth = g_strdup (" ");
+  }
+
+  label_aux = g_strconcat (sawtooth, *label, NULL);
+  g_free (*label);
+
+  *label = label_aux;
+}
+
+int
+main (int argc, char **args)
+{
+    int i;
+    HildonProgram *program;
+    GtkWidget *window, *tv, *panarea;
+    GtkTreeViewColumn *col;
+    GtkCellRenderer *renderer;
+    GtkListStore *store;
+    GtkVBox *vbox;
+
+    gtk_init (&argc, &args);
+
+    program = hildon_program_get_instance ();
+
+    ctx = g_new0 (HiddenColContext, 1);
+
+    /* 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);
+
+    /* Create a VBox and pack some buttons */
+    vbox = GTK_VBOX (gtk_vbox_new (FALSE, 1));
+
+    /* Create a treeview */
+    tv = gtk_tree_view_new ();
+    ctx->treeview = tv;
+
+    renderer = gtk_cell_renderer_text_new ();
+    col = gtk_tree_view_column_new_with_attributes ("Title", renderer, "text", TEXT_COLUMN, NULL);
+    gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
+
+    gtk_tree_view_column_set_fixed_width (col, 700);
+
+    gtk_tree_view_append_column (GTK_TREE_VIEW(tv), col);
+
+    col = gtk_tree_view_column_new_with_attributes ("Title", renderer, "text", OPTIONAL_COLUMN, NULL);
+    gtk_tree_view_append_column (GTK_TREE_VIEW(tv), col);
+
+    /* Add some rows to the treeview */
+    store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
+    for (i = 0; i < 100; i++) {
+            GtkTreeIter iter;
+            gchar *label = g_strdup_printf ("Row number %d", i);
+            gchar *label_optional = g_strdup_printf ("< >");
+
+            get_sawtooth_label (&label, i);
+
+            gtk_list_store_append (store, &iter);
+            gtk_list_store_set (store, &iter, TEXT_COLUMN, label, -1);
+            gtk_list_store_set (store, &iter, OPTIONAL_COLUMN, label_optional, -1);
+            g_free (label);
+            g_free (label_optional);
+    }
+    gtk_tree_view_set_model (GTK_TREE_VIEW (tv), GTK_TREE_MODEL (store));
+    g_object_unref (store);
+
+    /* Pack the treeview in the VBox */
+    gtk_box_pack_start (GTK_BOX (vbox), tv, TRUE, TRUE, 0);
+
+    /* Put everything in a pannable area */
+    panarea = hildon_pannable_area_new ();
+    g_object_set (panarea, "mov_mode", HILDON_PANNABLE_AREA_MOV_MODE_VERT,
+                  "hovershoot_max", 0,
+                  "hindicator_mode", HILDON_PANNABLE_AREA_INDICATOR_MODE_HIDE, NULL);
+
+    hildon_pannable_area_add_with_viewport (HILDON_PANNABLE_AREA (panarea), GTK_WIDGET (vbox));
+    gtk_container_add (GTK_CONTAINER (window), panarea);
+
+    g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (gtk_main_quit), NULL);
+
+    g_signal_connect (G_OBJECT (panarea), "horizontal_movement", G_CALLBACK (horizontal_movement), col);
+    g_signal_connect (G_OBJECT (panarea), "vertical_movement", G_CALLBACK (vertical_movement), NULL);
+
+    gtk_widget_show_all (GTK_WIDGET (window));
+
+    gtk_main ();
+
+    return 0;
+}
index 6fad716..d4a7f30 100644 (file)
@@ -28,3 +28,4 @@ BOOLEAN:INT,INT,INT
 BOOLEAN:POINTER
 VOID:OBJECT
 VOID:VOID
+VOID:INT,OBJECT,DOUBLE,DOUBLE
index cd102b2..88fee9d 100644 (file)
@@ -43,7 +43,7 @@
  * 6  x Reduce calls to queue_resize to improve performance
  * 7  x Make 'fast' factor a property
  * 8  - Strip out g_print/g_debug calls
- * 9  - Scroll policies (horizontal/vertical/both) suggest 1,2,3 for different policies (binary OR'd)
+ * 9  x Scroll policies (horizontal/vertical/both) suggest 1,2,3 for different policies (binary OR'd)
  * 10 x Delay click mode (only send synthetic clicks on mouse-up, as in previous
  *      versions.
  * 11 - 'Physical' mode for acceleration scrolling
 #include <cairo.h>
 #include <math.h>
 #include "hildon-pannable-area.h"
+#include "hildon-marshalers.h"
+#include "hildon-enum-types.h"
 
 #define SMOOTH_FACTOR 0.85
 #define FORCE 5
 #define BOUNCE_STEPS 6
 #define SCROLL_BAR_MIN_SIZE 5
 #define RATIO_TOLERANCE 0.000001
+#define DND_THREDSHOLD_INC 20
 
 G_DEFINE_TYPE (HildonPannableArea, hildon_pannable_area, GTK_TYPE_BIN)
 #define PANNABLE_AREA_PRIVATE(o)                                \
@@ -72,6 +75,7 @@ typedef struct _HildonPannableAreaPrivate HildonPannableAreaPrivate;
 
 struct _HildonPannableAreaPrivate {
   HildonPannableAreaMode mode;
+  HildonPannableAreaMovMode mov_mode;
   GdkWindow *event_window;
   gdouble x;           /* Used to store mouse co-ordinates of the first or */
   gdouble y;           /* previous events in a press-motion pair */
@@ -107,8 +111,10 @@ struct _HildonPannableAreaPrivate {
   gint scroll_indicator_timeout;
   gint scroll_indicator_event_interrupt;
   gint scroll_delay_counter;
-  gint overshoot_max;
+  gint vovershoot_max;
+  gint hovershoot_max;
   gboolean initial_hint;
+  gboolean first_drag;
 
   gboolean hscroll;
   gboolean vscroll;
@@ -129,9 +135,19 @@ struct _HildonPannableAreaPrivate {
 
 };
 
+/*signals*/
+enum {
+  HORIZONTAL_MOVEMENT,
+  VERTICAL_MOVEMENT,
+  LAST_SIGNAL
+};
+
+static guint pannable_area_signals [LAST_SIGNAL] = { 0 };
+
 enum {
   PROP_ENABLED = 1,
   PROP_MODE,
+  PROP_MOV_MODE,
   PROP_VELOCITY_MIN,
   PROP_VELOCITY_MAX,
   PROP_VELOCITY_FAST_FACTOR,
@@ -139,7 +155,8 @@ enum {
   PROP_SPS,
   PROP_VINDICATOR,
   PROP_HINDICATOR,
-  PROP_OVERSHOOT_MAX,
+  PROP_VOVERSHOOT_MAX,
+  PROP_HOVERSHOOT_MAX,
   PROP_SCROLL_TIME,
   PROP_INITIAL_HINT
 };
@@ -476,6 +493,7 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
                              gint *overshooting,
                              gint *overshot_dist,
                              gdouble *scroll_to,
+                             gint overshoot_max,
                              gboolean *s)
 {
   gdouble dist;
@@ -497,22 +515,26 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
 
       dist = adjust->lower;
 
-      if (priv->overshoot_max!=0) {
+      if (overshoot_max!=0) {
         *overshooting = 1;
         *scroll_to = -1;
-        *overshot_dist = CLAMP (*overshot_dist + *vel, 0, priv->overshoot_max);
+        *overshot_dist = CLAMP (*overshot_dist + *vel, 0, overshoot_max);
         gtk_widget_queue_resize (GTK_WIDGET (area));
+      } else {
+        *vel = 0.0;
       }
     } else if (dist > adjust->upper - adjust->page_size) {
       if (s) *s = FALSE;
 
       dist = adjust->upper - adjust->page_size;
 
-      if (priv->overshoot_max!=0) {
+      if (overshoot_max!=0) {
         *overshooting = 1;
         *scroll_to = -1;
-        *overshot_dist = CLAMP (*overshot_dist + *vel, -1*priv->overshoot_max, 0);
+        *overshot_dist = CLAMP (*overshot_dist + *vel, -1*overshoot_max, 0);
         gtk_widget_queue_resize (GTK_WIDGET (area));
+      } else {
+        *vel = 0.0;
       }
     } else {
       if ((*scroll_to) != -1) {
@@ -538,17 +560,17 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
 
         if ((*overshooting < BOUNCE_STEPS) && (*vel > 0)) {
           (*overshooting)++;
-          *vel = (((gdouble)*overshot_dist)/priv->overshoot_max) * (*vel);
+          *vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel);
         } else if ((*overshooting >= 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 */
-          *vel = MIN ((((gdouble)*overshot_dist)/priv->overshoot_max) * (*vel), -10.0);
+          *vel = MIN ((((gdouble)*overshot_dist)/overshoot_max) * (*vel), -10.0);
         }
 
-        *overshot_dist = CLAMP (*overshot_dist + *vel, 0, priv->overshoot_max);
+        *overshot_dist = CLAMP (*overshot_dist + *vel, 0, overshoot_max);
 
         gtk_widget_queue_resize (GTK_WIDGET (area));
 
@@ -556,17 +578,17 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
 
         if ((*overshooting < BOUNCE_STEPS) && (*vel < 0)) {
           (*overshooting)++;
-          *vel = (((gdouble)*overshot_dist)/priv->overshoot_max) * (*vel) * -1;
+          *vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1;
         } else if ((*overshooting >= 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 */
-          *vel = MAX ((((gdouble)*overshot_dist)/priv->overshoot_max) * (*vel) * -1, 10.0);
+          *vel = MAX ((((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1, 10.0);
         }
 
-        *overshot_dist = CLAMP (*overshot_dist + (*vel), -1*priv->overshoot_max, 0);
+        *overshot_dist = CLAMP (*overshot_dist + (*vel), -1*overshoot_max, 0);
 
         gtk_widget_queue_resize (GTK_WIDGET (area));
 
@@ -577,9 +599,9 @@ hildon_pannable_axis_scroll (HildonPannableArea *area,
       }
     } else {
       if (*overshot_dist > 0) {
-        *overshot_dist = CLAMP ((*overshot_dist) + inc, 0, priv->overshoot_max);
+        *overshot_dist = CLAMP ((*overshot_dist) + inc, 0, overshoot_max);
       } else if (*overshot_dist < 0) {
-        *overshot_dist = CLAMP ((*overshot_dist) + inc, -1 * priv->overshoot_max, 0);
+        *overshot_dist = CLAMP ((*overshot_dist) + inc, -1 * overshoot_max, 0);
       } else {
         *overshooting = 0;
         gtk_adjustment_set_value (adjust, dist);
@@ -613,13 +635,13 @@ hildon_pannable_area_scroll (HildonPannableArea *area,
   if (vscroll) {
     hildon_pannable_axis_scroll (area, priv->vadjust, &priv->vel_y, y,
                                  &priv->overshooting_y, &priv->overshot_dist_y,
-                                 &priv->scroll_to_y, &sy);
+                                 &priv->scroll_to_y, priv->vovershoot_max, &sy);
   }
 
   if (hscroll) {
     hildon_pannable_axis_scroll (area, priv->hadjust, &priv->vel_x, x,
                                  &priv->overshooting_x, &priv->overshot_dist_x,
-                                 &priv->scroll_to_x, &sx);
+                                 &priv->scroll_to_x, priv->hovershoot_max, &sx);
   }
 
   /* If the scroll on a particular axis wasn't succesful, reset the
@@ -710,6 +732,10 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
     return TRUE;
   }
 
+  if (priv->last_type == 1) {
+    priv->first_drag = TRUE;
+  }
+
   /* Only start the scroll if the mouse cursor passes beyond the
    * DnD threshold for dragging.
    */
@@ -718,10 +744,57 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
   x = event->x - priv->x;
   y = event->y - priv->y;
 
-  if ((!priv->moved) && ((ABS (x) > dnd_threshold)
-                        || (ABS (y) > dnd_threshold))) {
+  if ((!priv->moved) && ((ABS (x) > (dnd_threshold+DND_THREDSHOLD_INC))
+                        || (ABS (y) > (dnd_threshold+DND_THREDSHOLD_INC)))) {
     priv->moved = TRUE;
 
+    if (priv->first_drag) {
+      GdkWindow *window = NULL;
+      GtkWidget *child_widget = NULL;
+
+      window = hildon_pannable_area_get_topmost
+        (gtk_bin_get_child (GTK_BIN (widget))->window,
+         priv->click_x, priv->click_y, NULL, NULL);
+
+      gdk_window_get_user_data (window, (void**) &child_widget);
+
+      if (ABS (priv->click_y - event->y) >=
+          ABS (priv->click_x - event->x)) {
+        if (priv->click_y > event->y)
+          g_signal_emit (area,
+                         pannable_area_signals[VERTICAL_MOVEMENT],
+                         0, HILDON_PANNABLE_AREA_MOV_UP, child_widget,
+                         priv->click_x, priv->click_y);
+        else
+          g_signal_emit (area,
+                         pannable_area_signals[VERTICAL_MOVEMENT],
+                         0, HILDON_PANNABLE_AREA_MOV_DOWN, child_widget,
+                         priv->click_x, priv->click_y);
+
+        if (!((priv->vscroll)&&
+              (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_VERT)))
+          return TRUE;
+
+      } else {
+        if (priv->click_x > event->x)
+          g_signal_emit (area,
+                         pannable_area_signals[HORIZONTAL_MOVEMENT],
+                         0, HILDON_PANNABLE_AREA_MOV_LEFT, child_widget,
+                         priv->click_x, priv->click_y);
+        else
+          g_signal_emit (area,
+                         pannable_area_signals[HORIZONTAL_MOVEMENT],
+                         0, HILDON_PANNABLE_AREA_MOV_RIGHT, child_widget,
+                         priv->click_x, priv->click_y);
+
+        if (!((priv->hscroll)&&
+              (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_HORI)))
+          return TRUE;
+      }
+    }
+
+    priv->first_drag = FALSE;
+
     if ((priv->mode != HILDON_PANNABLE_AREA_MODE_PUSH) &&
        (priv->mode != HILDON_PANNABLE_AREA_MODE_AUTO)) {
 
@@ -762,33 +835,42 @@ hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
 
       delta = event->time - priv->last_time;
 
-      rawvel_x = (((event->x - priv->x) / ABS (delta)) *
-                 (gdouble) priv->sps) * FORCE;
-      rawvel_y = (((event->y - priv->y) / ABS (delta)) *
-                 (gdouble) priv->sps) * FORCE;
-
-      /* we store the direction and after the calculation we
-         change it, this reduces the ifs for the calculation */
-      direction_x = rawvel_x < 0 ? -1 : 1;
-      direction_y = rawvel_y < 0 ? -1 : 1;
-
-      rawvel_y = ABS (rawvel_y);
-      rawvel_x = ABS (rawvel_x);
-
-      priv->vel_x = priv->vel_x * (1 - SMOOTH_FACTOR) +
-       direction_x * rawvel_x * SMOOTH_FACTOR;
-      priv->vel_y = priv->vel_y * (1 - SMOOTH_FACTOR) +
-       direction_y * rawvel_y * SMOOTH_FACTOR;
+      if (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_HORI) {
+        rawvel_x = (((event->x - priv->x) / ABS (delta)) *
+                    (gdouble) priv->sps) * FORCE;
+        /* we store the direction and after the calculation we
+           change it, this reduces the ifs for the calculation */
+        direction_x = rawvel_x < 0 ? -1 : 1;
+        rawvel_x = ABS (rawvel_x);
+        priv->vel_x = priv->vel_x * (1 - SMOOTH_FACTOR) +
+          direction_x * rawvel_x * SMOOTH_FACTOR;
+        priv->vel_x = priv->vel_x > 0 ? MIN (priv->vel_x, priv->vmax)
+          : MAX (priv->vel_x, -1 * priv->vmax);
+      } else {
+        x = 0;
+        priv->vel_x = 0;
+      }
 
-      priv->vel_x = priv->vel_x > 0 ? MIN (priv->vel_x, priv->vmax)
-       : MAX (priv->vel_x, -1 * priv->vmax);
-      priv->vel_y = priv->vel_y > 0 ? MIN (priv->vel_y, priv->vmax)
-       : MAX (priv->vel_y, -1 * priv->vmax);
+      if (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_VERT) {
+        rawvel_y = (((event->y - priv->y) / ABS (delta)) *
+                    (gdouble) priv->sps) * FORCE;
+        direction_y = rawvel_y < 0 ? -1 : 1;
+        rawvel_y = ABS (rawvel_y);
+        priv->vel_y = priv->vel_y * (1 - SMOOTH_FACTOR) +
+          direction_y * rawvel_y * SMOOTH_FACTOR;
+        priv->vel_y = priv->vel_y > 0 ? MIN (priv->vel_y, priv->vmax)
+          : MAX (priv->vel_y, -1 * priv->vmax);
+      } else {
+        y = 0;
+        priv->vel_y = 0;
+      }
 
       hildon_pannable_area_scroll (area, x, y);
 
-      priv->x = event->x;
-      priv->y = event->y;
+      if (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_HORI)
+        priv->x = event->x;
+      if (priv->mov_mode&HILDON_PANNABLE_AREA_MOV_MODE_VERT)
+        priv->y = event->y;
 
       break;
 
@@ -1222,6 +1304,9 @@ hildon_pannable_area_get_property (GObject * object, guint property_id,
   case PROP_MODE:
     g_value_set_enum (value, priv->mode);
     break;
+  case PROP_MOV_MODE:
+    g_value_set_flags (value, priv->mov_mode);
+    break;
   case PROP_VELOCITY_MIN:
     g_value_set_double (value, priv->vmin);
     break;
@@ -1243,8 +1328,11 @@ hildon_pannable_area_get_property (GObject * object, guint property_id,
   case PROP_HINDICATOR:
     g_value_set_enum (value, priv->hindicator_mode);
     break;
-  case PROP_OVERSHOOT_MAX:
-    g_value_set_int (value, priv->overshoot_max);
+  case PROP_VOVERSHOOT_MAX:
+    g_value_set_int (value, priv->vovershoot_max);
+    break;
+  case PROP_HOVERSHOOT_MAX:
+    g_value_set_int (value, priv->hovershoot_max);
     break;
   case PROP_SCROLL_TIME:
     g_value_set_double (value, priv->scroll_time);
@@ -1281,6 +1369,9 @@ hildon_pannable_area_set_property (GObject * object, guint property_id,
   case PROP_MODE:
     priv->mode = g_value_get_enum (value);
     break;
+  case PROP_MOV_MODE:
+    priv->mov_mode = g_value_get_flags (value);
+    break;
   case PROP_VELOCITY_MIN:
     priv->vmin = g_value_get_double (value);
     break;
@@ -1304,8 +1395,11 @@ hildon_pannable_area_set_property (GObject * object, guint property_id,
   case PROP_HINDICATOR:
     priv->hindicator_mode = g_value_get_enum (value);
     break;
-  case PROP_OVERSHOOT_MAX:
-    priv->overshoot_max = g_value_get_int (value);
+  case PROP_VOVERSHOOT_MAX:
+    priv->vovershoot_max = g_value_get_int (value);
+    break;
+  case PROP_HOVERSHOOT_MAX:
+    priv->hovershoot_max = g_value_get_int (value);
     break;
   case PROP_SCROLL_TIME:
     priv->scroll_time = g_value_get_double (value);
@@ -1430,7 +1524,7 @@ hildon_pannable_area_map (GtkWidget * widget)
     gdk_window_show (priv->event_window);
 
   if (priv->initial_hint) {
-    if ((priv->overshoot_max != 0) &&
+    if (((priv->vovershoot_max != 0)||(priv->hovershoot_max != 0)) &&
         ((priv->mode == HILDON_PANNABLE_AREA_MODE_AUTO) ||
          (priv->mode == HILDON_PANNABLE_AREA_MODE_ACCEL))) {
       vscroll = (priv->vadjust->upper - priv->vadjust->lower >
@@ -1439,11 +1533,11 @@ hildon_pannable_area_map (GtkWidget * widget)
                  priv->hadjust->page_size) ? TRUE : FALSE;
       /* If scrolling is possible in both axes, only hint about scrolling in
          the vertical one. */
-      if (vscroll) {
-        priv->overshot_dist_y = priv->overshoot_max;
+      if ((vscroll)&&(priv->vovershoot_max != 0)) {
+        priv->overshot_dist_y = priv->vovershoot_max;
         priv->vel_y = priv->vmax * 0.1;
-      } else if (hscroll) {
-        priv->overshot_dist_x = priv->overshoot_max;
+      } else if ((hscroll)&&(priv->hovershoot_max != 0)) {
+        priv->overshot_dist_x = priv->hovershoot_max;
         priv->vel_x = priv->vmax * 0.1;
       }
 
@@ -1601,6 +1695,9 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
   container_class->add = hildon_pannable_area_add;
   container_class->remove = hildon_pannable_area_remove;
 
+  klass->horizontal_movement = NULL;
+  klass->vertical_movement = NULL;
+
   g_object_class_install_property (object_class,
                                   PROP_ENABLED,
                                   g_param_spec_boolean ("enabled",
@@ -1641,6 +1738,16 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                                      G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (object_class,
+                                  PROP_MOV_MODE,
+                                  g_param_spec_flags ("mov_mode",
+                                                       "Scroll movement mode",
+                                                       "Controls if the widget can scroll vertically, horizontally or both",
+                                                       HILDON_TYPE_PANNABLE_AREA_MOV_MODE,
+                                                       HILDON_PANNABLE_AREA_MOV_MODE_BOTH,
+                                                       G_PARAM_READWRITE |
+                                                       G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
                                   PROP_VELOCITY_MIN,
                                   g_param_spec_double ("velocity_min",
                                                        "Minimum scroll velocity",
@@ -1691,10 +1798,19 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                                      G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (object_class,
-                                  PROP_OVERSHOOT_MAX,
-                                  g_param_spec_int ("overshoot",
-                                                     "Overshoot distance",
-                                                     "Space we allow the widget to pass over its limits when hitting the edges, set 0 in order to deactivate overshooting.",
+                                  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.",
+                                                     G_MININT, G_MAXINT, 150,
+                                                     G_PARAM_READWRITE |
+                                                     G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                  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.",
                                                      G_MININT, G_MAXINT, 150,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT));
@@ -1725,6 +1841,34 @@ hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
                                            "Pixel width used to draw the scroll indicators.",
                                            0, G_MAXUINT, 8,
                                            G_PARAM_READWRITE));
+
+  pannable_area_signals[HORIZONTAL_MOVEMENT] =
+    g_signal_new ("horizontal_movement",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (HildonPannableAreaClass, horizontal_movement),
+                 NULL, NULL,
+                 _hildon_marshal_VOID__INT_OBJECT_DOUBLE_DOUBLE,
+                 G_TYPE_NONE, 4,
+                  G_TYPE_INT,
+                  GTK_TYPE_WIDGET,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_DOUBLE);
+
+  pannable_area_signals[VERTICAL_MOVEMENT] =
+    g_signal_new ("vertical_movement",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (HildonPannableAreaClass, vertical_movement),
+                 NULL, NULL,
+                 _hildon_marshal_VOID__INT_OBJECT_DOUBLE_DOUBLE,
+                 G_TYPE_NONE, 4,
+                  G_TYPE_INT,
+                  GTK_TYPE_WIDGET,
+                 G_TYPE_DOUBLE,
+                 G_TYPE_DOUBLE);
+
+
 }
 
 static void
@@ -1752,6 +1896,7 @@ hildon_pannable_area_init (HildonPannableArea * self)
   priv->scroll_delay_counter = 0;
   priv->scroll_to_x = -1;
   priv->scroll_to_y = -1;
+  priv->first_drag = TRUE;
 
   hildon_pannable_calculate_vel_factor (self);
 
@@ -2007,10 +2152,12 @@ hildon_pannable_area_jump_to (HildonPannableArea *area,
       gtk_widget_queue_resize (GTK_WIDGET (area));
     }
     g_source_remove (priv->scroll_indicator_timeout);
+    priv->scroll_indicator_timeout = 0;
   }
 
   if (priv->idle_id)
     g_source_remove (priv->idle_id);
+  priv->idle_id = 0;
 }
 
 /**
index c3f082f..d4b32f3 100644 (file)
@@ -50,17 +50,57 @@ G_BEGIN_DECLS
                                                 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
                                                 HILDON_TYPE_PANNABLE_AREA, HildonPannableAreaClass))
 
-GType
-hildon_pannable_area_mode_get_type              (void) G_GNUC_CONST;
+/**
+ * HildonPannableAreaMode:
+ * @HILDON_PANNABLE_AREA_MODE_PUSH: Areaing follows pointer
+ * @HILDON_PANNABLE_AREA_MODE_ACCEL: Areaing uses physics to "spin" the widget
+ * @HILDON_PANNABLE_AREA_MODE_AUTO: Automatically chooses between push and accel
+ * modes, depending on input.
+ *
+ * Used to change the behaviour of the pannable areaing
+ */
+typedef enum {
+  HILDON_PANNABLE_AREA_MODE_PUSH,
+  HILDON_PANNABLE_AREA_MODE_ACCEL,
+  HILDON_PANNABLE_AREA_MODE_AUTO
+} HildonPannableAreaMode;
 
-#define                                         HILDON_TYPE_PANNABLE_AREA_MODE \
-                                                (hildon_pannable_area_mode_get_type())
+/**
+ * HildonPannableAreaMovDirection:
+ * @HILDON_PANNABLE_AREA_MOV_MODE_HORIZ:
+ * @HILDON_PANNABLE_AREA_MOV_MODE_VERT:
+ *
+ * Used to control the movement of the pannable, we can allow or
+ * disallow horizontal or vertical movement. This way the applications
+ * can control the movement using scroll_to and jump_to functions
+ */
+typedef enum {
+  HILDON_PANNABLE_AREA_MOV_MODE_HORI = 1 << 1,
+  HILDON_PANNABLE_AREA_MOV_MODE_VERT = 1 << 2,
+  HILDON_PANNABLE_AREA_MOV_MODE_BOTH = 0x000006
+} HildonPannableAreaMovMode;
 
-GType
-hildon_pannable_area_indicator_mode_get_type    (void) G_GNUC_CONST;
+/**
+ * HildonPannableAreaMovDirection:
+ * @HILDON_PANNABLE_AREA_MOV_UP:
+ * @HILDON_PANNABLE_AREA_MOV_DOWN:
+ * @HILDON_PANNABLE_AREA_MOV_LEFT:
+ * @HILDON_PANNABLE_AREA_MOV_RIGHT:
+ *
+ * Used to point out the direction of the movement
+ */
+typedef enum {
+  HILDON_PANNABLE_AREA_MOV_UP,
+  HILDON_PANNABLE_AREA_MOV_DOWN,
+  HILDON_PANNABLE_AREA_MOV_LEFT,
+  HILDON_PANNABLE_AREA_MOV_RIGHT
+} HildonPannableAreaMovDirection;
 
-#define                                         HILDON_TYPE_PANNABLE_AREA_INDICATOR_MODE \
-                                                (hildon_pannable_area_indicator_mode_get_type())
+typedef enum {
+    HILDON_PANNABLE_AREA_INDICATOR_MODE_AUTO,
+    HILDON_PANNABLE_AREA_INDICATOR_MODE_SHOW,
+    HILDON_PANNABLE_AREA_INDICATOR_MODE_HIDE
+} HildonPannableAreaIndicatorMode;
 
 /**
  * HildonPannableArea:
@@ -78,28 +118,14 @@ struct                                          _HildonPannableArea
 struct                                          _HildonPannableAreaClass
 {
     GtkBinClass parent_class;
-};
 
-/**
- * HildonPannableAreaMode:
- * @HILDON_PANNABLE_AREA_MODE_PUSH: Areaing follows pointer
- * @HILDON_PANNABLE_AREA_MODE_ACCEL: Areaing uses physics to "spin" the widget
- * @HILDON_PANNABLE_AREA_MODE_AUTO: Automatically chooses between push and accel
- * modes, depending on input.
- *
- * Used to change the behaviour of the pannable areaing
- */
-typedef enum {
-    HILDON_PANNABLE_AREA_MODE_PUSH,
-    HILDON_PANNABLE_AREA_MODE_ACCEL,
-    HILDON_PANNABLE_AREA_MODE_AUTO
-} HildonPannableAreaMode;
-
-typedef enum {
-    HILDON_PANNABLE_AREA_INDICATOR_MODE_AUTO,
-    HILDON_PANNABLE_AREA_INDICATOR_MODE_SHOW,
-    HILDON_PANNABLE_AREA_INDICATOR_MODE_HIDE
-} HildonPannableAreaIndicatorMode;
+  void (* horizontal_movement) (HildonPannableArea *area,
+                                HildonPannableAreaIndicatorMode direction,
+                                GtkWidget *widget, gdouble x, gdouble y);
+  void (* vertical_movement) (HildonPannableArea *area,
+                              HildonPannableAreaIndicatorMode direction,
+                              GtkWidget *widget, gdouble x, gdouble y);
+};
 
 GType hildon_pannable_area_get_type             (void);