Skip to content

Spiral Turns Gizmo #2851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,9 @@ pub const AUTO_SAVE_TIMEOUT_SECONDS: u64 = 15;

// INPUT
pub const DOUBLE_CLICK_MILLISECONDS: u64 = 500;

/// SPIRAL NODE INPUT INDICES
pub const SPIRAL_TYPE_INDEX: usize = 1;
pub const SPIRAL_INNER_RADIUS: usize = 2;
pub const SPIRAL_OUTER_RADIUS_INDEX: usize = 3;
pub const SPIRAL_TURNS_INDEX: usize = 4;
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,7 @@ fn static_node_properties() -> NodeProperties {
map.insert("math_properties".to_string(), Box::new(node_properties::math_properties));
map.insert("rectangle_properties".to_string(), Box::new(node_properties::rectangle_properties));
map.insert("grid_properties".to_string(), Box::new(node_properties::grid_properties));
map.insert("spiral_properties".to_string(), Box::new(node_properties::spiral_properties));
map.insert("sample_polyline_properties".to_string(), Box::new(node_properties::sample_polyline_properties));
map.insert(
"identity_properties".to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use graphene_std::raster_types::{CPU, GPU, RasterDataTable};
use graphene_std::text::Font;
use graphene_std::transform::{Footprint, ReferencePoint};
use graphene_std::vector::VectorDataTable;
use graphene_std::vector::misc::GridType;
use graphene_std::vector::misc::{ArcType, MergeByDistanceAlgorithm};
use graphene_std::vector::misc::{CentroidType, PointSpacingType};
use graphene_std::vector::misc::{GridType, SpiralType};
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
use graphene_std::vector::style::{GradientType, PaintOrder, StrokeAlign, StrokeCap, StrokeJoin};
use graphene_std::{GraphicGroupTable, NodeInputDecleration};
Expand Down Expand Up @@ -1202,6 +1202,65 @@ pub(crate) fn grid_properties(node_id: NodeId, context: &mut NodePropertiesConte
widgets
}

pub(crate) fn spiral_properties(node_id: NodeId, context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
use graphene_std::vector::generator_nodes::spiral::*;

let spiral_type = enum_choice::<SpiralType>()
.for_socket(ParameterWidgetsInfo::new(node_id, SpiralTypeInput::INDEX, true, context))
.property_row();

let mut widgets = vec![spiral_type];

let document_node = match get_document_node(node_id, context) {
Ok(document_node) => document_node,
Err(err) => {
log::error!("Could not get document node in exposure_properties: {err}");
return Vec::new();
}
};

let Some(spiral_type_input) = document_node.inputs.get(SpiralTypeInput::INDEX) else {
log::warn!("A widget failed to be built because its node's input index is invalid.");
return vec![];
};
if let Some(&TaggedValue::SpiralType(spiral_type)) = spiral_type_input.as_non_exposed_value() {
match spiral_type {
SpiralType::Archimedean => {
let inner_radius = LayoutGroup::Row {
widgets: number_widget(ParameterWidgetsInfo::new(node_id, InnerRadiusInput::INDEX, true, context), NumberInput::default().min(0.).unit(" px")),
};

let outer_radius = LayoutGroup::Row {
widgets: number_widget(ParameterWidgetsInfo::new(node_id, OuterRadiusInput::INDEX, true, context), NumberInput::default().unit(" px")),
};

widgets.extend([inner_radius, outer_radius]);
}
SpiralType::Logarithmic => {
let inner_radius = LayoutGroup::Row {
widgets: number_widget(ParameterWidgetsInfo::new(node_id, InnerRadiusInput::INDEX, true, context), NumberInput::default().min(0.).unit(" px")),
};

let outer_radius = LayoutGroup::Row {
widgets: number_widget(ParameterWidgetsInfo::new(node_id, OuterRadiusInput::INDEX, true, context), NumberInput::default().min(0.1).unit(" px")),
};

widgets.extend([inner_radius, outer_radius]);
}
}
}

let turns = number_widget(ParameterWidgetsInfo::new(node_id, TurnsInput::INDEX, true, context), NumberInput::default().min(0.1));
let angle_offset = number_widget(
ParameterWidgetsInfo::new(node_id, AngleOffsetInput::INDEX, true, context),
NumberInput::default().min(0.1).max(180.).unit("°"),
);

widgets.extend([LayoutGroup::Row { widgets: turns }, LayoutGroup::Row { widgets: angle_offset }]);

widgets
}

pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SPACING: &str = "Use a point sampling density controlled by a distance between, or specific number of, points.";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_SEPARATION: &str = "Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled).";
pub(crate) const SAMPLE_POLYLINE_TOOLTIP_QUANTITY: &str = "Number of points to place along the path.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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::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;
Expand All @@ -23,6 +24,7 @@ pub enum ShapeGizmoHandlers {
None,
Star(StarGizmoHandler),
Polygon(PolygonGizmoHandler),
Spiral(SpiralGizmoHandler),
}

impl ShapeGizmoHandlers {
Expand All @@ -32,15 +34,17 @@ impl ShapeGizmoHandlers {
match self {
Self::Star(_) => "star",
Self::Polygon(_) => "polygon",
Self::Spiral(_) => "spiral",
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, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
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::Star(h) => h.handle_state(layer, mouse_position, document, input, responses),
Self::Polygon(h) => h.handle_state(layer, mouse_position, document, input, responses),
Self::Spiral(h) => h.handle_state(layer, mouse_position, document, input, responses),
Self::None => {}
}
}
Expand All @@ -50,6 +54,7 @@ impl ShapeGizmoHandlers {
match self {
Self::Star(h) => h.is_any_gizmo_hovered(),
Self::Polygon(h) => h.is_any_gizmo_hovered(),
Self::Spiral(h) => h.is_any_gizmo_hovered(),
Self::None => false,
}
}
Expand All @@ -59,6 +64,7 @@ impl ShapeGizmoHandlers {
match self {
Self::Star(h) => h.handle_click(),
Self::Polygon(h) => h.handle_click(),
Self::Spiral(h) => h.handle_click(),
Self::None => {}
}
}
Expand All @@ -68,6 +74,7 @@ impl ShapeGizmoHandlers {
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::Spiral(h) => h.handle_update(drag_start, document, input, responses),
Self::None => {}
}
}
Expand All @@ -77,6 +84,7 @@ impl ShapeGizmoHandlers {
match self {
Self::Star(h) => h.cleanup(),
Self::Polygon(h) => h.cleanup(),
Self::Spiral(h) => h.cleanup(),
Self::None => {}
}
}
Expand All @@ -94,6 +102,7 @@ impl ShapeGizmoHandlers {
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::Spiral(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
Self::None => {}
}
}
Expand All @@ -110,6 +119,7 @@ impl ShapeGizmoHandlers {
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::Spiral(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
Self::None => {}
}
}
Expand Down Expand Up @@ -147,6 +157,11 @@ impl GizmoManager {
return Some(ShapeGizmoHandlers::Polygon(PolygonGizmoHandler::default()));
}

// Spiral
if graph_modification_utils::get_spiral_id(layer, &document.network_interface).is_some() {
return Some(ShapeGizmoHandlers::Spiral(SpiralGizmoHandler::default()));
}

None
}

Expand All @@ -158,12 +173,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, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
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);
handler.handle_state(layer, mouse_position, document, input, responses);
let is_hovered = handler.is_any_gizmo_hovered();

if is_hovered {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod number_of_points_dial;
pub mod point_radius_handle;
pub mod spiral_turns_handle;
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -189,8 +189,8 @@ impl NumberOfPointsDial {
}

pub fn update_number_of_sides(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
let delta = input.mouse.position - document.metadata().document_to_viewport.transform_point2(drag_start);
let sign = (input.mouse.position.x - document.metadata().document_to_viewport.transform_point2(drag_start).x).signum();
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;

let Some(layer) = self.layer else { return };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,12 @@ impl PointRadiusHandle {
};

let viewport_transform = document.network_interface.document_metadata().transform_to_viewport(layer);
let document_transform = document.network_interface.document_metadata().transform_to_document(layer);
let center = viewport_transform.transform_point2(DVec2::ZERO);
let radius_index = self.radius_index;

let original_radius = self.initial_radius;

let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - document_transform.inverse().transform_point2(drag_start);
let radius = document.metadata().document_to_viewport.transform_point2(drag_start) - center;
let delta = viewport_transform.inverse().transform_point2(input.mouse.position) - viewport_transform.inverse().transform_point2(drag_start);
let radius = viewport_transform.inverse().transform_point2(drag_start);
let projection = delta.project_onto(radius);
let sign = radius.dot(delta).signum();

Expand Down
Loading
Loading