Import MxScrollView and dependencies

https://bugzilla.gnome.org/show_bug.cgi?id=591245
This commit is contained in:
Owen W. Taylor 2009-09-09 23:13:35 -04:00
parent d291e568fd
commit f6b80d5ed4
11 changed files with 4042 additions and 0 deletions

View File

@ -65,10 +65,15 @@ st-enum-types.c: stamp-st-enum-types.h st/st-enum-types.c.in
# please, keep this sorted alphabetically
st_source_h = \
st/st-adjustment.h \
st/st-bin.h \
st/st-button.h \
st/st-private.h \
st/st-stylable.h \
st/st-style.h \
st/st-scrollable.h \
st/st-scroll-bar.h \
st/st-scroll-view.h \
st/st-subtexture.h \
st/st-texture-cache.h \
st/st-texture-frame.h \
@ -79,8 +84,13 @@ st_source_h = \
# please, keep this sorted alphabetically
st_source_c = \
st/st-adjustment.c \
st/st-bin.c \
st/st-button.c \
st/st-private.c \
st/st-scrollable.c \
st/st-scroll-bar.c \
st/st-scroll-view.c \
st/st-stylable.c \
st/st-style.c \
st/st-subtexture.c \

776
src/st/st-adjustment.c Normal file
View File

@ -0,0 +1,776 @@
/*
* st-adjustment.c: Adjustment object
*
* Copyright (C) 2008 OpenedHand
* Copyright (c) 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
/**
* SECTION:st-adjustment
* @short_description: A GObject representing an adjustable bounded value
*
* The #StAdjustment object represents a range of values bounded between a
* minimum and maximum, together with step and page increments and a page size.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <clutter/clutter.h>
#include "st-adjustment.h"
#include "st-marshal.h"
#include "st-private.h"
G_DEFINE_TYPE (StAdjustment, st_adjustment, G_TYPE_OBJECT)
#define ADJUSTMENT_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_ADJUSTMENT, StAdjustmentPrivate))
struct _StAdjustmentPrivate
{
/* Do not sanity-check values while constructing,
* not all properties may be set yet. */
gboolean is_constructing : 1;
gdouble lower;
gdouble upper;
gdouble value;
gdouble step_increment;
gdouble page_increment;
gdouble page_size;
/* For interpolation */
ClutterTimeline *interpolation;
gdouble old_position;
gdouble new_position;
/* For elasticity */
gboolean elastic;
guint bounce_source;
ClutterAlpha *bounce_alpha;
};
enum
{
PROP_0,
PROP_LOWER,
PROP_UPPER,
PROP_VALUE,
PROP_STEP_INC,
PROP_PAGE_INC,
PROP_PAGE_SIZE,
PROP_ELASTIC,
};
enum
{
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
static gboolean st_adjustment_set_lower (StAdjustment *adjustment,
gdouble lower);
static gboolean st_adjustment_set_upper (StAdjustment *adjustment,
gdouble upper);
static gboolean st_adjustment_set_step_increment (StAdjustment *adjustment,
gdouble step);
static gboolean st_adjustment_set_page_increment (StAdjustment *adjustment,
gdouble page);
static gboolean st_adjustment_set_page_size (StAdjustment *adjustment,
gdouble size);
static void
st_adjustment_constructed (GObject *object)
{
GObjectClass *g_class;
StAdjustment *self = ST_ADJUSTMENT (object);
g_class = G_OBJECT_CLASS (st_adjustment_parent_class);
/* The docs say we're suppose to chain up, but would crash without
* some extra care. */
if (g_class && g_class->constructed &&
g_class->constructed != st_adjustment_constructed)
{
g_class->constructed (object);
}
ST_ADJUSTMENT (self)->priv->is_constructing = FALSE;
st_adjustment_clamp_page (self, self->priv->lower, self->priv->upper);
}
static void
st_adjustment_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
StAdjustmentPrivate *priv = ST_ADJUSTMENT (gobject)->priv;
switch (prop_id)
{
case PROP_LOWER:
g_value_set_double (value, priv->lower);
break;
case PROP_UPPER:
g_value_set_double (value, priv->upper);
break;
case PROP_VALUE:
g_value_set_double (value, priv->value);
break;
case PROP_STEP_INC:
g_value_set_double (value, priv->step_increment);
break;
case PROP_PAGE_INC:
g_value_set_double (value, priv->page_increment);
break;
case PROP_PAGE_SIZE:
g_value_set_double (value, priv->page_size);
break;
case PROP_ELASTIC:
g_value_set_boolean (value, priv->elastic);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
st_adjustment_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
StAdjustment *adj = ST_ADJUSTMENT (gobject);
switch (prop_id)
{
case PROP_LOWER:
st_adjustment_set_lower (adj, g_value_get_double (value));
break;
case PROP_UPPER:
st_adjustment_set_upper (adj, g_value_get_double (value));
break;
case PROP_VALUE:
st_adjustment_set_value (adj, g_value_get_double (value));
break;
case PROP_STEP_INC:
st_adjustment_set_step_increment (adj, g_value_get_double (value));
break;
case PROP_PAGE_INC:
st_adjustment_set_page_increment (adj, g_value_get_double (value));
break;
case PROP_PAGE_SIZE:
st_adjustment_set_page_size (adj, g_value_get_double (value));
break;
case PROP_ELASTIC:
st_adjustment_set_elastic (adj, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
stop_interpolation (StAdjustment *adjustment)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->interpolation)
{
clutter_timeline_stop (priv->interpolation);
g_object_unref (priv->interpolation);
priv->interpolation = NULL;
if (priv->bounce_alpha)
{
g_object_unref (priv->bounce_alpha);
priv->bounce_alpha = NULL;
}
}
if (priv->bounce_source)
{
g_source_remove (priv->bounce_source);
priv->bounce_source = 0;
}
}
static void
st_adjustment_dispose (GObject *object)
{
stop_interpolation (ST_ADJUSTMENT (object));
G_OBJECT_CLASS (st_adjustment_parent_class)->dispose (object);
}
static void
st_adjustment_class_init (StAdjustmentClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (StAdjustmentPrivate));
object_class->constructed = st_adjustment_constructed;
object_class->get_property = st_adjustment_get_property;
object_class->set_property = st_adjustment_set_property;
object_class->dispose = st_adjustment_dispose;
g_object_class_install_property (object_class,
PROP_LOWER,
g_param_spec_double ("lower",
"Lower",
"Lower bound",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_UPPER,
g_param_spec_double ("upper",
"Upper",
"Upper bound",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_VALUE,
g_param_spec_double ("value",
"Value",
"Current value",
-G_MAXDOUBLE,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_STEP_INC,
g_param_spec_double ("step-increment",
"Step Increment",
"Step increment",
0.0,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_PAGE_INC,
g_param_spec_double ("page-increment",
"Page Increment",
"Page increment",
0.0,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_PAGE_SIZE,
g_param_spec_double ("page-size",
"Page Size",
"Page size",
0.0,
G_MAXDOUBLE,
0.0,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_ELASTIC,
g_param_spec_boolean ("elastic",
"Elastic",
"Make interpolation "
"behave in an "
"'elastic' way and "
"stop clamping value.",
FALSE,
ST_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
/**
* StAdjustment::changed:
*
* Emitted when any of the adjustment values have changed
*/
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (StAdjustmentClass, changed),
NULL, NULL,
_st_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
st_adjustment_init (StAdjustment *self)
{
self->priv = ADJUSTMENT_PRIVATE (self);
self->priv->is_constructing = TRUE;
}
StAdjustment *
st_adjustment_new (gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size)
{
return g_object_new (ST_TYPE_ADJUSTMENT,
"value", value,
"lower", lower,
"upper", upper,
"step-increment", step_increment,
"page-increment", page_increment,
"page-size", page_size,
NULL);
}
gdouble
st_adjustment_get_value (StAdjustment *adjustment)
{
StAdjustmentPrivate *priv;
g_return_val_if_fail (ST_IS_ADJUSTMENT (adjustment), 0);
priv = adjustment->priv;
if (priv->interpolation)
{
return MAX (priv->lower,
MIN (priv->upper - priv->page_size,
priv->new_position));
}
else
return priv->value;
}
void
st_adjustment_set_value (StAdjustment *adjustment,
gdouble value)
{
StAdjustmentPrivate *priv;
g_return_if_fail (ST_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
stop_interpolation (adjustment);
/* Defer clamp until after construction. */
if (!priv->is_constructing)
{
if (!priv->elastic)
value = CLAMP (value,
priv->lower,
MAX (priv->lower, priv->upper - priv->page_size));
}
if (priv->value != value)
{
priv->value = value;
g_object_notify (G_OBJECT (adjustment), "value");
}
}
void
st_adjustment_clamp_page (StAdjustment *adjustment,
gdouble lower,
gdouble upper)
{
StAdjustmentPrivate *priv;
gboolean changed;
g_return_if_fail (ST_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
stop_interpolation (adjustment);
lower = CLAMP (lower, priv->lower, priv->upper - priv->page_size);
upper = CLAMP (upper, priv->lower + priv->page_size, priv->upper);
changed = FALSE;
if (priv->value + priv->page_size > upper)
{
priv->value = upper - priv->page_size;
changed = TRUE;
}
if (priv->value < lower)
{
priv->value = lower;
changed = TRUE;
}
if (changed)
g_object_notify (G_OBJECT (adjustment), "value");
}
static gboolean
st_adjustment_set_lower (StAdjustment *adjustment,
gdouble lower)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->lower != lower)
{
priv->lower = lower;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "lower");
/* Defer clamp until after construction. */
if (!priv->is_constructing)
st_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
static gboolean
st_adjustment_set_upper (StAdjustment *adjustment,
gdouble upper)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->upper != upper)
{
priv->upper = upper;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "upper");
/* Defer clamp until after construction. */
if (!priv->is_constructing)
st_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
static gboolean
st_adjustment_set_step_increment (StAdjustment *adjustment,
gdouble step)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->step_increment != step)
{
priv->step_increment = step;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "step-increment");
return TRUE;
}
return FALSE;
}
static gboolean
st_adjustment_set_page_increment (StAdjustment *adjustment,
gdouble page)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->page_increment != page)
{
priv->page_increment = page;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "page-increment");
return TRUE;
}
return FALSE;
}
static gboolean
st_adjustment_set_page_size (StAdjustment *adjustment,
gdouble size)
{
StAdjustmentPrivate *priv = adjustment->priv;
if (priv->page_size != size)
{
priv->page_size = size;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify (G_OBJECT (adjustment), "page_size");
/* Well explicitely clamp after construction. */
if (!priv->is_constructing)
st_adjustment_clamp_page (adjustment, priv->lower, priv->upper);
return TRUE;
}
return FALSE;
}
void
st_adjustment_set_values (StAdjustment *adjustment,
gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size)
{
StAdjustmentPrivate *priv;
gboolean emit_changed = FALSE;
g_return_if_fail (ST_IS_ADJUSTMENT (adjustment));
g_return_if_fail (page_size >= 0 && page_size <= G_MAXDOUBLE);
g_return_if_fail (step_increment >= 0 && step_increment <= G_MAXDOUBLE);
g_return_if_fail (page_increment >= 0 && page_increment <= G_MAXDOUBLE);
priv = adjustment->priv;
stop_interpolation (adjustment);
emit_changed = FALSE;
g_object_freeze_notify (G_OBJECT (adjustment));
emit_changed |= st_adjustment_set_lower (adjustment, lower);
emit_changed |= st_adjustment_set_upper (adjustment, upper);
emit_changed |= st_adjustment_set_step_increment (adjustment, step_increment);
emit_changed |= st_adjustment_set_page_increment (adjustment, page_increment);
emit_changed |= st_adjustment_set_page_size (adjustment, page_size);
if (value != priv->value)
{
st_adjustment_set_value (adjustment, value);
emit_changed = TRUE;
}
if (emit_changed)
g_signal_emit (G_OBJECT (adjustment), signals[CHANGED], 0);
g_object_thaw_notify (G_OBJECT (adjustment));
}
void
st_adjustment_get_values (StAdjustment *adjustment,
gdouble *value,
gdouble *lower,
gdouble *upper,
gdouble *step_increment,
gdouble *page_increment,
gdouble *page_size)
{
StAdjustmentPrivate *priv;
g_return_if_fail (ST_IS_ADJUSTMENT (adjustment));
priv = adjustment->priv;
if (lower)
*lower = priv->lower;
if (upper)
*upper = priv->upper;
if (value)
*value = st_adjustment_get_value (adjustment);
if (step_increment)
*step_increment = priv->step_increment;
if (page_increment)
*page_increment = priv->page_increment;
if (page_size)
*page_size = priv->page_size;
}
static void
interpolation_new_frame_cb (ClutterTimeline *timeline,
guint msecs,
StAdjustment *adjustment)
{
StAdjustmentPrivate *priv = adjustment->priv;
priv->interpolation = NULL;
if (priv->elastic)
{
gdouble progress = clutter_alpha_get_alpha (priv->bounce_alpha) / 1.0;
gdouble dx = priv->old_position
+ (priv->new_position - priv->old_position)
* progress;
st_adjustment_set_value (adjustment, dx);
}
else
st_adjustment_set_value (adjustment,
priv->old_position +
(priv->new_position - priv->old_position) *
clutter_timeline_get_progress (timeline));
priv->interpolation = timeline;
}
static void
interpolation_completed_cb (ClutterTimeline *timeline,
StAdjustment *adjustment)
{
StAdjustmentPrivate *priv = adjustment->priv;
stop_interpolation (adjustment);
st_adjustment_set_value (adjustment, priv->new_position);
}
/* Note, there's super-optimal code that does a similar thing in
* clutter-alpha.c
*
* Tried this instead of CLUTTER_ALPHA_SINE_INC, but I think SINE_INC looks
* better. Leaving code here in case this is revisited.
*/
/*
static guint32
bounce_alpha_func (ClutterAlpha *alpha,
gpointer user_data)
{
ClutterFixed progress, angle;
ClutterTimeline *timeline = clutter_alpha_get_timeline (alpha);
progress = clutter_timeline_get_progressx (timeline);
angle = clutter_qmulx (CFX_PI_2 + CFX_PI_4/2, progress);
return clutter_sinx (angle) +
(CFX_ONE - clutter_sinx (CFX_PI_2 + CFX_PI_4/2));
}
*/
void
st_adjustment_interpolate (StAdjustment *adjustment,
gdouble value,
guint duration)
{
StAdjustmentPrivate *priv = adjustment->priv;
stop_interpolation (adjustment);
if (duration <= 1)
{
st_adjustment_set_value (adjustment, value);
return;
}
priv->old_position = priv->value;
priv->new_position = value;
priv->interpolation = clutter_timeline_new (duration);
if (priv->elastic)
priv->bounce_alpha = clutter_alpha_new_full (priv->interpolation,
CLUTTER_LINEAR);
g_signal_connect (priv->interpolation,
"new-frame",
G_CALLBACK (interpolation_new_frame_cb),
adjustment);
g_signal_connect (priv->interpolation,
"completed",
G_CALLBACK (interpolation_completed_cb),
adjustment);
clutter_timeline_start (priv->interpolation);
}
gboolean
st_adjustment_get_elastic (StAdjustment *adjustment)
{
return adjustment->priv->elastic;
}
void
st_adjustment_set_elastic (StAdjustment *adjustment,
gboolean elastic)
{
adjustment->priv->elastic = elastic;
}
gboolean
st_adjustment_clamp (StAdjustment *adjustment,
gboolean interpolate,
guint duration)
{
StAdjustmentPrivate *priv = adjustment->priv;
gdouble dest = priv->value;
if (priv->value < priv->lower)
dest = priv->lower;
if (priv->value > priv->upper - priv->page_size)
dest = priv->upper - priv->page_size;
if (dest != priv->value)
{
if (interpolate)
st_adjustment_interpolate (adjustment, dest, duration);
else
st_adjustment_set_value (adjustment, dest);
return TRUE;
}
return FALSE;
}

121
src/st/st-adjustment.h Normal file
View File

@ -0,0 +1,121 @@
/*
* st-adjustment.h: Adjustment object
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>, inspired by GtkAdjustment
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#ifndef __ST_ADJUSTMENT_H__
#define __ST_ADJUSTMENT_H__
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define ST_TYPE_ADJUSTMENT (st_adjustment_get_type())
#define ST_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_ADJUSTMENT, StAdjustment))
#define ST_IS_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_ADJUSTMENT))
#define ST_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_ADJUSTMENT, StAdjustmentClass))
#define ST_IS_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_ADJUSTMENT))
#define ST_ADJUSTMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_ADJUSTMENT, StAdjustmentClass))
typedef struct _StAdjustment StAdjustment;
typedef struct _StAdjustmentPrivate StAdjustmentPrivate;
typedef struct _StAdjustmentClass StAdjustmentClass;
/**
* StAdjustment:
*
* Class for handling an interval between to values. The contents of
* the #StAdjustment are private and should be accessed using the
* public API.
*/
struct _StAdjustment
{
/*< private >*/
GObject parent_instance;
StAdjustmentPrivate *priv;
};
/**
* StAdjustmentClass
* @changed: Class handler for the ::changed signal.
*
* Base class for #StAdjustment.
*/
struct _StAdjustmentClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
void (* changed) (StAdjustment *adjustment);
};
GType st_adjustment_get_type (void) G_GNUC_CONST;
StAdjustment *st_adjustment_new (gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size);
gdouble st_adjustment_get_value (StAdjustment *adjustment);
void st_adjustment_set_value (StAdjustment *adjustment,
gdouble value);
void st_adjustment_clamp_page (StAdjustment *adjustment,
gdouble lower,
gdouble upper);
void st_adjustment_set_values (StAdjustment *adjustment,
gdouble value,
gdouble lower,
gdouble upper,
gdouble step_increment,
gdouble page_increment,
gdouble page_size);
void st_adjustment_get_values (StAdjustment *adjustment,
gdouble *value,
gdouble *lower,
gdouble *upper,
gdouble *step_increment,
gdouble *page_increment,
gdouble *page_size);
void st_adjustment_interpolate (StAdjustment *adjustment,
gdouble value,
guint duration);
gboolean st_adjustment_get_elastic (StAdjustment *adjustment);
void st_adjustment_set_elastic (StAdjustment *adjustment,
gboolean elastic);
gboolean st_adjustment_clamp (StAdjustment *adjustment,
gboolean interpolate,
guint duration);
G_END_DECLS
#endif /* __ST_ADJUSTMENT_H__ */

759
src/st/st-button.c Normal file
View File

@ -0,0 +1,759 @@
/*
* st-button.c: Plain button actor
*
* Copyright 2007 OpenedHand
* Copyright 2008, 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
* Thomas Wood <thomas@linux.intel.com>
*
*/
/**
* SECTION:st-button
* @short_description: Button widget
*
* A button widget with support for either a text label or icon, toggle mode
* and transitions effects between states.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "st-button.h"
#include "st-marshal.h"
#include "st-stylable.h"
#include "st-style.h"
#include "st-texture-frame.h"
#include "st-texture-cache.h"
#include "st-private.h"
enum
{
PROP_0,
PROP_LABEL,
PROP_TOGGLE,
PROP_ACTIVE,
PROP_TRANSITION
};
enum
{
CLICKED,
LAST_SIGNAL
};
#define ST_BUTTON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_BUTTON, StButtonPrivate))
struct _StButtonPrivate
{
gchar *text;
ClutterActor *old_bg;
gboolean old_bg_parented; /* TRUE if we have adopted old_bg */
guint8 old_opacity;
guint is_pressed : 1;
guint is_hover : 1;
guint is_checked : 1;
guint is_toggle : 1;
gint transition_duration;
ClutterAnimation *animation;
gint spacing;
};
static guint button_signals[LAST_SIGNAL] = { 0, };
static void st_stylable_iface_init (StStylableIface *iface);
G_DEFINE_TYPE_WITH_CODE (StButton, st_button, ST_TYPE_BIN,
G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE,
st_stylable_iface_init));
static void
st_stylable_iface_init (StStylableIface *iface)
{
static gboolean is_initialized = FALSE;
if (G_UNLIKELY (!is_initialized))
{
ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x00 };
GParamSpec *pspec;
is_initialized = TRUE;
pspec = g_param_spec_int ("border-spacing",
"Border Spacing",
"Spacing between internal elements",
0, G_MAXINT, 6,
G_PARAM_READWRITE);
st_stylable_iface_install_property (iface, ST_TYPE_BUTTON, pspec);
is_initialized = TRUE;
pspec = clutter_param_spec_color ("background-color",
"Background Color",
"The background color of an actor",
&bg_color,
G_PARAM_READWRITE);
st_stylable_iface_install_property (iface, ST_TYPE_BUTTON, pspec);
}
}
static void
st_button_update_label_style (StButton *button)
{
ClutterColor *real_color = NULL;
gchar *font_string = NULL;
gchar *font_name = NULL;
gint font_size = 0;
ClutterActor *label;
label = st_bin_get_child ((StBin*) button);
/* check the child is really a label */
if (!CLUTTER_IS_TEXT (label))
return;
st_stylable_get (ST_STYLABLE (button),
"color", &real_color,
"font-family", &font_name,
"font-size", &font_size,
NULL);
if (font_name || font_size)
{
if (font_name && font_size)
font_string = g_strdup_printf ("%s %dpx", font_name, font_size);
else
{
if (font_size)
font_string = g_strdup_printf ("%dpx", font_size);
else
font_string = font_name;
}
clutter_text_set_font_name (CLUTTER_TEXT (label), font_string);
if (font_string != font_name)
g_free (font_string);
}
g_free (font_name);
if (real_color)
{
clutter_text_set_color (CLUTTER_TEXT (label), real_color);
clutter_color_free (real_color);
}
}
static void
st_button_dispose_old_bg (StButton *button)
{
StButtonPrivate *priv = button->priv;
if (priv->old_bg)
{
if (priv->old_bg_parented)
{
clutter_actor_unparent (priv->old_bg);
priv->old_bg_parented = FALSE;
}
g_object_unref (priv->old_bg);
priv->old_bg = NULL;
}
}
static void
st_button_stylable_changed (StStylable *stylable)
{
StButton *button = ST_BUTTON (stylable);
ClutterActor *bg_image;
st_button_dispose_old_bg (button);
bg_image = st_widget_get_border_image ((StWidget*) button);
if (bg_image)
button->priv->old_bg = g_object_ref (bg_image);
}
static void
st_animation_completed (ClutterAnimation *animation,
StButton *button)
{
st_button_dispose_old_bg (button);
}
static void
st_button_style_changed (StWidget *widget)
{
StButton *button = ST_BUTTON (widget);
StButtonPrivate *priv = button->priv;
StButtonClass *button_class = ST_BUTTON_GET_CLASS (button);
/* get the spacing value */
st_stylable_get (ST_STYLABLE (widget),
"border-spacing", &priv->spacing,
NULL);
/* update the label styling */
st_button_update_label_style (button);
/* run a transition if applicable */
if (button_class->transition)
{
button_class->transition (button, priv->old_bg);
}
else
{
if (priv->old_bg &&
(!st_widget_get_style_pseudo_class (widget)))
{
ClutterAnimation *animation;
if (!clutter_actor_get_parent (priv->old_bg))
{
clutter_actor_set_parent (priv->old_bg, (ClutterActor*) widget);
priv->old_bg_parented = TRUE;
}
if (priv->transition_duration > 0)
{
animation = clutter_actor_animate (priv->old_bg,
CLUTTER_LINEAR,
priv->transition_duration,
"opacity", 0,
NULL);
g_signal_connect (animation, "completed",
G_CALLBACK (st_animation_completed), button);
}
else
{
st_button_dispose_old_bg (button);
}
}
}
}
static void
st_button_real_pressed (StButton *button)
{
st_widget_set_style_pseudo_class ((StWidget*) button, "active");
}
static void
st_button_real_released (StButton *button)
{
StButtonPrivate *priv = button->priv;
if (priv->is_checked)
st_widget_set_style_pseudo_class ((StWidget*) button, "checked");
else if (!priv->is_hover)
st_widget_set_style_pseudo_class ((StWidget*) button, NULL);
else
st_widget_set_style_pseudo_class ((StWidget*) button, "hover");
}
static gboolean
st_button_button_press (ClutterActor *actor,
ClutterButtonEvent *event)
{
st_widget_hide_tooltip (ST_WIDGET (actor));
if (event->button == 1)
{
StButton *button = ST_BUTTON (actor);
StButtonClass *klass = ST_BUTTON_GET_CLASS (button);
button->priv->is_pressed = TRUE;
clutter_grab_pointer (actor);
if (klass->pressed)
klass->pressed (button);
return TRUE;
}
return FALSE;
}
static gboolean
st_button_button_release (ClutterActor *actor,
ClutterButtonEvent *event)
{
if (event->button == 1)
{
StButton *button = ST_BUTTON (actor);
StButtonClass *klass = ST_BUTTON_GET_CLASS (button);
if (!button->priv->is_pressed)
return FALSE;
clutter_ungrab_pointer ();
if (button->priv->is_toggle)
{
st_button_set_checked (button, !button->priv->is_checked);
}
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
g_signal_emit (button, button_signals[CLICKED], 0);
return TRUE;
}
return FALSE;
}
static gboolean
st_button_enter (ClutterActor *actor,
ClutterCrossingEvent *event)
{
StButton *button = ST_BUTTON (actor);
if (!button->priv->is_checked)
st_widget_set_style_pseudo_class ((StWidget*) button, "hover");
button->priv->is_hover = 1;
return CLUTTER_ACTOR_CLASS (st_button_parent_class)->enter_event (actor, event);
}
static gboolean
st_button_leave (ClutterActor *actor,
ClutterCrossingEvent *event)
{
StButton *button = ST_BUTTON (actor);
button->priv->is_hover = 0;
if (button->priv->is_pressed)
{
StButtonClass *klass = ST_BUTTON_GET_CLASS (button);
clutter_ungrab_pointer ();
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
}
if (button->priv->is_checked)
st_widget_set_style_pseudo_class ((StWidget*) button, "checked");
else
st_widget_set_style_pseudo_class ((StWidget*) button, NULL);
return CLUTTER_ACTOR_CLASS (st_button_parent_class)->leave_event (actor, event);
}
static void
st_button_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
StButton *button = ST_BUTTON (gobject);
StButtonPrivate *priv = ST_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
st_button_set_label (button, g_value_get_string (value));
break;
case PROP_TOGGLE:
st_button_set_toggle_mode (button, g_value_get_boolean (value));
break;
case PROP_ACTIVE:
st_button_set_checked (button, g_value_get_boolean (value));
break;
case PROP_TRANSITION:
priv->transition_duration = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
st_button_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
StButtonPrivate *priv = ST_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
g_value_set_string (value, priv->text);
break;
case PROP_TOGGLE:
g_value_set_boolean (value, priv->is_toggle);
break;
case PROP_ACTIVE:
g_value_set_boolean (value, priv->is_checked);
break;
case PROP_TRANSITION:
g_value_set_int (value, priv->transition_duration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
st_button_finalize (GObject *gobject)
{
StButtonPrivate *priv = ST_BUTTON (gobject)->priv;
g_free (priv->text);
G_OBJECT_CLASS (st_button_parent_class)->finalize (gobject);
}
static void
st_button_dispose (GObject *gobject)
{
st_button_dispose_old_bg (ST_BUTTON (gobject));
G_OBJECT_CLASS (st_button_parent_class)->dispose (gobject);
}
static void
st_button_map (ClutterActor *self)
{
StButtonPrivate *priv = ST_BUTTON (self)->priv;
CLUTTER_ACTOR_CLASS (st_button_parent_class)->map (self);
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_map (priv->old_bg);
}
static void
st_button_unmap (ClutterActor *self)
{
StButtonPrivate *priv = ST_BUTTON (self)->priv;
CLUTTER_ACTOR_CLASS (st_button_parent_class)->unmap (self);
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_unmap (priv->old_bg);
}
static void
st_button_draw_background (StWidget *widget,
ClutterActor *background,
const ClutterColor *color)
{
StButtonPrivate *priv;
ST_WIDGET_CLASS (st_button_parent_class)->draw_background (widget, background, color);
priv = ST_BUTTON (widget)->priv;
if (priv->old_bg && priv->old_bg_parented)
clutter_actor_paint (priv->old_bg);
}
static void
st_button_class_init (StButtonClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (StButtonPrivate));
klass->pressed = st_button_real_pressed;
klass->released = st_button_real_released;
gobject_class->set_property = st_button_set_property;
gobject_class->get_property = st_button_get_property;
gobject_class->dispose = st_button_dispose;
gobject_class->finalize = st_button_finalize;
actor_class->button_press_event = st_button_button_press;
actor_class->button_release_event = st_button_button_release;
actor_class->enter_event = st_button_enter;
actor_class->leave_event = st_button_leave;
actor_class->map = st_button_map;
actor_class->unmap = st_button_unmap;
widget_class->draw_background = st_button_draw_background;
pspec = g_param_spec_string ("label",
"Label",
"Label of the button",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
pspec = g_param_spec_boolean ("toggle-mode",
"Toggle Mode",
"Enable or disable toggling",
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TOGGLE, pspec);
pspec = g_param_spec_boolean ("checked",
"Checked",
"Indicates if a toggle button is \"on\""
" or \"off\"",
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_ACTIVE, pspec);
pspec = g_param_spec_int ("transition-duration",
"Transition Duration",
"Duration of the state transition effect",
0, G_MAXINT, 120, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TRANSITION, pspec);
/**
* StButton::clicked:
* @button: the object that received the signal
*
* Emitted when the user activates the button, either with a mouse press and
* release or with the keyboard.
*/
button_signals[CLICKED] =
g_signal_new ("clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (StButtonClass, clicked),
NULL, NULL,
_st_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
st_button_init (StButton *button)
{
button->priv = ST_BUTTON_GET_PRIVATE (button);
button->priv->transition_duration = 120;
button->priv->spacing = 6;
clutter_actor_set_reactive ((ClutterActor *) button, TRUE);
g_signal_connect (button, "style-changed",
G_CALLBACK (st_button_style_changed), NULL);
g_signal_connect (button, "stylable-changed",
G_CALLBACK (st_button_stylable_changed), NULL);
}
/**
* st_button_new:
*
* Create a new button
*
* Returns: a new #StButton
*/
StWidget *
st_button_new (void)
{
return g_object_new (ST_TYPE_BUTTON, NULL);
}
/**
* st_button_new_with_label:
* @text: text to set the label to
*
* Create a new #StButton with the specified label
*
* Returns: a new #StButton
*/
StWidget *
st_button_new_with_label (const gchar *text)
{
return g_object_new (ST_TYPE_BUTTON, "label", text, NULL);
}
/**
* st_button_get_label:
* @button: a #StButton
*
* Get the text displayed on the button
*
* Returns: the text for the button. This must not be freed by the application
*/
G_CONST_RETURN gchar *
st_button_get_label (StButton *button)
{
g_return_val_if_fail (ST_IS_BUTTON (button), NULL);
return button->priv->text;
}
/**
* st_button_set_label:
* @button: a #Stbutton
* @text: text to set the label to
*
* Sets the text displayed on the button
*/
void
st_button_set_label (StButton *button,
const gchar *text)
{
StButtonPrivate *priv;
ClutterActor *label;
g_return_if_fail (ST_IS_BUTTON (button));
priv = button->priv;
g_free (priv->text);
if (text)
priv->text = g_strdup (text);
else
priv->text = g_strdup ("");
label = st_bin_get_child ((StBin*) button);
if (label && CLUTTER_IS_TEXT (label))
{
clutter_text_set_text (CLUTTER_TEXT (label), priv->text);
}
else
{
label = g_object_new (CLUTTER_TYPE_TEXT,
"text", priv->text,
"line-alignment", PANGO_ALIGN_CENTER,
"ellipsize", PANGO_ELLIPSIZE_END,
"use-markup", TRUE,
NULL);
st_bin_set_child ((StBin*) button, label);
}
st_stylable_changed ((StStylable*) button);
g_object_notify (G_OBJECT (button), "label");
}
/**
* st_button_get_toggle_mode:
* @button: a #StButton
*
* Get the toggle mode status of the button.
*
* Returns: #TRUE if toggle mode is set, otherwise #FALSE
*/
gboolean
st_button_get_toggle_mode (StButton *button)
{
g_return_val_if_fail (ST_IS_BUTTON (button), FALSE);
return button->priv->is_toggle;
}
/**
* st_button_set_toggle_mode:
* @button: a #Stbutton
* @toggle: #TRUE or #FALSE
*
* Enables or disables toggle mode for the button. In toggle mode, the active
* state will be "toggled" when the user clicks the button.
*/
void
st_button_set_toggle_mode (StButton *button,
gboolean toggle)
{
g_return_if_fail (ST_IS_BUTTON (button));
button->priv->is_toggle = toggle;
g_object_notify (G_OBJECT (button), "toggle-mode");
}
/**
* st_button_get_checked:
* @button: a #StButton
*
* Get the state of the button that is in toggle mode.
*
* Returns: #TRUE if the button is checked, or #FALSE if not
*/
gboolean
st_button_get_checked (StButton *button)
{
g_return_val_if_fail (ST_IS_BUTTON (button), FALSE);
return button->priv->is_checked;
}
/**
* st_button_set_checked:
* @button: a #Stbutton
* @checked: #TRUE or #FALSE
*
* Sets the pressed state of the button. This is only really useful if the
* button has #toggle-mode mode set to #TRUE.
*/
void
st_button_set_checked (StButton *button,
gboolean checked)
{
g_return_if_fail (ST_IS_BUTTON (button));
if (button->priv->is_checked != checked)
{
button->priv->is_checked = checked;
if (checked)
st_widget_set_style_pseudo_class ((StWidget*) button, "checked");
else
if (button->priv->is_hover)
st_widget_set_style_pseudo_class ((StWidget*) button, "hover");
else
st_widget_set_style_pseudo_class ((StWidget*) button, NULL);
}
g_object_notify (G_OBJECT (button), "checked");
}

93
src/st/st-button.h Normal file
View File

@ -0,0 +1,93 @@
/*
* st-button.h: Plain button actor
*
* Copyright 2007 OpenedHand
* Copyright 2008, 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
* Thomas Wood <thomas@linux.intel.com>
*
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#ifndef __ST_BUTTON_H__
#define __ST_BUTTON_H__
G_BEGIN_DECLS
#include <st/st-bin.h>
#define ST_TYPE_BUTTON (st_button_get_type ())
#define ST_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_BUTTON, StButton))
#define ST_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_BUTTON))
#define ST_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_BUTTON, StButtonClass))
#define ST_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_BUTTON))
#define ST_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_BUTTON, StButtonClass))
typedef struct _StButton StButton;
typedef struct _StButtonPrivate StButtonPrivate;
typedef struct _StButtonClass StButtonClass;
/**
* StButton:
*
* The contents of this structure is private and should only be accessed using
* the provided API.
*/
struct _StButton
{
/*< private >*/
StBin parent_instance;
StButtonPrivate *priv;
};
struct _StButtonClass
{
StBinClass parent_class;
/* vfuncs, not signals */
void (* pressed) (StButton *button);
void (* released) (StButton *button);
void (* transition) (StButton *button,
ClutterActor *old_bg);
/* signals */
void (* clicked) (StButton *button);
};
GType st_button_get_type (void) G_GNUC_CONST;
StWidget * st_button_new (void);
StWidget * st_button_new_with_label (const gchar *text);
G_CONST_RETURN gchar *st_button_get_label (StButton *button);
void st_button_set_label (StButton *button,
const gchar *text);
void st_button_set_toggle_mode (StButton *button,
gboolean toggle);
gboolean st_button_get_toggle_mode (StButton *button);
void st_button_set_checked (StButton *button,
gboolean checked);
gboolean st_button_get_checked (StButton *button);
G_END_DECLS
#endif /* __ST_BUTTON_H__ */

1105
src/st/st-scroll-bar.c Normal file

File diff suppressed because it is too large Load Diff

82
src/st/st-scroll-bar.h Normal file
View File

@ -0,0 +1,82 @@
/*
* st-scroll-bar.h: Scroll bar actor
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#ifndef __ST_SCROLL_BAR_H__
#define __ST_SCROLL_BAR_H__
#include <st/st-adjustment.h>
#include <st/st-bin.h>
G_BEGIN_DECLS
#define ST_TYPE_SCROLL_BAR (st_scroll_bar_get_type())
#define ST_SCROLL_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLL_BAR, StScrollBar))
#define ST_IS_SCROLL_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLL_BAR))
#define ST_SCROLL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SCROLL_BAR, StScrollBarClass))
#define ST_IS_SCROLL_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SCROLL_BAR))
#define ST_SCROLL_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SCROLL_BAR, StScrollBarClass))
typedef struct _StScrollBar StScrollBar;
typedef struct _StScrollBarPrivate StScrollBarPrivate;
typedef struct _StScrollBarClass StScrollBarClass;
/**
* StScrollBar:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _StScrollBar
{
/*< private >*/
StBin parent_instance;
StScrollBarPrivate *priv;
};
struct _StScrollBarClass
{
StBinClass parent_class;
/* signals */
void (*scroll_start) (StScrollBar *bar);
void (*scroll_stop) (StScrollBar *bar);
};
GType st_scroll_bar_get_type (void) G_GNUC_CONST;
StWidget *st_scroll_bar_new (StAdjustment *adjustment);
void st_scroll_bar_set_adjustment (StScrollBar *bar,
StAdjustment *adjustment);
StAdjustment *st_scroll_bar_get_adjustment (StScrollBar *bar);
G_END_DECLS
#endif /* __ST_SCROLL_BAR_H__ */

850
src/st/st-scroll-view.c Normal file
View File

@ -0,0 +1,850 @@
/*
* st-scroll-view.h: Container with scroll-bars
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
/**
* SECTION:st-scroll-view
* @short_description: a container for scrollable children
*
* #StScrollView is a single child container for actors that implement
* #StScrollable. It provides scrollbars around the edge of the child to
* allow the user to move around the scrollable area.
*/
#include "st-scroll-view.h"
#include "st-marshal.h"
#include "st-scroll-bar.h"
#include "st-scrollable.h"
#include "st-stylable.h"
#include <clutter/clutter.h>
static void clutter_container_iface_init (ClutterContainerIface *iface);
static void st_stylable_iface_init (StStylableIface *iface);
static ClutterContainerIface *st_scroll_view_parent_iface = NULL;
G_DEFINE_TYPE_WITH_CODE (StScrollView, st_scroll_view, ST_TYPE_BIN,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init)
G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE,
st_stylable_iface_init))
#define SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
ST_TYPE_SCROLL_VIEW, \
StScrollViewPrivate))
struct _StScrollViewPrivate
{
/* a pointer to the child; this is actually stored
* inside StBin:child, but we keep it to avoid
* calling st_bin_get_child() every time we need it
*/
ClutterActor *child;
ClutterActor *hscroll;
ClutterActor *vscroll;
gfloat row_size;
gfloat column_size;
gboolean row_size_set : 1;
gboolean column_size_set : 1;
guint mouse_scroll : 1;
};
enum {
PROP_0,
PROP_HSCROLL,
PROP_VSCROLL,
PROP_MOUSE_SCROLL
};
static void
st_scroll_view_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
StScrollViewPrivate *priv = ((StScrollView *) object)->priv;
switch (property_id)
{
case PROP_HSCROLL:
g_value_set_object (value, priv->hscroll);
break;
case PROP_VSCROLL:
g_value_set_object (value, priv->vscroll);
break;
case PROP_MOUSE_SCROLL:
g_value_set_boolean (value, priv->mouse_scroll);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_scroll_view_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
case PROP_MOUSE_SCROLL:
st_scroll_view_set_mouse_scrolling ((StScrollView *) object,
g_value_get_boolean (value));
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
st_scroll_view_dispose (GObject *object)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv;
priv->child = NULL;
if (priv->vscroll)
{
clutter_actor_unparent (priv->vscroll);
priv->vscroll = NULL;
}
if (priv->hscroll)
{
clutter_actor_unparent (priv->hscroll);
priv->hscroll = NULL;
}
G_OBJECT_CLASS (st_scroll_view_parent_class)->dispose (object);
}
static void
st_scroll_view_finalize (GObject *object)
{
G_OBJECT_CLASS (st_scroll_view_parent_class)->finalize (object);
}
static void
st_scroll_view_paint (ClutterActor *actor)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
/* StBin will paint the child */
CLUTTER_ACTOR_CLASS (st_scroll_view_parent_class)->paint (actor);
/* paint our custom children */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
clutter_actor_paint (priv->hscroll);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
clutter_actor_paint (priv->vscroll);
}
static void
st_scroll_view_pick (ClutterActor *actor,
const ClutterColor *color)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
/* Chain up so we get a bounding box pained (if we are reactive) */
CLUTTER_ACTOR_CLASS (st_scroll_view_parent_class)->pick (actor, color);
/* paint our custom children */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
clutter_actor_paint (priv->hscroll);
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
clutter_actor_paint (priv->vscroll);
}
static void
st_scroll_view_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
StPadding padding;
guint xthickness;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
if (!priv->child)
return;
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_stylable_get (ST_STYLABLE (actor),
"scrollbar-width", &xthickness,
NULL);
/* Our natural width is the natural width of the child */
clutter_actor_get_preferred_width (priv->child,
for_height,
NULL,
natural_width_p);
/* Add space for the scroll-bar if we can determine it will be necessary */
if ((for_height >= 0) && natural_width_p)
{
gfloat natural_height;
clutter_actor_get_preferred_height (priv->child, -1.0,
NULL,
&natural_height);
if (for_height < natural_height)
*natural_width_p += xthickness;
}
/* Add space for padding */
if (min_width_p)
*min_width_p = padding.left + padding.right;
if (natural_width_p)
*natural_width_p += padding.left + padding.right;
}
static void
st_scroll_view_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
StPadding padding;
guint ythickness;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
if (!priv->child)
return;
st_widget_get_padding (ST_WIDGET (actor), &padding);
st_stylable_get (ST_STYLABLE (actor),
"scrollbar-height", &ythickness,
NULL);
/* Our natural height is the natural height of the child */
clutter_actor_get_preferred_height (priv->child,
for_width,
NULL,
natural_height_p);
/* Add space for the scroll-bar if we can determine it will be necessary */
if ((for_width >= 0) && natural_height_p)
{
gfloat natural_width;
clutter_actor_get_preferred_width (priv->child, -1.0,
NULL,
&natural_width);
if (for_width < natural_width)
*natural_height_p += ythickness;
}
/* Add space for padding */
if (min_height_p)
*min_height_p = padding.top + padding.bottom;
if (natural_height_p)
*natural_height_p += padding.top + padding.bottom;
}
static void
st_scroll_view_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
StPadding padding;
ClutterActorBox child_box;
ClutterActorClass *parent_parent_class;
gfloat avail_width, avail_height, sb_width, sb_height;
StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv;
/* Chain up to the parent's parent class
*
* We do this because we do not want StBin to allocate the child, as we
* give it a different allocation later, depending on whether the scrollbars
* are visible
*/
parent_parent_class
= g_type_class_peek_parent (st_scroll_view_parent_class);
CLUTTER_ACTOR_CLASS (parent_parent_class)->
allocate (actor, box, flags);
st_widget_get_padding (ST_WIDGET (actor), &padding);
avail_width = (box->x2 - box->x1) - padding.left - padding.right;
avail_height = (box->y2 - box->y1) - padding.top - padding.bottom;
st_stylable_get (ST_STYLABLE (actor),
"scrollbar-width", &sb_width,
"scrollbar-height", &sb_height,
NULL);
sb_width = 28;
sb_height = 28;
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
sb_width = 0;
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
sb_height = 0;
/* Vertical scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
{
child_box.x1 = avail_width - sb_width;
child_box.y1 = padding.top;
child_box.x2 = avail_width;
child_box.y2 = child_box.y1 + avail_height - sb_height;
clutter_actor_allocate (priv->vscroll, &child_box, flags);
}
/* Horizontal scrollbar */
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
{
child_box.x1 = padding.left;
child_box.x2 = child_box.x1 + avail_width - sb_width;
child_box.y1 = avail_height - sb_height;
child_box.y2 = avail_height;
clutter_actor_allocate (priv->hscroll, &child_box, flags);
}
/* Child */
child_box.x1 = padding.left;
child_box.x2 = avail_width - sb_width;
child_box.y1 = padding.top;
child_box.y2 = avail_height - sb_height;
if (priv->child)
clutter_actor_allocate (priv->child, &child_box, flags);
}
static void
st_scroll_view_style_changed (StWidget *widget)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (widget)->priv;
st_stylable_changed ((StStylable *) priv->hscroll);
st_stylable_changed ((StStylable *) priv->vscroll);
}
static gboolean
st_scroll_view_scroll_event (ClutterActor *self,
ClutterScrollEvent *event)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv;
gdouble lower, value, upper, step;
StAdjustment *vadjustment, *hadjustment;
/* don't handle scroll events if requested not to */
if (!priv->mouse_scroll)
return FALSE;
hadjustment = st_scroll_bar_get_adjustment (ST_SCROLL_BAR(priv->hscroll));
vadjustment = st_scroll_bar_get_adjustment (ST_SCROLL_BAR(priv->vscroll));
switch (event->direction)
{
case CLUTTER_SCROLL_UP:
case CLUTTER_SCROLL_DOWN:
if (vadjustment)
g_object_get (vadjustment,
"lower", &lower,
"step-increment", &step,
"value", &value,
"upper", &upper,
NULL);
else
return FALSE;
break;
case CLUTTER_SCROLL_LEFT:
case CLUTTER_SCROLL_RIGHT:
if (vadjustment)
g_object_get (hadjustment,
"lower", &lower,
"step-increment", &step,
"value", &value,
"upper", &upper,
NULL);
else
return FALSE;
break;
}
switch (event->direction)
{
case CLUTTER_SCROLL_UP:
if (value == lower)
return FALSE;
else
st_adjustment_set_value (vadjustment, value - step);
break;
case CLUTTER_SCROLL_DOWN:
if (value == upper)
return FALSE;
else
st_adjustment_set_value (vadjustment, value + step);
break;
case CLUTTER_SCROLL_LEFT:
if (value == lower)
return FALSE;
else
st_adjustment_set_value (hadjustment, value - step);
break;
case CLUTTER_SCROLL_RIGHT:
if (value == upper)
return FALSE;
else
st_adjustment_set_value (hadjustment, value + step);
break;
}
return TRUE;
}
static void
st_scroll_view_class_init (StScrollViewClass *klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
g_type_class_add_private (klass, sizeof (StScrollViewPrivate));
object_class->get_property = st_scroll_view_get_property;
object_class->set_property = st_scroll_view_set_property;
object_class->dispose= st_scroll_view_dispose;
object_class->finalize = st_scroll_view_finalize;
actor_class->paint = st_scroll_view_paint;
actor_class->pick = st_scroll_view_pick;
actor_class->get_preferred_width = st_scroll_view_get_preferred_width;
actor_class->get_preferred_height = st_scroll_view_get_preferred_height;
actor_class->allocate = st_scroll_view_allocate;
actor_class->scroll_event = st_scroll_view_scroll_event;
g_object_class_install_property (object_class,
PROP_HSCROLL,
g_param_spec_object ("hscroll",
"StScrollBar",
"Horizontal scroll indicator",
ST_TYPE_SCROLL_BAR,
G_PARAM_READABLE));
g_object_class_install_property (object_class,
PROP_VSCROLL,
g_param_spec_object ("vscroll",
"StScrollBar",
"Vertical scroll indicator",
ST_TYPE_SCROLL_BAR,
G_PARAM_READABLE));
pspec = g_param_spec_boolean ("enable-mouse-scrolling",
"Enable Mouse Scrolling",
"Enable automatic mouse wheel scrolling",
TRUE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_MOUSE_SCROLL,
pspec);
}
static void
st_stylable_iface_init (StStylableIface *iface)
{
static gboolean is_initialized = FALSE;
if (!is_initialized)
{
GParamSpec *pspec;
is_initialized = TRUE;
pspec = g_param_spec_uint ("scrollbar-width",
"Vertical scroll-bar thickness",
"Thickness of vertical scrollbar, in px",
0, G_MAXUINT, 24,
G_PARAM_READWRITE);
st_stylable_iface_install_property (iface, ST_TYPE_SCROLL_VIEW, pspec);
pspec = g_param_spec_uint ("scrollbar-height",
"Horizontal scroll-bar thickness",
"Thickness of horizontal scrollbar, in px",
0, G_MAXUINT, 24,
G_PARAM_READWRITE);
st_stylable_iface_install_property (iface, ST_TYPE_SCROLL_VIEW, pspec);
}
}
static void
child_adjustment_changed_cb (StAdjustment *adjustment,
ClutterActor *bar)
{
StScrollView *scroll;
gdouble lower, upper, page_size;
scroll = ST_SCROLL_VIEW (clutter_actor_get_parent (bar));
/* Determine if this scroll-bar should be visible */
st_adjustment_get_values (adjustment, NULL,
&lower, &upper,
NULL, NULL,
&page_size);
if ((upper - lower) > page_size)
clutter_actor_show (bar);
else
clutter_actor_hide (bar);
/* Request a resize */
clutter_actor_queue_relayout (CLUTTER_ACTOR (scroll));
}
static void
child_hadjustment_notify_cb (GObject *gobject,
GParamSpec *arg1,
gpointer user_data)
{
StAdjustment *hadjust;
ClutterActor *actor = CLUTTER_ACTOR (gobject);
StScrollViewPrivate *priv = ST_SCROLL_VIEW (user_data)->priv;
hadjust = st_scroll_bar_get_adjustment (ST_SCROLL_BAR(priv->hscroll));
if (hadjust)
g_signal_handlers_disconnect_by_func (hadjust,
child_adjustment_changed_cb,
priv->hscroll);
st_scrollable_get_adjustments (ST_SCROLLABLE (actor), &hadjust, NULL);
if (hadjust)
{
/* Force scroll step if neede. */
if (priv->column_size_set)
{
g_object_set (hadjust,
"step-increment", priv->column_size,
NULL);
}
st_scroll_bar_set_adjustment (ST_SCROLL_BAR(priv->hscroll), hadjust);
g_signal_connect (hadjust, "changed", G_CALLBACK (
child_adjustment_changed_cb), priv->hscroll);
child_adjustment_changed_cb (hadjust, priv->hscroll);
}
}
static void
child_vadjustment_notify_cb (GObject *gobject,
GParamSpec *arg1,
gpointer user_data)
{
StAdjustment *vadjust;
ClutterActor *actor = CLUTTER_ACTOR (gobject);
StScrollViewPrivate *priv = ST_SCROLL_VIEW (user_data)->priv;
vadjust = st_scroll_bar_get_adjustment (ST_SCROLL_BAR(priv->vscroll));
if (vadjust)
g_signal_handlers_disconnect_by_func (vadjust,
child_adjustment_changed_cb,
priv->vscroll);
st_scrollable_get_adjustments (ST_SCROLLABLE(actor), NULL, &vadjust);
if (vadjust)
{
/* Force scroll step if neede. */
if (priv->row_size_set)
{
g_object_set (vadjust,
"step-increment", priv->row_size,
NULL);
}
st_scroll_bar_set_adjustment (ST_SCROLL_BAR(priv->vscroll), vadjust);
g_signal_connect (vadjust, "changed", G_CALLBACK (
child_adjustment_changed_cb), priv->vscroll);
child_adjustment_changed_cb (vadjust, priv->vscroll);
}
}
static void
st_scroll_view_init (StScrollView *self)
{
StScrollViewPrivate *priv = self->priv = SCROLL_VIEW_PRIVATE (self);
priv->hscroll = CLUTTER_ACTOR (st_scroll_bar_new (NULL));
priv->vscroll = g_object_new (ST_TYPE_SCROLL_BAR, "vertical", TRUE, NULL);
clutter_actor_set_parent (priv->hscroll, CLUTTER_ACTOR (self));
clutter_actor_set_parent (priv->vscroll, CLUTTER_ACTOR (self));
/* mouse scroll is enabled by default, so we also need to be reactive */
priv->mouse_scroll = TRUE;
g_object_set (G_OBJECT (self), "reactive", TRUE, "clip-to-allocation", TRUE,
NULL);
g_signal_connect (self, "style-changed",
G_CALLBACK (st_scroll_view_style_changed), NULL);
}
static void
st_scroll_view_add (ClutterContainer *container,
ClutterActor *actor)
{
StScrollView *self = ST_SCROLL_VIEW (container);
StScrollViewPrivate *priv = self->priv;
if (ST_IS_SCROLLABLE (actor))
{
priv->child = actor;
/* chain up to StBin::add() */
st_scroll_view_parent_iface->add (container, actor);
/* Get adjustments for scroll-bars */
g_signal_connect (actor, "notify::hadjustment",
G_CALLBACK (child_hadjustment_notify_cb),
container);
g_signal_connect (actor, "notify::vadjustment",
G_CALLBACK (child_vadjustment_notify_cb),
container);
child_hadjustment_notify_cb (G_OBJECT (actor), NULL, container);
child_vadjustment_notify_cb (G_OBJECT (actor), NULL, container);
}
else
{
g_warning ("Attempting to add an actor of type %s to "
"a StScrollView, but the actor does "
"not implement StScrollable.",
g_type_name (G_OBJECT_TYPE (actor)));
}
}
static void
st_scroll_view_remove (ClutterContainer *container,
ClutterActor *actor)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (container)->priv;
if (actor == priv->child)
{
g_object_ref (priv->child);
/* chain up to StBin::remove() */
st_scroll_view_parent_iface->remove (container, actor);
g_signal_handlers_disconnect_by_func (priv->child,
child_hadjustment_notify_cb,
container);
g_signal_handlers_disconnect_by_func (priv->child,
child_vadjustment_notify_cb,
container);
st_scrollable_set_adjustments ((StScrollable*) priv->child, NULL, NULL);
g_object_unref (priv->child);
priv->child = NULL;
}
}
static void
st_scroll_view_foreach_with_internals (ClutterContainer *container,
ClutterCallback callback,
gpointer user_data)
{
StScrollViewPrivate *priv = ST_SCROLL_VIEW (container)->priv;
if (priv->child != NULL)
callback (priv->child, user_data);
if (priv->hscroll != NULL)
callback (priv->hscroll, user_data);
if (priv->vscroll != NULL)
callback (priv->vscroll, user_data);
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
/* store a pointer to the StBin implementation of
* ClutterContainer so that we can chain up when
* overriding the methods
*/
st_scroll_view_parent_iface = g_type_interface_peek_parent (iface);
iface->add = st_scroll_view_add;
iface->remove = st_scroll_view_remove;
iface->foreach_with_internals = st_scroll_view_foreach_with_internals;
}
StWidget *
st_scroll_view_new (void)
{
return g_object_new (ST_TYPE_SCROLL_VIEW, NULL);
}
ClutterActor *
st_scroll_view_get_hscroll_bar (StScrollView *scroll)
{
g_return_val_if_fail (ST_IS_SCROLL_VIEW (scroll), NULL);
return scroll->priv->hscroll;
}
ClutterActor *
st_scroll_view_get_vscroll_bar (StScrollView *scroll)
{
g_return_val_if_fail (ST_IS_SCROLL_VIEW (scroll), NULL);
return scroll->priv->vscroll;
}
gfloat
st_scroll_view_get_column_size (StScrollView *scroll)
{
StAdjustment *adjustment;
gdouble column_size;
g_return_val_if_fail (scroll, 0);
adjustment = st_scroll_bar_get_adjustment (
ST_SCROLL_BAR (scroll->priv->hscroll));
g_object_get (adjustment,
"step-increment", &column_size,
NULL);
return column_size;
}
void
st_scroll_view_set_column_size (StScrollView *scroll,
gfloat column_size)
{
StAdjustment *adjustment;
g_return_if_fail (scroll);
if (column_size < 0)
{
scroll->priv->column_size_set = FALSE;
scroll->priv->column_size = -1;
}
else
{
scroll->priv->column_size_set = TRUE;
scroll->priv->column_size = column_size;
adjustment = st_scroll_bar_get_adjustment (
ST_SCROLL_BAR (scroll->priv->hscroll));
if (adjustment)
g_object_set (adjustment,
"step-increment", (gdouble) scroll->priv->column_size,
NULL);
}
}
gfloat
st_scroll_view_get_row_size (StScrollView *scroll)
{
StAdjustment *adjustment;
gdouble row_size;
g_return_val_if_fail (scroll, 0);
adjustment = st_scroll_bar_get_adjustment (
ST_SCROLL_BAR (scroll->priv->vscroll));
g_object_get (adjustment,
"step-increment", &row_size,
NULL);
return row_size;
}
void
st_scroll_view_set_row_size (StScrollView *scroll,
gfloat row_size)
{
StAdjustment *adjustment;
g_return_if_fail (scroll);
if (row_size < 0)
{
scroll->priv->row_size_set = FALSE;
scroll->priv->row_size = -1;
}
else
{
scroll->priv->row_size_set = TRUE;
scroll->priv->row_size = row_size;
adjustment = st_scroll_bar_get_adjustment (
ST_SCROLL_BAR (scroll->priv->vscroll));
if (adjustment)
g_object_set (adjustment,
"step-increment", (gdouble) scroll->priv->row_size,
NULL);
}
}
void
st_scroll_view_set_mouse_scrolling (StScrollView *scroll,
gboolean enabled)
{
StScrollViewPrivate *priv;
g_return_if_fail (ST_IS_SCROLL_VIEW (scroll));
priv = ST_SCROLL_VIEW (scroll)->priv;
if (priv->mouse_scroll != enabled)
{
priv->mouse_scroll = enabled;
/* make sure we can receive mouse wheel events */
if (enabled)
clutter_actor_set_reactive ((ClutterActor *) scroll, TRUE);
}
}
gboolean
st_scroll_view_get_mouse_scrolling (StScrollView *scroll)
{
StScrollViewPrivate *priv;
g_return_val_if_fail (ST_IS_SCROLL_VIEW (scroll), FALSE);
priv = ST_SCROLL_VIEW (scroll)->priv;
return priv->mouse_scroll;
}

