GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
graph: drop_target_cell_rect — the cell an in-flight node drag lands on
commit_drag's exact resolution (round to nearest cell, find_empty_cell
walks off occupied ones) as a read-only accessor, so a host's drop-target
highlight never lies about where the node deposits. On GraphController;
ContentBg answers None.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/widget/container/content_bg.rs | 1 +
src/widget/display/graph.rs | 25 +++++++++++++++++++++++++
src/widget/mod.rs | 4 ++++
3 files changed, 30 insertions(+)
diff --git a/src/widget/container/content_bg.rs b/src/widget/container/content_bg.rs
index 2701e1c..726fa20 100644
--- a/src/widget/container/content_bg.rs
+++ b/src/widget/container/content_bg.rs
@@ -272,4 +272,5 @@ impl GraphController for ContentBg {
fn node_at(&self, _px: f32, _py: f32) -> Option<usize> { None }
fn cell_corner_radius(&self) -> f32 { 0.0 }
fn geometry_quads_tagged(&self, _rect: crate::scene::layout::Rect) -> Vec<crate::widget::TaggedQuad> { Vec::new() }
+ fn drop_target_cell_rect(&self) -> Option<(f32, f32, f32, f32)> { None }
}
diff --git a/src/widget/display/graph.rs b/src/widget/display/graph.rs
index de2d8df..8fae672 100644
--- a/src/widget/display/graph.rs
+++ b/src/widget/display/graph.rs
@@ -188,6 +188,30 @@ impl Graph {
Some((nx, ny, self.grid_size_x, self.grid_size_y))
}
+ /// The grid cell an in-flight node drag will deposit on, as its pixel
+ /// rect — hosts highlight it as the drop target. Runs the SAME
+ /// resolution as `commit_drag` (round to the nearest cell, then
+ /// `find_empty_cell` walks off occupied ones), so the highlight never
+ /// lies about where the node actually lands. None outside a node drag.
+ pub fn drop_target_cell_rect(&self) -> Option<(f32, f32, f32, f32)> {
+ let idx = self.dragging_idx?;
+ let (nx, ny) = self.drag_node_pos?;
+ let step_x = self.grid_size_x + self.skipped_col_w;
+ let step_y = self.grid_size_y + self.skipped_row_h;
+ if step_x <= 0.0 || step_y <= 0.0 {
+ return None;
+ }
+ let c = ((nx - self.grid_origin_x) / step_x).round();
+ let r = ((ny - self.grid_origin_y) / step_y).round();
+ let (c, r) = self.find_empty_cell(c, r, Some(idx));
+ Some((
+ self.grid_origin_x + c * step_x,
+ self.grid_origin_y + r * step_y,
+ self.grid_size_x,
+ self.grid_size_y,
+ ))
+ }
+
pub fn is_node_rect(&self, qx: f32, qy: f32, qw: f32, qh: f32) -> bool {
for i in 0..self.nodes.len() {
if let Some((nx, ny, nw, nh)) = self.node_rect(i) {
@@ -1094,6 +1118,7 @@ impl GraphController for Graph {
fn get_nodes(&self) -> Vec<GraphNode> { self.nodes.clone() }
fn cell_corner_radius(&self) -> f32 { Graph::cell_corner_radius(self) }
fn geometry_quads_tagged(&self, rect: Rect) -> Vec<TaggedQuad> { Graph::geometry_quads_tagged(self, rect) }
+ fn drop_target_cell_rect(&self) -> Option<(f32, f32, f32, f32)> { Graph::drop_target_cell_rect(self) }
fn selected_node(&self) -> Option<usize> { self.selected_idx }
fn set_selected_node(&mut self, idx: Option<usize>) {
self.selected_idx = idx;
diff --git a/src/widget/mod.rs b/src/widget/mod.rs
index 60b7337..9387562 100644
--- a/src/widget/mod.rs
+++ b/src/widget/mod.rs
@@ -612,6 +612,10 @@ pub trait GraphController {
/// rounded corners — for hosts that draw the graph's quads themselves
/// (the designer) and want cells as superellipse tiles.
fn geometry_quads_tagged(&self, rect: crate::scene::layout::Rect) -> Vec<TaggedQuad>;
+ /// The pixel rect of the cell an in-flight node drag will deposit on
+ /// (`commit_drag`'s resolution), for hosts' drop-target highlight.
+ /// None outside a node drag.
+ fn drop_target_cell_rect(&self) -> Option<(f32, f32, f32, f32)>;
}
pub trait SpreadsheetController {