From fc39919856363fbaffe8957ddfc203d208b4e78e Mon Sep 17 00:00:00 2001 From: Maxim Ermilov Date: Tue, 23 Feb 2010 01:07:42 +0300 Subject: [PATCH] Add top and bottom shadows to app browser Add a 'vshadow' property to StScrollView, which, when turned on, overlays gradient shadows on the top and bottom of the StScrollView. Turn this on for the StScrollView used for the app browser. https://bugzilla.gnome.org/show_bug.cgi?id=609604 --- data/theme/gnome-shell.css | 16 +++++ js/ui/appDisplay.js | 5 +- src/st/st-scroll-view.c | 140 +++++++++++++++++++++++++++++++++++-- src/st/st-scroll-view.h | 3 + 4 files changed, 157 insertions(+), 7 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index c8cd4191a..f5ab8a41a 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -41,6 +41,22 @@ StScrollView scrollbar-height: 16px; } +StScrollView > .top-shadow +{ + background-gradient-direction: vertical; + background-gradient-start: rgba(0, 0, 0, 255); + background-gradient-end: rgba(0, 0, 0, 0); + height: 30px; +} + +StScrollView > .bottom-shadow +{ + background-gradient-direction: vertical; + background-gradient-start: rgba(0, 0, 0, 0); + background-gradient-end: rgba(0, 0, 0, 255); + height: 30px; +} + StScrollBar { background-color: #080808; border: 1px solid #2d2d2d; diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index f8fea7a2d..fd9445eb5 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -91,7 +91,10 @@ AllAppDisplay.prototype = { this.actor = new St.BoxLayout({ style_class: 'all-app', vertical: true }); this.actor.hide(); - let view = new St.ScrollView({ x_fill: true, y_fill: false, style_class: 'all-app-scroll-view' }); + let view = new St.ScrollView({ x_fill: true, + y_fill: false, + style_class: 'all-app-scroll-view', + vshadows: true }); this._scrollView = view; this.actor.add(bin); this.actor.add(view, { expand: true, y_fill: false, y_align: St.Align.START }); diff --git a/src/st/st-scroll-view.c b/src/st/st-scroll-view.c index bf463476c..7fef4a023 100644 --- a/src/st/st-scroll-view.c +++ b/src/st/st-scroll-view.c @@ -37,6 +37,7 @@ #include "st-scroll-bar.h" #include "st-scrollable.h" #include +#include static void clutter_container_iface_init (ClutterContainerIface *iface); @@ -67,9 +68,13 @@ struct _StScrollViewPrivate GtkPolicyType hscroll_policy; GtkPolicyType vscroll_policy; + ClutterActor *top_shadow; + ClutterActor *bottom_shadow; + gfloat row_size; gfloat column_size; + gboolean vshadows; gboolean row_size_set : 1; gboolean column_size_set : 1; guint mouse_scroll : 1; @@ -82,7 +87,8 @@ enum { PROP_VSCROLL, PROP_HSCROLLBAR_POLICY, PROP_VSCROLLBAR_POLICY, - PROP_MOUSE_SCROLL + PROP_MOUSE_SCROLL, + PROP_VSHADOWS }; static void @@ -110,11 +116,67 @@ st_scroll_view_get_property (GObject *object, case PROP_MOUSE_SCROLL: g_value_set_boolean (value, priv->mouse_scroll); break; + case PROP_VSHADOWS: + g_value_set_boolean (value, priv->vshadows); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } } +static void +update_shadow_visibility (GObject *gobject, + GParamSpec *arg1, + gpointer user_data) +{ + StAdjustment *vadjust = ST_ADJUSTMENT (gobject); + StScrollViewPrivate *priv = ST_SCROLL_VIEW (user_data)->priv; + + gdouble value, lower, upper, page_size; + + st_adjustment_get_values (vadjust, &value, &lower, &upper, NULL, NULL, &page_size); + + if (fabs (value - lower) > 0.1 && priv->vshadows) + clutter_actor_show (priv->top_shadow); + else + clutter_actor_hide (priv->top_shadow); + + if (fabs (upper - value - page_size) > 0.1 && priv->vshadows) + clutter_actor_show (priv->bottom_shadow); + else + clutter_actor_hide (priv->bottom_shadow); +} + +/** + * st_scroll_view_set_vshadows: + * @self: a #StScrollView + * @vshadows: Whether to enable vertical shadows + * + * Sets whether to show shadows at the top and bottom of the area. Shadows + * are omitted when fully scrolled to that edge. + */ +void +st_scroll_view_set_vshadows (StScrollView *self, + gboolean vshadows) +{ + StAdjustment *vadjust; + StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv; + + vshadows = vshadows != FALSE; + if (priv->vshadows == vshadows) + return; + + priv->vshadows = vshadows; + + vadjust = st_scroll_bar_get_adjustment (ST_SCROLL_BAR(priv->vscroll)); + + if (!vadjust) + return; + + update_shadow_visibility (G_OBJECT (vadjust), NULL, self); + g_object_notify (G_OBJECT (self), "vshadows"); +} + static void st_scroll_view_set_property (GObject *object, guint property_id, @@ -126,6 +188,9 @@ st_scroll_view_set_property (GObject *object, switch (property_id) { + case PROP_VSHADOWS: + st_scroll_view_set_vshadows (self, g_value_get_boolean (value)); + break; case PROP_MOUSE_SCROLL: st_scroll_view_set_mouse_scrolling (self, g_value_get_boolean (value)); @@ -170,6 +235,11 @@ st_scroll_view_dispose (GObject *object) static void st_scroll_view_finalize (GObject *object) { + StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv; + + g_object_unref (priv->top_shadow); + g_object_unref (priv->bottom_shadow); + G_OBJECT_CLASS (st_scroll_view_parent_class)->finalize (object); } @@ -186,6 +256,11 @@ st_scroll_view_paint (ClutterActor *actor) clutter_actor_paint (priv->hscroll); if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll)) clutter_actor_paint (priv->vscroll); + + if (CLUTTER_ACTOR_IS_VISIBLE (priv->top_shadow)) + clutter_actor_paint (priv->top_shadow); + if (CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow)) + clutter_actor_paint (priv->bottom_shadow); } static void @@ -202,6 +277,11 @@ st_scroll_view_pick (ClutterActor *actor, clutter_actor_paint (priv->hscroll); if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll)) clutter_actor_paint (priv->vscroll); + + if (CLUTTER_ACTOR_IS_VISIBLE (priv->top_shadow)) + clutter_actor_paint (priv->top_shadow); + if (CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow)) + clutter_actor_paint (priv->bottom_shadow); } static double @@ -372,6 +452,25 @@ st_scroll_view_allocate (ClutterActor *actor, if (priv->child) clutter_actor_allocate (priv->child, &child_box, flags); + + /*Shadows*/ + if (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 = MAX (child_box.y1, content_box.y1 + clutter_actor_get_height (priv->top_shadow)); + clutter_actor_allocate (priv->top_shadow, &child_box, flags); + } + + if (CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow)) + { + child_box.x1 = content_box.x1; + child_box.y1 = content_box.y2 - clutter_actor_get_height (priv->bottom_shadow); + child_box.x2 = MAX (child_box.x1, content_box.x2 - sb_width); + child_box.y2 = content_box.y2 + 1; + clutter_actor_allocate (priv->bottom_shadow, &child_box, flags); + } } static void @@ -382,6 +481,9 @@ st_scroll_view_style_changed (StWidget *widget) st_widget_style_changed (ST_WIDGET (priv->hscroll)); st_widget_style_changed (ST_WIDGET (priv->vscroll)); + 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); } @@ -525,6 +627,14 @@ st_scroll_view_class_init (StScrollViewClass *klass) PROP_MOUSE_SCROLL, pspec); + pspec = g_param_spec_boolean ("vshadows", + "Vertical Shadows", + "Show shadows at the top and and bottom of the area unless fully scrolled to that edge", + FALSE, + G_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_VSHADOWS, + pspec); } static void @@ -536,6 +646,9 @@ child_adjustment_changed_cb (StAdjustment *adjustment, scroll = ST_SCROLL_VIEW (clutter_actor_get_parent (bar)); + if (bar == scroll->priv->vscroll) + update_shadow_visibility (G_OBJECT (adjustment), NULL, scroll); + /* Determine if this scroll-bar should be visible */ st_adjustment_get_values (adjustment, NULL, &lower, &upper, @@ -604,13 +717,16 @@ child_vadjustment_notify_cb (GObject *gobject, 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); - + { + g_signal_handlers_disconnect_by_func (vadjust, + update_shadow_visibility, + user_data); + g_signal_handlers_disconnect_by_func (vadjust, + child_adjustment_changed_cb, + priv->vscroll); + } if (priv->vscroll_policy == GTK_POLICY_NEVER) return; - st_scrollable_get_adjustments (ST_SCROLLABLE(actor), NULL, &vadjust); if (vadjust) { @@ -627,7 +743,10 @@ child_vadjustment_notify_cb (GObject *gobject, { g_signal_connect (vadjust, "changed", G_CALLBACK ( child_adjustment_changed_cb), priv->vscroll); + g_signal_connect (vadjust, "notify::value", G_CALLBACK ( + update_shadow_visibility), user_data); child_adjustment_changed_cb (vadjust, priv->vscroll); + update_shadow_visibility (G_OBJECT (vadjust), NULL, user_data); } } } @@ -646,6 +765,12 @@ st_scroll_view_init (StScrollView *self) clutter_actor_set_parent (priv->hscroll, CLUTTER_ACTOR (self)); clutter_actor_set_parent (priv->vscroll, CLUTTER_ACTOR (self)); + priv->top_shadow = g_object_new (ST_TYPE_BIN, "style-class", "top-shadow", NULL); + priv->bottom_shadow = g_object_new (ST_TYPE_BIN, "style-class", "bottom-shadow", NULL); + + clutter_actor_set_parent (priv->bottom_shadow, CLUTTER_ACTOR (self)); + clutter_actor_set_parent (priv->top_shadow, 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, NULL); @@ -725,6 +850,9 @@ st_scroll_view_foreach_with_internals (ClutterContainer *container, if (priv->vscroll != NULL) callback (priv->vscroll, user_data); + + callback (priv->top_shadow, user_data); + callback (priv->bottom_shadow, user_data); } static void diff --git a/src/st/st-scroll-view.h b/src/st/st-scroll-view.h index 75e32b333..bcd4bbb5a 100644 --- a/src/st/st-scroll-view.h +++ b/src/st/st-scroll-view.h @@ -88,6 +88,9 @@ void st_scroll_view_set_policy (StScrollView *scroll, GtkPolicyType hscroll, GtkPolicyType vscroll); +void st_scroll_view_set_vshadows (StScrollView *self, + gboolean vshadows); + G_END_DECLS #endif /* __ST_SCROLL_VIEW_H__ */