89
src/st/st-scroll-view.h Normal file
View File

@ -0,0 +1,89 @@
/*
* st-scroll-view.h: Container with scroll-bars
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#ifndef __ST_SCROLL_VIEW_H__
#define __ST_SCROLL_VIEW_H__
#include <st/st-bin.h>
G_BEGIN_DECLS
#define ST_TYPE_SCROLL_VIEW (st_scroll_view_get_type())
#define ST_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLL_VIEW, StScrollView))
#define ST_IS_SCROLL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLL_VIEW))
#define ST_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SCROLL_VIEW, StScrollViewClass))
#define ST_IS_SCROLL_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SCROLL_VIEW))
#define ST_SCROLL_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SCROLL_VIEW, StScrollViewClass))
typedef struct _StScrollView StScrollView;
typedef struct _StScrollViewPrivate StScrollViewPrivate;
typedef struct _StScrollViewClass StScrollViewClass;
/**
* StScrollView:
*
* The contents of this structure are private and should only be accessed
* through the public API.
*/
struct _StScrollView
{
/*< private >*/
StBin parent_instance;
StScrollViewPrivate *priv;
};
struct _StScrollViewClass
{
StBinClass parent_class;
};
GType st_scroll_view_get_type (void) G_GNUC_CONST;
StWidget *st_scroll_view_new (void);
ClutterActor *st_scroll_view_get_hscroll_bar (StScrollView *scroll);
ClutterActor *st_scroll_view_get_vscroll_bar (StScrollView *scroll);
ClutterActor *st_scroll_view_get_child (StScrollView *scroll);
gfloat st_scroll_view_get_column_size (StScrollView *scroll);
void st_scroll_view_set_column_size (StScrollView *scroll,
gfloat column_size);
gfloat st_scroll_view_get_row_size (StScrollView *scroll);
void st_scroll_view_set_row_size (StScrollView *scroll,
gfloat row_size);
void st_scroll_view_set_mouse_scrolling (StScrollView *scroll,
gboolean enabled);
gboolean st_scroll_view_get_mouse_scrolling (StScrollView *scroll);
G_END_DECLS
#endif /* __ST_SCROLL_VIEW_H__ */

