From a15205e6c4ec94188f19b284ecf2796e8a928a70 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Mon, 21 Sep 2009 19:11:09 -0400 Subject: [PATCH] Fix interaction of borders/background and scrolling StBoxLayout: Make consistent that the area scrolled and clipped to is the content area (excluding borders and padding.) Translate back appropriately when chaining up so that the parent background is drawn at the right place and picking on the box (if it's reactive) picks at the right place on the screen. clip-to-allocation is removed from StScrollView since it's just not right - if the child has any non-moving elements, like headers or borders, it will need to set a narrower clip. And even if the entire child scrolls, we want to clip to an arrow that excludes the scrollbars. https://bugzilla.gnome.org/show_bug.cgi?id=595997 --- src/st/st-box-layout.c | 121 ++++++++++++++++++++++++--------- src/st/st-scroll-view.c | 3 +- tests/interactive/scrolling.js | 23 +++++-- 3 files changed, 106 insertions(+), 41 deletions(-) diff --git a/src/st/st-box-layout.c b/src/st/st-box-layout.c index 9084f1e43..11b7483af 100644 --- a/src/st/st-box-layout.c +++ b/src/st/st-box-layout.c @@ -924,15 +924,12 @@ static void st_box_layout_paint (ClutterActor *actor) { StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); GList *l; gdouble x, y; - ClutterActorBox child_b; - ClutterActorBox box_b; - - CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->paint (actor); - - if (priv->children == NULL) - return; + ClutterActorBox child_box; + ClutterActorBox allocation_box; + ClutterActorBox content_box; if (priv->hadjustment) x = st_adjustment_get_value (priv->hadjustment); @@ -944,11 +941,40 @@ st_box_layout_paint (ClutterActor *actor) else y = 0; - clutter_actor_get_allocation_box (actor, &box_b); - box_b.x2 = (box_b.x2 - box_b.x1) + x; - box_b.x1 = x; - box_b.y2 = (box_b.y2 - box_b.y1) + y; - box_b.y1 = y; + /* If we are translated, then we need to translate back before chaining + * up or the background and borders will be drawn in the wrong place */ + if (x != 0 || y != 0) + { + cogl_push_matrix (); + cogl_translate ((int)x, (int)y, 0); + } + + CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->paint (actor); + + if (x != 0 || y != 0) + { + cogl_pop_matrix (); + } + + if (priv->children == NULL) + return; + + clutter_actor_get_allocation_box (actor, &allocation_box); + st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); + + content_box.x1 += x; + content_box.y1 += y; + content_box.x2 += x; + content_box.y2 += y; + + /* The content area forms the viewport into the scrolled contents, while + * the borders and background stay in place; after drawing the borders and + * background, we clip to the content area */ + if (priv->hadjustment || priv->vadjustment) + cogl_clip_push ((int)content_box.x1, + (int)content_box.y1, + (int)content_box.x2 - (int)content_box.x1, + (int)content_box.y2 - (int)content_box.y1); for (l = priv->children; l; l = g_list_next (l)) { @@ -957,16 +983,19 @@ st_box_layout_paint (ClutterActor *actor) if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; - clutter_actor_get_allocation_box (child, &child_b); + clutter_actor_get_allocation_box (child, &child_box); - if ((child_b.x1 < box_b.x2) && - (child_b.x2 > box_b.x1) && - (child_b.y1 < box_b.y2) && - (child_b.y2 > box_b.y1)) + if ((child_box.x1 < content_box.x2) && + (child_box.x2 > content_box.x1) && + (child_box.y1 < content_box.y2) && + (child_box.y2 > content_box.y1)) { clutter_actor_paint (child); } } + + if (priv->hadjustment || priv->vadjustment) + cogl_clip_pop (); } static void @@ -974,15 +1003,12 @@ st_box_layout_pick (ClutterActor *actor, const ClutterColor *color) { StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (actor)->priv; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); GList *l; gdouble x, y; - ClutterActorBox child_b; - ClutterActorBox box_b; - - CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color); - - if (priv->children == NULL) - return; + ClutterActorBox child_box; + ClutterActorBox allocation_box; + ClutterActorBox content_box; if (priv->hadjustment) x = st_adjustment_get_value (priv->hadjustment); @@ -994,11 +1020,35 @@ st_box_layout_pick (ClutterActor *actor, else y = 0; - clutter_actor_get_allocation_box (actor, &box_b); - box_b.x2 = (box_b.x2 - box_b.x1) + x; - box_b.x1 = x; - box_b.y2 = (box_b.y2 - box_b.y1) + y; - box_b.y1 = y; + if (x != 0 || y != 0) + { + cogl_push_matrix (); + cogl_translate ((int)x, (int)y, 0); + } + + CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->pick (actor, color); + + if (x != 0 || y != 0) + { + cogl_pop_matrix (); + } + + if (priv->children == NULL) + return; + + clutter_actor_get_allocation_box (actor, &allocation_box); + st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); + + content_box.x1 += x; + content_box.y1 += y; + content_box.x2 += x; + content_box.y2 += y; + + if (priv->hadjustment || priv->vadjustment) + cogl_clip_push ((int)content_box.x1, + (int)content_box.y1, + (int)content_box.x2 - (int)content_box.x1, + (int)content_box.y2 - (int)content_box.y1); for (l = priv->children; l; l = g_list_next (l)) { @@ -1007,16 +1057,19 @@ st_box_layout_pick (ClutterActor *actor, if (!CLUTTER_ACTOR_IS_VISIBLE (child)) continue; - clutter_actor_get_allocation_box (child, &child_b); + clutter_actor_get_allocation_box (child, &child_box); - if ((child_b.x1 < box_b.x2) - && (child_b.x2 > box_b.x1) - && (child_b.y1 < box_b.y2) - && (child_b.y2 > box_b.y1)) + if ((child_box.x1 < content_box.x2) && + (child_box.x2 > content_box.x1) && + (child_box.y1 < content_box.y2) && + (child_box.y2 > content_box.y1)) { clutter_actor_paint (child); } } + + if (priv->hadjustment || priv->vadjustment) + cogl_clip_pop (); } static void diff --git a/src/st/st-scroll-view.c b/src/st/st-scroll-view.c index ac11b72eb..2dd6f6ee6 100644 --- a/src/st/st-scroll-view.c +++ b/src/st/st-scroll-view.c @@ -590,8 +590,7 @@ st_scroll_view_init (StScrollView *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_object_set (G_OBJECT (self), "reactive", TRUE, NULL); } static void diff --git a/tests/interactive/scrolling.js b/tests/interactive/scrolling.js index 15f985cee..b27619ea3 100644 --- a/tests/interactive/scrolling.js +++ b/tests/interactive/scrolling.js @@ -8,11 +8,17 @@ const UI = imports.testcommon.ui; UI.init(); let stage = Clutter.Stage.get_default(); -let v = new St.ScrollView({}); -stage.add_actor(v); +let vbox = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height, + style: "padding: 10px;" }); +stage.add_actor(vbox); + +let v = new St.ScrollView(); +vbox.add(v, { expand: true }); + let b = new St.BoxLayout({ vertical: true, - width: stage.width, - height: stage.height }); + style: "border: 2px solid #880000; border-radius: 10px; padding: 0px 5px;" }); v.add_actor(b); let cc_a = "a".charCodeAt(0); @@ -20,9 +26,16 @@ let s = ""; for (let i = 0; i < 26 * 3; i++) { s += String.fromCharCode(cc_a + i % 26); - let t = new St.Label({ "text": s}); + let t = new St.Label({ text: s, + reactive: true }); + let line = i + 1; + t.connect('button-press-event', + function() { + log("Click on line " + line); + }); b.add(t); } stage.show(); Clutter.main(); +stage.destroy();