StScrollView: Implement real fade effect

Implement an edge fade effect (top/bottom) using a
ClutterOffscreenEffect subclass, replacing the former
shadow hack.

https://bugzilla.gnome.org/show_bug.cgi?id=639460
This commit is contained in:
Adel Gadllah 2011-01-20 20:25:21 +01:00
parent df3560143d
commit 00ba937171
10 changed files with 446 additions and 159 deletions

View File

@ -40,7 +40,7 @@ AlphabeticalView.prototype = {
this.actor = new St.ScrollView({ x_fill: true, this.actor = new St.ScrollView({ x_fill: true,
y_fill: false, y_fill: false,
y_align: St.Align.START, y_align: St.Align.START,
vshadows: true }); vfade: true });
this.actor.add_actor(box); this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
}, },

View File

@ -386,7 +386,7 @@ Notification.prototype = {
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview', this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC, vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER, hscrollbar_policy: Gtk.PolicyType.NEVER,
vshadows: true }); vfade: true });
this.actor.add(this._scrollArea, { row: 1, this.actor.add(this._scrollArea, { row: 1,
col: 1 }); col: 1 });
this._contentArea = new St.BoxLayout({ name: 'notification-body', this._contentArea = new St.BoxLayout({ name: 'notification-body',

View File

@ -166,7 +166,7 @@ SearchResults.prototype = {
let scrollView = new St.ScrollView({ x_fill: true, let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false, y_fill: false,
vshadows: true }); vfade: true });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content); scrollView.add_actor(this._content);

View File

@ -159,11 +159,17 @@ st_source_c = \
st/st-widget.c \ st/st-widget.c \
$(NULL) $(NULL)
st_non_gir_sources = \
st/st-scroll-view-fade.c \
st/st-scroll-view-fade.h \
$(NULL)
noinst_LTLIBRARIES += libst-1.0.la noinst_LTLIBRARIES += libst-1.0.la
libst_1_0_la_LIBADD = -lm $(ST_LIBS) libst_1_0_la_LIBADD = -lm $(ST_LIBS)
libst_1_0_la_SOURCES = \ libst_1_0_la_SOURCES = \
$(st_source_c) \ $(st_source_c) \
$(st_non_gir_sources) \
$(st_source_private_h) \ $(st_source_private_h) \
$(st_source_private_c) \ $(st_source_private_c) \
$(st_source_h) \ $(st_source_h) \

View File

@ -262,7 +262,7 @@ St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
--libtool="$(LIBTOOL)" \ --libtool="$(LIBTOOL)" \
--library=libst-1.0.la \ --library=libst-1.0.la \
-DST_COMPILATION \ -DST_COMPILATION \
$(filter-out %-private.h, $(addprefix $(srcdir)/,$(st_source_h))) \ $(filter-out %-private.h $(st_non_gir_sources), $(addprefix $(srcdir)/,$(st_source_h))) \
$(addprefix $(srcdir)/,$(st_source_c)) \ $(addprefix $(srcdir)/,$(st_source_c)) \
$(srcdir)/st-enum-types.h \ $(srcdir)/st-enum-types.h \
$(st_cflags) \ $(st_cflags) \

View File

@ -0,0 +1,348 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-scroll-view-fade.h: Edge fade effect for StScrollView
*
* Copyright 2010 Intel Corporation.
* Copyright 2011 Adel Gadllah
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#define ST_SCROLL_VIEW_FADE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
#define ST_IS_SCROLL_VIEW_FADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SCROLL_VIEW_FADE))
#define ST_SCROLL_VIEW_FADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
#include "st-scroll-view-fade.h"
#include "st-scroll-view.h"
#include "st-scroll-bar.h"
#include "st-scrollable.h"
#include <clutter/clutter.h>
#include <cogl/cogl.h>
typedef struct _StScrollViewFadeClass StScrollViewFadeClass;
#define FADE_OFFSET 68.0f
static const gchar *fade_glsl_shader =
"uniform sampler2D tex;\n"
"uniform float height;\n"
"uniform float width;\n"
"uniform float scrollbar_width;\n"
"uniform float offset_bottom;\n"
"uniform float offset_top;\n"
"\n"
"void main ()\n"
"{\n"
" vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
" float y = height * cogl_tex_coord_in[0].y;\n"
" float x = width * cogl_tex_coord_in[0].x;\n"
" float ratio = 0.0;\n"
" float fade_bottom_start = height - offset_bottom;\n"
" \n"
" if (offset_top != 0.0 && y < offset_top && x < (width - scrollbar_width)) {\n"
" ratio = y / offset_top;\n"
" cogl_color_out = color * ratio;\n"
" }\n"
" else if (offset_bottom != 0.0 && y > fade_bottom_start && x < (width - scrollbar_width)) {\n"
" ratio = (height - y)/(height - fade_bottom_start);\n"
" cogl_color_out = color * ratio;\n"
" }\n"
" else { \n"
" cogl_color_out = color;\n"
" }\n"
"}\n";
struct _StScrollViewFade
{
ClutterOffscreenEffect parent_instance;
/* a back pointer to our actor, so that we can query it */
ClutterActor *actor;
CoglHandle shader;
CoglHandle program;
gint tex_uniform;
gint height_uniform;
gint width_uniform;
gint scrollbar_width_uniform;
gint offset_top_uniform;
gint offset_bottom_uniform;
StAdjustment *vadjustment;
guint is_attached : 1;
};
struct _StScrollViewFadeClass
{
ClutterOffscreenEffectClass parent_class;
};
G_DEFINE_TYPE (StScrollViewFade,
st_scroll_view_fade,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static gboolean
st_scroll_view_fade_pre_paint (ClutterEffect *effect)
{
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
ClutterEffectClass *parent_class;
if (self->shader == COGL_INVALID_HANDLE)
return FALSE;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (self->actor == NULL)
return FALSE;
if (self->program == COGL_INVALID_HANDLE)
self->program = cogl_create_program ();
if (!self->is_attached)
{
g_assert (self->shader != COGL_INVALID_HANDLE);
g_assert (self->program != COGL_INVALID_HANDLE);
cogl_program_attach_shader (self->program, self->shader);
cogl_program_link (self->program);
cogl_handle_unref (self->shader);
self->is_attached = TRUE;
self->tex_uniform =
cogl_program_get_uniform_location (self->program, "tex");
self->height_uniform =
cogl_program_get_uniform_location (self->program, "height");
self->width_uniform =
cogl_program_get_uniform_location (self->program, "width");
self->scrollbar_width_uniform =
cogl_program_get_uniform_location (self->program, "scrollbar_width");
self->offset_top_uniform =
cogl_program_get_uniform_location (self->program, "offset_top");
self->offset_bottom_uniform =
cogl_program_get_uniform_location (self->program, "offset_bottom");
}
parent_class = CLUTTER_EFFECT_CLASS (st_scroll_view_fade_parent_class);
return parent_class->pre_paint (effect);
}
static CoglHandle
st_scroll_view_fade_create_texture (ClutterOffscreenEffect *effect,
gfloat min_width,
gfloat min_height)
{
return cogl_texture_new_with_size (min_width,
min_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
}
static void
st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
{
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
ClutterOffscreenEffectClass *parent;
CoglHandle material;
gdouble value, lower, upper, page_size;
ClutterActor *vscroll = st_scroll_view_get_vscroll_bar (ST_SCROLL_VIEW (self->actor));
if (self->program == COGL_INVALID_HANDLE)
goto out;
st_adjustment_get_values (self->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
if (self->offset_top_uniform > -1) {
if (value > lower + 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, FADE_OFFSET);
else
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, 0.0f);
}
if (self->offset_bottom_uniform > -1) {
if (value < upper - page_size - 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, FADE_OFFSET);
else
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, 0.0f);
}
if (self->tex_uniform > -1)
cogl_program_set_uniform_1i (self->program, self->tex_uniform, 0);
if (self->height_uniform > -1)
cogl_program_set_uniform_1f (self->program, self->height_uniform, clutter_actor_get_height (self->actor));
if (self->width_uniform > -1)
cogl_program_set_uniform_1f (self->program, self->width_uniform, clutter_actor_get_width (self->actor));
if (self->scrollbar_width_uniform > -1)
cogl_program_set_uniform_1f (self->program, self->scrollbar_width_uniform, clutter_actor_get_width (vscroll));
material = clutter_offscreen_effect_get_target (effect);
cogl_material_set_user_program (material, self->program);
out:
parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (st_scroll_view_fade_parent_class);
parent->paint_target (effect);
}
static void
on_vadjustment_changed (StAdjustment *adjustment,
ClutterEffect *effect)
{
gdouble value, lower, upper, page_size;
gboolean needs_fade;
st_adjustment_get_values (adjustment, &value, &lower, &upper, NULL, NULL, &page_size);
needs_fade = (value > lower + 0.1) || (value < upper - page_size - 0.1);
clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), needs_fade);
}
static void
st_scroll_view_fade_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (meta);
ClutterActorMetaClass *parent;
g_return_if_fail (actor == NULL || ST_IS_SCROLL_VIEW (actor));
if (self->shader == COGL_INVALID_HANDLE)
{
clutter_actor_meta_set_enabled (meta, FALSE);
return;
}
if (self->vadjustment)
{
g_signal_handlers_disconnect_by_func (self->vadjustment,
(gpointer)on_vadjustment_changed,
self);
self->vadjustment = NULL;
}
if (actor)
{
StScrollView *scroll_view = ST_SCROLL_VIEW (actor);
StScrollBar *vscroll = ST_SCROLL_BAR (st_scroll_view_get_vscroll_bar (scroll_view));
self->vadjustment = ST_ADJUSTMENT (st_scroll_bar_get_adjustment (vscroll));
g_signal_connect (self->vadjustment, "changed",
G_CALLBACK (on_vadjustment_changed),
self);
on_vadjustment_changed (self->vadjustment, CLUTTER_EFFECT (self));
}
parent = CLUTTER_ACTOR_META_CLASS (st_scroll_view_fade_parent_class);
parent->set_actor (meta, actor);
/* we keep a back pointer here, to avoid going through the ActorMeta */
self->actor = clutter_actor_meta_get_actor (meta);
}
static void
st_scroll_view_fade_dispose (GObject *gobject)
{
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (gobject);
if (self->program != COGL_INVALID_HANDLE)
{
cogl_handle_unref (self->program);
self->program = COGL_INVALID_HANDLE;
self->shader = COGL_INVALID_HANDLE;
}
if (self->vadjustment)
{
g_signal_handlers_disconnect_by_func (self->vadjustment,
(gpointer)on_vadjustment_changed,
self);
self->vadjustment = NULL;
}
self->actor = NULL;
G_OBJECT_CLASS (st_scroll_view_fade_parent_class)->dispose (gobject);
}
static void
st_scroll_view_fade_class_init (StScrollViewFadeClass *klass)
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterOffscreenEffectClass *offscreen_class;
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
gobject_class->dispose = st_scroll_view_fade_dispose;
meta_class->set_actor = st_scroll_view_fade_set_actor;
effect_class->pre_paint = st_scroll_view_fade_pre_paint;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_texture = st_scroll_view_fade_create_texture;
offscreen_class->paint_target = st_scroll_view_fade_paint_target;
}
static void
st_scroll_view_fade_init (StScrollViewFade *self)
{
static CoglHandle shader = COGL_INVALID_HANDLE;
if (shader == COGL_INVALID_HANDLE)
{
if (clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
cogl_shader_source (shader, fade_glsl_shader);
cogl_shader_compile (shader);
if (!cogl_shader_is_compiled (shader))
{
gchar *log_buf = cogl_shader_get_info_log (shader);
g_warning (G_STRLOC ": Unable to compile the fade shader: %s",
log_buf);
g_free (log_buf);
cogl_handle_unref (shader);
shader = COGL_INVALID_HANDLE;
}
}
}
self->shader = shader;
self->is_attached = FALSE;
self->tex_uniform = -1;
self->height_uniform = -1;
self->width_uniform = -1;
self->scrollbar_width_uniform = -1;
self->offset_top_uniform = -1;
self->offset_bottom_uniform = -1;
if (shader != COGL_INVALID_HANDLE)
cogl_handle_ref (self->shader);
}
ClutterEffect *
st_scroll_view_fade_new (void)
{
return g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
}

