git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

src/curve_tool.rs (2.4K)

 1 //! The curve viewer state: the `curve` node's control points as draggable
 2 //! handles, entered from the node's context menu ("Edit Handles").
 3 //!
 4 //! This is now one [`HandleSource`] on the framework in
 5 //! [`crate::viewer_state`], which owns everything that used to live here:
 6 //! projection, hit-testing, the drag model, per-gesture undo, snapping, the
 7 //! HUD, and write-back through the SetParam resync sequence. What is left is
 8 //! the part that is actually about curves — an open-ended list of world
 9 //! positions in the "Points" parameter, which the pointer may extend and trim.
10 //!
11 //! The behaviour that survives the move, because it is the framework's now:
12 //!
13 //! - **left press on a handle** grabs it; dragging moves the point on the
14 //!   camera-facing plane at its own depth, so orbiting between edits never
15 //!   makes a drag jump;
16 //! - **left press on empty space** appends a point there, at the depth of the
17 //!   last one, and immediately drags it;
18 //! - **right press on a handle** deletes it; Delete/Backspace deletes the
19 //!   selected one;
20 //! - **undo / redo** step one gesture at a time — a whole drag is one step,
21 //!   an add-and-drag is one step, a delete is one step;
22 //! - **Escape** exits.
23 
24 use crate::app::FsNode;
25 use crate::geometry::{format_curve_points, node_param_str, parse_curve_points};
26 use crate::viewer_state::HandleSource;
27 use glam::Vec3;
28 
29 /// Re-exported for the call sites that predate the framework. The projection
30 /// helpers are the framework's; this module is only the curve's handles.
31 pub use crate::viewer_state::{
32     find_node_by_id, find_node_by_id_mut, project_point, unproject_point, HANDLE_HIT_RADIUS,
33 };
34 
35 pub struct CurveHandles;
36 
37 impl HandleSource for CurveHandles {
38     fn name(&self) -> &'static str {
39         "Curve Points"
40     }
41 
42     fn accepts(&self, node_type: &str) -> bool {
43         node_type.eq_ignore_ascii_case("curve")
44     }
45 
46     fn read(&self, node: &FsNode) -> Vec<Vec3> {
47         parse_curve_points(&node_param_str(node, "Points", ""))
48     }
49 
50     fn write(&self, node: &mut FsNode, handles: &[Vec3]) {
51         let formatted = format_curve_points(handles);
52         if let Some(p) = node.params.iter_mut().find(|p| p.name == "Points") {
53             p.default = formatted;
54         }
55     }
56 
57     fn extensible(&self) -> bool {
58         true
59     }
60 
61     fn hints(&self) -> &'static str {
62         "drag to move, click to add, right-click or Del to remove"
63     }
64 }