graphic design tool
git clone https://git.lucas.co/cce-designer.git
fix: the scene starts at the network plate's edge
cursor_in_viewport carved out the old column layout -- left of
splitter1_x + SPLITTER_W, above the network content's top -- which the
floating plates stopped following, so a band right of the network plate
and a strip along the top belonged to nothing and a right-click there
opened no menu. It is now the viewport's own rect minus the network
plates and the floating panes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/app.rs | 21 +++++++++++++++------
src/main.rs | 33 +++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 6 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index f68c413..32ac643 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -2675,12 +2675,21 @@ impl State {
// asked, and the spreadsheet's own header-click sort never fired.
// Same for the right-click menu and the pinch zoom, which gate on
// this test as well.
- let node_area_y = self.positions[CONTENT_IDX].1;
- !self.over_floating_pane()
- && self.cursor_x >= self.content_right_x()
- && self.cursor_x < self.splitter_layout.splitter2_x
- && self.cursor_y >= node_area_y
- && self.cursor_y < self.height - STATUS_H
+ //
+ // Bounded by the viewport's OWN rect, minus the network plates by
+ // their laid-out rects. Until 2026-09-25 this carved out the old
+ // column layout instead — left of `splitter1_x + SPLITTER_W`, above
+ // the network content's top — which the floating plates stopped
+ // following long ago, so a band right of the network plate and a
+ // strip along the top were neither the network's nor the scene's,
+ // and a right-click there opened nothing. The circular pane is
+ // excluded by its callers (`in_circle_network_pane`): its rect is
+ // the circle's bounding box, whose corners are scene.
+ let (px, py) = (self.cursor_x, self.cursor_y);
+ let inside = |(x, y, w, h): (f32, f32, f32, f32)| w > 0.0 && h > 0.0 && px >= x && px < x + w && py >= y && py < y + h;
+ let over_network = !self.circular_network_pane
+ && [NETWORK_PANEL_IDX, crate::slots::NETWORK_PANEL2_IDX].iter().any(|&idx| inside(self.positions[idx]));
+ inside(self.positions[VIEWPORT_IDX]) && !over_network && !self.over_floating_pane()
}
// --- Pane edge-resize hotspots. Each is the single source of truth for its zone:
diff --git a/src/main.rs b/src/main.rs
index a504f62..225ec77 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -471,6 +471,39 @@ mod tests {
/// before any widget is asked. So the toolkit's header-click sort
/// (tested in cce-ui) never fired in this app: clicking a header
/// hovered it, tinted it, and did nothing.
+ /// The scene is everything in the viewport's rect that no plate covers
+ /// — right up to the network plate's edge. The test used to carve out
+ /// the old COLUMN layout, so the band between the floating plate's right
+ /// edge and `splitter1_x + SPLITTER_W`, and the strip above the network
+ /// content, were nobody's: a right-click there opened no menu.
+ #[test]
+ fn the_scene_starts_at_the_network_plates_edge() {
+ use crate::slots::{NETWORK_PANEL_IDX, VIEWPORT_IDX};
+ use crate::window::{LocalPosition, WindowEvent};
+ use cce_ui::widget::{ElementState, MouseButton};
+ let mut state = State::new(false);
+ state.resize(1600.0, 900.0, 1.0);
+ state.network_plate = true;
+ state.splitter_layout.splitter1_x = 700.0;
+ state.rebuild_positions();
+ state.apply_layout();
+ let (nx, ny, nw, nh) = state.positions[NETWORK_PANEL_IDX];
+ assert!(nw > 0.0 && nx + nw < 690.0, "the plate ends short of the old column split");
+ let at = |state: &mut State, x: f32, y: f32| {
+ state.handle_event(&WindowEvent::CursorMoved { position: LocalPosition { x: x as f64, y: y as f64 } });
+ state.cursor_in_viewport()
+ };
+ assert!(!at(&mut state, nx + nw - 4.0, ny + nh * 0.5), "the plate is the network's");
+ assert!(at(&mut state, nx + nw + 4.0, ny + nh * 0.5), "just right of the plate is scene");
+ let (vx, vy, vw, _) = state.positions[VIEWPORT_IDX];
+ assert!(at(&mut state, vx + vw * 0.5, vy + 4.0), "the strip along the top is scene");
+
+ // And the right press there opens the viewport's menu.
+ at(&mut state, nx + nw + 4.0, ny + nh * 0.5);
+ state.handle_event(&WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Right });
+ assert!(state.viewport_menu_open(), "a right-click beside the plate opens the viewport menu");
+ }
+
#[test]
fn spreadsheet_header_press_reaches_the_widget_not_the_camera() {
use crate::slots::{SPREADSHEET_IDX, SPREADSHEET_MENUBAR_IDX, VIEWPORT_IDX};