88
src/st/st-scrollable.c Normal file
View File

@ -0,0 +1,88 @@
/*
* st-scrollable.c: Scrollable interface
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
#include "st-scrollable.h"
static void
st_scrollable_base_init (gpointer g_iface)
{
static gboolean initialized = FALSE;
if (!initialized)
{
g_object_interface_install_property (g_iface,
g_param_spec_object ("hadjustment",
"StAdjustment",
"Horizontal adjustment",
ST_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
g_object_interface_install_property (g_iface,
g_param_spec_object ("vadjustment",
"StAdjustment",
"Vertical adjustment",
ST_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
initialized = TRUE;
}
}
GType
st_scrollable_get_type (void)
{
static GType type = 0;
if (type == 0)
{
static const GTypeInfo info =
{
sizeof (StScrollableInterface),
st_scrollable_base_init, /* base_init */
NULL,
};
type = g_type_register_static (G_TYPE_INTERFACE,
"StScrollable", &info, 0);
}
return type;
}
void
st_scrollable_set_adjustments (StScrollable *scrollable,
StAdjustment *hadjustment,
StAdjustment *vadjustment)
{
ST_SCROLLABLE_GET_INTERFACE (scrollable)->set_adjustments (scrollable,
hadjustment,
vadjustment);
}
void
st_scrollable_get_adjustments (StScrollable *scrollable,
StAdjustment **hadjustment,
StAdjustment **vadjustment)
{
ST_SCROLLABLE_GET_INTERFACE (scrollable)->get_adjustments (scrollable,
hadjustment,
vadjustment);
}

