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

commit4de2aff0bb3d282157648468d2812010b1909db8
parente864618e57
authorLucas Galante <[email protected]>
date2026-06-18 02:01
Fix spinbox right-click crash and implement missing container pointer casts

 src/backend/window_runner.rs           | 10 ++++++++--
 src/widget/container/breadcrumb.rs     |  3 +++
 src/widget/container/container.rs      |  6 ++++++
 src/widget/container/content_bg.rs     |  6 ++++++
 src/widget/container/header.rs         |  6 ++++++
 src/widget/container/layer.rs          |  3 +++
 src/widget/container/page.rs           |  3 +++
 src/widget/container/paginator.rs      |  3 +++
 src/widget/container/plate.rs          |  3 +++
 src/widget/container/scroll_box.rs     |  6 ++++++
 src/widget/container/scrolling_list.rs |  6 ++++++
 src/widget/container/spreadsheet.rs    |  6 ++++++
 src/widget/container/viewport_bg.rs    |  6 ++++++
 13 files changed, 65 insertions(+), 2 deletions(-)

diff --git a/src/backend/window_runner.rs b/src/backend/window_runner.rs
index 491481e..38da5ec 100644
--- a/src/backend/window_runner.rs
+++ b/src/backend/window_runner.rs
@@ -2036,11 +2036,17 @@ pub fn run<A: Application>() {
                 if !is_context_menu {
                     let popover_widget = unsafe { &*active_popovers[0] };
                     let (rx, ry, rw, rh) = popover_widget.rect();
-                    positioner.set_anchor_rect(rx as i32, ry as i32, rw as i32, rh as i32);
+                    let scroll_y = crate::widget::hover_animation::get_scroll_offset();
+                    let screen_ry = ry - scroll_y;
+                    let ax = (rx as i32).clamp(0, (engine_state.logical_width as i32 - 1).max(0));
+                    let ay = (screen_ry as i32).clamp(0, (engine_state.logical_height as i32 - 1).max(0));
+                    positioner.set_anchor_rect(ax, ay, rw as i32, rh as i32);
                     positioner.set_anchor(Anchor::BottomLeft);
                     positioner.set_gravity(Gravity::BottomRight);
                 } else {
-                    positioner.set_anchor_rect(px as i32, py as i32, 1, 1);
+                    let ax = (px as i32).clamp(0, (engine_state.logical_width as i32 - 1).max(0));
+                    let ay = (py as i32).clamp(0, (engine_state.logical_height as i32 - 1).max(0));
+                    positioner.set_anchor_rect(ax, ay, 1, 1);
                     positioner.set_anchor(Anchor::TopLeft);
                     positioner.set_gravity(Gravity::BottomRight);
                 }
diff --git a/src/widget/container/breadcrumb.rs b/src/widget/container/breadcrumb.rs
index e00b5a5..efe5797 100644
--- a/src/widget/container/breadcrumb.rs
+++ b/src/widget/container/breadcrumb.rs
@@ -50,6 +50,9 @@ impl Element for Breadcrumb {
     fn as_ptr(&self) -> *mut (dyn Element + 'static) {
         self as *const Self as *mut Self as *mut (dyn Element + 'static)
     }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn rounded_corners(&self) -> (bool, bool, bool, bool) { (true, true, false, false) }
 
diff --git a/src/widget/container/container.rs b/src/widget/container/container.rs
index c3efa69..0e498d6 100644
--- a/src/widget/container/container.rs
+++ b/src/widget/container/container.rs
@@ -16,6 +16,12 @@ impl Element for Container {
     fn rect(&self) -> (f32, f32, f32, f32) { (0.0, 0.0, 0.0, 0.0) }
     fn set_rect(&mut self, _x: f32, _y: f32, _w: f32, _h: f32) {}
     fn color(&self) -> [f32; 4] { [0.0, 0.0, 0.0, 0.0] }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn focus(&mut self) {
         focus::set_focused(self);
diff --git a/src/widget/container/content_bg.rs b/src/widget/container/content_bg.rs
index 2620413..0bc0f73 100644
--- a/src/widget/container/content_bg.rs
+++ b/src/widget/container/content_bg.rs
@@ -22,6 +22,12 @@ impl ContentBg {
 impl Element for ContentBg {
     fn rect(&self) -> (f32, f32, f32, f32) { (self.x, self.y, self.w, self.h) }
     fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) { self.x = x; self.y = y; self.w = w; self.h = h; }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
     fn color(&self) -> [f32; 4] {
         if self.show_network_grid {
             [0.0, 0.0, 0.0, 0.0]
diff --git a/src/widget/container/header.rs b/src/widget/container/header.rs
index 44d6754..cc28ab8 100644
--- a/src/widget/container/header.rs
+++ b/src/widget/container/header.rs
@@ -14,6 +14,12 @@ impl Element for Header {
     fn rect(&self) -> (f32, f32, f32, f32) { (self.x, self.y, self.w, self.h) }
     fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) { self.x = x; self.y = y; self.w = w; self.h = h; }
     fn color(&self) -> [f32; 4] { colors::HEADER_BG }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
     fn set_hovered(&mut self, v: bool) { self.hovered = v; }
     fn hovered(&self) -> bool { self.hovered }
 }
diff --git a/src/widget/container/layer.rs b/src/widget/container/layer.rs
index b49e760..e3de6d1 100644
--- a/src/widget/container/layer.rs
+++ b/src/widget/container/layer.rs
@@ -36,6 +36,9 @@ impl Element for Layer {
     fn as_ptr(&self) -> *mut (dyn Element + 'static) {
         self as *const Self as *mut Self as *mut (dyn Element + 'static)
     }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn rect(&self) -> (f32, f32, f32, f32) {
         (self.base.x, self.base.y, self.base.w, self.base.h)
diff --git a/src/widget/container/page.rs b/src/widget/container/page.rs
index a64ef10..c774895 100644
--- a/src/widget/container/page.rs
+++ b/src/widget/container/page.rs
@@ -128,6 +128,9 @@ impl Element for Page {
     fn as_ptr(&self) -> *mut (dyn Element + 'static) {
         self as *const Self as *mut Self as *mut (dyn Element + 'static)
     }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn rect(&self) -> (f32, f32, f32, f32) {
         self.base.rect()
diff --git a/src/widget/container/paginator.rs b/src/widget/container/paginator.rs
index 1ec26b9..ab13485 100644
--- a/src/widget/container/paginator.rs
+++ b/src/widget/container/paginator.rs
@@ -473,6 +473,9 @@ impl Element for Paginator {
     fn as_ptr(&self) -> *mut (dyn Element + 'static) {
         self as *const Self as *mut Self as *mut (dyn Element + 'static)
     }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn rect(&self) -> (f32, f32, f32, f32) {
         (self.x, self.y, self.w, self.h)
diff --git a/src/widget/container/plate.rs b/src/widget/container/plate.rs
index edd5bfc..5b67de7 100644
--- a/src/widget/container/plate.rs
+++ b/src/widget/container/plate.rs
@@ -95,6 +95,9 @@ impl Element for Plate {
     fn as_ptr(&self) -> *mut (dyn Element + 'static) {
         self as *const Self as *mut Self as *mut (dyn Element + 'static)
     }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn is_plate(&self) -> bool { true }
     fn rounded_corners(&self) -> (bool, bool, bool, bool) { (true, true, true, true) }
diff --git a/src/widget/container/scroll_box.rs b/src/widget/container/scroll_box.rs
index aa83ba3..d48de70 100644
--- a/src/widget/container/scroll_box.rs
+++ b/src/widget/container/scroll_box.rs
@@ -63,6 +63,12 @@ impl Element for ScrollBox {
         self.viewport_h = h + self.viewport_offset_h;
     }
     fn color(&self) -> [f32; 4] { crate::color::scrollinglist_bg_color() }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
     fn set_hovered(&mut self, v: bool) { self.hovered = v; }
     fn hovered(&self) -> bool { self.hovered }
     fn highlight_color(&self, ctx: &UiContext) -> Option<[f32; 4]> { None }
diff --git a/src/widget/container/scrolling_list.rs b/src/widget/container/scrolling_list.rs
index 2475122..c9104c4 100644
--- a/src/widget/container/scrolling_list.rs
+++ b/src/widget/container/scrolling_list.rs
@@ -57,6 +57,12 @@ impl Element for ScrollingList {
     fn color(&self) -> [f32; 4] {
         self.scroll_box.color()
     }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn set_hovered(&mut self, v: bool) {
         self.scroll_box.set_hovered(v);
diff --git a/src/widget/container/spreadsheet.rs b/src/widget/container/spreadsheet.rs
index 2440960..7d5a79a 100644
--- a/src/widget/container/spreadsheet.rs
+++ b/src/widget/container/spreadsheet.rs
@@ -42,6 +42,12 @@ impl Spreadsheet {
 
 impl Element for Spreadsheet {
     fn rounded_corners(&self) -> (bool, bool, bool, bool) { (true, true, true, true) }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
 
     fn rect(&self) -> (f32, f32, f32, f32) {
         if !self.visible {
diff --git a/src/widget/container/viewport_bg.rs b/src/widget/container/viewport_bg.rs
index 036cd51..94bde12 100644
--- a/src/widget/container/viewport_bg.rs
+++ b/src/widget/container/viewport_bg.rs
@@ -14,6 +14,12 @@ impl Element for ViewportBg {
     fn rect(&self) -> (f32, f32, f32, f32) { (self.x, self.y, self.w, self.h) }
     fn set_rect(&mut self, x: f32, y: f32, w: f32, h: f32) { self.x = x; self.y = y; self.w = w; self.h = h; }
     fn color(&self) -> [f32; 4] { colors::VIEWPORT_BG }
+    fn as_ptr(&self) -> *mut (dyn Element + 'static) {
+        self as *const Self as *mut Self as *mut (dyn Element + 'static)
+    }
+    fn as_ptr_mut(&mut self) -> *mut (dyn Element + 'static) {
+        self as *mut Self as *mut (dyn Element + 'static)
+    }
     fn set_hovered(&mut self, v: bool) { self.hovered = v; }
     fn hovered(&self) -> bool { self.hovered }
     fn hit_test(&self, _px: f32, _py: f32, _ctx: &UiContext) -> bool { false }