View File

@ -0,0 +1,40 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-scroll-view-fade.h: Edge fade effect for StScrollView
*
* Copyright 2010 Intel Corporation.
* Copyright 2011 Adel Gadllah
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ST_SCROLL_VIEW_FADE_H__
#define __ST_SCROLL_VIEW_FADE_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define ST_TYPE_SCROLL_VIEW_FADE (st_scroll_view_fade_get_type ())
#define ST_SCROLL_VIEW_FADE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFade))
#define ST_IS_SCROLL_VIEW_FADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLL_VIEW_FADE))
typedef struct _StScrollViewFade StScrollViewFade;
GType st_scroll_view_fade_get_type (void) G_GNUC_CONST;
ClutterEffect *st_scroll_view_fade_new (void);
G_END_DECLS
#endif /* __ST_SCROLL_VIEW_FADE_H__ */

View File

@ -62,6 +62,7 @@
#include "st-marshal.h" #include "st-marshal.h"
#include "st-scroll-bar.h" #include "st-scroll-bar.h"
#include "st-scrollable.h" #include "st-scrollable.h"
#include "st-scroll-view-fade.h"
#include <clutter/clutter.h> #include <clutter/clutter.h>
#include <math.h> #include <math.h>
@ -93,20 +94,17 @@ struct _StScrollViewPrivate
GtkPolicyType hscrollbar_policy; GtkPolicyType hscrollbar_policy;
GtkPolicyType vscrollbar_policy; GtkPolicyType vscrollbar_policy;
ClutterActor *top_shadow;
ClutterActor *bottom_shadow;
gfloat row_size; gfloat row_size;
gfloat column_size; gfloat column_size;
gboolean vshadows; gboolean vfade;
StScrollViewFade *vfade_effect;
gboolean row_size_set : 1; gboolean row_size_set : 1;
gboolean column_size_set : 1; gboolean column_size_set : 1;
guint mouse_scroll : 1; guint mouse_scroll : 1;
guint hscrollbar_visible : 1; guint hscrollbar_visible : 1;
guint vscrollbar_visible : 1; guint vscrollbar_visible : 1;
guint top_shadow_visible : 1;
guint bottom_shadow_visible : 1;
}; };
enum { enum {
@ -117,7 +115,7 @@ enum {
PROP_HSCROLLBAR_POLICY, PROP_HSCROLLBAR_POLICY,
PROP_VSCROLLBAR_POLICY, PROP_VSCROLLBAR_POLICY,
PROP_MOUSE_SCROLL, PROP_MOUSE_SCROLL,
PROP_VSHADOWS PROP_VFADE
}; };
static void static void
@ -145,80 +143,50 @@ st_scroll_view_get_property (GObject *object,
case PROP_MOUSE_SCROLL: case PROP_MOUSE_SCROLL:
g_value_set_boolean (value, priv->mouse_scroll); g_value_set_boolean (value, priv->mouse_scroll);
break; break;
case PROP_VSHADOWS: case PROP_VFADE:
g_value_set_boolean (value, priv->vshadows); g_value_set_boolean (value, priv->vfade);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
} }
} }
static void
update_shadow_visibility (StScrollView *scroll)
{
StScrollViewPrivate *priv = scroll->priv;
if (priv->vshadows)
{
gdouble value, lower, upper, page_size;
st_adjustment_get_values (priv->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
priv->top_shadow_visible = value > lower + 0.1;
priv->bottom_shadow_visible = value < upper - page_size - 0.1;
}
else
{
priv->top_shadow_visible = FALSE;
priv->bottom_shadow_visible = FALSE;
}
}
/** /**
* st_scroll_view_set_vshadows: * st_scroll_view_set_vfade:
* @self: a #StScrollView * @self: a #StScrollView
* @vshadows: Whether to enable vertical shadows * @vfade: Whether to enable the vertical fade effect
* *
* Sets whether to show shadows at the top and bottom of the area. Shadows * Sets whether to fade the content at the top and bottom of the area when not
* are omitted when fully scrolled to that edge. * fully scrolled to that edge.
*/ */
void void
st_scroll_view_set_vshadows (StScrollView *self, st_scroll_view_set_vfade (StScrollView *self,
gboolean vshadows) gboolean vfade)
{ {
StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv; StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv;
vshadows = vshadows != FALSE; vfade = vfade != FALSE;
if (priv->vshadows == vshadows) if (priv->vfade == vfade)
return; return;
priv->vshadows = vshadows; priv->vfade = vfade;
if (vshadows) if (vfade)
{ {
if (priv->top_shadow) if (priv->vfade_effect == NULL)
{ priv->vfade_effect = g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
clutter_actor_show (priv->top_shadow);
clutter_actor_show (priv->bottom_shadow); clutter_actor_add_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
} }
else else
{ {
priv->top_shadow = g_object_new (ST_TYPE_BIN, "style-class", "top-shadow", NULL); clutter_actor_remove_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
priv->bottom_shadow = g_object_new (ST_TYPE_BIN, "style-class", "bottom-shadow", NULL); priv->vfade_effect = NULL;
clutter_actor_set_parent (priv->bottom_shadow, CLUTTER_ACTOR (self));
clutter_actor_set_parent (priv->top_shadow, CLUTTER_ACTOR (self));
}
}
else
{
clutter_actor_hide (priv->top_shadow);
clutter_actor_hide (priv->bottom_shadow);
} }
update_shadow_visibility (self); clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "vshadows"); g_object_notify (G_OBJECT (self), "vfade");
} }
static void static void
@ -232,8 +200,8 @@ st_scroll_view_set_property (GObject *object,
switch (property_id) switch (property_id)
{ {
case PROP_VSHADOWS: case PROP_VFADE:
st_scroll_view_set_vshadows (self, g_value_get_boolean (value)); st_scroll_view_set_vfade (self, g_value_get_boolean (value));
break; break;
case PROP_MOUSE_SCROLL: case PROP_MOUSE_SCROLL:
st_scroll_view_set_mouse_scrolling (self, st_scroll_view_set_mouse_scrolling (self,
@ -259,6 +227,12 @@ st_scroll_view_dispose (GObject *object)
{ {
StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv; StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv;
if (priv->vfade_effect)
{
clutter_actor_remove_effect (CLUTTER_ACTOR (object), CLUTTER_EFFECT (priv->vfade_effect));
priv->vfade_effect = NULL;
}
if (priv->vscroll) if (priv->vscroll)
clutter_actor_destroy (priv->vscroll); clutter_actor_destroy (priv->vscroll);
@ -284,20 +258,6 @@ st_scroll_view_dispose (GObject *object)
priv->vadjustment = NULL; priv->vadjustment = NULL;
} }
/* since it's impossible to get a handle to these actors, we can
* just directly unparent them and not go through destroy/remove */
if (priv->top_shadow)
{
clutter_actor_unparent (priv->top_shadow);
priv->top_shadow = NULL;
}
if (priv->bottom_shadow)
{
clutter_actor_unparent (priv->bottom_shadow);
priv->bottom_shadow = NULL;
}
G_OBJECT_CLASS (st_scroll_view_parent_class)->dispose (object); G_OBJECT_CLASS (st_scroll_view_parent_class)->dispose (object);
} }
@ -314,11 +274,6 @@ st_scroll_view_paint (ClutterActor *actor)
clutter_actor_paint (priv->hscroll); clutter_actor_paint (priv->hscroll);
if (priv->vscrollbar_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll)) if (priv->vscrollbar_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
clutter_actor_paint (priv->vscroll); clutter_actor_paint (priv->vscroll);
if (priv->top_shadow_visible)
clutter_actor_paint (priv->top_shadow);
if (priv->bottom_shadow_visible)
clutter_actor_paint (priv->bottom_shadow);
} }
static void static void
@ -532,18 +487,6 @@ st_scroll_view_get_preferred_height (ClutterActor *actor,
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p); st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
} }
static gfloat
get_shadow_height (ClutterActor *shadow)
{
gfloat natural_height;
/* The shadows are empty StBin and have no height-for-width behavior */
clutter_actor_get_preferred_height (shadow, -1, NULL, &natural_height);
return natural_height;
}
static void static void
st_scroll_view_allocate (ClutterActor *actor, st_scroll_view_allocate (ClutterActor *actor,
const ClutterActorBox *box, const ClutterActorBox *box,
@ -688,25 +631,6 @@ st_scroll_view_allocate (ClutterActor *actor,
if (priv->child) if (priv->child)
clutter_actor_allocate (priv->child, &child_box, flags); clutter_actor_allocate (priv->child, &child_box, flags);
/* Shadows */
if (priv->top_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->top_shadow))
{
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y1;
child_box.x2 = MAX (child_box.x1, content_box.x2 - sb_width);
child_box.y2 = content_box.y1 + get_shadow_height (priv->top_shadow);
clutter_actor_allocate (priv->top_shadow, &child_box, flags);
}
if (priv->bottom_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow))
{
child_box.x1 = content_box.x1;
child_box.y1 = content_box.y2 - sb_height - get_shadow_height (priv->bottom_shadow);
child_box.x2 = MAX (content_box.x1, content_box.x2 - sb_width);
child_box.y2 = content_box.y2 - sb_height;
clutter_actor_allocate (priv->bottom_shadow, &child_box, flags);
}
priv->hscrollbar_visible = hscrollbar_visible; priv->hscrollbar_visible = hscrollbar_visible;
priv->vscrollbar_visible = vscrollbar_visible; priv->vscrollbar_visible = vscrollbar_visible;
} }
@ -719,12 +643,6 @@ st_scroll_view_style_changed (StWidget *widget)
st_widget_style_changed (ST_WIDGET (priv->hscroll)); st_widget_style_changed (ST_WIDGET (priv->hscroll));
st_widget_style_changed (ST_WIDGET (priv->vscroll)); st_widget_style_changed (ST_WIDGET (priv->vscroll));
if (priv->top_shadow)
{
st_widget_style_changed (ST_WIDGET (priv->top_shadow));
st_widget_style_changed (ST_WIDGET (priv->bottom_shadow));
}
ST_WIDGET_CLASS (st_scroll_view_parent_class)->style_changed (widget); ST_WIDGET_CLASS (st_scroll_view_parent_class)->style_changed (widget);
} }
@ -857,31 +775,16 @@ st_scroll_view_class_init (StScrollViewClass *klass)
PROP_MOUSE_SCROLL, PROP_MOUSE_SCROLL,
pspec); pspec);
pspec = g_param_spec_boolean ("vshadows", pspec = g_param_spec_boolean ("vfade",
"Vertical Shadows", "Vertical Shadows",
"Show shadows at the top and and bottom of the area unless fully scrolled to that edge", "Fade the content at the top and and bottom of the area unless fully scrolled to that edge",
FALSE, FALSE,
G_PARAM_READWRITE); G_PARAM_READWRITE);
g_object_class_install_property (object_class, g_object_class_install_property (object_class,
PROP_VSHADOWS, PROP_VFADE,
pspec); pspec);
} }
static void
child_adjustment_changed_cb (StAdjustment *adjustment,
StScrollView *scroll)
{
update_shadow_visibility (scroll);
}
static void
child_adjustment_notify_value (GObject *gobject,
GParamSpec *pspec,
StScrollView *scroll)
{
update_shadow_visibility (scroll);
}
static void static void
st_scroll_view_init (StScrollView *self) st_scroll_view_init (StScrollView *self)
{ {
@ -897,10 +800,6 @@ st_scroll_view_init (StScrollView *self)
NULL); NULL);
priv->vadjustment = g_object_new (ST_TYPE_ADJUSTMENT, NULL); priv->vadjustment = g_object_new (ST_TYPE_ADJUSTMENT, NULL);
g_signal_connect (priv->vadjustment, "changed",
G_CALLBACK (child_adjustment_changed_cb), self);
g_signal_connect (priv->vadjustment, "notify::value",
G_CALLBACK (child_adjustment_notify_value), self);
priv->vscroll = g_object_new (ST_TYPE_SCROLL_BAR, priv->vscroll = g_object_new (ST_TYPE_SCROLL_BAR,
"adjustment", priv->vadjustment, "adjustment", priv->vadjustment,
"vertical", TRUE, "vertical", TRUE,
@ -988,12 +887,6 @@ st_scroll_view_foreach_with_internals (ClutterContainer *container,
if (priv->vscroll != NULL) if (priv->vscroll != NULL)
callback (priv->vscroll, user_data); callback (priv->vscroll, user_data);
if (priv->top_shadow)
{
callback (priv->top_shadow, user_data);
callback (priv->bottom_shadow, user_data);
}
} }
static void static void

View File

@ -84,8 +84,8 @@ void st_scroll_view_set_policy (StScrollView *scroll,
GtkPolicyType hscroll, GtkPolicyType hscroll,
GtkPolicyType vscroll); GtkPolicyType vscroll);
void st_scroll_view_set_vshadows (StScrollView *self, void st_scroll_view_set_vfade (StScrollView *self,
gboolean vshadows); gboolean vfade);
G_END_DECLS G_END_DECLS

