2009-09-29 15:08:01 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
2009-09-09 23:13:35 -04:00
|
|
|
/*
|
|
|
|
* st-scroll-bar.c: Scroll bar actor
|
|
|
|
*
|
|
|
|
* Copyright 2008 OpenedHand
|
2010-11-10 17:00:45 -05:00
|
|
|
* Copyright 2008, 2009 Intel Corporation.
|
|
|
|
* Copyright 2009, 2010 Red Hat, Inc.
|
|
|
|
* Copyright 2010 Maxim Ermilov
|
2009-09-09 23:13:35 -04:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU Lesser General Public License,
|
|
|
|
* version 2.1, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope 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
|
2010-11-10 17:00:45 -05:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2009-09-09 23:13:35 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:st-scroll-bar
|
|
|
|
* @short_description: a user interface element to control scrollable areas.
|
|
|
|
*
|
|
|
|
* The #StScrollBar allows users to scroll scrollable actors, either by
|
|
|
|
* the step or page amount, or by manually dragging the handle.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2012-03-19 16:30:09 -04:00
|
|
|
#include <math.h>
|
2009-09-09 23:13:35 -04:00
|
|
|
#include <clutter/clutter.h>
|
|
|
|
|
|
|
|
#include "st-scroll-bar.h"
|
|
|
|
#include "st-bin.h"
|
|
|
|
#include "st-enum-types.h"
|
|
|
|
#include "st-private.h"
|
|
|
|
#include "st-button.h"
|
|
|
|
|
2010-08-26 15:33:09 -04:00
|
|
|
G_DEFINE_TYPE (StScrollBar, st_scroll_bar, ST_TYPE_WIDGET)
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
#define ST_SCROLL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_SCROLL_BAR, StScrollBarPrivate))
|
|
|
|
|
|
|
|
#define PAGING_INITIAL_REPEAT_TIMEOUT 500
|
|
|
|
#define PAGING_SUBSEQUENT_REPEAT_TIMEOUT 200
|
|
|
|
|
|
|
|
struct _StScrollBarPrivate
|
|
|
|
{
|
|
|
|
StAdjustment *adjustment;
|
|
|
|
|
|
|
|
gulong capture_handler;
|
|
|
|
gfloat x_origin;
|
|
|
|
gfloat y_origin;
|
|
|
|
|
|
|
|
ClutterActor *trough;
|
|
|
|
ClutterActor *handle;
|
|
|
|
|
|
|
|
gfloat move_x;
|
|
|
|
gfloat move_y;
|
|
|
|
|
|
|
|
/* Trough-click handling. */
|
|
|
|
enum { NONE, UP, DOWN } paging_direction;
|
|
|
|
guint paging_source_id;
|
|
|
|
guint paging_event_no;
|
|
|
|
|
|
|
|
ClutterAnimation *paging_animation;
|
|
|
|
|
2010-03-05 16:17:07 -05:00
|
|
|
guint vertical : 1;
|
2009-09-09 23:13:35 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_ADJUSTMENT,
|
|
|
|
PROP_VERTICAL
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
SCROLL_START,
|
|
|
|
SCROLL_STOP,
|
|
|
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0, };
|
|
|
|
|
2010-06-19 22:16:06 -04:00
|
|
|
extern gfloat st_slow_down_factor;
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
static gboolean
|
|
|
|
handle_button_press_event_cb (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event,
|
|
|
|
StScrollBar *bar);
|
|
|
|
|
2011-04-05 10:54:28 -04:00
|
|
|
static void stop_scrolling (StScrollBar *bar);
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
static void
|
|
|
|
st_scroll_bar_get_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = ST_SCROLL_BAR (gobject)->priv;
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_ADJUSTMENT:
|
|
|
|
g_value_set_object (value, priv->adjustment);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_VERTICAL:
|
|
|
|
g_value_set_boolean (value, priv->vertical);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_set_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (gobject);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_ADJUSTMENT:
|
|
|
|
st_scroll_bar_set_adjustment (bar, g_value_get_object (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_VERTICAL:
|
|
|
|
bar->priv->vertical = g_value_get_boolean (value);
|
|
|
|
if (bar->priv->vertical)
|
2012-02-13 23:13:26 -05:00
|
|
|
clutter_actor_set_name (CLUTTER_ACTOR (bar->priv->handle),
|
|
|
|
"vhandle");
|
2009-09-09 23:13:35 -04:00
|
|
|
else
|
2012-02-13 23:13:26 -05:00
|
|
|
clutter_actor_set_name (CLUTTER_ACTOR (bar->priv->handle),
|
|
|
|
"hhandle");
|
2009-09-09 23:13:35 -04:00
|
|
|
clutter_actor_queue_relayout ((ClutterActor*) gobject);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (gobject);
|
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
|
|
|
|
if (priv->adjustment)
|
|
|
|
st_scroll_bar_set_adjustment (bar, NULL);
|
|
|
|
|
|
|
|
if (priv->handle)
|
|
|
|
{
|
2012-02-14 10:48:00 -05:00
|
|
|
clutter_actor_destroy (priv->handle);
|
2009-09-09 23:13:35 -04:00
|
|
|
priv->handle = NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-26 12:48:07 -05:00
|
|
|
if (priv->trough)
|
|
|
|
{
|
2012-02-14 10:48:00 -05:00
|
|
|
clutter_actor_destroy (priv->trough);
|
2010-02-26 12:48:07 -05:00
|
|
|
priv->trough = NULL;
|
|
|
|
}
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (st_scroll_bar_parent_class)->dispose (gobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_unmap (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
CLUTTER_ACTOR_CLASS (st_scroll_bar_parent_class)->unmap (actor);
|
|
|
|
|
2011-04-05 10:54:28 -04:00
|
|
|
stop_scrolling (ST_SCROLL_BAR (actor));
|
2009-09-09 23:13:35 -04:00
|
|
|
}
|
|
|
|
|
2010-03-05 16:17:07 -05:00
|
|
|
static void
|
|
|
|
scroll_bar_allocate_children (StScrollBar *bar,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (bar));
|
2012-02-13 23:13:26 -05:00
|
|
|
ClutterActorBox content_box, trough_box;
|
2009-09-09 23:13:35 -04:00
|
|
|
|
2009-09-20 13:41:13 -04:00
|
|
|
st_theme_node_get_content_box (theme_node, box, &content_box);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
{
|
2009-09-20 13:41:13 -04:00
|
|
|
trough_box.x1 = content_box.x1;
|
2012-02-13 23:13:26 -05:00
|
|
|
trough_box.y1 = content_box.y1;
|
2009-09-20 13:41:13 -04:00
|
|
|
trough_box.x2 = content_box.x2;
|
2012-02-13 23:13:26 -05:00
|
|
|
trough_box.y2 = content_box.y2;
|
2009-09-09 23:13:35 -04:00
|
|
|
clutter_actor_allocate (priv->trough, &trough_box, flags);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-13 23:13:26 -05:00
|
|
|
trough_box.x1 = content_box.x1;
|
2009-09-20 13:41:13 -04:00
|
|
|
trough_box.y1 = content_box.y1;
|
2012-02-13 23:13:26 -05:00
|
|
|
trough_box.x2 = content_box.x2;
|
2009-09-20 13:41:13 -04:00
|
|
|
trough_box.y2 = content_box.y2;
|
2009-09-09 23:13:35 -04:00
|
|
|
clutter_actor_allocate (priv->trough, &trough_box, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (priv->adjustment)
|
|
|
|
{
|
2012-02-13 23:13:26 -05:00
|
|
|
float handle_size, position, avail_size;
|
2009-09-19 21:10:15 -04:00
|
|
|
gdouble value, lower, upper, page_size, increment, min_size, max_size;
|
2009-09-09 23:13:35 -04:00
|
|
|
ClutterActorBox handle_box = { 0, };
|
|
|
|
|
|
|
|
st_adjustment_get_values (priv->adjustment,
|
|
|
|
&value,
|
|
|
|
&lower,
|
|
|
|
&upper,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&page_size);
|
|
|
|
|
|
|
|
if ((upper == lower)
|
|
|
|
|| (page_size >= (upper - lower)))
|
|
|
|
increment = 1.0;
|
|
|
|
else
|
|
|
|
increment = page_size / (upper - lower);
|
|
|
|
|
2009-09-19 21:10:15 -04:00
|
|
|
min_size = 32.;
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 17:38:36 -04:00
|
|
|
st_theme_node_lookup_length (theme_node, "min-size", FALSE, &min_size);
|
2009-09-19 21:10:15 -04:00
|
|
|
max_size = G_MAXINT16;
|
StThemeNode: simplify use of get_color/get_double/get_length
Although within St itself there are situations where the semantics of
these functions (return TRUE or FALSE and return the actual value in
an out parameter) is useful, it's mostly just annoying at the
application level, where you generally know that the CSS property is
going to specified, and there is no especially sane fallback if it's
not.
So rename the current methods to lookup_color, lookup_double, and
lookup_length, and add new get_color, get_double, and get_length
methods that don't take an "inherit" parameter, and return their
values directly. (Well, except for get_color, due to the lack of (out
caller-allocates) in gjs.)
And update the code to use either the old or new methods as appropriate.
https://bugzilla.gnome.org/show_bug.cgi?id=632590
2010-09-26 17:38:36 -04:00
|
|
|
st_theme_node_lookup_length (theme_node, "max-size", FALSE, &max_size);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
if (upper - lower - page_size <= 0)
|
|
|
|
position = 0;
|
|
|
|
else
|
|
|
|
position = (value - lower) / (upper - lower - page_size);
|
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
{
|
2012-02-13 23:13:26 -05:00
|
|
|
avail_size = content_box.y2 - content_box.y1;
|
2009-09-09 23:13:35 -04:00
|
|
|
handle_size = increment * avail_size;
|
|
|
|
handle_size = CLAMP (handle_size, min_size, max_size);
|
|
|
|
|
2009-09-20 13:41:13 -04:00
|
|
|
handle_box.x1 = content_box.x1;
|
2012-02-13 23:13:26 -05:00
|
|
|
handle_box.y1 = content_box.y1 + position * (avail_size - handle_size);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
2009-09-20 13:41:13 -04:00
|
|
|
handle_box.x2 = content_box.x2;
|
2009-09-09 23:13:35 -04:00
|
|
|
handle_box.y2 = handle_box.y1 + handle_size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-13 23:13:26 -05:00
|
|
|
avail_size = content_box.x2 - content_box.x1;
|
2009-09-09 23:13:35 -04:00
|
|
|
handle_size = increment * avail_size;
|
|
|
|
handle_size = CLAMP (handle_size, min_size, max_size);
|
|
|
|
|
2012-02-13 23:13:26 -05:00
|
|
|
handle_box.x1 = content_box.x1 + position * (avail_size - handle_size);
|
2009-09-20 13:41:13 -04:00
|
|
|
handle_box.y1 = content_box.y1;
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
handle_box.x2 = handle_box.x1 + handle_size;
|
2009-09-20 13:41:13 -04:00
|
|
|
handle_box.y2 = content_box.y2;
|
2009-09-09 23:13:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* snap to pixel */
|
|
|
|
handle_box.x1 = (int) handle_box.x1;
|
|
|
|
handle_box.y1 = (int) handle_box.y1;
|
|
|
|
handle_box.x2 = (int) handle_box.x2;
|
|
|
|
handle_box.y2 = (int) handle_box.y2;
|
|
|
|
|
|
|
|
clutter_actor_allocate (priv->handle,
|
|
|
|
&handle_box,
|
|
|
|
flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-09 04:48:49 -04:00
|
|
|
static void
|
|
|
|
st_scroll_bar_get_preferred_width (ClutterActor *self,
|
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (self);
|
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
|
2012-02-13 23:18:36 -05:00
|
|
|
gfloat trough_min_width, trough_natural_width;
|
|
|
|
gfloat handle_min_width, handle_natural_width;
|
2010-09-09 04:48:49 -04:00
|
|
|
|
|
|
|
st_theme_node_adjust_for_height (theme_node, &for_height);
|
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
_st_actor_get_preferred_width (priv->trough, for_height, TRUE,
|
|
|
|
&trough_min_width, &trough_natural_width);
|
|
|
|
|
|
|
|
_st_actor_get_preferred_width (priv->handle, for_height, TRUE,
|
|
|
|
&handle_min_width, &handle_natural_width);
|
2010-09-09 04:48:49 -04:00
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
{
|
2012-02-13 23:18:36 -05:00
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = MAX (trough_min_width, handle_min_width);
|
2010-09-09 04:48:49 -04:00
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
if (natural_width_p)
|
|
|
|
*natural_width_p = MAX (trough_natural_width, handle_natural_width);
|
2010-09-09 04:48:49 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-13 23:18:36 -05:00
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = trough_min_width + handle_min_width;
|
2010-09-09 04:48:49 -04:00
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
if (natural_width_p)
|
|
|
|
*natural_width_p = trough_natural_width + handle_natural_width;
|
2010-09-09 04:48:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_get_preferred_height (ClutterActor *self,
|
|
|
|
gfloat for_width,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (self);
|
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
|
2012-02-13 23:18:36 -05:00
|
|
|
gfloat trough_min_height, trough_natural_height;
|
|
|
|
gfloat handle_min_height, handle_natural_height;
|
2010-09-09 04:48:49 -04:00
|
|
|
|
|
|
|
st_theme_node_adjust_for_width (theme_node, &for_width);
|
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
_st_actor_get_preferred_height (priv->trough, for_width, TRUE,
|
|
|
|
&trough_min_height, &trough_natural_height);
|
|
|
|
|
|
|
|
_st_actor_get_preferred_height (priv->handle, for_width, TRUE,
|
|
|
|
&handle_min_height, &handle_natural_height);
|
2010-09-09 04:48:49 -04:00
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
{
|
2012-02-13 23:18:36 -05:00
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = trough_min_height + handle_min_height;
|
2010-09-09 04:48:49 -04:00
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = trough_natural_height + handle_natural_height;
|
2010-09-09 04:48:49 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-02-13 23:18:36 -05:00
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = MAX (trough_min_height, handle_min_height);
|
2010-09-09 04:48:49 -04:00
|
|
|
|
2012-02-13 23:18:36 -05:00
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = MAX (trough_natural_height, handle_natural_height);
|
2010-09-09 04:48:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
|
|
|
|
}
|
|
|
|
|
2010-03-05 16:17:07 -05:00
|
|
|
static void
|
|
|
|
st_scroll_bar_allocate (ClutterActor *actor,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (actor);
|
|
|
|
|
2012-02-15 07:11:41 -05:00
|
|
|
clutter_actor_set_allocation (actor, box, flags);
|
2010-03-05 16:17:07 -05:00
|
|
|
|
|
|
|
scroll_bar_allocate_children (bar, box, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scroll_bar_update_positions (StScrollBar *bar)
|
|
|
|
{
|
|
|
|
ClutterActorBox box;
|
|
|
|
|
|
|
|
/* Due to a change in the adjustments, we need to reposition our
|
|
|
|
* children; since adjustments changes can come from allocation
|
|
|
|
* changes in the scrolled area, we can't just queue a new relayout -
|
|
|
|
* we may already be in a relayout cycle. On the other hand, if
|
|
|
|
* a relayout is already queued, we can't just go ahead and allocate
|
|
|
|
* our children, since we don't have a valid allocation, and calling
|
|
|
|
* clutter_actor_get_allocation_box() will trigger an immediate
|
|
|
|
* stage relayout. So what we do is go ahead and immediately
|
|
|
|
* allocate our children if we already have a valid allocation, and
|
|
|
|
* otherwise just wait for the queued relayout.
|
|
|
|
*/
|
2011-04-05 10:49:21 -04:00
|
|
|
if (!clutter_actor_has_allocation (CLUTTER_ACTOR (bar)))
|
2010-03-05 16:17:07 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
clutter_actor_get_allocation_box (CLUTTER_ACTOR (bar), &box);
|
|
|
|
scroll_bar_allocate_children (bar, &box, CLUTTER_ALLOCATION_NONE);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
static void
|
|
|
|
st_scroll_bar_style_changed (StWidget *widget)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = ST_SCROLL_BAR (widget)->priv;
|
|
|
|
|
2009-09-19 21:10:15 -04:00
|
|
|
st_widget_style_changed (ST_WIDGET (priv->trough));
|
|
|
|
st_widget_style_changed (ST_WIDGET (priv->handle));
|
2009-09-09 23:13:35 -04:00
|
|
|
|
2009-09-19 21:10:15 -04:00
|
|
|
ST_WIDGET_CLASS (st_scroll_bar_parent_class)->style_changed (widget);
|
2009-09-09 23:13:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bar_reactive_notify_cb (GObject *gobject,
|
|
|
|
GParamSpec *arg1,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
StScrollBar *bar = ST_SCROLL_BAR (gobject);
|
|
|
|
|
|
|
|
clutter_actor_set_reactive (bar->priv->handle,
|
|
|
|
clutter_actor_get_reactive (CLUTTER_ACTOR (bar)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static GObject*
|
|
|
|
st_scroll_bar_constructor (GType type,
|
|
|
|
guint n_properties,
|
|
|
|
GObjectConstructParam *properties)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class;
|
|
|
|
GObject *obj;
|
|
|
|
StScrollBar *bar;
|
|
|
|
|
|
|
|
gobject_class = G_OBJECT_CLASS (st_scroll_bar_parent_class);
|
|
|
|
obj = gobject_class->constructor (type, n_properties, properties);
|
|
|
|
|
|
|
|
bar = ST_SCROLL_BAR (obj);
|
|
|
|
|
|
|
|
g_signal_connect (bar, "notify::reactive",
|
|
|
|
G_CALLBACK (bar_reactive_notify_cb), NULL);
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
st_scroll_bar_scroll_event (ClutterActor *actor,
|
|
|
|
ClutterScrollEvent *event)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = ST_SCROLL_BAR (actor)->priv;
|
2012-03-19 19:19:08 -04:00
|
|
|
gdouble step, value, delta_x, delta_y;
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
if (priv->adjustment)
|
|
|
|
{
|
|
|
|
g_object_get (priv->adjustment,
|
|
|
|
"step-increment", &step,
|
|
|
|
"value", &value,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (event->direction)
|
|
|
|
{
|
2012-03-19 16:30:09 -04:00
|
|
|
case CLUTTER_SCROLL_SMOOTH:
|
|
|
|
clutter_event_get_scroll_delta ((ClutterEvent *)event,
|
|
|
|
&delta_x, &delta_y);
|
|
|
|
if (fabs (delta_x) > fabs (delta_y))
|
|
|
|
st_adjustment_set_value (priv->adjustment, value + delta_x);
|
|
|
|
else
|
|
|
|
st_adjustment_set_value (priv->adjustment, value + delta_y);
|
|
|
|
break;
|
2009-09-09 23:13:35 -04:00
|
|
|
case CLUTTER_SCROLL_UP:
|
|
|
|
case CLUTTER_SCROLL_LEFT:
|
2012-03-19 19:19:08 -04:00
|
|
|
st_adjustment_set_value (priv->adjustment, value - step);
|
2009-09-09 23:13:35 -04:00
|
|
|
break;
|
|
|
|
case CLUTTER_SCROLL_DOWN:
|
|
|
|
case CLUTTER_SCROLL_RIGHT:
|
2012-03-19 19:19:08 -04:00
|
|
|
st_adjustment_set_value (priv->adjustment, value + step);
|
2009-09-09 23:13:35 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_class_init (StScrollBarClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
2009-09-19 21:10:15 -04:00
|
|
|
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
|
2009-09-09 23:13:35 -04:00
|
|
|
GParamSpec *pspec;
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (StScrollBarPrivate));
|
|
|
|
|
|
|
|
object_class->get_property = st_scroll_bar_get_property;
|
|
|
|
object_class->set_property = st_scroll_bar_set_property;
|
|
|
|
object_class->dispose = st_scroll_bar_dispose;
|
|
|
|
object_class->constructor = st_scroll_bar_constructor;
|
|
|
|
|
2010-09-09 04:48:49 -04:00
|
|
|
actor_class->get_preferred_width = st_scroll_bar_get_preferred_width;
|
|
|
|
actor_class->get_preferred_height = st_scroll_bar_get_preferred_height;
|
2009-09-09 23:13:35 -04:00
|
|
|
actor_class->allocate = st_scroll_bar_allocate;
|
|
|
|
actor_class->scroll_event = st_scroll_bar_scroll_event;
|
|
|
|
actor_class->unmap = st_scroll_bar_unmap;
|
|
|
|
|
2009-09-19 21:10:15 -04:00
|
|
|
widget_class->style_changed = st_scroll_bar_style_changed;
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
g_object_class_install_property
|
|
|
|
(object_class,
|
|
|
|
PROP_ADJUSTMENT,
|
|
|
|
g_param_spec_object ("adjustment",
|
|
|
|
"Adjustment",
|
|
|
|
"The adjustment",
|
|
|
|
ST_TYPE_ADJUSTMENT,
|
|
|
|
ST_PARAM_READWRITE));
|
|
|
|
|
|
|
|
pspec = g_param_spec_boolean ("vertical",
|
|
|
|
"Vertical Orientation",
|
|
|
|
"Vertical Orientation",
|
|
|
|
FALSE,
|
|
|
|
ST_PARAM_READWRITE);
|
|
|
|
g_object_class_install_property (object_class, PROP_VERTICAL, pspec);
|
|
|
|
|
|
|
|
signals[SCROLL_START] =
|
|
|
|
g_signal_new ("scroll-start",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (StScrollBarClass, scroll_start),
|
2011-10-18 18:17:49 -04:00
|
|
|
NULL, NULL, NULL,
|
2009-09-09 23:13:35 -04:00
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
signals[SCROLL_STOP] =
|
|
|
|
g_signal_new ("scroll-stop",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (StScrollBarClass, scroll_stop),
|
2011-10-18 18:17:49 -04:00
|
|
|
NULL, NULL, NULL,
|
2009-09-09 23:13:35 -04:00
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
move_slider (StScrollBar *bar,
|
|
|
|
gfloat x,
|
|
|
|
gfloat y)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
gdouble position, lower, upper, page_size;
|
|
|
|
gfloat ux, uy, pos, size;
|
|
|
|
|
|
|
|
if (!priv->adjustment)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!clutter_actor_transform_stage_point (priv->trough, x, y, &ux, &uy))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
size = clutter_actor_get_height (priv->trough)
|
|
|
|
- clutter_actor_get_height (priv->handle);
|
|
|
|
else
|
|
|
|
size = clutter_actor_get_width (priv->trough)
|
|
|
|
- clutter_actor_get_width (priv->handle);
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (priv->vertical)
|
|
|
|
pos = uy - priv->y_origin;
|
|
|
|
else
|
|
|
|
pos = ux - priv->x_origin;
|
|
|
|
pos = CLAMP (pos, 0, size);
|
|
|
|
|
|
|
|
st_adjustment_get_values (priv->adjustment,
|
|
|
|
NULL,
|
|
|
|
&lower,
|
|
|
|
&upper,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&page_size);
|
|
|
|
|
|
|
|
position = ((pos / size)
|
|
|
|
* (upper - lower - page_size))
|
|
|
|
+ lower;
|
|
|
|
|
|
|
|
st_adjustment_set_value (priv->adjustment, position);
|
|
|
|
}
|
|
|
|
|
2011-04-05 10:54:28 -04:00
|
|
|
static void
|
|
|
|
stop_scrolling (StScrollBar *bar)
|
|
|
|
{
|
2011-10-19 13:29:19 -04:00
|
|
|
ClutterStage *stage;
|
2011-04-05 10:54:28 -04:00
|
|
|
|
|
|
|
if (!bar->priv->capture_handler)
|
|
|
|
return;
|
|
|
|
|
2012-08-01 08:15:03 -04:00
|
|
|
st_widget_remove_style_pseudo_class (bar->priv->handle, "active");
|
|
|
|
|
2011-10-19 13:29:19 -04:00
|
|
|
stage = CLUTTER_STAGE (clutter_actor_get_stage (bar->priv->trough));
|
2011-04-05 10:54:28 -04:00
|
|
|
g_signal_handler_disconnect (stage, bar->priv->capture_handler);
|
|
|
|
bar->priv->capture_handler = 0;
|
|
|
|
|
2011-10-19 13:29:19 -04:00
|
|
|
clutter_stage_set_motion_events_enabled (stage, TRUE);
|
2011-04-05 10:54:28 -04:00
|
|
|
g_signal_emit (bar, signals[SCROLL_STOP], 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
static gboolean
|
|
|
|
handle_capture_event_cb (ClutterActor *trough,
|
|
|
|
ClutterEvent *event,
|
|
|
|
StScrollBar *bar)
|
|
|
|
{
|
|
|
|
if (clutter_event_type (event) == CLUTTER_MOTION)
|
|
|
|
{
|
|
|
|
move_slider (bar,
|
|
|
|
((ClutterMotionEvent*) event)->x,
|
|
|
|
((ClutterMotionEvent*) event)->y);
|
|
|
|
}
|
|
|
|
else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE
|
|
|
|
&& ((ClutterButtonEvent*) event)->button == 1)
|
|
|
|
{
|
|
|
|
ClutterActor *stage, *target;
|
|
|
|
|
2011-04-05 10:54:28 -04:00
|
|
|
stop_scrolling (bar);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
/* check if the mouse pointer has left the handle during the drag and
|
|
|
|
* remove the hover state if it has */
|
2011-04-05 10:54:28 -04:00
|
|
|
stage = clutter_actor_get_stage (bar->priv->trough);
|
2009-09-09 23:13:35 -04:00
|
|
|
target = clutter_stage_get_actor_at_pos ((ClutterStage*) stage,
|
|
|
|
CLUTTER_PICK_REACTIVE,
|
|
|
|
((ClutterButtonEvent*) event)->x,
|
|
|
|
((ClutterButtonEvent*) event)->y);
|
|
|
|
if (target != bar->priv->handle)
|
|
|
|
{
|
2010-03-19 11:37:04 -04:00
|
|
|
st_widget_remove_style_pseudo_class ((StWidget*) bar->priv->handle, "hover");
|
2009-09-09 23:13:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
handle_button_press_event_cb (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event,
|
|
|
|
StScrollBar *bar)
|
|
|
|
{
|
2011-10-19 13:29:19 -04:00
|
|
|
ClutterStage *stage;
|
2009-09-09 23:13:35 -04:00
|
|
|
StScrollBarPrivate *priv = bar->priv;
|
|
|
|
|
|
|
|
if (event->button != 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!clutter_actor_transform_stage_point (priv->handle,
|
|
|
|
event->x,
|
|
|
|
event->y,
|
|
|
|
&priv->x_origin,
|
|
|
|
&priv->y_origin))
|
|
|
|
return FALSE;
|
|
|
|
|
2012-08-01 08:15:03 -04:00
|
|
|
st_widget_add_style_pseudo_class (priv->handle, "active");
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
/* Account for the scrollbar-trough-handle nesting. */
|
|
|
|
priv->x_origin += clutter_actor_get_x (priv->trough);
|
|
|
|
priv->y_origin += clutter_actor_get_y (priv->trough);
|
|
|
|
|
2011-10-19 13:29:19 -04:00
|
|
|
stage = CLUTTER_STAGE (clutter_actor_get_stage (bar->priv->trough));
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
/* Turn off picking for motion events */
|
2011-10-19 13:29:19 -04:00
|
|
|
clutter_stage_set_motion_events_enabled (stage, FALSE);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
priv->capture_handler = g_signal_connect_after (
|
|
|
|
clutter_actor_get_stage (priv->trough),
|
|
|
|
"captured-event",
|
|
|
|
G_CALLBACK (handle_capture_event_cb),
|
|
|
|
bar);
|
|
|
|
g_signal_emit (bar, signals[SCROLL_START], 0);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
animation_completed_cb (ClutterAnimation *animation,
|
|
|
|
StScrollBarPrivate *priv)
|
|
|
|
{
|
|
|
|
g_object_unref (priv->paging_animation);
|
|
|
|
priv->paging_animation = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
trough_paging_cb (StScrollBar *self)
|
|
|
|
{
|
|
|
|
gfloat handle_pos, event_pos, tx, ty;
|
|
|
|
gdouble value;
|
|
|
|
gdouble page_increment;
|
|
|
|
gboolean ret;
|
|
|
|
|
|
|
|
gulong mode;
|
|
|
|
ClutterAnimation *a;
|
|
|
|
GValue v = { 0, };
|
|
|
|
ClutterTimeline *t;
|
|
|
|
|
|
|
|
if (self->priv->paging_event_no == 0)
|
|
|
|
{
|
|
|
|
/* Scroll on after initial timeout. */
|
|
|
|
mode = CLUTTER_EASE_OUT_CUBIC;
|
|
|
|
ret = FALSE;
|
|
|
|
self->priv->paging_event_no = 1;
|
|
|
|
self->priv->paging_source_id = g_timeout_add (
|
|
|
|
PAGING_INITIAL_REPEAT_TIMEOUT,
|
|
|
|
(GSourceFunc) trough_paging_cb,
|
|
|
|
self);
|
|
|
|
}
|
|
|
|
else if (self->priv->paging_event_no == 1)
|
|
|
|
{
|
|
|
|
/* Scroll on after subsequent timeout. */
|
|
|
|
ret = FALSE;
|
|
|
|
mode = CLUTTER_EASE_IN_CUBIC;
|
|
|
|
self->priv->paging_event_no = 2;
|
|
|
|
self->priv->paging_source_id = g_timeout_add (
|
|
|
|
PAGING_SUBSEQUENT_REPEAT_TIMEOUT,
|
|
|
|
(GSourceFunc) trough_paging_cb,
|
|
|
|
self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Keep scrolling. */
|
|
|
|
ret = TRUE;
|
|
|
|
mode = CLUTTER_LINEAR;
|
|
|
|
self->priv->paging_event_no++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the scrolling */
|
|
|
|
st_adjustment_get_values (self->priv->adjustment,
|
|
|
|
&value, NULL, NULL,
|
|
|
|
NULL, &page_increment, NULL);
|
|
|
|
|
|
|
|
if (self->priv->vertical)
|
|
|
|
handle_pos = clutter_actor_get_y (self->priv->handle);
|
|
|
|
else
|
|
|
|
handle_pos = clutter_actor_get_x (self->priv->handle);
|
|
|
|
|
|
|
|
clutter_actor_transform_stage_point (CLUTTER_ACTOR (self->priv->trough),
|
|
|
|
self->priv->move_x,
|
|
|
|
self->priv->move_y,
|
|
|
|
&tx, &ty);
|
|
|
|
|
|
|
|
if (self->priv->vertical)
|
|
|
|
event_pos = ty;
|
|
|
|
else
|
|
|
|
event_pos = tx;
|
|
|
|
|
|
|
|
if (event_pos > handle_pos)
|
|
|
|
{
|
|
|
|
if (self->priv->paging_direction == NONE)
|
|
|
|
{
|
|
|
|
/* Remember direction. */
|
|
|
|
self->priv->paging_direction = DOWN;
|
|
|
|
}
|
|
|
|
if (self->priv->paging_direction == UP)
|
|
|
|
{
|
|
|
|
/* Scrolled far enough. */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
value += page_increment;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (self->priv->paging_direction == NONE)
|
|
|
|
{
|
|
|
|
/* Remember direction. */
|
|
|
|
self->priv->paging_direction = UP;
|
|
|
|
}
|
|
|
|
if (self->priv->paging_direction == DOWN)
|
|
|
|
{
|
|
|
|
/* Scrolled far enough. */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
value -= page_increment;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self->priv->paging_animation)
|
|
|
|
{
|
|
|
|
clutter_animation_completed (self->priv->paging_animation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: Creating a new animation for each scroll is probably not the best
|
|
|
|
* idea, but it's a lot less involved than extenind the current animation */
|
|
|
|
a = self->priv->paging_animation = g_object_new (CLUTTER_TYPE_ANIMATION,
|
|
|
|
"object", self->priv->adjustment,
|
2010-06-19 22:16:06 -04:00
|
|
|
"duration", (guint)(PAGING_SUBSEQUENT_REPEAT_TIMEOUT * st_slow_down_factor),
|
2009-09-09 23:13:35 -04:00
|
|
|
"mode", mode,
|
|
|
|
NULL);
|
|
|
|
g_value_init (&v, G_TYPE_DOUBLE);
|
|
|
|
g_value_set_double (&v, value);
|
|
|
|
clutter_animation_bind (self->priv->paging_animation, "value", &v);
|
|
|
|
t = clutter_animation_get_timeline (self->priv->paging_animation);
|
|
|
|
g_signal_connect (a, "completed", G_CALLBACK (animation_completed_cb),
|
|
|
|
self->priv);
|
|
|
|
clutter_timeline_start (t);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
trough_button_press_event_cb (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event,
|
|
|
|
StScrollBar *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (self, FALSE);
|
|
|
|
|
|
|
|
if (event->button != 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (self->priv->adjustment == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
self->priv->move_x = event->x;
|
|
|
|
self->priv->move_y = event->y;
|
|
|
|
self->priv->paging_direction = NONE;
|
|
|
|
self->priv->paging_event_no = 0;
|
|
|
|
trough_paging_cb (self);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
trough_button_release_event_cb (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event,
|
|
|
|
StScrollBar *self)
|
|
|
|
{
|
|
|
|
if (event->button != 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (self->priv->paging_source_id)
|
|
|
|
{
|
|
|
|
g_source_remove (self->priv->paging_source_id);
|
|
|
|
self->priv->paging_source_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
trough_leave_event_cb (ClutterActor *actor,
|
|
|
|
ClutterEvent *event,
|
|
|
|
StScrollBar *self)
|
|
|
|
{
|
|
|
|
if (self->priv->paging_source_id)
|
|
|
|
{
|
|
|
|
g_source_remove (self->priv->paging_source_id);
|
|
|
|
self->priv->paging_source_id = 0;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_notify_reactive (StScrollBar *self)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
gboolean reactive = CLUTTER_ACTOR_IS_REACTIVE (self);
|
|
|
|
|
|
|
|
clutter_actor_set_reactive (CLUTTER_ACTOR (priv->trough), reactive);
|
|
|
|
clutter_actor_set_reactive (CLUTTER_ACTOR (priv->handle), reactive);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
st_scroll_bar_init (StScrollBar *self)
|
|
|
|
{
|
|
|
|
self->priv = ST_SCROLL_BAR_GET_PRIVATE (self);
|
|
|
|
|
|
|
|
self->priv->trough = (ClutterActor *) st_bin_new ();
|
|
|
|
clutter_actor_set_reactive ((ClutterActor *) self->priv->trough, TRUE);
|
|
|
|
clutter_actor_set_name (CLUTTER_ACTOR (self->priv->trough), "trough");
|
2012-02-13 15:22:53 -05:00
|
|
|
clutter_actor_add_child (CLUTTER_ACTOR (self),
|
|
|
|
CLUTTER_ACTOR (self->priv->trough));
|
2009-09-09 23:13:35 -04:00
|
|
|
g_signal_connect (self->priv->trough, "button-press-event",
|
|
|
|
G_CALLBACK (trough_button_press_event_cb), self);
|
|
|
|
g_signal_connect (self->priv->trough, "button-release-event",
|
|
|
|
G_CALLBACK (trough_button_release_event_cb), self);
|
|
|
|
g_signal_connect (self->priv->trough, "leave-event",
|
|
|
|
G_CALLBACK (trough_leave_event_cb), self);
|
|
|
|
|
|
|
|
self->priv->handle = (ClutterActor *) st_button_new ();
|
|
|
|
clutter_actor_set_name (CLUTTER_ACTOR (self->priv->handle), "hhandle");
|
2012-02-13 15:22:53 -05:00
|
|
|
clutter_actor_add_child (CLUTTER_ACTOR (self),
|
|
|
|
CLUTTER_ACTOR (self->priv->handle));
|
2009-09-09 23:13:35 -04:00
|
|
|
g_signal_connect (self->priv->handle, "button-press-event",
|
|
|
|
G_CALLBACK (handle_button_press_event_cb), self);
|
|
|
|
|
|
|
|
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
|
|
|
|
|
|
|
|
g_signal_connect (self, "notify::reactive",
|
|
|
|
G_CALLBACK (st_scroll_bar_notify_reactive), NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
StWidget *
|
|
|
|
st_scroll_bar_new (StAdjustment *adjustment)
|
|
|
|
{
|
|
|
|
return g_object_new (ST_TYPE_SCROLL_BAR,
|
|
|
|
"adjustment", adjustment,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2010-03-05 16:17:07 -05:00
|
|
|
static void
|
|
|
|
on_notify_value (GObject *object,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
StScrollBar *bar)
|
|
|
|
{
|
|
|
|
scroll_bar_update_positions (bar);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_changed (StAdjustment *adjustment,
|
|
|
|
StScrollBar *bar)
|
|
|
|
{
|
|
|
|
scroll_bar_update_positions (bar);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
void
|
|
|
|
st_scroll_bar_set_adjustment (StScrollBar *bar,
|
|
|
|
StAdjustment *adjustment)
|
|
|
|
{
|
|
|
|
StScrollBarPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (ST_IS_SCROLL_BAR (bar));
|
|
|
|
|
|
|
|
priv = bar->priv;
|
2010-03-10 18:32:10 -05:00
|
|
|
|
|
|
|
if (adjustment == priv->adjustment)
|
|
|
|
return;
|
|
|
|
|
2009-09-09 23:13:35 -04:00
|
|
|
if (priv->adjustment)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->adjustment,
|
2010-03-05 16:17:07 -05:00
|
|
|
on_notify_value,
|
2009-09-09 23:13:35 -04:00
|
|
|
bar);
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->adjustment,
|
2010-03-05 16:17:07 -05:00
|
|
|
on_changed,
|
2009-09-09 23:13:35 -04:00
|
|
|
bar);
|
|
|
|
g_object_unref (priv->adjustment);
|
|
|
|
priv->adjustment = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (adjustment)
|
|
|
|
{
|
|
|
|
priv->adjustment = g_object_ref (adjustment);
|
|
|
|
|
2010-03-05 16:17:07 -05:00
|
|
|
g_signal_connect (priv->adjustment, "notify::value",
|
|
|
|
G_CALLBACK (on_notify_value),
|
|
|
|
bar);
|
|
|
|
g_signal_connect (priv->adjustment, "changed",
|
|
|
|
G_CALLBACK (on_changed),
|
|
|
|
bar);
|
2009-09-09 23:13:35 -04:00
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (bar));
|
|
|
|
}
|
2010-03-10 18:32:10 -05:00
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (bar), "adjustment");
|
2009-09-09 23:13:35 -04:00
|
|
|
}
|
|
|
|
|
2009-09-16 19:07:23 -04:00
|
|
|
/**
|
|
|
|
* st_scroll_bar_get_adjustment:
|
|
|
|
* @bar: a #StScrollbar
|
|
|
|
*
|
|
|
|
* Gets the adjustment object that stores the current position
|
|
|
|
* of the scrollbar.
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the adjustment
|
|
|
|
*/
|
2009-09-09 23:13:35 -04:00
|
|
|
StAdjustment *
|
|
|
|
st_scroll_bar_get_adjustment (StScrollBar *bar)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (ST_IS_SCROLL_BAR (bar), NULL);
|
|
|
|
|
|
|
|
return bar->priv->adjustment;
|
|
|
|
}
|
|
|
|
|