2
* This file is a part of hildon
4
* Copyright (C) 2008 Nokia Corporation, all rights reserved.
6
* Contact: Karl Lattimer <karl.lattimer@nokia.com>
8
* This widget is based on MokoFingerScroll from libmokoui
9
* OpenMoko Application Framework UI Library
10
* Authored by Chris Lord <chris@openedhand.com>
11
* Copyright (C) 2006-2007 OpenMoko Inc.
13
* This program is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU Lesser Public License as published by
15
* the Free Software Foundation; version 2 of the license.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU Lesser Public License for more details.
25
* SECTION: hildon-pannable-area
26
* @short_description: A scrolling widget designed for touch screens
27
* @see_also: #GtkScrolledWindow
29
* #HildonPannableArea implements a scrolled window designed to be used with a
30
* touch screen interface. The user scrolls the child widget by activating the
31
* pointing device and dragging it over the widget.
39
#include "hildon-pannable-area.h"
40
#include "hildon-marshalers.h"
41
#include "hildon-enum-types.h"
43
#define SMOOTH_FACTOR 0.85
45
#define BOUNCE_STEPS 6
46
#define SCROLL_BAR_MIN_SIZE 5
47
#define RATIO_TOLERANCE 0.000001
48
#define DND_THRESHOLD_INC 20
49
#define SCROLLBAR_FADE_DELAY 30
51
G_DEFINE_TYPE (HildonPannableArea, hildon_pannable_area, GTK_TYPE_BIN)
53
#define PANNABLE_AREA_PRIVATE(o) \
54
(G_TYPE_INSTANCE_GET_PRIVATE ((o), HILDON_TYPE_PANNABLE_AREA, \
55
HildonPannableAreaPrivate))
57
struct _HildonPannableAreaPrivate {
58
HildonPannableAreaMode mode;
59
HildonMovementMode mov_mode;
60
GdkWindow *event_window;
61
gdouble x; /* Used to store mouse co-ordinates of the first or */
62
gdouble y; /* previous events in a press-motion pair */
63
gdouble ex; /* Used to store mouse co-ordinates of the last */
64
gdouble ey; /* motion event in acceleration mode */
67
guint32 last_time; /* Last event time, to stop infinite loops */
80
gint ix; /* Initial click mouse co-ordinates */
82
gint cx; /* Initial click child window mouse co-ordinates */
91
gdouble scroll_indicator_alpha;
92
gint scroll_indicator_timeout;
93
gint scroll_indicator_event_interrupt;
94
gint scroll_delay_counter;
97
gboolean initial_hint;
98
gboolean initial_effect;
101
gboolean hscroll_visible;
102
gboolean vscroll_visible;
103
GdkRectangle hscroll_rect;
104
GdkRectangle vscroll_rect;
107
GtkAdjustment *hadjust;
108
GtkAdjustment *vadjust;
110
GtkPolicyType vscrollbar_policy;
111
GtkPolicyType hscrollbar_policy;
121
static guint pannable_area_signals [LAST_SIGNAL] = { 0 };
129
PROP_VELOCITY_FAST_FACTOR,
132
PROP_VSCROLLBAR_POLICY,
133
PROP_HSCROLLBAR_POLICY,
140
static void hildon_pannable_area_class_init (HildonPannableAreaClass * klass);
141
static void hildon_pannable_area_init (HildonPannableArea * area);
142
static void hildon_pannable_area_get_property (GObject * object,
146
static void hildon_pannable_area_set_property (GObject * object,
148
const GValue * value,
150
static void hildon_pannable_area_dispose (GObject * object);
151
static void hildon_pannable_area_realize (GtkWidget * widget);
152
static void hildon_pannable_area_unrealize (GtkWidget * widget);
153
static void hildon_pannable_area_size_request (GtkWidget * widget,
154
GtkRequisition * requisition);
155
static void hildon_pannable_area_size_allocate (GtkWidget * widget,
156
GtkAllocation * allocation);
157
static void hildon_pannable_area_style_set (GtkWidget * widget,
158
GtkStyle * previous_style);
159
static void hildon_pannable_area_map (GtkWidget * widget);
160
static void hildon_pannable_area_unmap (GtkWidget * widget);
161
static void hildon_pannable_area_grab_notify (GtkWidget *widget,
162
gboolean was_grabbed,
164
static void rgb_from_gdkcolor (GdkColor *color, gdouble *r, gdouble *g, gdouble *b);
165
static void hildon_pannable_draw_vscroll (GtkWidget * widget,
166
GdkColor *back_color,
167
GdkColor *scroll_color);
168
static void hildon_pannable_draw_hscroll (GtkWidget * widget,
169
GdkColor *back_color,
170
GdkColor *scroll_color);
171
static void hildon_pannable_area_initial_effect (GtkWidget * widget);
172
static void hildon_pannable_area_redraw (HildonPannableArea * area);
173
static gboolean hildon_pannable_area_scroll_indicator_fade(HildonPannableArea * area);
174
static gboolean hildon_pannable_area_expose_event (GtkWidget * widget,
175
GdkEventExpose * event);
176
static GdkWindow * hildon_pannable_area_get_topmost (GdkWindow * window,
178
gint * tx, gint * ty);
179
static void synth_crossing (GdkWindow * child,
181
gint x_root, gint y_root,
182
guint32 time, gboolean in);
183
static gboolean hildon_pannable_area_button_press_cb (GtkWidget * widget,
184
GdkEventButton * event);
185
static void hildon_pannable_area_refresh (HildonPannableArea * area);
186
static void hildon_pannable_axis_scroll (HildonPannableArea *area,
187
GtkAdjustment *adjust,
195
static void hildon_pannable_area_scroll (HildonPannableArea *area,
196
gdouble x, gdouble y);
197
static gboolean hildon_pannable_area_timeout (HildonPannableArea * area);
198
static void hildon_pannable_area_calculate_velocity (gdouble *vel,
203
static gboolean hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
204
GdkEventMotion * event);
205
static gboolean hildon_pannable_area_button_release_cb (GtkWidget * widget,
206
GdkEventButton * event);
207
static gboolean hildon_pannable_area_scroll_cb (GtkWidget *widget,
208
GdkEventScroll *event);
209
static void hildon_pannable_area_child_mapped (GtkWidget *widget,
212
static void hildon_pannable_area_add (GtkContainer *container, GtkWidget *child);
213
static void hildon_pannable_area_remove (GtkContainer *container, GtkWidget *child);
214
static void hildon_pannable_calculate_vel_factor (HildonPannableArea * self);
218
hildon_pannable_area_class_init (HildonPannableAreaClass * klass)
220
GObjectClass *object_class = G_OBJECT_CLASS (klass);
221
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
222
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
225
g_type_class_add_private (klass, sizeof (HildonPannableAreaPrivate));
227
object_class->get_property = hildon_pannable_area_get_property;
228
object_class->set_property = hildon_pannable_area_set_property;
229
object_class->dispose = hildon_pannable_area_dispose;
231
widget_class->realize = hildon_pannable_area_realize;
232
widget_class->unrealize = hildon_pannable_area_unrealize;
233
widget_class->map = hildon_pannable_area_map;
234
widget_class->unmap = hildon_pannable_area_unmap;
235
widget_class->size_request = hildon_pannable_area_size_request;
236
widget_class->size_allocate = hildon_pannable_area_size_allocate;
237
widget_class->expose_event = hildon_pannable_area_expose_event;
238
widget_class->style_set = hildon_pannable_area_style_set;
239
widget_class->button_press_event = hildon_pannable_area_button_press_cb;
240
widget_class->button_release_event = hildon_pannable_area_button_release_cb;
241
widget_class->motion_notify_event = hildon_pannable_area_motion_notify_cb;
242
widget_class->scroll_event = hildon_pannable_area_scroll_cb;
244
container_class->add = hildon_pannable_area_add;
245
container_class->remove = hildon_pannable_area_remove;
247
klass->horizontal_movement = NULL;
248
klass->vertical_movement = NULL;
250
g_object_class_install_property (object_class,
252
g_param_spec_boolean ("enabled",
254
"Enable or disable finger-scroll.",
259
g_object_class_install_property (object_class,
260
PROP_VSCROLLBAR_POLICY,
261
g_param_spec_enum ("vscrollbar_policy",
263
"Visual policy of the vertical scrollbar",
264
GTK_TYPE_POLICY_TYPE,
265
GTK_POLICY_AUTOMATIC,
269
g_object_class_install_property (object_class,
270
PROP_HSCROLLBAR_POLICY,
271
g_param_spec_enum ("hscrollbar_policy",
273
"Visual policy of the horizontal scrollbar",
274
GTK_TYPE_POLICY_TYPE,
275
GTK_POLICY_AUTOMATIC,
279
g_object_class_install_property (object_class,
281
g_param_spec_enum ("mode",
283
"Change the finger-scrolling mode.",
284
HILDON_TYPE_PANNABLE_AREA_MODE,
285
HILDON_PANNABLE_AREA_MODE_AUTO,
289
g_object_class_install_property (object_class,
291
g_param_spec_flags ("mov_mode",
292
"Scroll movement mode",
293
"Controls if the widget can scroll vertically, horizontally or both",
294
HILDON_TYPE_MOVEMENT_MODE,
295
HILDON_MOVEMENT_MODE_VERT,
299
g_object_class_install_property (object_class,
301
g_param_spec_double ("velocity_min",
302
"Minimum scroll velocity",
303
"Minimum distance the child widget should scroll "
304
"per 'frame', in pixels.",
309
g_object_class_install_property (object_class,
311
g_param_spec_double ("velocity_max",
312
"Maximum scroll velocity",
313
"Maximum distance the child widget should scroll "
314
"per 'frame', in pixels.",
319
g_object_class_install_property (object_class,
320
PROP_VELOCITY_FAST_FACTOR,
321
g_param_spec_double ("velocity_fast_factor",
322
"Fast velocity factor",
323
"Minimum velocity that is considered 'fast': "
324
"children widgets won't receive button presses. "
325
"Expressed as a fraction of the maximum velocity.",
330
g_object_class_install_property (object_class,
332
g_param_spec_double ("deceleration",
333
"Deceleration multiplier",
334
"The multiplier used when decelerating when in "
335
"acceleration scrolling mode.",
340
g_object_class_install_property (object_class,
342
g_param_spec_uint ("sps",
343
"Scrolls per second",
344
"Amount of scroll events to generate per second.",
349
g_object_class_install_property (object_class,
351
g_param_spec_int ("vovershoot_max",
352
"Vertical overshoot distance",
353
"Space we allow the widget to pass over its vertical limits when hitting the edges, set 0 in order to deactivate overshooting.",
358
g_object_class_install_property (object_class,
360
g_param_spec_int ("hovershoot_max",
361
"Horizontal overshoot distance",
362
"Space we allow the widget to pass over its horizontal limits when hitting the edges, set 0 in order to deactivate overshooting.",
367
g_object_class_install_property (object_class,
369
g_param_spec_double ("scroll_time",
370
"Time to scroll to a position",
371
"The time to scroll to a position when calling the hildon_pannable_scroll_to function"
372
"acceleration scrolling mode.",
377
g_object_class_install_property (object_class,
379
g_param_spec_boolean ("initial-hint",
381
"Whether to hint the user about the pannability of the container.",
386
gtk_widget_class_install_style_property (widget_class,
389
"Width of the scroll indicators",
390
"Pixel width used to draw the scroll indicators.",
394
pannable_area_signals[HORIZONTAL_MOVEMENT] =
395
g_signal_new ("horizontal_movement",
396
G_TYPE_FROM_CLASS (object_class),
397
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
398
G_STRUCT_OFFSET (HildonPannableAreaClass, horizontal_movement),
400
_hildon_marshal_VOID__INT_DOUBLE_DOUBLE,
406
pannable_area_signals[VERTICAL_MOVEMENT] =
407
g_signal_new ("vertical_movement",
408
G_TYPE_FROM_CLASS (object_class),
409
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
410
G_STRUCT_OFFSET (HildonPannableAreaClass, vertical_movement),
412
_hildon_marshal_VOID__INT_DOUBLE_DOUBLE,
422
hildon_pannable_area_init (HildonPannableArea * area)
424
HildonPannableAreaPrivate *priv = PANNABLE_AREA_PRIVATE (area);
429
priv->clicked = FALSE;
432
priv->vscroll_visible = TRUE;
433
priv->hscroll_visible = TRUE;
434
priv->area_width = 6;
435
priv->overshot_dist_x = 0;
436
priv->overshot_dist_y = 0;
437
priv->overshooting_y = 0;
438
priv->overshooting_x = 0;
442
priv->scroll_indicator_alpha = 0.0;
443
priv->scroll_indicator_timeout = 0;
444
priv->scroll_indicator_event_interrupt = 0;
445
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
446
priv->scroll_to_x = -1;
447
priv->scroll_to_y = -1;
448
priv->first_drag = TRUE;
449
priv->initial_effect = TRUE;
451
hildon_pannable_calculate_vel_factor (area);
453
gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_HINT_MASK);
456
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
458
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
460
g_object_ref_sink (G_OBJECT (priv->hadjust));
461
g_object_ref_sink (G_OBJECT (priv->vadjust));
463
g_signal_connect_swapped (G_OBJECT (priv->hadjust), "value-changed",
464
G_CALLBACK (hildon_pannable_area_redraw), area);
465
g_signal_connect_swapped (G_OBJECT (priv->vadjust), "value-changed",
466
G_CALLBACK (hildon_pannable_area_redraw), area);
467
g_signal_connect (G_OBJECT (area), "grab-notify",
468
G_CALLBACK (hildon_pannable_area_grab_notify), NULL);
472
hildon_pannable_area_get_property (GObject * object,
477
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (object)->priv;
479
switch (property_id) {
481
g_value_set_boolean (value, priv->enabled);
484
g_value_set_enum (value, priv->mode);
486
case PROP_MOVEMENT_MODE:
487
g_value_set_flags (value, priv->mov_mode);
489
case PROP_VELOCITY_MIN:
490
g_value_set_double (value, priv->vmin);
492
case PROP_VELOCITY_MAX:
493
g_value_set_double (value, priv->vmax);
495
case PROP_VELOCITY_FAST_FACTOR:
496
g_value_set_double (value, priv->vfast_factor);
498
case PROP_DECELERATION:
499
g_value_set_double (value, priv->decel);
502
g_value_set_uint (value, priv->sps);
504
case PROP_VSCROLLBAR_POLICY:
505
g_value_set_enum (value, priv->vscrollbar_policy);
507
case PROP_HSCROLLBAR_POLICY:
508
g_value_set_enum (value, priv->hscrollbar_policy);
510
case PROP_VOVERSHOOT_MAX:
511
g_value_set_int (value, priv->vovershoot_max);
513
case PROP_HOVERSHOOT_MAX:
514
g_value_set_int (value, priv->hovershoot_max);
516
case PROP_SCROLL_TIME:
517
g_value_set_double (value, priv->scroll_time);
519
case PROP_INITIAL_HINT:
520
g_value_set_boolean (value, priv->initial_hint);
524
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
529
hildon_pannable_area_set_property (GObject * object,
531
const GValue * value,
534
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (object)->priv;
537
switch (property_id) {
539
enabled = g_value_get_boolean (value);
541
if ((priv->enabled != enabled) && (GTK_WIDGET_REALIZED (object))) {
543
gdk_window_raise (priv->event_window);
545
gdk_window_lower (priv->event_window);
548
priv->enabled = enabled;
551
priv->mode = g_value_get_enum (value);
553
case PROP_MOVEMENT_MODE:
554
priv->mov_mode = g_value_get_flags (value);
556
case PROP_VELOCITY_MIN:
557
priv->vmin = g_value_get_double (value);
559
case PROP_VELOCITY_MAX:
560
priv->vmax = g_value_get_double (value);
562
case PROP_VELOCITY_FAST_FACTOR:
563
priv->vfast_factor = g_value_get_double (value);
565
case PROP_DECELERATION:
566
hildon_pannable_calculate_vel_factor (HILDON_PANNABLE_AREA (object));
568
priv->decel = g_value_get_double (value);
571
priv->sps = g_value_get_uint (value);
573
case PROP_VSCROLLBAR_POLICY:
574
priv->vscrollbar_policy = g_value_get_enum (value);
576
gtk_widget_queue_resize (GTK_WIDGET (object));
578
case PROP_HSCROLLBAR_POLICY:
579
priv->hscrollbar_policy = g_value_get_enum (value);
581
gtk_widget_queue_resize (GTK_WIDGET (object));
583
case PROP_VOVERSHOOT_MAX:
584
priv->vovershoot_max = g_value_get_int (value);
586
case PROP_HOVERSHOOT_MAX:
587
priv->hovershoot_max = g_value_get_int (value);
589
case PROP_SCROLL_TIME:
590
priv->scroll_time = g_value_get_double (value);
592
hildon_pannable_calculate_vel_factor (HILDON_PANNABLE_AREA (object));
594
case PROP_INITIAL_HINT:
595
priv->initial_hint = g_value_get_boolean (value);
599
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
604
hildon_pannable_area_dispose (GObject * object)
606
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (object)->priv;
607
GtkWidget *child = gtk_bin_get_child (GTK_BIN (object));
610
g_source_remove (priv->idle_id);
614
if (priv->scroll_indicator_timeout){
615
g_source_remove (priv->scroll_indicator_timeout);
616
priv->scroll_indicator_timeout = 0;
620
g_object_unref (priv->hadjust);
621
priv->hadjust = NULL;
624
g_object_unref (priv->vadjust);
625
priv->vadjust = NULL;
629
g_signal_handlers_disconnect_by_func (GTK_WIDGET (child),
630
G_CALLBACK (hildon_pannable_area_child_mapped),
634
if (G_OBJECT_CLASS (hildon_pannable_area_parent_class)->dispose)
635
G_OBJECT_CLASS (hildon_pannable_area_parent_class)->dispose (object);
639
hildon_pannable_area_realize (GtkWidget * widget)
641
GdkWindowAttr attributes;
642
gint attributes_mask;
644
HildonPannableAreaPrivate *priv;
646
priv = HILDON_PANNABLE_AREA (widget)->priv;
648
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
650
border_width = GTK_CONTAINER (widget)->border_width;
652
attributes.x = widget->allocation.x + border_width;
653
attributes.y = widget->allocation.y + border_width;
654
attributes.width = MAX (widget->allocation.width - 2 * border_width -
655
(priv->vscroll_visible ? priv->vscroll_rect.width : 0), 0);
656
attributes.height = MAX (widget->allocation.height - 2 * border_width -
657
(priv->hscroll_visible ? priv->hscroll_rect.height : 0), 0);
658
attributes.window_type = GDK_WINDOW_CHILD;
659
attributes.event_mask = gtk_widget_get_events (widget)
660
| GDK_BUTTON_MOTION_MASK
661
| GDK_BUTTON_PRESS_MASK
662
| GDK_BUTTON_RELEASE_MASK
664
| GDK_EXPOSURE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK;
666
widget->window = gtk_widget_get_parent_window (widget);
667
g_object_ref (widget->window);
669
attributes.wclass = GDK_INPUT_ONLY;
670
attributes_mask = GDK_WA_X | GDK_WA_Y;
672
priv->event_window = gdk_window_new (widget->window,
673
&attributes, attributes_mask);
674
gdk_window_set_user_data (priv->event_window, widget);
676
widget->style = gtk_style_attach (widget->style, widget->window);
680
hildon_pannable_area_unrealize (GtkWidget * widget)
682
HildonPannableAreaPrivate *priv;
684
priv = HILDON_PANNABLE_AREA (widget)->priv;
686
if (priv->event_window != NULL) {
687
gdk_window_set_user_data (priv->event_window, NULL);
688
gdk_window_destroy (priv->event_window);
689
priv->event_window = NULL;
692
if (GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->unrealize)
693
(*GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->unrealize)(widget);
697
hildon_pannable_area_size_request (GtkWidget * widget,
698
GtkRequisition * requisition)
700
GtkRequisition child_requisition;
701
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
702
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
704
if (child && GTK_WIDGET_VISIBLE (child))
706
gtk_widget_size_request (child, &child_requisition);
709
if (priv->hscrollbar_policy == GTK_POLICY_NEVER) {
710
requisition->width = child_requisition.width;
712
requisition->width = priv->area_width;
715
if (priv->vscrollbar_policy == GTK_POLICY_NEVER) {
716
requisition->height = child_requisition.height;
718
requisition->height = priv->area_width;
721
requisition->width += 2 * GTK_CONTAINER (widget)->border_width;
722
requisition->height += 2 * GTK_CONTAINER (widget)->border_width;
726
hildon_pannable_area_size_allocate (GtkWidget * widget,
727
GtkAllocation * allocation)
729
GtkAllocation child_allocation;
730
HildonPannableAreaPrivate *priv;
731
GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
733
widget->allocation = *allocation;
735
priv = HILDON_PANNABLE_AREA (widget)->priv;
737
child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width;
738
child_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width;
739
child_allocation.width = MAX (allocation->width -
740
2 * GTK_CONTAINER (widget)->border_width -
741
(priv->vscroll_visible ? priv->vscroll_rect.width : 0), 0);
742
child_allocation.height = MAX (allocation->height -
743
2 * GTK_CONTAINER (widget)->border_width -
744
(priv->hscroll_visible ? priv->hscroll_rect.height : 0), 0);
746
if (GTK_WIDGET_REALIZED (widget)) {
747
if (priv->event_window != NULL)
748
gdk_window_move_resize (priv->event_window,
751
child_allocation.width,
752
child_allocation.height);
755
if (priv->overshot_dist_y > 0) {
756
child_allocation.y = MIN (child_allocation.y + priv->overshot_dist_y,
757
allocation->y + child_allocation.height);
758
child_allocation.height = MAX (child_allocation.height - priv->overshot_dist_y, 0);
759
} else if (priv->overshot_dist_y < 0) {
760
child_allocation.height = MAX (child_allocation.height + priv->overshot_dist_y, 0);
763
if (priv->overshot_dist_x > 0) {
764
child_allocation.x = MIN (child_allocation.x + priv->overshot_dist_x,
765
allocation->x + child_allocation.width);
766
child_allocation.width = MAX (child_allocation.width - priv->overshot_dist_x, 0);
767
} else if (priv->overshot_dist_x < 0) {
768
child_allocation.width = MAX (child_allocation.width + priv->overshot_dist_x, 0);
772
gtk_widget_size_allocate (child, &child_allocation);
774
/* we have to do this after child size_allocate because page_size is
775
* changed when we allocate the size of the children */
776
if (priv->overshot_dist_y < 0) {
777
gtk_adjustment_set_value (priv->vadjust, priv->vadjust->upper -
778
priv->vadjust->page_size);
781
if (priv->overshot_dist_x < 0) {
782
gtk_adjustment_set_value (priv->hadjust, priv->hadjust->upper -
783
priv->hadjust->page_size);
786
hildon_pannable_area_refresh (HILDON_PANNABLE_AREA (widget));
790
hildon_pannable_area_style_set (GtkWidget * widget,
791
GtkStyle * previous_style)
793
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
795
GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->
796
style_set (widget, previous_style);
798
gtk_widget_style_get (widget, "indicator-width", &priv->area_width, NULL);
802
hildon_pannable_area_map (GtkWidget * widget)
804
HildonPannableAreaPrivate *priv;
806
priv = HILDON_PANNABLE_AREA (widget)->priv;
808
if (priv->event_window != NULL && !priv->enabled)
809
gdk_window_show (priv->event_window);
811
(*GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->map) (widget);
813
if (priv->event_window != NULL && priv->enabled)
814
gdk_window_show (priv->event_window);
818
hildon_pannable_area_unmap (GtkWidget * widget)
820
HildonPannableAreaPrivate *priv;
822
priv = HILDON_PANNABLE_AREA (widget)->priv;
824
if (priv->event_window != NULL)
825
gdk_window_hide (priv->event_window);
827
(*GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->unmap) (widget);
831
hildon_pannable_area_grab_notify (GtkWidget *widget,
832
gboolean was_grabbed,
835
/* an internal widget has grabbed the focus and now has returned it,
836
we have to do some release actions */
838
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
840
priv->scroll_indicator_event_interrupt = 0;
841
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
843
if (!priv->scroll_indicator_timeout) {
844
priv->scroll_indicator_timeout = gdk_threads_add_timeout
845
((gint) (1000.0 / (gdouble) priv->sps),
846
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade, widget);
855
rgb_from_gdkcolor (GdkColor *color, gdouble *r, gdouble *g, gdouble *b)
857
*r = (color->red >> 8) / 255.0;
858
*g = (color->green >> 8) / 255.0;
859
*b = (color->blue >> 8) / 255.0;
863
hildon_pannable_draw_vscroll (GtkWidget * widget,
864
GdkColor *back_color,
865
GdkColor *scroll_color)
867
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
870
cairo_pattern_t *pattern;
872
gint radius = (priv->vscroll_rect.width/2) - 1;
874
cr = gdk_cairo_create(widget->window);
876
/* Draw the background */
877
rgb_from_gdkcolor (back_color, &r, &g, &b);
878
cairo_set_source_rgb (cr, r, g, b);
879
cairo_rectangle(cr, priv->vscroll_rect.x, priv->vscroll_rect.y,
880
priv->vscroll_rect.width,
881
priv->vscroll_rect.height);
882
cairo_fill_preserve (cr);
885
/* Calculate the scroll bar height and position */
886
y = widget->allocation.y +
887
((priv->vadjust->value / priv->vadjust->upper) *
888
(widget->allocation.height -
889
(priv->hscroll_visible ? priv->area_width : 0)));
890
height = (widget->allocation.y +
891
(((priv->vadjust->value +
892
priv->vadjust->page_size) /
893
priv->vadjust->upper) *
894
(widget->allocation.height -
895
(priv->hscroll_visible ? priv->area_width : 0)))) - y;
897
/* Set a minimum height */
898
height = MAX (SCROLL_BAR_MIN_SIZE, height);
900
/* Check the max y position */
901
y = MIN (y, widget->allocation.y + widget->allocation.height -
902
(priv->hscroll_visible ? priv->hscroll_rect.height : 0) -
905
/* Draw the scrollbar */
906
rgb_from_gdkcolor (scroll_color, &r, &g, &b);
908
pattern = cairo_pattern_create_linear(radius+1, y, radius+1,y + height);
909
cairo_pattern_add_color_stop_rgb(pattern, 0, r, g, b);
910
cairo_pattern_add_color_stop_rgb(pattern, 1, r/2, g/2, b/2);
911
cairo_set_source(cr, pattern);
913
cairo_pattern_destroy(pattern);
915
cairo_arc(cr, priv->vscroll_rect.x + radius + 1, y + radius + 1, radius, G_PI, 0);
916
cairo_line_to(cr, priv->vscroll_rect.x + (radius * 2) + 1, y + height - radius);
917
cairo_arc(cr, priv->vscroll_rect.x + radius + 1, y + height - radius, radius, 0, G_PI);
918
cairo_line_to(cr, priv->vscroll_rect.x + 1, y + height - radius);
921
cairo_paint_with_alpha(cr, priv->scroll_indicator_alpha);
927
hildon_pannable_draw_hscroll (GtkWidget * widget,
928
GdkColor *back_color,
929
GdkColor *scroll_color)
931
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
934
cairo_pattern_t *pattern;
936
gint radius = (priv->hscroll_rect.height/2) - 1;
938
cr = gdk_cairo_create(widget->window);
940
/* Draw the background */
941
rgb_from_gdkcolor (back_color, &r, &g, &b);
942
cairo_set_source_rgb (cr, r, g, b);
943
cairo_rectangle(cr, priv->hscroll_rect.x, priv->hscroll_rect.y,
944
priv->hscroll_rect.width,
945
priv->hscroll_rect.height);
946
cairo_fill_preserve (cr);
949
/* calculate the scrollbar width and position */
950
x = widget->allocation.x +
951
((priv->hadjust->value / priv->hadjust->upper) *
952
(widget->allocation.width - (priv->vscroll_visible ? priv->area_width : 0)));
954
(widget->allocation.x +
955
(((priv->hadjust->value +
956
priv->hadjust->page_size) / priv->hadjust->upper) *
957
(widget->allocation.width -
958
(priv->vscroll_visible ? priv->area_width : 0)))) - x;
960
/* Set a minimum width */
961
width = MAX (SCROLL_BAR_MIN_SIZE, width);
963
/* Check the max x position */
964
x = MIN (x, widget->allocation.x + widget->allocation.width -
965
(priv->vscroll_visible ? priv->vscroll_rect.width : 0) -
968
/* Draw the scrollbar */
969
rgb_from_gdkcolor (scroll_color, &r, &g, &b);
971
pattern = cairo_pattern_create_linear(x, radius+1, x+width, radius+1);
972
cairo_pattern_add_color_stop_rgb(pattern, 0, r, g, b);
973
cairo_pattern_add_color_stop_rgb(pattern, 1, r/2, g/2, b/2);
974
cairo_set_source(cr, pattern);
976
cairo_pattern_destroy(pattern);
978
cairo_arc_negative(cr, x + radius + 1, priv->hscroll_rect.y + radius + 1, radius, 3*G_PI_2, G_PI_2);
979
cairo_line_to(cr, x + width - radius, priv->hscroll_rect.y + (radius * 2) + 1);
980
cairo_arc_negative(cr, x + width - radius, priv->hscroll_rect.y + radius + 1, radius, G_PI_2, 3*G_PI_2);
981
cairo_line_to(cr, x + width - radius, priv->hscroll_rect.y + 1);
984
cairo_paint_with_alpha(cr, priv->scroll_indicator_alpha);
990
hildon_pannable_area_initial_effect (GtkWidget * widget)
992
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
993
gboolean hscroll_visible, vscroll_visible;
995
if (priv->initial_hint) {
996
if (((priv->vovershoot_max != 0)||(priv->hovershoot_max != 0)) &&
997
((priv->mode == HILDON_PANNABLE_AREA_MODE_AUTO) ||
998
(priv->mode == HILDON_PANNABLE_AREA_MODE_ACCEL))) {
999
vscroll_visible = (priv->vadjust->upper - priv->vadjust->lower >
1000
priv->vadjust->page_size);
1001
hscroll_visible = (priv->hadjust->upper - priv->hadjust->lower >
1002
priv->hadjust->page_size);
1003
/* If scrolling is possible in both axes, only hint about scrolling in
1004
the vertical one. */
1005
if ((vscroll_visible)&&(priv->vovershoot_max != 0)) {
1006
priv->overshot_dist_y = priv->vovershoot_max;
1007
priv->vel_y = priv->vmax * 0.1;
1008
} else if ((hscroll_visible)&&(priv->hovershoot_max != 0)) {
1009
priv->overshot_dist_x = priv->hovershoot_max;
1010
priv->vel_x = priv->vmax * 0.1;
1013
if (vscroll_visible || hscroll_visible) {
1014
priv->idle_id = gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps),
1016
hildon_pannable_area_timeout, widget);
1020
if (priv->vscroll_visible || priv->hscroll_visible) {
1021
priv->scroll_indicator_alpha = 1.0;
1023
priv->scroll_indicator_timeout =
1024
gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps),
1025
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade,
1032
hildon_pannable_area_redraw (HildonPannableArea * area)
1034
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (area)->priv;
1036
/* Redraw scroll indicators */
1037
if (GTK_WIDGET_DRAWABLE (area)) {
1038
if (priv->hscroll_visible) {
1039
gdk_window_invalidate_rect (GTK_WIDGET (area)->window,
1040
&priv->hscroll_rect, FALSE);
1043
if (priv->vscroll_visible) {
1044
gdk_window_invalidate_rect (GTK_WIDGET (area)->window,
1045
&priv->vscroll_rect, FALSE);
1051
hildon_pannable_area_scroll_indicator_fade(HildonPannableArea * area)
1054
HildonPannableAreaPrivate *priv = area->priv;
1056
/* if moving do not fade out */
1057
if (((ABS (priv->vel_y)>1.0)||
1058
(ABS (priv->vel_x)>1.0))&&(!priv->clicked)) {
1063
if (priv->scroll_indicator_event_interrupt) {
1064
/* Stop a fade out, and fade back in */
1065
if (priv->scroll_indicator_alpha >= 0.9) {
1066
priv->scroll_indicator_timeout = 0;
1067
priv->scroll_indicator_alpha = 1.0;
1070
priv->scroll_indicator_alpha += 0.2;
1073
hildon_pannable_area_redraw (area);
1076
if ((priv->scroll_indicator_alpha > 0.9) &&
1077
(priv->scroll_delay_counter > 0)) {
1078
priv->scroll_delay_counter--;
1083
if (!priv->scroll_indicator_event_interrupt) {
1084
/* Continue fade out */
1085
if (priv->scroll_indicator_alpha <= 0.1) {
1086
priv->scroll_indicator_timeout = 0;
1087
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
1088
priv->scroll_indicator_alpha = 0.0;
1091
priv->scroll_indicator_alpha -= 0.2;
1094
hildon_pannable_area_redraw (area);
1101
hildon_pannable_area_expose_event (GtkWidget * widget,
1102
GdkEventExpose * event)
1105
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
1106
GdkColor back_color = widget->style->bg[GTK_STATE_NORMAL];
1107
GdkColor scroll_color = widget->style->base[GTK_STATE_SELECTED];
1109
if (gtk_bin_get_child (GTK_BIN (widget))) {
1111
if (priv->scroll_indicator_alpha > 0.1) {
1112
if (priv->vscroll_visible) {
1113
hildon_pannable_draw_vscroll (widget, &back_color, &scroll_color);
1115
if (priv->hscroll_visible) {
1116
hildon_pannable_draw_hscroll (widget, &back_color, &scroll_color);
1120
/* draw overshooting rectangles */
1121
if (priv->overshot_dist_y > 0) {
1122
gint overshot_height;
1124
overshot_height = MIN (priv->overshot_dist_y, widget->allocation.height -
1125
(priv->hscroll_visible ? priv->hscroll_rect.height : 0));
1127
gdk_draw_rectangle (widget->window,
1128
widget->style->bg_gc[GTK_STATE_NORMAL],
1130
widget->allocation.x,
1131
widget->allocation.y,
1132
widget->allocation.width -
1133
(priv->vscroll_visible ? priv->vscroll_rect.width : 0),
1135
} else if (priv->overshot_dist_y < 0) {
1136
gint overshot_height;
1140
MAX (priv->overshot_dist_y,
1141
-(widget->allocation.height -
1142
(priv->hscroll_visible ? priv->hscroll_rect.height : 0)));
1144
overshot_y = MAX (widget->allocation.y +
1145
widget->allocation.height +
1147
(priv->hscroll_visible ? priv->hscroll_rect.height : 0), 0);
1149
gdk_draw_rectangle (widget->window,
1150
widget->style->bg_gc[GTK_STATE_NORMAL],
1152
widget->allocation.x,
1154
widget->allocation.width -
1155
priv->vscroll_rect.width,
1159
if (priv->overshot_dist_x > 0) {
1160
gint overshot_width;
1162
overshot_width = MIN (priv->overshot_dist_x, widget->allocation.width -
1163
(priv->vscroll_visible ? priv->vscroll_rect.width : 0));
1165
gdk_draw_rectangle (widget->window,
1166
widget->style->bg_gc[GTK_STATE_NORMAL],
1168
widget->allocation.x,
1169
widget->allocation.y,
1171
widget->allocation.height -
1172
(priv->hscroll_visible ? priv->hscroll_rect.height : 0));
1173
} else if (priv->overshot_dist_x < 0) {
1174
gint overshot_width;
1178
MAX (priv->overshot_dist_x,
1179
-(widget->allocation.width -
1180
(priv->vscroll_visible ? priv->vscroll_rect.width : 0)));
1182
overshot_x = MAX (widget->allocation.x +
1183
widget->allocation.width +
1185
(priv->vscroll_visible ? priv->vscroll_rect.width : 0), 0);
1187
gdk_draw_rectangle (widget->window,
1188
widget->style->bg_gc[GTK_STATE_NORMAL],
1191
widget->allocation.y,
1193
widget->allocation.height -
1194
priv->hscroll_rect.height);
1199
if (G_UNLIKELY (priv->initial_effect)) {
1201
hildon_pannable_area_initial_effect (widget);
1203
priv->initial_effect = FALSE;
1206
return GTK_WIDGET_CLASS (hildon_pannable_area_parent_class)->expose_event (widget, event);
1210
hildon_pannable_area_get_topmost (GdkWindow * window,
1212
gint * tx, gint * ty)
1214
/* Find the GdkWindow at the given point, by recursing from a given
1215
* parent GdkWindow. Optionally return the co-ordinates transformed
1216
* relative to the child window.
1220
gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
1221
if ((x < 0) || (x >= width) || (y < 0) || (y >= height))
1225
gint child_x = 0, child_y = 0;
1226
GList *c, *children = gdk_window_peek_children (window);
1227
GdkWindow *old_window = window;
1229
for (c = children; c; c = c->next) {
1230
GdkWindow *child = (GdkWindow *) c->data;
1233
gdk_drawable_get_size (GDK_DRAWABLE (child), &width, &height);
1234
gdk_window_get_position (child, &wx, &wy);
1236
if (((x >= wx) && (x < (wx + width)) && (y >= wy)
1237
&& (y < (wy + height))) && (gdk_window_is_visible (child))) {
1244
if (window == old_window)
1260
synth_crossing (GdkWindow * child,
1262
gint x_root, gint y_root,
1263
guint32 time, gboolean in)
1265
GdkEventCrossing *crossing_event;
1266
GdkEventType type = in ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
1268
/* Send synthetic enter event */
1269
crossing_event = (GdkEventCrossing *) gdk_event_new (type);
1270
((GdkEventAny *) crossing_event)->type = type;
1271
((GdkEventAny *) crossing_event)->window = g_object_ref (child);
1272
((GdkEventAny *) crossing_event)->send_event = FALSE;
1273
crossing_event->subwindow = g_object_ref (child);
1274
crossing_event->time = time;
1275
crossing_event->x = x;
1276
crossing_event->y = y;
1277
crossing_event->x_root = x_root;
1278
crossing_event->y_root = y_root;
1279
crossing_event->mode = GDK_CROSSING_NORMAL;
1280
crossing_event->detail = GDK_NOTIFY_UNKNOWN;
1281
crossing_event->focus = FALSE;
1282
crossing_event->state = 0;
1283
gdk_event_put ((GdkEvent *) crossing_event);
1284
gdk_event_free ((GdkEvent *) crossing_event);
1288
hildon_pannable_area_button_press_cb (GtkWidget * widget,
1289
GdkEventButton * event)
1292
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
1294
if ((!priv->enabled) || (event->button != 1) ||
1295
((event->time == priv->last_time) &&
1296
(priv->last_type == 1)) || (gtk_bin_get_child (GTK_BIN (widget)) == NULL))
1299
priv->scroll_indicator_event_interrupt = 1;
1300
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
1302
if (!priv->scroll_indicator_timeout){
1303
priv->scroll_indicator_timeout = gdk_threads_add_timeout
1304
((gint) (1000.0 / (gdouble) (priv->sps*2)),
1305
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade, widget);
1308
priv->last_time = event->time;
1309
priv->last_type = 1;
1311
priv->scroll_to_x = -1;
1312
priv->scroll_to_y = -1;
1314
if (priv->clicked && priv->child) {
1315
/* Widget stole focus on last click, send crossing-out event */
1316
synth_crossing (priv->child, 0, 0, event->x_root, event->y_root,
1317
event->time, FALSE);
1325
/* Don't allow a click if we're still moving fast */
1326
if ((ABS (priv->vel_x) <= (priv->vmax * priv->vfast_factor)) &&
1327
(ABS (priv->vel_y) <= (priv->vmax * priv->vfast_factor)))
1329
hildon_pannable_area_get_topmost (gtk_bin_get_child (GTK_BIN (widget))->window,
1330
event->x, event->y, &x, &y);
1334
priv->clicked = TRUE;
1336
/* Stop scrolling on mouse-down (so you can flick, then hold to stop) */
1342
g_object_add_weak_pointer ((GObject *) priv->child,
1343
(gpointer) & priv->child);
1345
event = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
1351
synth_crossing (priv->child, x, y, event->x_root,
1352
event->y_root, event->time, TRUE);
1354
/* Send synthetic click (button press/release) event */
1355
((GdkEventAny *) event)->window = g_object_ref (priv->child);
1357
gdk_event_put ((GdkEvent *) event);
1358
gdk_event_free ((GdkEvent *) event);
1366
hildon_pannable_area_refresh (HildonPannableArea * area)
1368
HildonPannableAreaPrivate *priv = area->priv;
1369
gboolean prev_hscroll_visible, prev_vscroll_visible;
1371
if (!gtk_bin_get_child (GTK_BIN (area))) {
1372
priv->vscroll_visible = FALSE;
1373
priv->hscroll_visible = FALSE;
1377
prev_hscroll_visible = priv->hscroll_visible;
1378
prev_vscroll_visible = priv->vscroll_visible;
1380
switch (priv->hscrollbar_policy) {
1381
case GTK_POLICY_ALWAYS:
1382
priv->hscroll_visible = TRUE;
1384
case GTK_POLICY_NEVER:
1385
priv->hscroll_visible = FALSE;
1388
priv->hscroll_visible = (priv->hadjust->upper - priv->hadjust->lower >
1389
priv->hadjust->page_size);
1392
switch (priv->vscrollbar_policy) {
1393
case GTK_POLICY_ALWAYS:
1394
priv->vscroll_visible = TRUE;
1396
case GTK_POLICY_NEVER:
1397
priv->vscroll_visible = FALSE;
1400
priv->vscroll_visible = (priv->vadjust->upper - priv->vadjust->lower >
1401
priv->vadjust->page_size);
1404
/* Store the vscroll/hscroll areas for redrawing */
1405
if (priv->vscroll_visible) {
1406
GtkAllocation *allocation = >K_WIDGET (area)->allocation;
1407
priv->vscroll_rect.x = allocation->x + allocation->width -
1409
priv->vscroll_rect.y = allocation->y;
1410
priv->vscroll_rect.width = priv->area_width;
1411
priv->vscroll_rect.height = allocation->height -
1412
(priv->hscroll_visible ? priv->area_width : 0);
1414
if (priv->hscroll_visible) {
1415
GtkAllocation *allocation = >K_WIDGET (area)->allocation;
1416
priv->hscroll_rect.y = allocation->y + allocation->height -
1418
priv->hscroll_rect.x = allocation->x;
1419
priv->hscroll_rect.height = priv->area_width;
1420
priv->hscroll_rect.width = allocation->width -
1421
(priv->vscroll_visible ? priv->area_width : 0);
1424
if (GTK_WIDGET_DRAWABLE (area)) {
1425
if (priv->hscroll_visible != prev_hscroll_visible) {
1426
gtk_widget_queue_resize (GTK_WIDGET (area));
1429
if (priv->vscroll_visible != prev_vscroll_visible) {
1430
gtk_widget_queue_resize (GTK_WIDGET (area));
1436
/* Scroll by a particular amount (in pixels). Optionally, return if
1437
* the scroll on a particular axis was successful.
1440
hildon_pannable_axis_scroll (HildonPannableArea *area,
1441
GtkAdjustment *adjust,
1445
gint *overshot_dist,
1451
HildonPannableAreaPrivate *priv = area->priv;
1453
dist = gtk_adjustment_get_value (adjust) - inc;
1456
* We use overshot_dist to define the distance of the current overshoot,
1457
* and overshooting to define the direction/whether or not we are overshot
1459
if (!(*overshooting)) {
1461
/* Initiation of the overshoot happens when the finger is released
1462
* and the current position of the pannable contents are out of range
1464
if (dist < adjust->lower) {
1467
dist = adjust->lower;
1469
if (overshoot_max!=0) {
1472
*overshot_dist = CLAMP (*overshot_dist + *vel, 0, overshoot_max);
1473
gtk_widget_queue_resize (GTK_WIDGET (area));
1477
} else if (dist > adjust->upper - adjust->page_size) {
1480
dist = adjust->upper - adjust->page_size;
1482
if (overshoot_max!=0) {
1485
*overshot_dist = CLAMP (*overshot_dist + *vel, -overshoot_max, 0);
1486
gtk_widget_queue_resize (GTK_WIDGET (area));
1491
if ((*scroll_to) != -1) {
1492
if (((inc < 0)&&(*scroll_to <= dist))||
1493
((inc > 0)&&(*scroll_to >= dist))) {
1501
gtk_adjustment_set_value (adjust, dist);
1503
if (!priv->clicked) {
1505
/* When the overshoot has started we continue for BOUNCE_STEPS more steps into the overshoot
1506
* before we reverse direction. The deceleration factor is calculated based on
1507
* the percentage distance from the first item with each iteration, therefore always
1508
* returning us to the top/bottom most element
1510
if (*overshot_dist > 0) {
1512
if ((*overshooting < BOUNCE_STEPS) && (*vel > 0)) {
1514
*vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel);
1515
} else if ((*overshooting >= BOUNCE_STEPS) && (*vel > 0)) {
1518
} else if ((*overshooting > 1) && (*vel < 0)) {
1520
/* we add the MAX in order to avoid very small speeds */
1521
*vel = MIN ((((gdouble)*overshot_dist)/overshoot_max) * (*vel), -10.0);
1524
*overshot_dist = CLAMP (*overshot_dist + *vel, 0, overshoot_max);
1526
gtk_widget_queue_resize (GTK_WIDGET (area));
1528
} else if (*overshot_dist < 0) {
1530
if ((*overshooting < BOUNCE_STEPS) && (*vel < 0)) {
1532
*vel = (((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1;
1533
} else if ((*overshooting >= BOUNCE_STEPS) && (*vel < 0)) {
1536
} else if ((*overshooting > 1) && (*vel > 0)) {
1538
/* we add the MIN in order to avoid very small speeds */
1539
*vel = MAX ((((gdouble)*overshot_dist)/overshoot_max) * (*vel) * -1, 10.0);
1542
*overshot_dist = CLAMP (*overshot_dist + (*vel), -overshoot_max, 0);
1544
gtk_widget_queue_resize (GTK_WIDGET (area));
1549
gtk_widget_queue_resize (GTK_WIDGET (area));
1552
if (*overshot_dist > 0) {
1553
*overshot_dist = CLAMP ((*overshot_dist) + inc, 0, overshoot_max);
1554
} else if (*overshot_dist < 0) {
1555
*overshot_dist = CLAMP ((*overshot_dist) + inc, -1 * overshoot_max, 0);
1558
gtk_adjustment_set_value (adjust, dist);
1560
gtk_widget_queue_resize (GTK_WIDGET (area));
1566
hildon_pannable_area_scroll (HildonPannableArea *area,
1567
gdouble x, gdouble y)
1570
HildonPannableAreaPrivate *priv = area->priv;
1571
gboolean hscroll_visible, vscroll_visible;
1573
if (gtk_bin_get_child (GTK_BIN (area)) == NULL)
1576
vscroll_visible = (priv->vadjust->upper - priv->vadjust->lower >
1577
priv->vadjust->page_size);
1578
hscroll_visible = (priv->hadjust->upper - priv->hadjust->lower >
1579
priv->hadjust->page_size);
1584
if (vscroll_visible) {
1585
hildon_pannable_axis_scroll (area, priv->vadjust, &priv->vel_y, y,
1586
&priv->overshooting_y, &priv->overshot_dist_y,
1587
&priv->scroll_to_y, priv->vovershoot_max, &sy);
1592
if (hscroll_visible) {
1593
hildon_pannable_axis_scroll (area, priv->hadjust, &priv->vel_x, x,
1594
&priv->overshooting_x, &priv->overshot_dist_x,
1595
&priv->scroll_to_x, priv->hovershoot_max, &sx);
1600
/* If the scroll on a particular axis wasn't succesful, reset the
1601
* initial scroll position to the new mouse co-ordinate. This means
1602
* when you get to the top of the page, dragging down works immediately.
1615
hildon_pannable_area_timeout (HildonPannableArea * area)
1617
HildonPannableAreaPrivate *priv = area->priv;
1619
if ((!priv->enabled) || (priv->mode == HILDON_PANNABLE_AREA_MODE_PUSH)) {
1625
if (!priv->clicked) {
1626
/* Decelerate gradually when pointer is raised */
1627
if ((!priv->overshot_dist_y) &&
1628
(!priv->overshot_dist_x)) {
1630
/* in case we move to a specific point do not decelerate when arriving */
1631
if ((priv->scroll_to_x != -1)||(priv->scroll_to_y != -1)) {
1633
if (ABS (priv->vel_x) >= 1.5) {
1634
priv->vel_x *= priv->decel;
1637
if (ABS (priv->vel_y) >= 1.5) {
1638
priv->vel_y *= priv->decel;
1642
priv->vel_x *= priv->decel;
1643
priv->vel_y *= priv->decel;
1645
if ((ABS (priv->vel_x) < 1.0) && (ABS (priv->vel_y) < 1.0)) {
1654
} else if (priv->mode == HILDON_PANNABLE_AREA_MODE_AUTO) {
1660
hildon_pannable_area_scroll (area, priv->vel_x, priv->vel_y);
1666
hildon_pannable_area_calculate_velocity (gdouble *vel,
1674
if (ABS (dist) >= 0.00001) {
1675
rawvel = ((dist / ABS (delta)) *
1676
(gdouble) sps) * FORCE;
1677
*vel = *vel * (1 - SMOOTH_FACTOR) +
1678
rawvel * SMOOTH_FACTOR;
1679
*vel = *vel > 0 ? MIN (*vel, vmax)
1680
: MAX (dist, -1 * vmax);
1685
hildon_pannable_area_motion_notify_cb (GtkWidget * widget,
1686
GdkEventMotion * event)
1688
HildonPannableArea *area = HILDON_PANNABLE_AREA (widget);
1689
HildonPannableAreaPrivate *priv = area->priv;
1694
if (gtk_bin_get_child (GTK_BIN (widget)) == NULL)
1697
if ((!priv->enabled) || (!priv->clicked) ||
1698
((event->time == priv->last_time) && (priv->last_type == 2))) {
1699
gdk_window_get_pointer (widget->window, NULL, NULL, 0);
1703
if (priv->last_type == 1) {
1704
priv->first_drag = TRUE;
1707
/* Only start the scroll if the mouse cursor passes beyond the
1708
* DnD threshold for dragging.
1710
g_object_get (G_OBJECT (gtk_settings_get_default ()),
1711
"gtk-dnd-drag-threshold", &dnd_threshold, NULL);
1712
x = event->x - priv->x;
1713
y = event->y - priv->y;
1715
if (priv->first_drag && (!priv->moved) &&
1716
((ABS (x) > (dnd_threshold+DND_THRESHOLD_INC))
1717
|| (ABS (y) > (dnd_threshold+DND_THRESHOLD_INC)))) {
1722
if (priv->first_drag) {
1724
if (ABS (priv->iy - event->y) >=
1725
ABS (priv->ix - event->x)) {
1726
gboolean vscroll_visible;
1728
g_signal_emit (area,
1729
pannable_area_signals[VERTICAL_MOVEMENT],
1730
0, (priv->iy > event->y) ?
1731
HILDON_MOVEMENT_UP :
1732
HILDON_MOVEMENT_DOWN,
1733
(gdouble)priv->ix, (gdouble)priv->iy);
1735
vscroll_visible = (priv->vadjust->upper - priv->vadjust->lower >
1736
priv->vadjust->page_size);
1738
if (!((vscroll_visible)&&
1739
(priv->mov_mode&HILDON_MOVEMENT_MODE_VERT)))
1740
priv->moved = FALSE;
1743
gboolean hscroll_visible;
1745
g_signal_emit (area,
1746
pannable_area_signals[HORIZONTAL_MOVEMENT],
1747
0, (priv->ix > event->x) ?
1748
HILDON_MOVEMENT_LEFT :
1749
HILDON_MOVEMENT_RIGHT,
1750
(gdouble)priv->ix, (gdouble)priv->iy);
1752
hscroll_visible = (priv->hadjust->upper - priv->hadjust->lower >
1753
priv->hadjust->page_size);
1755
if (!((hscroll_visible)&&
1756
(priv->mov_mode&HILDON_MOVEMENT_MODE_HORIZ)))
1757
priv->moved = FALSE;
1761
priv->first_drag = FALSE;
1763
if ((priv->mode != HILDON_PANNABLE_AREA_MODE_PUSH) &&
1764
(priv->mode != HILDON_PANNABLE_AREA_MODE_AUTO)) {
1767
priv->idle_id = gdk_threads_add_timeout ((gint)
1768
(1000.0 / (gdouble) priv->sps),
1770
hildon_pannable_area_timeout, area);
1775
switch (priv->mode) {
1776
case HILDON_PANNABLE_AREA_MODE_PUSH:
1777
/* Scroll by the amount of pixels the cursor has moved
1778
* since the last motion event.
1780
hildon_pannable_area_scroll (area, x, y);
1784
case HILDON_PANNABLE_AREA_MODE_ACCEL:
1785
/* Set acceleration relative to the initial click */
1786
priv->ex = event->x;
1787
priv->ey = event->y;
1788
priv->vel_x = ((x > 0) ? 1 : -1) *
1790
(gdouble) widget->allocation.width) *
1791
(priv->vmax - priv->vmin)) + priv->vmin);
1792
priv->vel_y = ((y > 0) ? 1 : -1) *
1794
(gdouble) widget->allocation.height) *
1795
(priv->vmax - priv->vmin)) + priv->vmin);
1797
case HILDON_PANNABLE_AREA_MODE_AUTO:
1799
delta = event->time - priv->last_time;
1801
if (priv->mov_mode&HILDON_MOVEMENT_MODE_VERT) {
1802
gdouble dist = event->y - priv->y;
1804
hildon_pannable_area_calculate_velocity (&priv->vel_y,
1815
if (priv->mov_mode&HILDON_MOVEMENT_MODE_HORIZ) {
1816
gdouble dist = event->x - priv->x;
1818
hildon_pannable_area_calculate_velocity (&priv->vel_x,
1828
hildon_pannable_area_scroll (area, x, y);
1830
if (priv->mov_mode&HILDON_MOVEMENT_MODE_HORIZ)
1832
if (priv->mov_mode&HILDON_MOVEMENT_MODE_VERT)
1843
/* Send motion notify to child */
1844
priv->last_time = event->time;
1845
priv->last_type = 2;
1846
event = (GdkEventMotion *) gdk_event_copy ((GdkEvent *) event);
1847
event->x = priv->cx + (event->x - priv->ix);
1848
event->y = priv->cy + (event->y - priv->iy);
1849
event->window = g_object_ref (priv->child);
1850
gdk_event_put ((GdkEvent *) event);
1851
gdk_event_free ((GdkEvent *) event);
1854
gdk_window_get_pointer (widget->window, NULL, NULL, 0);
1860
hildon_pannable_area_button_release_cb (GtkWidget * widget,
1861
GdkEventButton * event)
1863
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
1867
if (gtk_bin_get_child (GTK_BIN (widget)) == NULL)
1870
priv->scroll_indicator_event_interrupt = 0;
1871
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY;
1873
if ((ABS (priv->vel_y) > 1.0)||
1874
(ABS (priv->vel_x) > 1.0)) {
1875
priv->scroll_indicator_alpha = 1.0;
1878
if (!priv->scroll_indicator_timeout) {
1879
priv->scroll_indicator_timeout = gdk_threads_add_timeout
1880
((gint) (1000.0 / (gdouble) priv->sps),
1881
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade, widget);
1884
if ((!priv->clicked) || (!priv->enabled) || (event->button != 1) ||
1885
((event->time == priv->last_time) && (priv->last_type == 3)))
1888
priv->clicked = FALSE;
1890
if (priv->mode == HILDON_PANNABLE_AREA_MODE_AUTO ||
1891
priv->mode == HILDON_PANNABLE_AREA_MODE_ACCEL) {
1893
/* If overshoot has been initiated with a finger down, on release set max speed */
1894
if (priv->overshot_dist_y != 0) {
1895
priv->overshooting_y = BOUNCE_STEPS; /* Hack to stop a bounce in the finger down case */
1896
priv->vel_y = priv->vmax;
1899
if (priv->overshot_dist_x != 0) {
1900
priv->overshooting_x = BOUNCE_STEPS; /* Hack to stop a bounce in the finger down case */
1901
priv->vel_x = priv->vmax;
1905
priv->idle_id = gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps),
1907
hildon_pannable_area_timeout, widget);
1910
priv->last_time = event->time;
1911
priv->last_type = 3;
1914
priv->moved = FALSE;
1919
hildon_pannable_area_get_topmost (gtk_bin_get_child (GTK_BIN (widget))->window,
1920
event->x, event->y, &x, &y);
1922
event = (GdkEventButton *) gdk_event_copy ((GdkEvent *) event);
1926
/* Leave the widget if we've moved - This doesn't break selection,
1927
* but stops buttons from being clicked.
1929
if ((child != priv->child) || (priv->moved)) {
1930
/* Send synthetic leave event */
1931
synth_crossing (priv->child, x, y, event->x_root,
1932
event->y_root, event->time, FALSE);
1933
/* Send synthetic button release event */
1934
((GdkEventAny *) event)->window = g_object_ref (priv->child);
1935
gdk_event_put ((GdkEvent *) event);
1937
/* Send synthetic button release event */
1938
((GdkEventAny *) event)->window = g_object_ref (child);
1939
gdk_event_put ((GdkEvent *) event);
1940
/* Send synthetic leave event */
1941
synth_crossing (priv->child, x, y, event->x_root,
1942
event->y_root, event->time, FALSE);
1944
g_object_remove_weak_pointer ((GObject *) priv->child,
1945
(gpointer) & priv->child);
1947
priv->moved = FALSE;
1948
gdk_event_free ((GdkEvent *) event);
1953
/* utility event handler */
1955
hildon_pannable_area_scroll_cb (GtkWidget *widget,
1956
GdkEventScroll *event)
1958
GtkAdjustment *adj = NULL;
1959
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (widget)->priv;
1961
if ((!priv->enabled) ||
1962
(gtk_bin_get_child (GTK_BIN (widget)) == NULL))
1965
priv->scroll_indicator_event_interrupt = 0;
1966
priv->scroll_indicator_alpha = 1.0;
1967
priv->scroll_delay_counter = SCROLLBAR_FADE_DELAY + 20;
1969
if (!priv->scroll_indicator_timeout) {
1970
priv->scroll_indicator_timeout = gdk_threads_add_timeout
1971
((gint) (1000.0 / (gdouble) (priv->sps*2)),
1972
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade, widget);
1975
/* Stop inertial scrolling */
1976
if (priv->idle_id) {
1979
priv->overshooting_x = 0;
1980
priv->overshooting_y = 0;
1982
if ((priv->overshot_dist_x>0)||(priv->overshot_dist_y>0)) {
1983
priv->overshot_dist_x = 0;
1984
priv->overshot_dist_y = 0;
1986
gtk_widget_queue_resize (GTK_WIDGET (widget));
1989
g_source_remove (priv->idle_id);
1993
if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
1994
adj = priv->vadjust;
1996
adj = priv->hadjust;
2000
gdouble delta, new_value;
2002
/* from gtkrange.c calculate delta*/
2003
delta = pow (adj->page_size, 2.0 / 3.0);
2005
if (event->direction == GDK_SCROLL_UP ||
2006
event->direction == GDK_SCROLL_LEFT)
2009
new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
2011
gtk_adjustment_set_value (adj, new_value);
2018
hildon_pannable_area_child_mapped (GtkWidget *widget,
2022
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (user_data)->priv;
2024
if (priv->event_window != NULL && priv->enabled)
2025
gdk_window_raise (priv->event_window);
2029
hildon_pannable_area_add (GtkContainer *container, GtkWidget *child)
2031
HildonPannableAreaPrivate *priv = HILDON_PANNABLE_AREA (container)->priv;
2033
g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == NULL);
2035
gtk_widget_set_parent (child, GTK_WIDGET (container));
2036
GTK_BIN (container)->child = child;
2038
g_signal_connect_after (child, "map-event",
2039
G_CALLBACK (hildon_pannable_area_child_mapped),
2042
if (!gtk_widget_set_scroll_adjustments (child, priv->hadjust, priv->vadjust)) {
2043
g_warning ("%s: cannot add non scrollable widget, "
2044
"wrap it in a viewport", __FUNCTION__);
2049
hildon_pannable_area_remove (GtkContainer *container, GtkWidget *child)
2051
g_return_if_fail (HILDON_IS_PANNABLE_AREA (container));
2052
g_return_if_fail (child != NULL);
2053
g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == child);
2055
gtk_widget_set_scroll_adjustments (child, NULL, NULL);
2057
g_signal_handlers_disconnect_by_func (GTK_WIDGET (child),
2058
G_CALLBACK (hildon_pannable_area_child_mapped),
2061
/* chain parent class handler to remove child */
2062
GTK_CONTAINER_CLASS (hildon_pannable_area_parent_class)->remove (container, child);
2066
hildon_pannable_calculate_vel_factor (HildonPannableArea * self)
2068
HildonPannableAreaPrivate *priv = self->priv;
2073
n = ceil (priv->sps * priv->scroll_time);
2075
for (i = 0; i < n && fct_i >= RATIO_TOLERANCE; i++) {
2076
fct_i *= priv->decel;
2080
priv->vel_factor = fct;
2084
* hildon_pannable_area_new:
2086
* Create a new pannable area widget
2088
* Returns: the newly created #HildonPannableArea
2092
hildon_pannable_area_new (void)
2094
return g_object_new (HILDON_TYPE_PANNABLE_AREA, NULL);
2098
* hildon_pannable_area_new_full:
2099
* @mode: #HildonPannableAreaMode
2100
* @enabled: Value for the enabled property
2101
* @vel_min: Value for the velocity-min property
2102
* @vel_max: Value for the velocity-max property
2103
* @decel: Value for the deceleration property
2104
* @sps: Value for the sps property
2106
* Create a new #HildonPannableArea widget and set various properties
2108
* returns: the newly create #HildonPannableArea
2112
hildon_pannable_area_new_full (gint mode, gboolean enabled,
2113
gdouble vel_min, gdouble vel_max,
2114
gdouble decel, guint sps)
2116
return g_object_new (HILDON_TYPE_PANNABLE_AREA,
2119
"velocity_min", vel_min,
2120
"velocity_max", vel_max,
2121
"deceleration", decel, "sps", sps, NULL);
2125
* hildon_pannable_area_add_with_viewport:
2126
* @area: A #HildonPannableArea
2127
* @child: Child widget to add to the viewport
2129
* Convenience function used to add a child to a #GtkViewport, and add the
2130
* viewport to the scrolled window.
2134
hildon_pannable_area_add_with_viewport (HildonPannableArea * area,
2138
GtkWidget *viewport;
2140
g_return_if_fail (HILDON_IS_PANNABLE_AREA (area));
2141
g_return_if_fail (GTK_IS_WIDGET (child));
2142
g_return_if_fail (child->parent == NULL);
2144
bin = GTK_BIN (area);
2146
if (bin->child != NULL)
2148
g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
2149
g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
2151
viewport = bin->child;
2155
HildonPannableAreaPrivate *priv = area->priv;
2157
viewport = gtk_viewport_new (priv->hadjust,
2159
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
2160
gtk_container_add (GTK_CONTAINER (area), viewport);
2163
gtk_widget_show (viewport);
2164
gtk_container_add (GTK_CONTAINER (viewport), child);
2168
* hildon_pannable_area_scroll_to:
2169
* @area: A #HildonPannableArea.
2170
* @x: The x coordinate of the destination point or -1 to ignore this axis.
2171
* @y: The y coordinate of the destination point or -1 to ignore this axis.
2173
* Smoothly scrolls @area to ensure that (@x, @y) is a visible point
2174
* on the widget. To move in only one coordinate, you must set the other one
2175
* to -1. Notice that, in %HILDON_PANNABLE_AREA_MODE_PUSH mode, this function
2176
* works just like hildon_pannable_area_jump_to().
2178
* This function is useful if you need to present the user with a particular
2179
* element inside a scrollable widget, like #GtkTreeView. For instance,
2180
* the following example shows how to scroll inside a #GtkTreeView to
2181
* make visible an item, indicated by the #GtkTreeIter @iter.
2185
* GtkTreePath *path;
2186
* GdkRectangle *rect;
2188
* path = gtk_tree_model_get_path (model, &iter);
2189
* gtk_tree_view_get_background_area (GTK_TREE_VIEW (treeview),
2190
* path, NULL, &rect);
2191
* gtk_tree_view_convert_bin_window_to_tree_coords (GTK_TREE_VIEW (treeview),
2192
* 0, rect.y, NULL, &y);
2193
* hildon_pannable_area_scroll_to (panarea, -1, y);
2194
* gtk_tree_path_free (path);
2198
* If you want to present a child widget in simpler scenarios,
2199
* use hildon_pannable_area_scroll_to_child() instead.
2201
* There is a precondition to this function: the widget must be
2202
* already realized. Check the hildon_pannable_area_jump_to_child() for
2203
* more tips regarding how to call this function during
2207
hildon_pannable_area_scroll_to (HildonPannableArea *area,
2208
const gint x, const gint y)
2210
HildonPannableAreaPrivate *priv;
2212
gint dist_x, dist_y;
2213
gboolean hscroll_visible, vscroll_visible;
2215
g_return_if_fail (GTK_WIDGET_REALIZED (area));
2216
g_return_if_fail (HILDON_IS_PANNABLE_AREA (area));
2220
vscroll_visible = (priv->vadjust->upper - priv->vadjust->lower >
2221
priv->vadjust->page_size);
2222
hscroll_visible = (priv->hadjust->upper - priv->hadjust->lower >
2223
priv->hadjust->page_size);
2225
if (((!vscroll_visible)&&(!hscroll_visible)) ||
2226
(x == -1 && y == -1)) {
2230
if (priv->mode == HILDON_PANNABLE_AREA_MODE_PUSH)
2231
hildon_pannable_area_jump_to (area, x, y);
2233
width = priv->hadjust->upper - priv->hadjust->lower;
2234
height = priv->vadjust->upper - priv->vadjust->lower;
2236
g_return_if_fail (x < width || y < height);
2239
priv->scroll_to_x = x - priv->hadjust->page_size/2;
2240
dist_x = priv->scroll_to_x - priv->hadjust->value;
2242
priv->scroll_to_x = -1;
2244
priv->vel_x = - dist_x/priv->vel_factor;
2247
priv->scroll_to_x = -1;
2251
priv->scroll_to_y = y - priv->vadjust->page_size/2;
2252
dist_y = priv->scroll_to_y - priv->vadjust->value;
2254
priv->scroll_to_y = -1;
2256
priv->vel_y = - dist_y/priv->vel_factor;
2259
priv->scroll_to_y = y;
2262
if ((priv->scroll_to_y == -1) && (priv->scroll_to_y == -1)) {
2266
priv->scroll_indicator_alpha = 1.0;
2268
if (!priv->scroll_indicator_timeout)
2269
priv->scroll_indicator_timeout = gdk_threads_add_timeout
2270
((gint) (1000.0 / (gdouble) priv->sps),
2271
(GSourceFunc) hildon_pannable_area_scroll_indicator_fade, area);
2274
priv->idle_id = gdk_threads_add_timeout ((gint) (1000.0 / (gdouble) priv->sps),
2276
hildon_pannable_area_timeout, area);
2280
* hildon_pannable_area_jump_to:
2281
* @area: A #HildonPannableArea.
2282
* @x: The x coordinate of the destination point or -1 to ignore this axis.
2283
* @y: The y coordinate of the destination point or -1 to ignore this axis.
2285
* Jumps the position of @area to ensure that (@x, @y) is a visible
2286
* point in the widget. In order to move in only one coordinate, you
2287
* must set the other one to -1. See hildon_pannable_area_scroll_to()
2288
* function for an example of how to calculate the position of
2289
* children in scrollable widgets like #GtkTreeview.
2291
* There is a precondition to this function: the widget must be
2292
* already realized. Check the hildon_pannable_area_jump_to_child() for
2293
* more tips regarding how to call this function during
2297
hildon_pannable_area_jump_to (HildonPannableArea *area,
2298
const gint x, const gint y)
2300
HildonPannableAreaPrivate *priv;
2303
g_return_if_fail (HILDON_IS_PANNABLE_AREA (area));
2304
g_return_if_fail (GTK_WIDGET_REALIZED (area));
2305
g_return_if_fail (x >= -1 && y >= -1);
2307
if (x == -1 && y == -1) {
2313
width = priv->hadjust->upper - priv->hadjust->lower;
2314
height = priv->vadjust->upper - priv->vadjust->lower;
2316
g_return_if_fail (x < width || y < height);
2319
gdouble jump_to = x - priv->hadjust->page_size/2;
2321
if (jump_to > priv->hadjust->upper - priv->hadjust->page_size) {
2322
jump_to = priv->hadjust->upper - priv->hadjust->page_size;
2325
gtk_adjustment_set_value (priv->hadjust, jump_to);
2329
gdouble jump_to = y - priv->vadjust->page_size/2;
2331
if (jump_to > priv->vadjust->upper - priv->vadjust->page_size) {
2332
jump_to = priv->vadjust->upper - priv->vadjust->page_size;
2335
gtk_adjustment_set_value (priv->vadjust, jump_to);
2338
priv->scroll_indicator_alpha = 1.0;
2340
if (priv->scroll_indicator_timeout) {
2341
g_source_remove (priv->scroll_indicator_timeout);
2342
priv->scroll_indicator_timeout = 0;
2345
if (priv->idle_id) {
2348
priv->overshooting_x = 0;
2349
priv->overshooting_y = 0;
2351
if ((priv->overshot_dist_x>0)||(priv->overshot_dist_y>0)) {
2352
priv->overshot_dist_x = 0;
2353
priv->overshot_dist_y = 0;
2355
gtk_widget_queue_resize (GTK_WIDGET (area));
2358
g_source_remove (priv->idle_id);
2364
* hildon_pannable_area_scroll_to_child:
2365
* @area: A #HildonPannableArea.
2366
* @child: A #GtkWidget, descendant of @area.
2368
* Smoothly scrolls until @child is visible inside @area. @child must
2369
* be a descendant of @area. If you need to scroll inside a scrollable
2370
* widget, e.g., #GtkTreeview, see hildon_pannable_area_scroll_to().
2372
* There is a precondition to this function: the widget must be
2373
* already realized. Check the hildon_pannable_area_jump_to_child() for
2374
* more tips regarding how to call this function during
2378
hildon_pannable_area_scroll_to_child (HildonPannableArea *area, GtkWidget *child)
2380
GtkWidget *bin_child;
2383
g_return_if_fail (GTK_WIDGET_REALIZED (area));
2384
g_return_if_fail (HILDON_IS_PANNABLE_AREA (area));
2385
g_return_if_fail (GTK_IS_WIDGET (child));
2386
g_return_if_fail (gtk_widget_is_ancestor (child, GTK_WIDGET (area)));
2388
if (GTK_BIN (area)->child == NULL)
2391
/* We need to get to check the child of the inside the area */
2392
bin_child = GTK_BIN (area)->child;
2394
/* we check if we added a viewport */
2395
if (GTK_IS_VIEWPORT (bin_child)) {
2396
bin_child = GTK_BIN (bin_child)->child;
2399
if (gtk_widget_translate_coordinates (child, bin_child, 0, 0, &x, &y))
2400
hildon_pannable_area_scroll_to (area, x, y);
2404
* hildon_pannable_area_jump_to_child:
2405
* @area: A #HildonPannableArea.
2406
* @child: A #GtkWidget, descendant of @area.
2408
* Jumps to make sure @child is visible inside @area. @child must
2409
* be a descendant of @area. If you want to move inside a scrollable
2410
* widget, like, #GtkTreeview, see hildon_pannable_area_scroll_to().
2412
* There is a precondition to this function: the widget must be
2413
* already realized. You can control if the widget is ready with the
2414
* GTK_WIDGET_REALIZED macro. If you want to call this function during
2415
* the initialization process of the widget do it inside a callback to
2416
* the ::realize signal, using g_signal_connect_after() function.
2419
hildon_pannable_area_jump_to_child (HildonPannableArea *area, GtkWidget *child)
2421
GtkWidget *bin_child;
2424
g_return_if_fail (GTK_WIDGET_REALIZED (area));
2425
g_return_if_fail (HILDON_IS_PANNABLE_AREA (area));
2426
g_return_if_fail (GTK_IS_WIDGET (child));
2427
g_return_if_fail (gtk_widget_is_ancestor (child, GTK_WIDGET (area)));
2429
if (gtk_bin_get_child (GTK_BIN (area)) == NULL)
2432
/* We need to get to check the child of the inside the area */
2433
bin_child = gtk_bin_get_child (GTK_BIN (area));
2435
/* we check if we added a viewport */
2436
if (GTK_IS_VIEWPORT (bin_child)) {
2437
bin_child = gtk_bin_get_child (GTK_BIN (bin_child));
2440
if (gtk_widget_translate_coordinates (child, bin_child, 0, 0, &x, &y))
2441
hildon_pannable_area_jump_to (area, x, y);
2445
* hildon_pannable_get_child_widget_at:
2446
* @area: A #HildonPannableArea.
2447
* @x: horizontal coordinate of the point
2448
* @y: vertical coordinate of the point
2450
* Get the widget at the point (x, y) inside the pannable area. In
2451
* case no widget found it returns NULL.
2453
* returns: the #GtkWidget if we find a widget, NULL in any other case
2456
hildon_pannable_get_child_widget_at (HildonPannableArea *area,
2457
gdouble x, gdouble y)
2459
GdkWindow *window = NULL;
2460
GtkWidget *child_widget = NULL;
2462
window = hildon_pannable_area_get_topmost
2463
(gtk_bin_get_child (GTK_BIN (area))->window,
2466
gdk_window_get_user_data (window, (gpointer) &child_widget);
2468
return child_widget;