View File

@ -319,17 +319,17 @@ function togglePolicy(button) {
hpolicy.connect('clicked', function() { togglePolicy(hpolicy); }); hpolicy.connect('clicked', function() { togglePolicy(hpolicy); });
vpolicy.connect('clicked', function() { togglePolicy(vpolicy); }); vpolicy.connect('clicked', function() { togglePolicy(vpolicy); });
let shadowsBox = new St.BoxLayout({ vertical: false }); let fadeBox = new St.BoxLayout({ vertical: false });
mainBox.add(shadowsBox); mainBox.add(fadeBox);
spacer = new St.Bin(); spacer = new St.Bin();
shadowsBox.add(spacer, { expand: true }); fadeBox.add(spacer, { expand: true });
shadowsBox.add(new St.Label({ text: 'Vertical Shadows: '})); fadeBox.add(new St.Label({ text: 'Vertical Fade: '}));
let vshadows = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' }); let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
shadowsBox.add(vshadows); fadeBox.add(vfade);
function toggleShadows(button) { function toggleFade(button) {
switch(button.label) { switch(button.label) {
case 'No': case 'No':
button.label = 'Yes'; button.label = 'Yes';
@ -338,10 +338,10 @@ function toggleShadows(button) {
button.label = 'No'; button.label = 'No';
break; break;
} }
scrollView.set_vshadows(vshadows.label == 'Yes'); scrollView.set_vfade(vfade.label == 'Yes');
} }
vshadows.connect('clicked', function() { toggleShadows(vshadows); }); vfade.connect('clicked', function() { toggleFade(vfade); });
stage.show(); stage.show();
Clutter.main(); Clutter.main();