Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ use crate::messages::tool::common_functionality::shape_editor::ShapeState;
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::grid_shape::GridGizmoHandler;
use crate::messages::tool::common_functionality::shapes::heart_shape::HeartGizmoHandler;
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 crate::messages::tool::common_functionality::shapes::teardrop_shape::TeardropGizmoHandler;

use glam::DVec2;
use std::collections::VecDeque;

Expand All @@ -32,6 +35,8 @@ pub enum ShapeGizmoHandlers {
Circle(CircleGizmoHandler),
Grid(GridGizmoHandler),
Spiral(SpiralGizmoHandler),
Teardrop(TeardropGizmoHandler),
Heart(HeartGizmoHandler),
}

impl ShapeGizmoHandlers {
Expand All @@ -45,6 +50,8 @@ impl ShapeGizmoHandlers {
Self::Circle(_) => "circle",
Self::Grid(_) => "grid",
Self::Spiral(_) => "spiral",
Self::Teardrop(_) => "teardrop",
Self::Heart(_) => "heart",
Self::None => "none",
}
}
Expand All @@ -58,6 +65,8 @@ impl ShapeGizmoHandlers {
Self::Circle(h) => h.handle_state(layer, mouse_position, document, responses),
Self::Grid(h) => h.handle_state(layer, mouse_position, document, responses),
Self::Spiral(h) => h.handle_state(layer, mouse_position, document, responses),
Self::Teardrop(h) => h.handle_state(layer, mouse_position, document, responses),
Self::Heart(h) => h.handle_state(layer, mouse_position, document, responses),
Self::None => {}
}
}
Expand All @@ -71,6 +80,8 @@ impl ShapeGizmoHandlers {
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::Teardrop(h) => h.is_any_gizmo_hovered(),
Self::Heart(h) => h.is_any_gizmo_hovered(),
Self::None => false,
}
}
Expand All @@ -84,6 +95,8 @@ impl ShapeGizmoHandlers {
Self::Circle(h) => h.handle_click(),
Self::Grid(h) => h.handle_click(),
Self::Spiral(h) => h.handle_click(),
Self::Teardrop(h) => h.handle_click(),
Self::Heart(h) => h.handle_click(),
Self::None => {}
}
}
Expand All @@ -97,6 +110,8 @@ impl ShapeGizmoHandlers {
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::Teardrop(h) => h.handle_update(drag_start, document, input, responses),
Self::Heart(h) => h.handle_update(drag_start, document, input, responses),
Self::None => {}
}
}
Expand All @@ -110,6 +125,8 @@ impl ShapeGizmoHandlers {
Self::Circle(h) => h.cleanup(),
Self::Grid(h) => h.cleanup(),
Self::Spiral(h) => h.cleanup(),
Self::Teardrop(h) => h.cleanup(),
Self::Heart(h) => h.cleanup(),
Self::None => {}
}
}
Expand All @@ -131,6 +148,8 @@ impl ShapeGizmoHandlers {
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::Teardrop(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
Self::Heart(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
Self::None => {}
}
}
Expand All @@ -151,6 +170,8 @@ impl ShapeGizmoHandlers {
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::Teardrop(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
Self::Heart(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
Self::None => {}
}
}
Expand All @@ -163,6 +184,8 @@ impl ShapeGizmoHandlers {
Self::Circle(h) => h.mouse_cursor_icon(),
Self::Grid(h) => h.mouse_cursor_icon(),
Self::Spiral(h) => h.mouse_cursor_icon(),
Self::Teardrop(h) => h.mouse_cursor_icon(),
Self::Heart(h) => h.mouse_cursor_icon(),
Self::None => None,
}
}
Expand Down Expand Up @@ -214,6 +237,14 @@ impl GizmoManager {
if graph_modification_utils::get_spiral_id(layer, &document.network_interface).is_some() {
return Some(ShapeGizmoHandlers::Spiral(SpiralGizmoHandler::default()));
}
// Teardrop
if graph_modification_utils::get_teardrop_id(layer, &document.network_interface).is_some() {
return Some(ShapeGizmoHandlers::Teardrop(TeardropGizmoHandler::default()));
}
// Heart
if graph_modification_utils::get_heart_id(layer, &document.network_interface).is_some() {
return Some(ShapeGizmoHandlers::Heart(HeartGizmoHandler::default()));
}

None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,14 @@ pub fn get_spiral_id(layer: LayerNodeIdentifier, network_interface: &NodeNetwork
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::spiral::IDENTIFIER))
}

pub fn get_teardrop_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::teardrop::IDENTIFIER))
}

pub fn get_heart_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::heart::IDENTIFIER))
}
Comment on lines +380 to +386
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

It looks like there's a copy-paste error in these new functions. Both get_teardrop_id and get_heart_id are checking for the spiral identifier. They should be checking for their respective shape identifiers.

Suggested change
pub fn get_teardrop_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::spiral::IDENTIFIER))
}
pub fn get_heart_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::spiral::IDENTIFIER))
}
pub fn get_teardrop_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::teardrop::IDENTIFIER))
}
pub fn get_heart_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::heart::IDENTIFIER))
}


pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER))
}
Expand Down
162 changes: 162 additions & 0 deletions editor/src/messages/tool/common_functionality/shapes/heart_shape.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use super::shape_utility::{ShapeToolModifierKey, update_radius_sign};
use super::*;
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, 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::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;
use crate::messages::tool::tool_messages::tool_prelude::*;
use glam::DAffine2;
use graph_craft::document::NodeInput;
use graph_craft::document::value::TaggedValue;
use std::collections::VecDeque;

