mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
Merge 9d34664989 into e73e524f3d
This commit is contained in:
commit
b90fd49519
8 changed files with 372 additions and 8 deletions
|
|
@ -10,6 +10,7 @@ use crate::messages::tool::common_functionality::shapes::circle_shape::CircleGiz
|
|||
use crate::messages::tool::common_functionality::shapes::grid_shape::GridGizmoHandler;
|
||||
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::spiral_shape::SpiralGizmoHandler;
|
||||
use crate::messages::tool::common_functionality::shapes::star_shape::StarGizmoHandler;
|
||||
use glam::DVec2;
|
||||
use std::collections::VecDeque;
|
||||
|
|
@ -30,6 +31,7 @@ pub enum ShapeGizmoHandlers {
|
|||
Arc(ArcGizmoHandler),
|
||||
Circle(CircleGizmoHandler),
|
||||
Grid(GridGizmoHandler),
|
||||
Spiral(SpiralGizmoHandler),
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandlers {
|
||||
|
|
@ -42,6 +44,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(_) => "arc",
|
||||
Self::Circle(_) => "circle",
|
||||
Self::Grid(_) => "grid",
|
||||
Self::Spiral(_) => "spiral",
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
|
|
@ -51,6 +54,7 @@ impl ShapeGizmoHandlers {
|
|||
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::Spiral(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::Grid(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
|
|
@ -66,6 +70,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(h) => h.is_any_gizmo_hovered(),
|
||||
Self::Circle(h) => h.is_any_gizmo_hovered(),
|
||||
Self::Grid(h) => h.is_any_gizmo_hovered(),
|
||||
Self::Spiral(h) => h.is_any_gizmo_hovered(),
|
||||
Self::None => false,
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +83,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(h) => h.handle_click(),
|
||||
Self::Circle(h) => h.handle_click(),
|
||||
Self::Grid(h) => h.handle_click(),
|
||||
Self::Spiral(h) => h.handle_click(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,6 +96,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Circle(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Grid(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::Spiral(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +109,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(h) => h.cleanup(),
|
||||
Self::Circle(h) => h.cleanup(),
|
||||
Self::Grid(h) => h.cleanup(),
|
||||
Self::Spiral(h) => h.cleanup(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -122,6 +130,7 @@ impl ShapeGizmoHandlers {
|
|||
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::Grid(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Spiral(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -141,6 +150,7 @@ impl ShapeGizmoHandlers {
|
|||
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::Grid(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::Spiral(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -152,6 +162,7 @@ impl ShapeGizmoHandlers {
|
|||
Self::Arc(h) => h.mouse_cursor_icon(),
|
||||
Self::Circle(h) => h.mouse_cursor_icon(),
|
||||
Self::Grid(h) => h.mouse_cursor_icon(),
|
||||
Self::Spiral(h) => h.mouse_cursor_icon(),
|
||||
Self::None => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -200,6 +211,11 @@ impl GizmoManager {
|
|||
return Some(ShapeGizmoHandlers::Grid(GridGizmoHandler::default()));
|
||||
}
|
||||
|
||||
// Spiral
|
||||
if graph_modification_utils::get_spiral_id(layer, &document.network_interface).is_some() {
|
||||
return Some(ShapeGizmoHandlers::Spiral(SpiralGizmoHandler::default()));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ pub mod circle_arc_radius_handle;
|
|||
pub mod grid_rows_columns_gizmo;
|
||||
pub mod number_of_points_dial;
|
||||
pub mod point_radius_handle;
|
||||
pub mod spiral_turns_handle;
|
||||
pub mod sweep_angle_gizmo;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl NumberOfPointsDial {
|
|||
self.handle_state = state;
|
||||
}
|
||||
|
||||
pub fn is_hovering(&self) -> bool {
|
||||
pub fn hovered(&self) -> bool {
|
||||
self.handle_state == NumberOfPointsDialState::Hover
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,233 @@
|
|||
use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD};
|
||||
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, InputPreprocessorMessageHandler, 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_spiral_parameters;
|
||||
use crate::messages::tool::common_functionality::shapes::spiral_shape::calculate_spiral_endpoints;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::subpath::{calculate_b, spiral_point};
|
||||
use graphene_std::vector::misc::SpiralType;
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::TAU;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub enum GizmoType {
|
||||
#[default]
|
||||
None,
|
||||
Start,
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub enum SpiralTurnsState {
|
||||
#[default]
|
||||
Inactive,
|
||||
Hover,
|
||||
Dragging,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SpiralTurns {
|
||||
pub layer: Option<LayerNodeIdentifier>,
|
||||
pub handle_state: SpiralTurnsState,
|
||||
initial_turns: f64,
|
||||
initial_outer_radius: f64,
|
||||
initial_inner_radius: f64,
|
||||
initial_b: f64,
|
||||
initial_start_angle: f64,
|
||||
previous_mouse_position: DVec2,
|
||||
total_angle_delta: f64,
|
||||
gizmo_type: GizmoType,
|
||||
spiral_type: SpiralType,
|
||||
}
|
||||
|
||||
impl SpiralTurns {
|
||||
pub fn cleanup(&mut self) {
|
||||
self.handle_state = SpiralTurnsState::Inactive;
|
||||
self.total_angle_delta = 0.;
|
||||
self.gizmo_type = GizmoType::None;
|
||||
self.layer = None;
|
||||
}
|
||||
|
||||
pub fn update_state(&mut self, state: SpiralTurnsState) {
|
||||
self.handle_state = state;
|
||||
}
|
||||
|
||||
pub fn hovered(&self) -> bool {
|
||||
self.handle_state == SpiralTurnsState::Hover
|
||||
}
|
||||
|
||||
pub fn is_dragging(&self) -> bool {
|
||||
self.handle_state == SpiralTurnsState::Dragging
|
||||
}
|
||||
|
||||
pub fn store_initial_parameters(
|
||||
&mut self,
|
||||
layer: LayerNodeIdentifier,
|
||||
a: f64,
|
||||
turns: f64,
|
||||
outer_radius: f64,
|
||||
mouse_position: DVec2,
|
||||
start_angle: f64,
|
||||
gizmo_type: GizmoType,
|
||||
spiral_type: SpiralType,
|
||||
) {
|
||||
self.layer = Some(layer);
|
||||
self.initial_turns = turns;
|
||||
self.initial_b = calculate_b(a, turns, outer_radius, spiral_type);
|
||||
self.initial_inner_radius = a;
|
||||
self.initial_outer_radius = outer_radius;
|
||||
self.initial_start_angle = start_angle;
|
||||
self.previous_mouse_position = mouse_position;
|
||||
self.spiral_type = spiral_type;
|
||||
self.gizmo_type = gizmo_type;
|
||||
self.update_state(SpiralTurnsState::Hover);
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, _responses: &mut VecDeque<Message>) {
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
match &self.handle_state {
|
||||
SpiralTurnsState::Inactive => {
|
||||
// Archimedean
|
||||
if let Some((spiral_type, start_angle, inner_radius, outer_radius, turns, _)) = extract_spiral_parameters(layer, document) {
|
||||
let b = calculate_b(inner_radius, turns, outer_radius, spiral_type);
|
||||
let end_point = viewport.transform_point2(spiral_point(turns * TAU + start_angle.to_radians(), inner_radius, b, spiral_type));
|
||||
let start_point = viewport.transform_point2(spiral_point(0. + start_angle.to_radians(), inner_radius, b, spiral_type));
|
||||
|
||||
if mouse_position.distance(end_point) < POINT_RADIUS_HANDLE_SNAP_THRESHOLD {
|
||||
self.store_initial_parameters(layer, inner_radius, turns, outer_radius, mouse_position, start_angle, GizmoType::End, spiral_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if mouse_position.distance(start_point) < POINT_RADIUS_HANDLE_SNAP_THRESHOLD {
|
||||
self.store_initial_parameters(layer, inner_radius, turns, outer_radius, mouse_position, start_angle, GizmoType::Start, spiral_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
SpiralTurnsState::Hover | SpiralTurnsState::Dragging => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, document: &DocumentMessageHandler, layer: Option<LayerNodeIdentifier>, _shape_editor: &mut &mut ShapeState, _mouse_position: DVec2, overlay_context: &mut OverlayContext) {
|
||||
let Some(layer) = layer.or(self.layer) else { return };
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
match &self.handle_state {
|
||||
SpiralTurnsState::Inactive => {
|
||||
if let Some((p1, p2)) = calculate_spiral_endpoints(layer, document, viewport, 0.).zip(calculate_spiral_endpoints(layer, document, viewport, TAU)) {
|
||||
overlay_context.manipulator_handle(p1, false, None);
|
||||
overlay_context.manipulator_handle(p2, false, None);
|
||||
}
|
||||
}
|
||||
|
||||
SpiralTurnsState::Hover | SpiralTurnsState::Dragging => {
|
||||
// Is true only when hovered over the gizmo
|
||||
let selected = self.layer.is_some();
|
||||
|
||||
let angle = match self.gizmo_type {
|
||||
GizmoType::End => TAU,
|
||||
GizmoType::Start => 0.,
|
||||
GizmoType::None => return,
|
||||
};
|
||||
|
||||
if let Some(endpoint) = calculate_spiral_endpoints(layer, document, viewport, angle) {
|
||||
overlay_context.manipulator_handle(endpoint, selected, Some(COLOR_OVERLAY_RED));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_number_of_turns(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
use graphene_std::vector::generator_nodes::spiral::*;
|
||||
|
||||
let Some(layer) = self.layer else {
|
||||
return;
|
||||
};
|
||||
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
|
||||
let angle_delta = viewport
|
||||
.inverse()
|
||||
.transform_vector2(input.mouse.position - center)
|
||||
.angle_to(viewport.inverse().transform_vector2(self.previous_mouse_position - center))
|
||||
.to_degrees();
|
||||
|
||||
log::info!("{:?}", input.mouse.position);
|
||||
log::info!("{:?}", self.previous_mouse_position);
|
||||
|
||||
log::info!(
|
||||
"angle is {:?}",
|
||||
viewport
|
||||
.inverse()
|
||||
.transform_point2(input.mouse.position)
|
||||
.angle_to(viewport.inverse().transform_point2(self.previous_mouse_position))
|
||||
.to_degrees()
|
||||
);
|
||||
|
||||
// Increase the number of turns and outer radius in unison such that growth and tightness remain same
|
||||
let total_delta = self.total_angle_delta + angle_delta;
|
||||
|
||||
// Convert the total angle (in degrees) to number of full turns
|
||||
let turns_delta = total_delta / 360.;
|
||||
|
||||
// Calculate the new outer radius based on spiral type and turn change
|
||||
let outer_radius_change = match self.spiral_type {
|
||||
SpiralType::Archimedean => turns_delta * (self.initial_b) * TAU,
|
||||
SpiralType::Logarithmic => self.initial_outer_radius * ((self.initial_b * TAU * turns_delta).exp() - 1.),
|
||||
};
|
||||
|
||||
let Some(node_id) = graph_modification_utils::get_spiral_id(layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
match self.gizmo_type {
|
||||
GizmoType::Start => {
|
||||
let sign = -1.;
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, StartAngleInput::INDEX),
|
||||
input: NodeInput::value(TaggedValue::F64(self.initial_start_angle + total_delta), false),
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, TurnsInput::INDEX),
|
||||
input: NodeInput::value(TaggedValue::F64(self.initial_turns + turns_delta * sign), false),
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, OuterRadiusInput::INDEX),
|
||||
input: NodeInput::value(TaggedValue::F64(self.initial_outer_radius + outer_radius_change * sign), false),
|
||||
});
|
||||
}
|
||||
GizmoType::End => {
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, TurnsInput::INDEX),
|
||||
input: NodeInput::value(TaggedValue::F64(self.initial_turns + turns_delta), false),
|
||||
});
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, OuterRadiusInput::INDEX),
|
||||
input: NodeInput::value(TaggedValue::F64(self.initial_outer_radius + outer_radius_change), false),
|
||||
});
|
||||
}
|
||||
GizmoType::None => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
|
||||
self.total_angle_delta += angle_delta;
|
||||
self.previous_mouse_position = input.mouse.position;
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ pub struct PolygonGizmoHandler {
|
|||
|
||||
impl ShapeGizmoHandler for PolygonGizmoHandler {
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered()
|
||||
self.number_of_points_dial.hovered() || self.point_radius_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
|
|
@ -34,7 +34,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
|
|||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
if self.number_of_points_dial.is_hovering() {
|
||||
if self.number_of_points_dial.hovered() {
|
||||
self.number_of_points_dial.update_state(NumberOfPointsDialState::Dragging);
|
||||
return;
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ impl ShapeGizmoHandler for PolygonGizmoHandler {
|
|||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
if self.number_of_points_dial.is_dragging() || self.number_of_points_dial.is_hovering() {
|
||||
if self.number_of_points_dial.is_dragging() || self.number_of_points_dial.hovered() {
|
||||
return Some(MouseCursorIcon::EWResize);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use graph_craft::document::value::TaggedValue;
|
|||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::subpath::{self, Subpath};
|
||||
use graphene_std::vector::click_target::ClickTargetType;
|
||||
use graphene_std::vector::misc::{ArcType, GridType, dvec2_to_point};
|
||||
use graphene_std::vector::misc::{ArcType, GridType, SpiralType, dvec2_to_point};
|
||||
use kurbo::{BezPath, PathEl, Shape};
|
||||
use std::collections::VecDeque;
|
||||
use std::f64::consts::{PI, TAU};
|
||||
|
|
@ -243,6 +243,35 @@ pub fn extract_star_parameters(layer: Option<LayerNodeIdentifier>, document: &Do
|
|||
Some((sides, radius_1, radius_2))
|
||||
}
|
||||
|
||||
/// Extract the node input values of spiral.
|
||||
/// Returns an option of (spiral type, start angle, inner radius, outer radius, turns, angle resolution).
|
||||
pub fn extract_spiral_parameters(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<(SpiralType, f64, f64, f64, f64, f64)> {
|
||||
use graphene_std::vector::generator_nodes::spiral::*;
|
||||
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Spiral")?;
|
||||
|
||||
let (
|
||||
Some(&TaggedValue::SpiralType(spiral_type)),
|
||||
Some(&TaggedValue::F64(start_angle)),
|
||||
Some(&TaggedValue::F64(inner_radius)),
|
||||
Some(&TaggedValue::F64(outer_radius)),
|
||||
Some(&TaggedValue::F64(turns)),
|
||||
Some(&TaggedValue::F64(angle_resolution)),
|
||||
) = (
|
||||
node_inputs.get(SpiralTypeInput::INDEX)?.as_value(),
|
||||
node_inputs.get(StartAngleInput::INDEX)?.as_value(),
|
||||
node_inputs.get(InnerRadiusInput::INDEX)?.as_value(),
|
||||
node_inputs.get(OuterRadiusInput::INDEX)?.as_value(),
|
||||
node_inputs.get(TurnsInput::INDEX)?.as_value(),
|
||||
node_inputs.get(AngularResolutionInput::INDEX)?.as_value(),
|
||||
)
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some((spiral_type, start_angle, inner_radius, outer_radius, turns, angle_resolution))
|
||||
}
|
||||
|
||||
/// Extract the node input values of Polygon.
|
||||
/// Returns an option of (sides, radius).
|
||||
pub fn extract_polygon_parameters(layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) -> Option<(u32, f64)> {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
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::spiral_turns_handle::{SpiralTurns, SpiralTurnsState};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer};
|
||||
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::{ShapeGizmoHandler, extract_spiral_parameters};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapData, SnapTypeConfiguration};
|
||||
use crate::messages::tool::tool_messages::shape_tool::ShapeOptionsUpdate;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
|
|
@ -11,12 +15,82 @@ use glam::DAffine2;
|
|||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_std::NodeInputDecleration;
|
||||
use graphene_std::subpath::{calculate_b, spiral_point};
|
||||
use graphene_std::vector::misc::SpiralType;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Spiral;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SpiralGizmoHandler {
|
||||
turns_handle: SpiralTurns,
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandler for SpiralGizmoHandler {
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
self.turns_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_spiral_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.turns_handle.handle_actions(selected_spiral_layer, mouse_position, document, responses);
|
||||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
if self.turns_handle.hovered() {
|
||||
self.turns_handle.update_state(SpiralTurnsState::Dragging);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, _drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
if self.turns_handle.is_dragging() {
|
||||
self.turns_handle.update_number_of_turns(document, input, responses);
|
||||
}
|
||||
}
|
||||
|
||||
fn overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
selected_spiral_layer: Option<LayerNodeIdentifier>,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
if self.turns_handle.hovered() {
|
||||
self.turns_handle.overlays(document, selected_spiral_layer, shape_editor, mouse_position, overlay_context);
|
||||
return;
|
||||
}
|
||||
|
||||
self.turns_handle.overlays(document, selected_spiral_layer, shape_editor, mouse_position, overlay_context);
|
||||
}
|
||||
|
||||
fn dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
shape_editor: &mut &mut ShapeState,
|
||||
mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
if self.turns_handle.is_dragging() {
|
||||
self.turns_handle.overlays(document, None, shape_editor, mouse_position, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
if self.turns_handle.hovered() || self.turns_handle.is_dragging() {
|
||||
return Some(MouseCursorIcon::Default);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {
|
||||
self.turns_handle.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
impl Spiral {
|
||||
pub fn create_node(spiral_type: SpiralType, turns: f64) -> NodeTemplate {
|
||||
let inner_radius = match spiral_type {
|
||||
|
|
@ -121,3 +195,14 @@ impl Spiral {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_spiral_endpoints(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, viewport: DAffine2, theta: f64) -> Option<DVec2> {
|
||||
let Some((spiral_type, start_angle, a, outer_radius, turns, _)) = extract_spiral_parameters(layer, document) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let theta = turns * theta + start_angle.to_radians();
|
||||
let b = calculate_b(a, turns, outer_radius, spiral_type);
|
||||
|
||||
Some(viewport.transform_point2(spiral_point(theta, a, b, spiral_type)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub struct StarGizmoHandler {
|
|||
|
||||
impl ShapeGizmoHandler for StarGizmoHandler {
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered()
|
||||
self.number_of_points_dial.hovered() || self.point_radius_handle.hovered()
|
||||
}
|
||||
|
||||
fn handle_state(&mut self, selected_star_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
|
|
@ -34,7 +34,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
|
|||
}
|
||||
|
||||
fn handle_click(&mut self) {
|
||||
if self.number_of_points_dial.is_hovering() {
|
||||
if self.number_of_points_dial.hovered() {
|
||||
self.number_of_points_dial.update_state(NumberOfPointsDialState::Dragging);
|
||||
return;
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ impl ShapeGizmoHandler for StarGizmoHandler {
|
|||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
if self.number_of_points_dial.is_dragging() || self.number_of_points_dial.is_hovering() {
|
||||
if self.number_of_points_dial.is_dragging() || self.number_of_points_dial.hovered() {
|
||||
return Some(MouseCursorIcon::EWResize);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue