Skip to content

Commit d651ec3

Browse files
committed
impl GizmoHandlerTrait,Gizmo-manager and add comments
1 parent 0e8eb48 commit d651ec3

14 files changed

Lines changed: 1290 additions & 827 deletions

File tree

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
use std::collections::VecDeque;
2+
3+
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
4+
use crate::messages::tool::common_functionality::graph_modification_utils::{self};
5+
use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGizmoHandler;
6+
use glam::DVec2;
7+
8+
use crate::messages::{
9+
message::Message,
10+
portfolio::document::overlays::utility_types::OverlayContext,
11+
prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler},
12+
tool::common_functionality::{
13+
shape_editor::ShapeState,
14+
shapes::{polygon_shape::PolygonGizmoHandler, star_shape::StarGizmoHandler},
15+
},
16+
};
17+
/// A unified enum wrapper around all available shape-specific gizmo handlers.
18+
///
19+
/// This abstraction allows `GizmoManager` to interact with different shape gizmos (like Star or Polygon)
20+
/// using a common interface without needing to know the specific shape type at compile time.
21+
///
22+
/// Each variant stores a concrete handler (e.g., `StarGizmoHandler`, `PolygonGizmoHandler`) that implements
23+
/// the shape-specific logic for rendering overlays, responding to input, and modifying shape parameters.
24+
#[derive(Clone, Debug, Default)]
25+
pub enum ShapeGizmoHandlers {
26+
#[default]
27+
None,
28+
Star(StarGizmoHandler),
29+
Polygon(PolygonGizmoHandler),
30+
}
31+
32+
impl ShapeGizmoHandlers {
33+
/// Returns the kind of shape the handler is managing, such as `"star"` or `"polygon"`.
34+
/// Used for grouping logic and distinguishing between handler types at runtime.
35+
pub fn kind(&self) -> &'static str {
36+
match self {
37+
Self::Star(_) => "star",
38+
Self::Polygon(_) => "polygon",
39+
Self::None => "none",
40+
}
41+
}
42+
43+
/// Dispatches interaction state updates to the corresponding shape-specific handler.
44+
pub fn handle_state(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
45+
match self {
46+
Self::Star(h) => h.handle_state(layer, mouse_position, document, responses),
47+
Self::Polygon(h) => h.handle_state(layer, mouse_position, document, responses),
48+
Self::None => {}
49+
}
50+
}
51+
52+
/// Checks if any interactive part of the gizmo is currently hovered.
53+
pub fn is_any_gizmo_hovered(&self) -> bool {
54+
match self {
55+
Self::Star(h) => h.is_any_gizmo_hovered(),
56+
Self::Polygon(h) => h.is_any_gizmo_hovered(),
57+
Self::None => false,
58+
}
59+
}
60+
61+
/// Passes the click interaction to the appropriate gizmo handler if one is hovered.
62+
pub fn handle_click(&mut self) {
63+
match self {
64+
Self::Star(h) => h.handle_click(),
65+
Self::Polygon(h) => h.handle_click(),
66+
Self::None => {}
67+
}
68+
}
69+
70+
/// Updates the gizmo state while the user is dragging a handle (e.g., adjusting radius).
71+
pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
72+
match self {
73+
Self::Star(h) => h.handle_update(drag_start, document, input, responses),
74+
Self::Polygon(h) => h.handle_update(drag_start, document, input, responses),
75+
Self::None => {}
76+
}
77+
}
78+
79+
pub fn cleanup(&mut self) {
80+
match self {
81+
Self::Star(h) => h.cleanup(),
82+
Self::Polygon(h) => h.cleanup(),
83+
Self::None => {}
84+
}
85+
}
86+
87+
/// Draws overlays like control points or outlines for the shape handled by this gizmo.
88+
pub fn overlays(
89+
&self,
90+
document: &DocumentMessageHandler,
91+
layer: Option<LayerNodeIdentifier>,
92+
input: &InputPreprocessorMessageHandler,
93+
shape_editor: &mut &mut ShapeState,
94+
mouse_position: DVec2,
95+
overlay_context: &mut OverlayContext,
96+
) {
97+
match self {
98+
Self::Star(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
99+
Self::Polygon(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
100+
Self::None => {}
101+
}
102+
}
103+
104+
/// Draws live-updating overlays during drag interactions for the shape handled by this gizmo.
105+
pub fn dragging_overlays(
106+
&self,
107+
document: &DocumentMessageHandler,
108+
input: &InputPreprocessorMessageHandler,
109+
shape_editor: &mut &mut ShapeState,
110+
mouse_position: DVec2,
111+
overlay_context: &mut OverlayContext,
112+
) {
113+
match self {
114+
Self::Star(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
115+
Self::Polygon(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
116+
Self::None => {}
117+
}
118+
}
119+
}
120+
121+
/// Central manager that coordinates shape gizmo handlers for interactive editing on the canvas.
122+
///
123+
/// The `GizmoManager` is responsible for detecting which shapes are selected, activating the appropriate
124+
/// shape-specific gizmo, and routing user interactions (hover, click, drag) to the correct handler.
125+
/// It allows editing multiple shapes of the same type or focusing on a single active shape when a gizmo is hovered.
126+
///
127+
/// ## Responsibilities:
128+
/// - Detect which selected layers support shape gizmos (e.g., stars, polygons)
129+
/// - Activate the correct handler and manage state between frames
130+
/// - Route click, hover, and drag events to the proper shape gizmo
131+
/// - Render overlays and dragging visuals
132+
#[derive(Clone, Debug, Default)]
133+
pub struct GizmoManager {
134+
active_shape_handler: Option<ShapeGizmoHandlers>,
135+
layers_handlers: Vec<(ShapeGizmoHandlers, Vec<LayerNodeIdentifier>)>,
136+
}
137+
138+
impl GizmoManager {
139+
/// Detects and returns a shape gizmo handler based on the layer type (e.g., star, polygon).
140+
///
141+
/// Returns `None` if the given layer does not represent a shape with a registered gizmo.
142+
pub fn detect_shape_handler(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<ShapeGizmoHandlers> {
143+
if graph_modification_utils::get_star_id(layer, &document.network_interface).is_some() {
144+
return Some(ShapeGizmoHandlers::Star(StarGizmoHandler::new()));
145+
}
146+
if graph_modification_utils::get_polygon_id(layer, &document.network_interface).is_some() {
147+
return Some(ShapeGizmoHandlers::Polygon(PolygonGizmoHandler::new()));
148+
}
149+
150+
None
151+
}
152+
153+
/// Returns `true` if a gizmo is currently active (hovered or being interacted with).
154+
pub fn hovering_over_gizmo(&self) -> bool {
155+
self.active_shape_handler.is_some()
156+
}
157+
158+
/// Called every frame to check selected layers and update the active shape gizmo, if hovered.
159+
///
160+
/// Also groups all shape layers with the same kind of gizmo to support multi-shape overlays.
161+
pub fn handle_actions(&mut self, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
162+
let mut handlers_layer: Vec<(ShapeGizmoHandlers, Vec<LayerNodeIdentifier>)> = Vec::new();
163+
164+
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
165+
if let Some(mut handler) = Self::detect_shape_handler(layer, document) {
166+
handler.handle_state(layer, mouse_position, document, responses);
167+
let is_hovered = handler.is_any_gizmo_hovered();
168+
169+
if is_hovered {
170+
self.layers_handlers.clear();
171+
self.active_shape_handler = Some(handler);
172+
return;
173+
}
174+
175+
// Try to group this handler with others of the same type
176+
if let Some((_, layers)) = handlers_layer.iter_mut().find(|(existing_handler, _)| existing_handler.kind() == handler.kind()) {
177+
layers.push(layer);
178+
} else {
179+
handlers_layer.push((handler, vec![layer]));
180+
}
181+
}
182+
}
183+
184+
self.layers_handlers = handlers_layer;
185+
self.active_shape_handler = None;
186+
}
187+
188+
/// Handles click interactions if a gizmo is active. Returns `true` if a gizmo handled the click.
189+
pub fn handle_click(&mut self) -> bool {
190+
if let Some(handle) = &mut self.active_shape_handler {
191+
handle.handle_click();
192+
return true;
193+
}
194+
false
195+
}
196+
197+
pub fn handle_cleanup(&mut self) {
198+
if let Some(handle) = &mut self.active_shape_handler {
199+
handle.cleanup();
200+
}
201+
}
202+
203+
/// Passes drag update data to the active gizmo to update shape parameters live.
204+
pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
205+
if let Some(handle) = &mut self.active_shape_handler {
206+
handle.handle_update(drag_start, document, input, responses);
207+
}
208+
}
209+
210+
/// Draws overlays for the currently active shape gizmo during a drag interaction.
211+
pub fn dragging_overlays(
212+
&self,
213+
document: &DocumentMessageHandler,
214+
input: &InputPreprocessorMessageHandler,
215+
shape_editor: &mut &mut ShapeState,
216+
mouse_position: DVec2,
217+
overlay_context: &mut OverlayContext,
218+
) {
219+
if let Some(handle) = &self.active_shape_handler {
220+
handle.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context);
221+
}
222+
}
223+
224+
/// Draws overlays for either the active gizmo (if hovered) or all grouped selected gizmos.
225+
///
226+
/// If no single gizmo is active, it renders overlays for all grouped layers with associated handlers.
227+
pub fn overlays(
228+
&self,
229+
document: &DocumentMessageHandler,
230+
input: &InputPreprocessorMessageHandler,
231+
shape_editor: &mut &mut ShapeState,
232+
mouse_position: DVec2,
233+
overlay_context: &mut OverlayContext,
234+
) {
235+
if let Some(handler) = &self.active_shape_handler {
236+
handler.overlays(document, None, input, shape_editor, mouse_position, overlay_context);
237+
return;
238+
}
239+
240+
for (handler, selected_layers) in &self.layers_handlers {
241+
for layer in selected_layers {
242+
handler.overlays(document, Some(*layer), input, shape_editor, mouse_position, overlay_context);
243+
}
244+
}
245+
}
246+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod gizmo_manager;
2+
pub mod shape_gizmos;

editor/src/messages/tool/common_functionality/shape_gizmos/mod.rs renamed to editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/mod.rs

File renamed without changes.

0 commit comments

Comments
 (0)