git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commit37c856b5f009de61e3f88704547e1206e6bc012a
parent9ee9c5680a
authorLucas Galante <[email protected]>
date2026-07-30 12:59
fix: the params pane swallows every wheel over it

The pane's wheel arm returned 'changed', so a wheel that moved nothing —
a near-miss on a slider halo over a pane too short to scroll — fell
through to whatever lies BEHIND the plate: the designer routes unhandled
wheels to the 3D viewport, whose rect is the whole window in the floating
layout, so trying to catch the band orbited the camera through the pane.
An opaque pane now consumes every wheel whose pointer is over it (or its
popover), scrolled or not.

Co-Authored-By: Claude Fable 5 <[email protected]>

 src/widget/container/parameters_bg.rs | 40 ++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index b541a77..44bce82 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -2282,7 +2282,8 @@ impl Input for ParametersBg {
 
                 // The legacy tail's `self.hit_test(px, py, ctx)`: occlusion via the adapter's
                 // address, then rect-or-popover containment.
-                if !changed && !ui.is_coordinate_covered(self_id, px, py) {
+                let mut swallowed = changed;
+                if !ui.is_coordinate_covered(self_id, px, py) {
                     let in_rect = px >= self.rect.x
                         && px <= self.rect.x + self.rect.width
                         && py >= self.rect.y
@@ -2291,24 +2292,33 @@ impl Input for ParametersBg {
                         px >= rx && px <= rx + rw && py >= ry && py <= ry + rh
                     });
                     if in_rect || in_popover {
-                        let scroll_speed = 24.0;
-                        let dy = match delta {
-                            MouseScrollDelta::LineDelta(_, y) => -y * scroll_speed,
-                            MouseScrollDelta::PixelDelta(pos) => -pos.y as f32,
-                        };
-                        let old_scroll = self.scroll_y;
-                        let max_scroll = (self.content_h - self.rect.height).max(0.0);
-                        self.scroll_y = (self.scroll_y + dy).clamp(0.0, max_scroll);
-                        if (self.scroll_y - old_scroll).abs() > 0.01 {
-                            self.update_slider_rects();
-                            self.scroll_activity = SCROLL_ACTIVE_HOLD;
-                            self.recompute_scrollbar_raised();
-                            changed = true;
+                        if !changed {
+                            let scroll_speed = 24.0;
+                            let dy = match delta {
+                                MouseScrollDelta::LineDelta(_, y) => -y * scroll_speed,
+                                MouseScrollDelta::PixelDelta(pos) => -pos.y as f32,
+                            };
+                            let old_scroll = self.scroll_y;
+                            let max_scroll = (self.content_h - self.rect.height).max(0.0);
+                            self.scroll_y = (self.scroll_y + dy).clamp(0.0, max_scroll);
+                            if (self.scroll_y - old_scroll).abs() > 0.01 {
+                                self.update_slider_rects();
+                                self.scroll_activity = SCROLL_ACTIVE_HOLD;
+                                self.recompute_scrollbar_raised();
+                            }
                         }
+                        // An opaque pane swallows EVERY wheel over it, whether
+                        // anything moved or not: returning false would hand the
+                        // event to whatever lies BEHIND the plate — the designer
+                        // routes unhandled wheels to the 3D viewport, whose rect
+                        // is the whole window in the floating layout, so a
+                        // near-miss on a slider would orbit the camera through
+                        // the pane.
+                        swallowed = true;
                     }
                 }
 
-                changed
+                swallowed
             }
             _ => false,
         }