mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
added multi select changed added gizmo context
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler};
|
||||
use crate::messages::prelude::DocumentMessageHandler;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::operations::circular_repeat::CircularRepeatGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::arc_shape::ArcGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::circle_shape::CircleGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::polygon_shape::PolygonGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeGizmoHandler};
|
||||
use crate::messages::tool::common_functionality::shapes::star_shape::StarGizmoHandler;
|
||||
use glam::DVec2;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A unified enum wrapper around all available shape-specific gizmo handlers.
|
||||
///
|
||||
@@ -28,6 +27,7 @@ pub enum ShapeGizmoHandlers {
|
||||
Polygon(PolygonGizmoHandler),
|
||||
Arc(ArcGizmoHandler),
|
||||
Circle(CircleGizmoHandler),
|
||||
CircularRepeat(CircularRepeatGizmoHandler),
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandlers {
|
||||
@@ -39,17 +39,19 @@ impl ShapeGizmoHandlers {
|
||||
Self::Polygon(_) => "polygon",
|
||||
Self::Arc(_) => "arc",
|
||||
Self::Circle(_) => "circle",
|
||||
Self::CircularRepeat(_) => "circular_repeat",
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatches interaction state updates to the corresponding shape-specific handler.
|
||||
pub fn handle_state(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_state(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
match self {
|
||||
Self::Star(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
Self::Polygon(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
Self::Arc(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
Self::Circle(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
Self::Star(h) => h.handle_state(layer, mouse_position, ctx),
|
||||
Self::Polygon(h) => h.handle_state(layer, mouse_position, ctx),
|
||||
Self::Arc(h) => h.handle_state(layer, mouse_position, ctx),
|
||||
Self::Circle(h) => h.handle_state(layer, mouse_position, ctx),
|
||||
Self::CircularRepeat(h) => h.handle_state(layer, mouse_position, ctx),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +63,7 @@ impl ShapeGizmoHandlers {
|
||||
Self::Polygon(h) => h.is_any_gizmo_hovered(),
|
||||
Self::Arc(h) => h.is_any_gizmo_hovered(),
|
||||
Self::Circle(h) => h.is_any_gizmo_hovered(),
|
||||
Self::CircularRepeat(h) => h.is_any_gizmo_hovered(),
|
||||
Self::None => false,
|
||||
}
|
||||
}
|
||||
@@ -72,17 +75,19 @@ impl ShapeGizmoHandlers {
|
||||
Self::Polygon(h) => h.handle_click(),
|
||||
Self::Arc(h) => h.handle_click(),
|
||||
Self::Circle(h) => h.handle_click(),
|
||||
Self::CircularRepeat(h) => h.handle_click(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the gizmo state while the user is dragging a handle (e.g., adjusting radius).
|
||||
pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
match self {
|
||||
Self::Star(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Polygon(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Arc(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Circle(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Star(h) => h.handle_update(drag_start, ctx),
|
||||
Self::Polygon(h) => h.handle_update(drag_start, ctx),
|
||||
Self::Arc(h) => h.handle_update(drag_start, ctx),
|
||||
Self::Circle(h) => h.handle_update(drag_start, ctx),
|
||||
Self::CircularRepeat(h) => h.handle_update(drag_start, ctx),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -94,43 +99,31 @@ impl ShapeGizmoHandlers {
|
||||
Self::Polygon(h) => h.cleanup(),
|
||||
Self::Arc(h) => h.cleanup(),
|
||||
Self::Circle(h) => h.cleanup(),
|
||||
Self::CircularRepeat(h) => h.cleanup(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws overlays like control points or outlines for the shape handled by this gizmo.
|
||||
pub fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
layer: Option<LayerNodeIdentifier>,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
pub fn overlays(&self, layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
match self {
|
||||
Self::Star(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Polygon(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Arc(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Circle(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Star(h) => h.overlays(layer, mouse_position, ctx, overlay_context),
|
||||
Self::Polygon(h) => h.overlays(layer, mouse_position, ctx, overlay_context),
|
||||
Self::Arc(h) => h.overlays(layer, mouse_position, ctx, overlay_context),
|
||||
Self::Circle(h) => h.overlays(layer, mouse_position, ctx, overlay_context),
|
||||
Self::CircularRepeat(h) => h.overlays(layer, mouse_position, ctx, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws live-updating overlays during drag interactions for the shape handled by this gizmo.
|
||||
pub fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
pub fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
match self {
|
||||
Self::Star(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Polygon(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Arc(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Circle(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Star(h) => h.dragging_overlays(mouse_position, ctx, overlay_context),
|
||||
Self::Polygon(h) => h.dragging_overlays(mouse_position, ctx, overlay_context),
|
||||
Self::Arc(h) => h.dragging_overlays(mouse_position, ctx, overlay_context),
|
||||
Self::Circle(h) => h.dragging_overlays(mouse_position, ctx, overlay_context),
|
||||
Self::CircularRepeat(h) => h.dragging_overlays(mouse_position, ctx, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -141,6 +134,7 @@ impl ShapeGizmoHandlers {
|
||||
Self::Polygon(h) => h.mouse_cursor_icon(),
|
||||
Self::Arc(h) => h.mouse_cursor_icon(),
|
||||
Self::Circle(h) => h.mouse_cursor_icon(),
|
||||
Self::CircularRepeat(h) => h.mouse_cursor_icon(),
|
||||
Self::None => None,
|
||||
}
|
||||
}
|
||||
@@ -188,6 +182,16 @@ impl GizmoManager {
|
||||
None
|
||||
}
|
||||
|
||||
/// Detects and returns a operation gizmo handler based on the layer type (e.g., circular_repeat, repeat).
|
||||
pub fn detect_operation_gizmo_handler(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<ShapeGizmoHandlers> {
|
||||
// Circular Repeat
|
||||
if graph_modification_utils::get_circular_repeat(layer, &document.network_interface).is_some() {
|
||||
return Some(ShapeGizmoHandlers::CircularRepeat(CircularRepeatGizmoHandler::default()));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns `true` if a gizmo is currently active (hovered or being interacted with).
|
||||
pub fn hovering_over_gizmo(&self) -> bool {
|
||||
self.active_shape_handler.is_some()
|
||||
@@ -196,12 +200,12 @@ impl GizmoManager {
|
||||
/// Called every frame to check selected layers and update the active shape gizmo, if hovered.
|
||||
///
|
||||
/// Also groups all shape layers with the same kind of gizmo to support overlays for multi-shape editing.
|
||||
pub fn handle_actions(&mut self, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_actions(&mut self, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let mut handlers_layer: Vec<(ShapeGizmoHandlers, Vec<LayerNodeIdentifier>)> = Vec::new();
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
|
||||
if let Some(mut handler) = Self::detect_shape_handler(layer, document) {
|
||||
handler.handle_state(layer, mouse_position, document, responses);
|
||||
for layer in ctx.document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&ctx.document.network_interface) {
|
||||
if let Some(mut handler) = Self::detect_shape_handler(layer, ctx.document) {
|
||||
handler.handle_state(layer, mouse_position, ctx);
|
||||
let is_hovered = handler.is_any_gizmo_hovered();
|
||||
|
||||
if is_hovered {
|
||||
@@ -210,7 +214,7 @@ impl GizmoManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to group this handler with others of the same type
|
||||
// Group same-kind handlers together
|
||||
if let Some((_, layers)) = handlers_layer.iter_mut().find(|(existing_handler, _)| existing_handler.kind() == handler.kind()) {
|
||||
layers.push(layer);
|
||||
} else {
|
||||
@@ -223,6 +227,38 @@ impl GizmoManager {
|
||||
self.active_shape_handler = None;
|
||||
}
|
||||
|
||||
pub fn handle_operation_actions(&mut self, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.active_shape_handler = None;
|
||||
|
||||
let mut handlers_map: HashMap<&'static str, ShapeGizmoHandlers> = HashMap::new();
|
||||
let mut maybe_active_kind: Option<&'static str> = None;
|
||||
|
||||
for layer in ctx.document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&ctx.document.network_interface) {
|
||||
if let Some(mut handler) = Self::detect_operation_gizmo_handler(layer, ctx.document) {
|
||||
let kind = handler.kind();
|
||||
|
||||
// Reuse existing handler to accumulate layers
|
||||
if let Some(existing_handler) = handlers_map.remove(kind) {
|
||||
handler = existing_handler;
|
||||
}
|
||||
|
||||
handler.handle_state(layer, mouse_position, ctx);
|
||||
|
||||
if handler.is_any_gizmo_hovered() {
|
||||
maybe_active_kind = Some(kind);
|
||||
}
|
||||
|
||||
handlers_map.insert(kind, handler);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(kind) = maybe_active_kind {
|
||||
if let Some(handler) = handlers_map.remove(kind) {
|
||||
self.active_shape_handler = Some(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles click interactions if a gizmo is active. Returns `true` if a gizmo handled the click.
|
||||
pub fn handle_click(&mut self) -> bool {
|
||||
if let Some(handle) = &mut self.active_shape_handler {
|
||||
@@ -239,45 +275,31 @@ impl GizmoManager {
|
||||
}
|
||||
|
||||
/// Passes drag update data to the active gizmo to update shape parameters live.
|
||||
pub fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if let Some(handle) = &mut self.active_shape_handler {
|
||||
handle.handle_update(drag_start, document, input, responses);
|
||||
handle.handle_update(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws overlays for the currently active shape gizmo during a drag interaction.
|
||||
pub fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
pub fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if let Some(handle) = &self.active_shape_handler {
|
||||
handle.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context);
|
||||
handle.dragging_overlays(mouse_position, ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws overlays for either the active gizmo (if hovered) or all grouped selected gizmos.
|
||||
///
|
||||
/// If no single gizmo is active, it renders overlays for all grouped layers with associated handlers.
|
||||
pub fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
pub fn overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if let Some(handler) = &self.active_shape_handler {
|
||||
handler.overlays(document, None, input, shape_editor, mouse_position, overlay_context);
|
||||
handler.overlays(None, mouse_position, ctx, overlay_context);
|
||||
return;
|
||||
}
|
||||
|
||||
for (handler, selected_layers) in &self.layers_handlers {
|
||||
for layer in selected_layers {
|
||||
handler.overlays(document, Some(*layer), input, shape_editor, mouse_position, overlay_context);
|
||||
handler.overlays(Some(*layer), mouse_position, ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod gizmo_manager;
|
||||
pub mod operation_gizmos;
|
||||
pub mod shape_gizmos;
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
use crate::consts::{NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION, NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH};
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::NodeGraphMessage;
|
||||
use crate::messages::prelude::Responses;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, extract_circular_repeat_parameters};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::HashMap;
|
||||
use std::f64::consts::{FRAC_PI_2, TAU};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub enum RepeatCountDialState {
|
||||
#[default]
|
||||
Inactive,
|
||||
Hover,
|
||||
Dragging,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct RepeatCountDial {
|
||||
pub layer: Option<LayerNodeIdentifier>,
|
||||
pub initial_points: u32,
|
||||
pub handle_state: RepeatCountDialState,
|
||||
|
||||
// store the other layers whose gizmo is not hovered but still has repeat node in them
|
||||
selected_layers: HashMap<LayerNodeIdentifier, u32>,
|
||||
}
|
||||
|
||||
impl RepeatCountDial {
|
||||
pub fn cleanup(&mut self) {
|
||||
self.handle_state = RepeatCountDialState::Inactive;
|
||||
self.layer = None;
|
||||
self.selected_layers.clear();
|
||||
}
|
||||
|
||||
pub fn update_state(&mut self, state: RepeatCountDialState) {
|
||||
self.handle_state = state;
|
||||
}
|
||||
|
||||
pub fn is_hovering(&self) -> bool {
|
||||
self.handle_state == RepeatCountDialState::Hover
|
||||
}
|
||||
|
||||
pub fn is_dragging(&self) -> bool {
|
||||
self.handle_state == RepeatCountDialState::Dragging
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
RepeatCountDialState::Inactive => {
|
||||
let Some((_, radius, count)) = extract_circular_repeat_parameters(Some(layer), document) else {
|
||||
return;
|
||||
};
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
let offset_vector = document.metadata().downstream_transform_to_viewport(layer).transform_vector2(DVec2::NEG_Y * radius);
|
||||
|
||||
let repeat_center = center + offset_vector;
|
||||
|
||||
if repeat_center.distance(mouse_position) < NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH {
|
||||
self.layer = Some(layer);
|
||||
self.update_state(RepeatCountDialState::Hover);
|
||||
self.initial_points = count;
|
||||
}
|
||||
|
||||
self.selected_layers.insert(layer, count);
|
||||
}
|
||||
RepeatCountDialState::Hover | RepeatCountDialState::Dragging => {
|
||||
// Even though we the gizmo is in hovered state store the other layers
|
||||
let Some((_, _, count)) = extract_circular_repeat_parameters(Some(layer), document) else {
|
||||
return;
|
||||
};
|
||||
self.selected_layers.insert(layer, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
RepeatCountDialState::Inactive => {
|
||||
let Some(layer) = layer else { return };
|
||||
let Some((angle, radius, count)) = extract_circular_repeat_parameters(Some(layer), document) else {
|
||||
return;
|
||||
};
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
let offset_vector = document.metadata().downstream_transform_to_viewport(layer).transform_vector2(DVec2::NEG_Y * radius);
|
||||
let repeat_center = center + offset_vector;
|
||||
|
||||
if repeat_center.distance(mouse_position) < radius.abs() {
|
||||
self.draw_spokes(repeat_center, document.metadata().downstream_transform_to_viewport(layer), count, angle.to_radians(), overlay_context);
|
||||
}
|
||||
}
|
||||
RepeatCountDialState::Hover | RepeatCountDialState::Dragging => {
|
||||
let Some(layer) = self.layer else { return };
|
||||
let Some((angle, radius, count)) = extract_circular_repeat_parameters(Some(layer), document) else {
|
||||
return;
|
||||
};
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
let offset_vector = document.metadata().downstream_transform_to_viewport(layer).transform_vector2(DVec2::NEG_Y * radius);
|
||||
|
||||
let repeat_center = center + offset_vector;
|
||||
|
||||
self.draw_spokes(repeat_center, document.metadata().downstream_transform_to_viewport(layer), count, angle.to_radians(), overlay_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_spokes(&self, center: DVec2, viewport: DAffine2, count: u32, angle: f64, overlay_context: &mut OverlayContext) {
|
||||
for i in 0..count {
|
||||
let angle = ((i as f64) * TAU) / (count as f64) + angle + FRAC_PI_2;
|
||||
|
||||
let direction_vector = viewport.transform_vector2(DVec2 { x: angle.cos(), y: -angle.sin() });
|
||||
|
||||
let end_point = direction_vector * 20.;
|
||||
if matches!(self.handle_state, RepeatCountDialState::Hover | RepeatCountDialState::Dragging) {
|
||||
overlay_context.line(center, end_point * NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION + center, None, None);
|
||||
} else {
|
||||
overlay_context.line(center, end_point + center, None, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_number_of_sides(&self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, input, responses, .. } = ctx;
|
||||
|
||||
let delta = input.mouse.position - drag_start;
|
||||
let sign = (input.mouse.position.x - drag_start.x).signum();
|
||||
let net_delta = (delta.length() / 25.).round() * sign;
|
||||
|
||||
for (layer, count) in &self.selected_layers {
|
||||
let Some(node_id) = graph_modification_utils::get_circular_repeat(*layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
let new_point_count = ((*count as i32) + (net_delta as i32)).max(1);
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 3),
|
||||
input: NodeInput::value(TaggedValue::U32(new_point_count as u32), false),
|
||||
});
|
||||
}
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod count_gizmos;
|
||||
@@ -1,17 +1,15 @@
|
||||
use crate::consts::GIZMO_HIDE_THRESHOLD;
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::prelude::{DocumentMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::prelude::{FrontendMessage, Responses};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_arc_id, get_stroke_width};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_arc_parameters, extract_circle_radius};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, extract_arc_parameters, extract_circle_radius};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::FRAC_PI_2;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
@@ -77,7 +75,9 @@ impl RadiusHandle {
|
||||
stroke_width + extra_spacing
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, responses, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
RadiusHandleState::Inactive => {
|
||||
let Some(radius) = extract_circle_radius(layer, document).or(extract_arc_parameters(Some(layer), document).map(|(r, _, _, _)| r)) else {
|
||||
@@ -107,7 +107,9 @@ impl RadiusHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
pub fn overlays(&self, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
RadiusHandleState::Inactive => {}
|
||||
RadiusHandleState::Dragging | RadiusHandleState::Hover => {
|
||||
@@ -145,7 +147,9 @@ impl RadiusHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_inner_radius(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
||||
pub fn update_inner_radius(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, responses, input, .. } = ctx;
|
||||
|
||||
let Some(layer) = self.layer else { return };
|
||||
let Some(node_id) = graph_modification_utils::get_circle_id(layer, &document.network_interface).or(get_arc_id(layer, &document.network_interface)) else {
|
||||
return;
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
use crate::consts::{GIZMO_HIDE_THRESHOLD, NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION, NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH, POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::Responses;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, FrontendMessage, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::prelude::{FrontendMessage, NodeGraphMessage};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_polygon_parameters, inside_polygon, inside_star, polygon_outline, polygon_vertex_position, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{
|
||||
GizmoContext, extract_polygon_parameters, inside_polygon, inside_star, polygon_outline, polygon_vertex_position, star_outline,
|
||||
};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
@@ -49,7 +48,8 @@ impl NumberOfPointsDial {
|
||||
self.handle_state == NumberOfPointsDialState::Dragging
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, responses, .. } = ctx;
|
||||
match &self.handle_state {
|
||||
NumberOfPointsDialState::Inactive => {
|
||||
// Star
|
||||
@@ -97,7 +97,9 @@ impl NumberOfPointsDial {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, document: &DocumentMessageHandler, layer: Option<LayerNodeIdentifier>, shape_editor: &mut &mut ShapeState, mouse_position: DVec2, overlay_context: &mut OverlayContext) {
|
||||
pub fn overlays(&self, layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
let GizmoContext { document, shape_editor, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
NumberOfPointsDialState::Inactive => {
|
||||
let Some(layer) = layer else { return };
|
||||
@@ -188,7 +190,9 @@ impl NumberOfPointsDial {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_number_of_sides(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
||||
pub fn update_number_of_sides(&self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, input, responses, .. } = ctx;
|
||||
|
||||
let delta = input.mouse.position - drag_start;
|
||||
let sign = (input.mouse.position.x - drag_start.x).signum();
|
||||
let net_delta = (delta.length() / 25.).round() * sign;
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
use crate::consts::GIZMO_HIDE_THRESHOLD;
|
||||
use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD};
|
||||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector};
|
||||
use crate::messages::prelude::FrontendMessage;
|
||||
use crate::messages::prelude::Responses;
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::prelude::{DocumentMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{draw_snapping_ticks, extract_polygon_parameters, polygon_outline, polygon_vertex_position, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, draw_snapping_ticks, extract_polygon_parameters, polygon_outline, polygon_vertex_position, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{extract_star_parameters, star_vertex_position};
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::{FRAC_1_SQRT_2, FRAC_PI_4, PI, SQRT_2};
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
@@ -54,7 +52,8 @@ impl PointRadiusHandle {
|
||||
self.handle_state = state;
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, responses, .. } = ctx;
|
||||
match &self.handle_state {
|
||||
PointRadiusHandleState::Inactive => {
|
||||
// Draw the point handle gizmo for the star shape
|
||||
@@ -142,7 +141,9 @@ impl PointRadiusHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
pub fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
let GizmoContext { document, input, .. } = ctx;
|
||||
|
||||
match &self.handle_state {
|
||||
PointRadiusHandleState::Inactive => {
|
||||
let Some(layer) = selected_star_layer else { return };
|
||||
@@ -411,7 +412,9 @@ impl PointRadiusHandle {
|
||||
.map(|(i, rad)| (i, *rad - original_radius))
|
||||
}
|
||||
|
||||
pub fn update_inner_radius(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
||||
pub fn update_inner_radius(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, responses, input, .. } = ctx;
|
||||
|
||||
let Some(layer) = self.layer else { return };
|
||||
|
||||
let Some(node_id) = graph_modification_utils::get_star_id(layer, &document.network_interface).or(graph_modification_utils::get_polygon_id(layer, &document.network_interface)) else {
|
||||
|
||||
@@ -3,9 +3,8 @@ use crate::messages::message::Message;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||
use crate::messages::prelude::DocumentMessageHandler;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{arc_end_points, calculate_arc_text_transform, extract_arc_parameters, format_rounded};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, arc_end_points, calculate_arc_text_transform, extract_arc_parameters, format_rounded};
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
@@ -56,7 +55,9 @@ impl SweepAngleGizmo {
|
||||
self.handle_state == SweepAngleGizmoState::Dragging || self.handle_state == SweepAngleGizmoState::Snapped
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2) {
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
|
||||
if self.handle_state == SweepAngleGizmoState::Inactive {
|
||||
let Some((start, end)) = arc_end_points(Some(layer), document) else { return };
|
||||
let Some((_, start_angle, sweep_angle, _)) = extract_arc_parameters(Some(layer), document) else {
|
||||
@@ -92,14 +93,9 @@ impl SweepAngleGizmo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(
|
||||
&self,
|
||||
selected_arc_layer: Option<LayerNodeIdentifier>,
|
||||
document: &DocumentMessageHandler,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
_mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
pub fn overlays(&self, selected_arc_layer: Option<LayerNodeIdentifier>, _mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
|
||||
let tilt_offset = document.document_ptz.unmodified_tilt();
|
||||
|
||||
match self.handle_state {
|
||||
@@ -183,7 +179,9 @@ impl SweepAngleGizmo {
|
||||
overlay_context.arc_sweep_angle(offset_angle, angle, final_point, bold_radius, center, &text, transform);
|
||||
}
|
||||
|
||||
pub fn update_arc(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
pub fn update_arc(&mut self, ctx: &mut GizmoContext) {
|
||||
let GizmoContext { document, input, responses, .. } = ctx;
|
||||
|
||||
let Some(layer) = self.layer else { return };
|
||||
let Some((_, current_start_angle, current_sweep_angle, _)) = extract_arc_parameters(Some(layer), document) else {
|
||||
return;
|
||||
|
||||
@@ -367,6 +367,10 @@ pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text")
|
||||
}
|
||||
|
||||
pub fn get_circular_repeat(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Circular Repeat")
|
||||
}
|
||||
|
||||
/// Gets properties from the Text node
|
||||
pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig, bool)> {
|
||||
let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?;
|
||||
|
||||
@@ -1,10 +1,60 @@
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::extract_circular_repeat_parameters;
|
||||
use crate::messages::tool::common_functionality::gizmos::operation_gizmos::count_gizmos::{RepeatCountDial, RepeatCountDialState};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeGizmoHandler, extract_circular_repeat_parameters};
|
||||
use crate::messages::tool::tool_messages::operation_tool::{OperationToolData, OperationToolFsmState};
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CircularRepeatGizmoHandler {
|
||||
count_dial: RepeatCountDial,
|
||||
}
|
||||
|
||||
impl CircularRepeatGizmoHandler {
|
||||
pub fn new() -> Self {
|
||||
Self { ..Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandler for CircularRepeatGizmoHandler {
|
||||
fn handle_state(&mut self, selected_shape_layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.count_dial.handle_actions(selected_shape_layer, mouse_position, ctx);
|
||||
}
|
||||
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
self.count_dial.is_hovering()
|
||||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
if self.count_dial.is_hovering() {
|
||||
self.count_dial.update_state(RepeatCountDialState::Dragging);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if self.count_dial.is_dragging() {
|
||||
self.count_dial.update_number_of_sides(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if self.count_dial.is_dragging() {
|
||||
self.count_dial.overlays(None, mouse_position, ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(&self, selected_shape_layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
self.count_dial.overlays(selected_shape_layer, mouse_position, ctx, overlay_context);
|
||||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
None
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CircularRepeatOperation;
|
||||
|
||||
@@ -77,9 +127,7 @@ impl CircularRepeatOperation {
|
||||
for (layer, initial_radius) in &tool_data.circular_operation_data.layers_dragging {
|
||||
// If the layer’s sign differs from the clicked layer, invert delta to preserve consistent in/out dragging behavior
|
||||
|
||||
let Some((angle, _, count)) = extract_circular_repeat_parameters(Some(*layer), document) else {
|
||||
return;
|
||||
};
|
||||
let (angle, _, count) = extract_circular_repeat_parameters(Some(*layer), document).unwrap_or((0.0, 0.0, 6));
|
||||
|
||||
let new_radius = if initial_radius.signum() == clicked_radius.signum() {
|
||||
*initial_radius + delta
|
||||
@@ -107,25 +155,12 @@ impl CircularRepeatOperation {
|
||||
) {
|
||||
match tool_state {
|
||||
OperationToolFsmState::Ready => {
|
||||
// Draw overlays for all selected layers
|
||||
for layer in document.network_interface.selected_nodes().selected_layers(document.metadata()) {
|
||||
Self::draw_layer_overlay(layer, document, input, overlay_context)
|
||||
}
|
||||
|
||||
// Also highlight the hovered layer if it’s not selected
|
||||
if let Some(layer) = document.click(&input) {
|
||||
Self::draw_layer_overlay(layer, document, input, overlay_context);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// While dragging, only draw overlays for the layers being modified
|
||||
for layer in tool_data.circular_operation_data.layers_dragging.iter().map(|(l, _)| l) {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(*layer) else { continue };
|
||||
let viewport = document.metadata().transform_to_viewport(*layer);
|
||||
|
||||
overlay_context.outline_vector(&vector, viewport);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,11 +168,11 @@ impl CircularRepeatOperation {
|
||||
if let Some(vector) = document.network_interface.compute_modified_vector(layer) {
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
|
||||
// Show a small circle if the mouse is near the repeat center
|
||||
if center.distance(input.mouse.position) < 5. {
|
||||
overlay_context.circle(center, 3., None, None);
|
||||
}
|
||||
overlay_context.outline_vector(&vector, viewport);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ use super::shape_utility::ShapeToolModifierKey;
|
||||
use super::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::sweep_angle_gizmo::{SweepAngleGizmo, SweepAngleGizmoState};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, arc_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeGizmoHandler, arc_outline};
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::NodeInput;
|
||||
@@ -28,9 +29,9 @@ impl ArcGizmoHandler {
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandler for ArcGizmoHandler {
|
||||
fn handle_state(&mut self, selected_shape_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.sweep_angle_gizmo.handle_actions(selected_shape_layer, document, mouse_position);
|
||||
self.arc_radius_handle.handle_actions(selected_shape_layer, document, mouse_position, responses);
|
||||
fn handle_state(&mut self, selected_shape_layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.sweep_angle_gizmo.handle_actions(selected_shape_layer, mouse_position, ctx);
|
||||
self.arc_radius_handle.handle_actions(selected_shape_layer, mouse_position, ctx);
|
||||
}
|
||||
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
@@ -54,61 +55,46 @@ impl ShapeGizmoHandler for ArcGizmoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if self.sweep_angle_gizmo.is_dragging_or_snapped() {
|
||||
self.sweep_angle_gizmo.update_arc(document, input, responses);
|
||||
self.sweep_angle_gizmo.update_arc(ctx);
|
||||
}
|
||||
|
||||
if self.arc_radius_handle.is_dragging() {
|
||||
self.arc_radius_handle.update_inner_radius(document, input, responses, drag_start);
|
||||
self.arc_radius_handle.update_inner_radius(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
_shape_editor: &mut &mut crate::messages::tool::common_functionality::shape_editor::ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut crate::messages::portfolio::document::overlays::utility_types::OverlayContext,
|
||||
) {
|
||||
fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if self.sweep_angle_gizmo.is_dragging_or_snapped() {
|
||||
self.sweep_angle_gizmo.overlays(None, document, input, mouse_position, overlay_context);
|
||||
arc_outline(self.sweep_angle_gizmo.layer, document, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(None, mouse_position, ctx, overlay_context);
|
||||
arc_outline(self.sweep_angle_gizmo.layer, ctx.document, overlay_context);
|
||||
}
|
||||
|
||||
if self.arc_radius_handle.is_dragging() {
|
||||
self.sweep_angle_gizmo.overlays(self.arc_radius_handle.layer, document, input, mouse_position, overlay_context);
|
||||
self.arc_radius_handle.overlays(document, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(self.arc_radius_handle.layer, mouse_position, ctx, overlay_context);
|
||||
self.arc_radius_handle.overlays(ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
selected_shape_layer: Option<LayerNodeIdentifier>,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
_shape_editor: &mut &mut crate::messages::tool::common_functionality::shape_editor::ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut crate::messages::portfolio::document::overlays::utility_types::OverlayContext,
|
||||
) {
|
||||
fn overlays(&self, selected_shape_layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
// If hovering over both the gizmos give priority to sweep angle gizmo
|
||||
if self.sweep_angle_gizmo.hovered() && self.arc_radius_handle.hovered() {
|
||||
self.sweep_angle_gizmo.overlays(selected_shape_layer, document, input, mouse_position, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(selected_shape_layer, mouse_position, ctx, overlay_context);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.arc_radius_handle.hovered() {
|
||||
let layer = self.arc_radius_handle.layer;
|
||||
|
||||
self.arc_radius_handle.overlays(document, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(layer, document, input, mouse_position, overlay_context);
|
||||
self.arc_radius_handle.overlays(ctx, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(layer, mouse_position, ctx, overlay_context);
|
||||
}
|
||||
|
||||
self.sweep_angle_gizmo.overlays(selected_shape_layer, document, input, mouse_position, overlay_context);
|
||||
self.arc_radius_handle.overlays(document, overlay_context);
|
||||
self.sweep_angle_gizmo.overlays(selected_shape_layer, mouse_position, ctx, overlay_context);
|
||||
self.arc_radius_handle.overlays(ctx, overlay_context);
|
||||
|
||||
arc_outline(selected_shape_layer.or(self.sweep_angle_gizmo.layer), document, overlay_context);
|
||||
arc_outline(selected_shape_layer.or(self.sweep_angle_gizmo.layer), ctx.document, overlay_context);
|
||||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
|
||||
@@ -5,8 +5,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, ShapeToolModifierKey};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeGizmoHandler, ShapeToolModifierKey};
|
||||
use crate::messages::tool::tool_messages::shape_tool::ShapeToolData;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
@@ -23,8 +22,8 @@ impl ShapeGizmoHandler for CircleGizmoHandler {
|
||||
self.circle_radius_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_circle_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.circle_radius_handle.handle_actions(selected_circle_layer, document, mouse_position, responses);
|
||||
fn handle_state(&mut self, selected_circle_layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.circle_radius_handle.handle_actions(selected_circle_layer, mouse_position, ctx);
|
||||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
@@ -33,34 +32,19 @@ impl ShapeGizmoHandler for CircleGizmoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if self.circle_radius_handle.is_dragging() {
|
||||
self.circle_radius_handle.update_inner_radius(document, input, responses, drag_start);
|
||||
self.circle_radius_handle.update_inner_radius(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
_selected_circle_layer: Option<LayerNodeIdentifier>,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
_shape_editor: &mut &mut ShapeState,
|
||||
_mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
self.circle_radius_handle.overlays(document, overlay_context);
|
||||
fn overlays(&self, _selected_circle_layer: Option<LayerNodeIdentifier>, _mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
self.circle_radius_handle.overlays(ctx, overlay_context);
|
||||
}
|
||||
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
_shape_editor: &mut &mut ShapeState,
|
||||
_mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
fn dragging_overlays(&self, _mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if self.circle_radius_handle.is_dragging() {
|
||||
self.circle_radius_handle.overlays(document, overlay_context);
|
||||
self.circle_radius_handle.overlays(ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::PointRadiusHandle;
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::PointRadiusHandleState;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::GizmoContext;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::ShapeGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::polygon_outline;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
@@ -31,9 +31,9 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
|
||||
self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.number_of_points_dial.handle_actions(selected_star_layer, mouse_position, document, responses);
|
||||
self.point_radius_handle.handle_actions(selected_star_layer, document, mouse_position, responses);
|
||||
fn handle_state(&mut self, selected_polygon_layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.number_of_points_dial.handle_actions(selected_polygon_layer, mouse_position, ctx);
|
||||
self.point_radius_handle.handle_actions(selected_polygon_layer, mouse_position, ctx);
|
||||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
@@ -47,45 +47,31 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if self.number_of_points_dial.is_dragging() {
|
||||
self.number_of_points_dial.update_number_of_sides(document, input, responses, drag_start);
|
||||
self.number_of_points_dial.update_number_of_sides(drag_start, ctx);
|
||||
}
|
||||
|
||||
if self.point_radius_handle.is_dragging_or_snapped() {
|
||||
self.point_radius_handle.update_inner_radius(document, input, responses, drag_start);
|
||||
self.point_radius_handle.update_inner_radius(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
selected_polygon_layer: Option<LayerNodeIdentifier>,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
self.number_of_points_dial.overlays(document, selected_polygon_layer, shape_editor, mouse_position, overlay_context);
|
||||
self.point_radius_handle.overlays(selected_polygon_layer, document, input, overlay_context);
|
||||
fn overlays(&self, selected_polygon_layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
self.number_of_points_dial.overlays(selected_polygon_layer, mouse_position, ctx, overlay_context);
|
||||
self.point_radius_handle.overlays(selected_polygon_layer, ctx, overlay_context);
|
||||
|
||||
let GizmoContext { document, .. } = ctx;
|
||||
polygon_outline(selected_polygon_layer, document, overlay_context);
|
||||
}
|
||||
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if self.number_of_points_dial.is_dragging() {
|
||||
self.number_of_points_dial.overlays(document, None, shape_editor, mouse_position, overlay_context);
|
||||
self.number_of_points_dial.overlays(None, mouse_position, ctx, overlay_context);
|
||||
}
|
||||
|
||||
if self.point_radius_handle.is_dragging_or_snapped() {
|
||||
self.point_radius_handle.overlays(None, document, input, overlay_context);
|
||||
self.point_radius_handle.overlays(None, ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,13 +79,20 @@ impl ShapeType {
|
||||
|
||||
pub type ShapeToolModifierKey = [Key; 3];
|
||||
|
||||
pub struct GizmoContext<'a> {
|
||||
pub document: &'a DocumentMessageHandler,
|
||||
pub input: &'a InputPreprocessorMessageHandler,
|
||||
pub responses: &'a mut VecDeque<Message>,
|
||||
pub shape_editor: &'a mut ShapeState,
|
||||
}
|
||||
|
||||
/// The `ShapeGizmoHandler` trait defines the interactive behavior and overlay logic for shape-specific tools in the editor.
|
||||
/// A gizmo is a visual handle or control point used to manipulate a shape's properties (e.g., number of sides, radius, angle).
|
||||
pub trait ShapeGizmoHandler {
|
||||
/// Called every frame to update the gizmo's interaction state based on the mouse position and selection.
|
||||
///
|
||||
/// This includes detecting hover states and preparing interaction flags or visual feedback (e.g., highlighting a hovered handle).
|
||||
fn handle_state(&mut self, selected_shape_layers: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>);
|
||||
fn handle_state(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext);
|
||||
|
||||
/// Called when a mouse click occurs over the canvas and a gizmo handle is hovered.
|
||||
///
|
||||
@@ -96,32 +103,17 @@ pub trait ShapeGizmoHandler {
|
||||
/// Called during a drag interaction to update the shape's parameters in real time.
|
||||
///
|
||||
/// For example, a handle might calculate the distance from the drag start to determine a new radius or update the number of points.
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>);
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext);
|
||||
|
||||
/// Draws the static or hover-dependent overlays associated with the gizmo.
|
||||
///
|
||||
/// These overlays include visual indicators like shape outlines, control points, and hover highlights.
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
selected_shape_layers: Option<LayerNodeIdentifier>,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
);
|
||||
fn overlays(&self, selected_shape_layers: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext);
|
||||
|
||||
/// Draws overlays specifically during a drag operation.
|
||||
///
|
||||
/// Used to give real-time visual feedback based on drag progress, such as showing the updated shape preview or snapping guides.
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
);
|
||||
fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext);
|
||||
|
||||
/// Returns `true` if any handle or control point in the gizmo is currently being hovered.
|
||||
fn is_any_gizmo_hovered(&self) -> bool;
|
||||
|
||||
@@ -8,8 +8,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Inp
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::number_of_points_dial::{NumberOfPointsDial, NumberOfPointsDialState};
|
||||
use crate::messages::tool::common_functionality::gizmos::shape_gizmos::point_radius_handle::{PointRadiusHandle, PointRadiusHandleState};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, star_outline};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeGizmoHandler, star_outline};
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use core::f64;
|
||||
use glam::DAffine2;
|
||||
@@ -28,9 +27,9 @@ impl ShapeGizmoHandler for StarGizmoHandler {
|
||||
self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.number_of_points_dial.handle_actions(selected_star_layer, mouse_position, document, responses);
|
||||
self.point_radius_handle.handle_actions(selected_star_layer, document, mouse_position, responses);
|
||||
fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, ctx: &mut GizmoContext) {
|
||||
self.number_of_points_dial.handle_actions(selected_star_layer, mouse_position, ctx);
|
||||
self.point_radius_handle.handle_actions(selected_star_layer, mouse_position, ctx);
|
||||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
@@ -44,45 +43,30 @@ impl ShapeGizmoHandler for StarGizmoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
fn handle_update(&mut self, drag_start: DVec2, ctx: &mut GizmoContext) {
|
||||
if self.number_of_points_dial.is_dragging() {
|
||||
self.number_of_points_dial.update_number_of_sides(document, input, responses, drag_start);
|
||||
self.number_of_points_dial.update_number_of_sides(drag_start, ctx);
|
||||
}
|
||||
|
||||
if self.point_radius_handle.is_dragging_or_snapped() {
|
||||
self.point_radius_handle.update_inner_radius(document, input, responses, drag_start);
|
||||
self.point_radius_handle.update_inner_radius(drag_start, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
selected_star_layer: Option<LayerNodeIdentifier>,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
self.number_of_points_dial.overlays(document, selected_star_layer, shape_editor, mouse_position, overlay_context);
|
||||
self.point_radius_handle.overlays(selected_star_layer, document, input, overlay_context);
|
||||
fn overlays(&self, selected_star_layer: Option<LayerNodeIdentifier>, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
self.number_of_points_dial.overlays(selected_star_layer, mouse_position, ctx, overlay_context);
|
||||
self.point_radius_handle.overlays(selected_star_layer, ctx, overlay_context);
|
||||
|
||||
star_outline(selected_star_layer, document, overlay_context);
|
||||
star_outline(selected_star_layer, ctx.document, overlay_context);
|
||||
}
|
||||
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
fn dragging_overlays(&self, mouse_position: DVec2, ctx: &mut GizmoContext, overlay_context: &mut OverlayContext) {
|
||||
if self.number_of_points_dial.is_dragging() {
|
||||
self.number_of_points_dial.overlays(document, None, shape_editor, mouse_position, overlay_context);
|
||||
self.number_of_points_dial.overlays(None, mouse_position, ctx, overlay_context);
|
||||
}
|
||||
|
||||
if self.point_radius_handle.is_dragging_or_snapped() {
|
||||
self.point_radius_handle.overlays(None, document, input, overlay_context);
|
||||
self.point_radius_handle.overlays(None, ctx, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use super::tool_prelude::*;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoManager;
|
||||
use crate::messages::tool::common_functionality::operations::circular_repeat::{CircularRepeatOperation, CircularRepeatOperationData};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::GizmoContext;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||
pub enum OperationType {
|
||||
@@ -52,6 +55,7 @@ pub enum OperationToolMessage {
|
||||
pub enum OperationToolFsmState {
|
||||
#[default]
|
||||
Ready,
|
||||
ModifyingGizmo,
|
||||
Drawing,
|
||||
}
|
||||
|
||||
@@ -124,7 +128,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Oper
|
||||
Confirm,
|
||||
Abort,
|
||||
),
|
||||
OperationToolFsmState::Drawing => actions!(OperationToolMessageDiscriminant;
|
||||
OperationToolFsmState::Drawing | OperationToolFsmState::ModifyingGizmo => actions!(OperationToolMessageDiscriminant;
|
||||
DragStop,
|
||||
PointerMove,
|
||||
Confirm,
|
||||
@@ -151,12 +155,24 @@ impl ToolTransition for OperationTool {
|
||||
pub struct OperationToolData {
|
||||
pub drag_start: DVec2,
|
||||
pub circular_operation_data: CircularRepeatOperationData,
|
||||
gizmo_manager: GizmoManager,
|
||||
}
|
||||
|
||||
impl OperationToolData {
|
||||
fn cleanup(&mut self) {
|
||||
CircularRepeatOperation::cleanup(self);
|
||||
}
|
||||
|
||||
fn common_overlays(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
|
||||
outline_layer(layer, document, overlay_context);
|
||||
|
||||
let Some(hovered_layer) = document.click(input) else { continue };
|
||||
if hovered_layer != layer {
|
||||
outline_layer(hovered_layer, document, overlay_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fsm for OperationToolFsmState {
|
||||
@@ -171,19 +187,37 @@ impl Fsm for OperationToolFsmState {
|
||||
tool_options: &Self::ToolOptions,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) -> Self {
|
||||
let ToolActionMessageContext { document, input, .. } = tool_action_data;
|
||||
let ToolActionMessageContext { document, input, shape_editor, .. } = tool_action_data;
|
||||
|
||||
let mut ctx = GizmoContext {
|
||||
document,
|
||||
input,
|
||||
responses,
|
||||
shape_editor,
|
||||
};
|
||||
|
||||
let ToolMessage::Operation(event) = event else { return self };
|
||||
match (self, event) {
|
||||
(_, OperationToolMessage::Overlays { context: mut overlay_context }) => {
|
||||
match tool_options.operation_type {
|
||||
OperationType::CircularRepeat => CircularRepeatOperation::overlays(&self, tool_data, document, input, &mut overlay_context),
|
||||
_ => {}
|
||||
if matches!(self, OperationToolFsmState::Ready) {
|
||||
tool_data.gizmo_manager.handle_operation_actions(input.mouse.position, &mut ctx);
|
||||
tool_data.gizmo_manager.overlays(input.mouse.position, &mut ctx, &mut overlay_context);
|
||||
CircularRepeatOperation::overlays(&self, tool_data, document, input, &mut overlay_context);
|
||||
}
|
||||
|
||||
if matches!(self, OperationToolFsmState::ModifyingGizmo) {
|
||||
tool_data.gizmo_manager.overlays(input.mouse.position, &mut ctx, &mut overlay_context);
|
||||
}
|
||||
|
||||
tool_data.common_overlays(document, input, &mut overlay_context);
|
||||
|
||||
self
|
||||
}
|
||||
(OperationToolFsmState::Ready, OperationToolMessage::DragStart) => {
|
||||
if tool_data.gizmo_manager.handle_click() {
|
||||
tool_data.drag_start = input.mouse.position;
|
||||
return OperationToolFsmState::ModifyingGizmo;
|
||||
}
|
||||
match tool_options.operation_type {
|
||||
OperationType::CircularRepeat => {
|
||||
CircularRepeatOperation::create_node(tool_data, document, responses, input);
|
||||
@@ -193,7 +227,7 @@ impl Fsm for OperationToolFsmState {
|
||||
|
||||
OperationToolFsmState::Drawing
|
||||
}
|
||||
(OperationToolFsmState::Drawing, OperationToolMessage::DragStop) => {
|
||||
(OperationToolFsmState::Drawing | OperationToolFsmState::ModifyingGizmo, OperationToolMessage::DragStop) => {
|
||||
if tool_data.drag_start.distance(input.mouse.position) < 5. {
|
||||
responses.add(DocumentMessage::AbortTransaction);
|
||||
};
|
||||
@@ -216,6 +250,12 @@ impl Fsm for OperationToolFsmState {
|
||||
|
||||
OperationToolFsmState::Drawing
|
||||
}
|
||||
(OperationToolFsmState::ModifyingGizmo, OperationToolMessage::PointerMove) => {
|
||||
// Don't add the repeat node unless dragging more that 5 px
|
||||
tool_data.gizmo_manager.handle_update(tool_data.drag_start, &mut ctx);
|
||||
|
||||
OperationToolFsmState::ModifyingGizmo
|
||||
}
|
||||
(OperationToolFsmState::Drawing, OperationToolMessage::IncreaseCount) => {
|
||||
match tool_options.operation_type {
|
||||
OperationType::CircularRepeat => CircularRepeatOperation::increase_decrease_count(tool_data, true, document, responses),
|
||||
@@ -237,7 +277,7 @@ impl Fsm for OperationToolFsmState {
|
||||
|
||||
(OperationToolFsmState::Drawing, OperationToolMessage::PointerOutsideViewport) => OperationToolFsmState::Drawing,
|
||||
(state, OperationToolMessage::PointerOutsideViewport) => state,
|
||||
(OperationToolFsmState::Drawing, OperationToolMessage::Abort) => {
|
||||
(OperationToolFsmState::Drawing | OperationToolFsmState::ModifyingGizmo, OperationToolMessage::Abort) => {
|
||||
responses.add(DocumentMessage::AbortTransaction);
|
||||
OperationToolFsmState::Ready
|
||||
}
|
||||
@@ -248,11 +288,11 @@ impl Fsm for OperationToolFsmState {
|
||||
|
||||
fn update_hints(&self, responses: &mut VecDeque<Message>) {
|
||||
let hint_data = match self {
|
||||
OperationToolFsmState::Ready => HintData(vec![HintGroup(vec![
|
||||
OperationToolFsmState::Ready | OperationToolFsmState::ModifyingGizmo => HintData(vec![HintGroup(vec![
|
||||
HintInfo::mouse(MouseMotion::Lmb, "Draw Spline"),
|
||||
HintInfo::keys([Key::Shift], "Append to Selected Layer").prepend_plus(),
|
||||
])]),
|
||||
OperationToolFsmState::Drawing => HintData(vec![
|
||||
_ => HintData(vec![
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
|
||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Extend Spline")]),
|
||||
HintGroup(vec![HintInfo::keys([Key::Enter], "End Spline")]),
|
||||
@@ -266,3 +306,9 @@ impl Fsm for OperationToolFsmState {
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
|
||||
}
|
||||
}
|
||||
|
||||
fn outline_layer(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else { return };
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
overlay_context.outline_vector(&vector, viewport);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::messages::tool::common_functionality::shapes::arc_shape::Arc;
|
||||
use crate::messages::tool::common_functionality::shapes::circle_shape::Circle;
|
||||
use crate::messages::tool::common_functionality::shapes::line_shape::{LineToolData, clicked_on_line_endpoints};
|
||||
use crate::messages::tool::common_functionality::shapes::polygon_shape::Polygon;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeToolModifierKey, ShapeType, anchor_overlays, transform_cage_overlays};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{GizmoContext, ShapeToolModifierKey, ShapeType, anchor_overlays, transform_cage_overlays};
|
||||
use crate::messages::tool::common_functionality::shapes::star_shape::Star;
|
||||
use crate::messages::tool::common_functionality::shapes::{Ellipse, Line, Rectangle};
|
||||
use crate::messages::tool::common_functionality::snapping::{self, SnapCandidatePoint, SnapData, SnapTypeConfiguration};
|
||||
@@ -477,12 +477,24 @@ impl Fsm for ShapeToolFsmState {
|
||||
.unwrap_or(input.mouse.position);
|
||||
|
||||
if matches!(self, Self::Ready(_)) && !input.keyboard.key(Key::Control) {
|
||||
tool_data.gizmo_manager.handle_actions(mouse_position, document, responses);
|
||||
tool_data.gizmo_manager.overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
let mut ctx = GizmoContext {
|
||||
document,
|
||||
input,
|
||||
responses,
|
||||
shape_editor,
|
||||
};
|
||||
tool_data.gizmo_manager.handle_actions(mouse_position, &mut ctx);
|
||||
tool_data.gizmo_manager.overlays(mouse_position, &mut ctx, &mut overlay_context);
|
||||
}
|
||||
|
||||
if matches!(self, ShapeToolFsmState::ModifyingGizmo) && !input.keyboard.key(Key::Control) {
|
||||
tool_data.gizmo_manager.dragging_overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
let mut ctx = GizmoContext {
|
||||
document,
|
||||
input,
|
||||
responses,
|
||||
shape_editor,
|
||||
};
|
||||
tool_data.gizmo_manager.dragging_overlays(mouse_position, &mut ctx, &mut overlay_context);
|
||||
let cursor = tool_data.gizmo_manager.mouse_cursor_icon().unwrap_or(MouseCursorIcon::Crosshair);
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
@@ -541,9 +553,15 @@ impl Fsm for ShapeToolFsmState {
|
||||
}
|
||||
|
||||
if matches!(self, ShapeToolFsmState::Drawing(_) | ShapeToolFsmState::DraggingLineEndpoints) {
|
||||
let mut ctx = GizmoContext {
|
||||
document,
|
||||
input,
|
||||
responses,
|
||||
shape_editor,
|
||||
};
|
||||
Line::overlays(document, tool_data, &mut overlay_context);
|
||||
if tool_options.shape_type == ShapeType::Circle {
|
||||
tool_data.gizmo_manager.overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
tool_data.gizmo_manager.overlays(mouse_position, &mut ctx, &mut overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,7 +840,13 @@ impl Fsm for ShapeToolFsmState {
|
||||
self
|
||||
}
|
||||
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove { .. }) => {
|
||||
tool_data.gizmo_manager.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
|
||||
let mut ctx = GizmoContext {
|
||||
document,
|
||||
input,
|
||||
responses,
|
||||
shape_editor,
|
||||
};
|
||||
tool_data.gizmo_manager.handle_update(tool_data.data.viewport_drag_start(document), &mut ctx);
|
||||
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user