#[derive(Clone, Debug, Default)]
pub struct HeartGizmoHandler {
number_of_points_dial: NumberOfPointsDial,
point_radius_handle: PointRadiusHandle,
Comment on lines +20 to +22
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The HeartGizmoHandler seems to be using gizmos for number_of_points_dial and point_radius_handle, which appear to be copied from another shape handler. The number_of_points_dial is not applicable to a heart shape. While point_radius_handle could potentially be used to control a property like the spike length, the heart generator node currently doesn't expose such a parameter. This will lead to incorrect and confusing behavior for the user. Please implement gizmos appropriate for the heart shape.

}

impl ShapeGizmoHandler for HeartGizmoHandler {
fn is_any_gizmo_hovered(&self) -> bool {
self.number_of_points_dial.is_hovering() || self.point_radius_handle.hovered()
}

fn handle_state(&mut self, selected_heart_layer: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
self.number_of_points_dial.handle_actions(selected_heart_layer, mouse_position, document, responses);
self.point_radius_handle.handle_actions(selected_heart_layer, document, mouse_position, responses);
}

fn handle_click(&mut self) {
if self.number_of_points_dial.is_hovering() {
self.number_of_points_dial.update_state(NumberOfPointsDialState::Dragging);
return;
}

if self.point_radius_handle.hovered() {
self.point_radius_handle.update_state(PointRadiusHandleState::Dragging);
}
}

fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
if self.number_of_points_dial.is_dragging() {
self.number_of_points_dial.update_number_of_sides(document, input, responses, drag_start);
}

if self.point_radius_handle.is_dragging_or_snapped() {
self.point_radius_handle.update_inner_radius(document, input, responses, drag_start);
}
}

fn overlays(
&self,
document: &DocumentMessageHandler,
selected_heart_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_heart_layer, shape_editor, mouse_position, overlay_context);
self.point_radius_handle.overlays(selected_heart_layer, document, overlay_context);
}

fn dragging_overlays(
&self,
document: &DocumentMessageHandler,
_input: &InputPreprocessorMessageHandler,
shape_editor: &mut &mut ShapeState,
mouse_position: DVec2,
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);
}

if self.point_radius_handle.is_dragging_or_snapped() {
self.point_radius_handle.overlays(None, document, overlay_context);
}
}

fn cleanup(&mut self) {
self.number_of_points_dial.cleanup();
self.point_radius_handle.cleanup();
}

fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
if self.number_of_points_dial.is_dragging() || self.number_of_points_dial.is_hovering() {
return Some(MouseCursorIcon::EWResize);
}

if self.point_radius_handle.is_dragging_or_snapped() || self.point_radius_handle.hovered() {
return Some(MouseCursorIcon::Default);
}

None
}
}

#[derive(Default)]
pub struct Heart;

impl Heart {
pub fn create_node(_vertices: u32) -> NodeTemplate {
let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::heart::IDENTIFIER);
let node_type = resolve_document_node_type(&identifier).expect("Heart node can't be found");
node_type.node_template_input_override([
None,
Some(NodeInput::value(TaggedValue::F64(100.), false)),
Some(NodeInput::value(TaggedValue::F64(100.), false)),
Some(NodeInput::value(TaggedValue::F64(50.), false)),
])
}

pub fn update_shape(
document: &DocumentMessageHandler,
ipp: &InputPreprocessorMessageHandler,
viewport: &ViewportMessageHandler,
layer: LayerNodeIdentifier,
shape_tool_data: &mut ShapeToolData,
modifier: ShapeToolModifierKey,
responses: &mut VecDeque<Message>,
) {
let [center, lock_ratio, _] = modifier;

if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, viewport, center, lock_ratio) {
update_radius_sign(end, start, layer, document, responses);

let dimensions = (start - end).abs();
let width = dimensions.x;
let height = dimensions.y;

let Some(node_id) = graph_modification_utils::get_heart_id(layer, &document.network_interface) else {
return;
};

responses.add(NodeGraphMessage::SetInput {
input_connector: InputConnector::node(node_id, 1),
input: NodeInput::value(TaggedValue::F64(width), false),
});

responses.add(NodeGraphMessage::SetInput {
input_connector: InputConnector::node(node_id, 2),
input: NodeInput::value(TaggedValue::F64(height), false),
});

let center_x = (start.x + end.x) / 2.0;
let center_y = (start.y + end.y) / 2.0;

responses.add(GraphOperationMessage::TransformSet {
layer,
transform: DAffine2::from_translation(DVec2::new(center_x, center_y)),
transform_in: TransformIn::Viewport,
skip_rerender: false,
});
}
}
}
2 changes: 2 additions & 0 deletions editor/src/messages/tool/common_functionality/shapes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ pub mod arrow_shape;
pub mod circle_shape;
pub mod ellipse_shape;
pub mod grid_shape;
pub mod heart_shape;
pub mod line_shape;
pub mod polygon_shape;
pub mod rectangle_shape;
pub mod shape_utility;
pub mod spiral_shape;
pub mod star_shape;
pub mod teardrop_shape;

pub use super::shapes::arrow_shape::Arrow;
pub use super::shapes::ellipse_shape::Ellipse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum ShapeType {
Spiral,
Grid,
Arrow,
Teardrop,
Heart,
Line, // KEEP THIS AT THE END
Rectangle, // KEEP THIS AT THE END
Ellipse, // KEEP THIS AT THE END
Expand All @@ -50,6 +52,8 @@ impl ShapeType {
Self::Spiral => "Spiral",
Self::Grid => "Grid",
Self::Arrow => "Arrow",
Self::Teardrop => "Teardrop",
Self::Heart => "Heart",
Self::Line => "Line",
Self::Rectangle => "Rectangle",
Self::Ellipse => "Ellipse",
Expand Down
Loading