69
src/st/st-scrollable.h Normal file
View File

@ -0,0 +1,69 @@
/*
* st-scrollable.h: Scrollable interface
*
* Copyright 2008 OpenedHand
* Copyright 2009 Intel Corporation.
*
* 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
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
* Written by: Chris Lord <chris@openedhand.com>
* Port to St by: Robert Staudinger <robsta@openedhand.com>
*
*/
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
#error "Only <st/st.h> can be included directly.h"
#endif
#ifndef __ST_SCROLLABLE_H__
#define __ST_SCROLLABLE_H__
#include <glib-object.h>
#include <st/st-adjustment.h>
G_BEGIN_DECLS
#define ST_TYPE_SCROLLABLE (st_scrollable_get_type ())
#define ST_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLLABLE, StScrollable))
#define ST_IS_SCROLLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLLABLE))
#define ST_SCROLLABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), ST_TYPE_SCROLLABLE, StScrollableInterface))
typedef struct _StScrollable StScrollable; /* Dummy object */
typedef struct _StScrollableInterface StScrollableInterface;
struct _StScrollableInterface
{
GTypeInterface parent;
void (* set_adjustments) (StScrollable *scrollable,
StAdjustment *hadjustment,
StAdjustment *vadjustment);
void (* get_adjustments) (StScrollable *scrollable,
StAdjustment **hadjustment,
StAdjustment **vadjustment);
};
GType st_scrollable_get_type (void) G_GNUC_CONST;
void st_scrollable_set_adjustments (StScrollable *scrollable,
StAdjustment *hadjustment,
StAdjustment *vadjustment);
void st_scrollable_get_adjustments (StScrollable *scrollable,
StAdjustment **hadjustment,
StAdjustment **vadjustment);
G_END_DECLS
#endif /* __ST_SCROLLABLE_H__ */