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:
parent
df3560143d
commit
00ba937171
@ -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);
|
||||||
},
|
},
|
||||||
|
@ -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',
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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) \
|
||||||
|
@ -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) \
|
||||||
|
348
src/st/st-scroll-view-fade.c
Normal file
348
src/st/st-scroll-view-fade.c
Normal 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);
|
||||||
|
}
|
40
src/st/st-scroll-view-fade.h
Normal file
40
src/st/st-scroll-view-fade.h
Normal 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__ */
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user