mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
impl circle shape and circle gizmos
This commit is contained in:
@@ -294,6 +294,73 @@ impl OverlayContext {
|
||||
self.end_dpi_aware_transform();
|
||||
}
|
||||
|
||||
pub fn dashed_circle(
|
||||
&mut self,
|
||||
position: DVec2,
|
||||
radius: f64,
|
||||
color_fill: Option<&str>,
|
||||
color_stroke: Option<&str>,
|
||||
dash_width: Option<f64>,
|
||||
dash_gap_width: Option<f64>,
|
||||
dash_offset: Option<f64>,
|
||||
transform: Option<DAffine2>,
|
||||
) {
|
||||
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
||||
let position = position.round();
|
||||
|
||||
self.start_dpi_aware_transform();
|
||||
|
||||
if let Some(transform) = transform {
|
||||
let [a, b, c, d, e, f] = transform.to_cols_array();
|
||||
self.render_context.transform(a, b, c, d, e, f).expect("Failed to transform circle");
|
||||
}
|
||||
|
||||
if let Some(dash_width) = dash_width {
|
||||
let dash_gap_width = dash_gap_width.unwrap_or(1.);
|
||||
let array = js_sys::Array::new();
|
||||
array.push(&JsValue::from(dash_width));
|
||||
array.push(&JsValue::from(dash_gap_width));
|
||||
|
||||
if let Some(dash_offset) = dash_offset {
|
||||
if dash_offset != 0. {
|
||||
self.render_context.set_line_dash_offset(dash_offset);
|
||||
}
|
||||
}
|
||||
|
||||
self.render_context
|
||||
.set_line_dash(&JsValue::from(array))
|
||||
.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
|
||||
.ok();
|
||||
}
|
||||
|
||||
self.render_context.begin_path();
|
||||
self.render_context.arc(position.x, position.y, radius, 0., TAU).expect("Failed to draw the circle");
|
||||
self.render_context.set_stroke_style_str(color_stroke);
|
||||
|
||||
if let Some(fill_color) = color_fill {
|
||||
self.render_context.set_fill_style_str(fill_color);
|
||||
self.render_context.fill();
|
||||
}
|
||||
self.render_context.stroke();
|
||||
|
||||
// Reset the dash pattern back to solid
|
||||
if dash_width.is_some() {
|
||||
self.render_context
|
||||
.set_line_dash(&JsValue::from(js_sys::Array::new()))
|
||||
.map_err(|error| log::warn!("Error drawing dashed line: {:?}", error))
|
||||
.ok();
|
||||
}
|
||||
if dash_offset.is_some() && dash_offset != Some(0.) {
|
||||
self.render_context.set_line_dash_offset(0.);
|
||||
}
|
||||
|
||||
self.end_dpi_aware_transform();
|
||||
}
|
||||
|
||||
pub fn circle(&mut self, position: DVec2, radius: f64, color_fill: Option<&str>, color_stroke: Option<&str>) {
|
||||
self.dashed_circle(position, radius, color_fill, color_stroke, None, None, None, None);
|
||||
}
|
||||
|
||||
pub fn manipulator_handle(&mut self, position: DVec2, selected: bool, color: Option<&str>) {
|
||||
self.start_dpi_aware_transform();
|
||||
|
||||
@@ -374,23 +441,6 @@ impl OverlayContext {
|
||||
self.end_dpi_aware_transform();
|
||||
}
|
||||
|
||||
pub fn circle(&mut self, position: DVec2, radius: f64, color_fill: Option<&str>, color_stroke: Option<&str>) {
|
||||
let color_fill = color_fill.unwrap_or(COLOR_OVERLAY_WHITE);
|
||||
let color_stroke = color_stroke.unwrap_or(COLOR_OVERLAY_BLUE);
|
||||
let position = position.round();
|
||||
|
||||
self.start_dpi_aware_transform();
|
||||
|
||||
self.render_context.begin_path();
|
||||
self.render_context.arc(position.x, position.y, radius, 0., TAU).expect("Failed to draw the circle");
|
||||
self.render_context.set_fill_style_str(color_fill);
|
||||
self.render_context.set_stroke_style_str(color_stroke);
|
||||
self.render_context.fill();
|
||||
self.render_context.stroke();
|
||||
|
||||
self.end_dpi_aware_transform();
|
||||
}
|
||||
|
||||
pub fn draw_arc(&mut self, center: DVec2, radius: f64, start_from: f64, end_at: f64) {
|
||||
let segments = ((end_at - start_from).abs() / (std::f64::consts::PI / 4.)).ceil() as usize;
|
||||
let step = (end_at - start_from) / segments as f64;
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::prelude::{DocumentMessageHandler, InputPreprocessorMessageHandler};
|
||||
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::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::star_shape::StarGizmoHandler;
|
||||
@@ -23,6 +24,7 @@ pub enum ShapeGizmoHandlers {
|
||||
None,
|
||||
Star(StarGizmoHandler),
|
||||
Polygon(PolygonGizmoHandler),
|
||||
Circle(CircleGizmoHandler),
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandlers {
|
||||
@@ -32,6 +34,7 @@ impl ShapeGizmoHandlers {
|
||||
match self {
|
||||
Self::Star(_) => "star",
|
||||
Self::Polygon(_) => "polygon",
|
||||
Self::Circle(_) => "circle",
|
||||
Self::None => "none",
|
||||
}
|
||||
}
|
||||
@@ -41,6 +44,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::Circle(h) => h.handle_state(layer, mouse_position, document, responses),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -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::Circle(h) => h.is_any_gizmo_hovered(),
|
||||
Self::None => false,
|
||||
}
|
||||
}
|
||||
@@ -59,6 +64,7 @@ impl ShapeGizmoHandlers {
|
||||
match self {
|
||||
Self::Star(h) => h.handle_click(),
|
||||
Self::Polygon(h) => h.handle_click(),
|
||||
Self::Circle(h) => h.handle_click(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -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::Circle(h) => h.handle_update(drag_start, document, input, responses),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +84,7 @@ impl ShapeGizmoHandlers {
|
||||
match self {
|
||||
Self::Star(h) => h.cleanup(),
|
||||
Self::Polygon(h) => h.cleanup(),
|
||||
Self::Circle(h) => h.cleanup(),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -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::Circle(h) => h.overlays(document, layer, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -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::Circle(h) => h.dragging_overlays(document, input, shape_editor, mouse_position, overlay_context),
|
||||
Self::None => {}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +157,11 @@ impl GizmoManager {
|
||||
return Some(ShapeGizmoHandlers::Polygon(PolygonGizmoHandler::default()));
|
||||
}
|
||||
|
||||
// Polygon
|
||||
if graph_modification_utils::get_circle_id(layer, &document.network_interface).is_some() {
|
||||
return Some(ShapeGizmoHandlers::Circle(CircleGizmoHandler::default()));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
use crate::consts::GIZMO_HIDE_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::{DocumentMessageHandler, InputPreprocessorMessageHandler, NodeGraphMessage};
|
||||
use crate::messages::prelude::{FrontendMessage, Responses};
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{self};
|
||||
use crate::messages::tool::common_functionality::shapes::shape_utility::extract_circle_radius;
|
||||
use glam::DVec2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub enum RadiusHandleState {
|
||||
#[default]
|
||||
Inactive,
|
||||
Hover,
|
||||
Dragging,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct RadiusHandle {
|
||||
pub layer: Option<LayerNodeIdentifier>,
|
||||
initial_radius: f64,
|
||||
handle_state: RadiusHandleState,
|
||||
angle: f64,
|
||||
previous_mouse_position: DVec2,
|
||||
}
|
||||
|
||||
impl RadiusHandle {
|
||||
pub fn cleanup(&mut self) {
|
||||
self.handle_state = RadiusHandleState::Inactive;
|
||||
self.layer = None;
|
||||
}
|
||||
|
||||
pub fn hovered(&self) -> bool {
|
||||
self.handle_state == RadiusHandleState::Hover
|
||||
}
|
||||
|
||||
pub fn is_dragging_or_snapped(&self) -> bool {
|
||||
self.handle_state == RadiusHandleState::Dragging
|
||||
}
|
||||
|
||||
pub fn update_state(&mut self, state: RadiusHandleState) {
|
||||
self.handle_state = state;
|
||||
}
|
||||
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2, responses: &mut VecDeque<Message>) {
|
||||
match &self.handle_state {
|
||||
RadiusHandleState::Inactive => {
|
||||
let Some(radius) = extract_circle_radius(layer, document) else { return };
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
let angle = viewport.inverse().transform_point2(mouse_position).angle_to(DVec2::X);
|
||||
|
||||
let point_position = viewport.transform_point2(get_circle_point_position(angle, radius.abs()));
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
|
||||
log::info!("reaching here");
|
||||
if point_position.distance(center) < GIZMO_HIDE_THRESHOLD {
|
||||
return;
|
||||
}
|
||||
|
||||
if mouse_position.distance(center) <= point_position.distance(center) {
|
||||
self.layer = Some(layer);
|
||||
self.initial_radius = radius;
|
||||
self.previous_mouse_position = mouse_position;
|
||||
self.angle = angle;
|
||||
self.update_state(RadiusHandleState::Hover);
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::EWResize });
|
||||
}
|
||||
}
|
||||
|
||||
RadiusHandleState::Dragging | RadiusHandleState::Hover => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overlays(&self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext) {
|
||||
match &self.handle_state {
|
||||
RadiusHandleState::Inactive => {}
|
||||
|
||||
RadiusHandleState::Dragging | RadiusHandleState::Hover => {
|
||||
let Some(layer) = self.layer else { return };
|
||||
let Some(radius) = extract_circle_radius(layer, document) else { return };
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
|
||||
overlay_context.dashed_circle(DVec2::ZERO, radius.abs(), None, None, Some(20.), Some(4.), Some(0.5), Some(viewport));
|
||||
// overlay_context.dashed_line(center, point_position, None, None, Some(4.), Some(4.), Some(0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_inner_radius(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
||||
let Some(layer) = self.layer else { return };
|
||||
|
||||
let Some(node_id) = graph_modification_utils::get_circle_id(layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(current_radius) = extract_circle_radius(layer, document) else { return };
|
||||
|
||||
let viewport_transform = document.network_interface.document_metadata().transform_to_viewport(layer);
|
||||
let center = viewport_transform.transform_point2(DVec2::ZERO);
|
||||
|
||||
let delta_vector = viewport_transform.inverse().transform_point2(input.mouse.position) - viewport_transform.inverse().transform_point2(self.previous_mouse_position);
|
||||
let radius = document.metadata().document_to_viewport.transform_point2(drag_start) - center;
|
||||
let sign = radius.dot(delta_vector).signum();
|
||||
|
||||
let net_delta = delta_vector.length() * sign * self.initial_radius.signum();
|
||||
self.previous_mouse_position = input.mouse.position;
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 1),
|
||||
input: NodeInput::value(TaggedValue::F64(current_radius + net_delta), false),
|
||||
});
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_circle_point_position(theta: f64, radius: f64) -> DVec2 {
|
||||
DVec2::new(radius * theta.cos(), -radius * theta.sin())
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod circle_radius_handle;
|
||||
pub mod number_of_points_dial;
|
||||
pub mod point_radius_handle;
|
||||
|
||||
@@ -332,6 +332,10 @@ pub fn get_fill_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Fill")
|
||||
}
|
||||
|
||||
pub fn get_circle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Circle")
|
||||
}
|
||||
|
||||
pub fn get_ellipse_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
|
||||
NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Ellipse")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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_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;
|
||||
use crate::messages::tool::tool_messages::tool_prelude::*;
|
||||
use glam::DAffine2;
|
||||
use graph_craft::document::NodeInput;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CircleGizmoHandler {
|
||||
circle_radius_handle: RadiusHandle,
|
||||
}
|
||||
|
||||
impl ShapeGizmoHandler for CircleGizmoHandler {
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
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_click(&mut self) {
|
||||
if self.circle_radius_handle.hovered() {
|
||||
self.circle_radius_handle.update_state(RadiusHandleState::Dragging);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_update(&mut self, drag_start: DVec2, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
if self.circle_radius_handle.is_dragging_or_snapped() {
|
||||
self.circle_radius_handle.update_inner_radius(document, input, responses, drag_start);
|
||||
}
|
||||
}
|
||||
|
||||
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 dragging_overlays(
|
||||
&self,
|
||||
document: &DocumentMessageHandler,
|
||||
_input: &InputPreprocessorMessageHandler,
|
||||
_shape_editor: &mut &mut ShapeState,
|
||||
_mouse_position: DVec2,
|
||||
overlay_context: &mut OverlayContext,
|
||||
) {
|
||||
if self.circle_radius_handle.is_dragging_or_snapped() {
|
||||
self.circle_radius_handle.overlays(document, overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {
|
||||
self.circle_radius_handle.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Circle;
|
||||
|
||||
impl Circle {
|
||||
pub fn create_node() -> NodeTemplate {
|
||||
let node_type = resolve_document_node_type("Circle").expect("Circle can't be found");
|
||||
node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.), false))])
|
||||
}
|
||||
|
||||
pub fn update_shape(document: &DocumentMessageHandler, ipp: &InputPreprocessorMessageHandler, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) {
|
||||
let Some(node_id) = graph_modification_utils::get_circle_id(layer, &document.network_interface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let viewport = document.metadata().transform_to_viewport(layer);
|
||||
let center = viewport.transform_point2(DVec2::ZERO);
|
||||
|
||||
let radius = ipp.mouse.position.distance(center);
|
||||
|
||||
responses.add(NodeGraphMessage::SetInput {
|
||||
input_connector: InputConnector::node(node_id, 1),
|
||||
input: NodeInput::value(TaggedValue::F64(radius), false),
|
||||
});
|
||||
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer,
|
||||
transform: DAffine2::from_translation(center),
|
||||
transform_in: TransformIn::Viewport,
|
||||
skip_rerender: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod circle_shape;
|
||||
pub mod ellipse_shape;
|
||||
pub mod line_shape;
|
||||
pub mod polygon_shape;
|
||||
|
||||
@@ -24,9 +24,10 @@ pub enum ShapeType {
|
||||
#[default]
|
||||
Polygon = 0,
|
||||
Star = 1,
|
||||
Rectangle = 2,
|
||||
Ellipse = 3,
|
||||
Line = 4,
|
||||
Circle = 2,
|
||||
Rectangle = 3,
|
||||
Ellipse = 4,
|
||||
Line = 5,
|
||||
}
|
||||
|
||||
impl ShapeType {
|
||||
@@ -37,6 +38,7 @@ impl ShapeType {
|
||||
Self::Rectangle => "Rectangle",
|
||||
Self::Ellipse => "Ellipse",
|
||||
Self::Line => "Line",
|
||||
Self::Circle => "Circle",
|
||||
})
|
||||
.into()
|
||||
}
|
||||
@@ -234,6 +236,18 @@ pub fn extract_polygon_parameters(layer: Option<LayerNodeIdentifier>, document:
|
||||
Some((n, radius))
|
||||
}
|
||||
|
||||
/// Extract the node input values of Circle.
|
||||
/// Returns an option of (radius).
|
||||
pub fn extract_circle_radius(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<f64> {
|
||||
let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Circle")?;
|
||||
|
||||
let Some(&TaggedValue::F64(radius)) = node_inputs.get(1)?.as_value() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(radius)
|
||||
}
|
||||
|
||||
/// Calculate the viewport position of as a star vertex given its index
|
||||
pub fn star_vertex_position(viewport: DAffine2, vertex_index: i32, n: u32, radius1: f64, radius2: f64) -> DVec2 {
|
||||
let angle = ((vertex_index as f64) * PI) / (n as f64);
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::messages::tool::common_functionality::gizmos::gizmo_manager::GizmoMan
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::NodeGraphLayer;
|
||||
use crate::messages::tool::common_functionality::resize::Resize;
|
||||
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};
|
||||
@@ -109,6 +110,9 @@ fn create_shape_option_widget(shape_type: ShapeType) -> WidgetHolder {
|
||||
MenuListEntry::new("Star")
|
||||
.label("Star")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Star)).into()),
|
||||
MenuListEntry::new("Circle")
|
||||
.label("Circle")
|
||||
.on_commit(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(ShapeType::Circle)).into()),
|
||||
]];
|
||||
DropdownInput::new(entries).selected_index(Some(shape_type as u32)).widget_holder()
|
||||
}
|
||||
@@ -422,6 +426,9 @@ impl Fsm for ShapeToolFsmState {
|
||||
|
||||
if matches!(self, ShapeToolFsmState::Drawing(_) | ShapeToolFsmState::DraggingLineEndpoints) {
|
||||
Line::overlays(document, tool_data, &mut overlay_context);
|
||||
if matches!(tool_options.shape_type, ShapeType::Circle) {
|
||||
tool_data.gizmo_manger.overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
@@ -578,7 +585,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
};
|
||||
|
||||
match tool_data.current_shape {
|
||||
ShapeType::Polygon | ShapeType::Star | ShapeType::Ellipse | ShapeType::Rectangle => tool_data.data.start(document, input),
|
||||
ShapeType::Polygon | ShapeType::Star | ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Circle => tool_data.data.start(document, input),
|
||||
ShapeType::Line => {
|
||||
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
|
||||
let snapped = tool_data.data.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
|
||||
@@ -594,6 +601,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
ShapeType::Rectangle => Rectangle::create_node(),
|
||||
ShapeType::Ellipse => Ellipse::create_node(),
|
||||
ShapeType::Line => Line::create_node(document, tool_data.data.drag_start),
|
||||
ShapeType::Circle => Circle::create_node(),
|
||||
};
|
||||
|
||||
let nodes = vec![(NodeId(0), node)];
|
||||
@@ -602,7 +610,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
responses.add(Message::StartBuffer);
|
||||
|
||||
match tool_data.current_shape {
|
||||
ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Polygon | ShapeType::Star => {
|
||||
ShapeType::Ellipse | ShapeType::Rectangle | ShapeType::Polygon | ShapeType::Star | ShapeType::Circle => {
|
||||
responses.add(GraphOperationMessage::TransformSet {
|
||||
layer,
|
||||
transform: DAffine2::from_scale_angle_translation(DVec2::ONE, 0., input.mouse.position),
|
||||
@@ -635,6 +643,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
ShapeType::Line => Line::update_shape(document, input, layer, tool_data, modifier, responses),
|
||||
ShapeType::Polygon => Polygon::update_shape(document, input, layer, tool_data, modifier, responses),
|
||||
ShapeType::Star => Star::update_shape(document, input, layer, tool_data, modifier, responses),
|
||||
ShapeType::Circle => Circle::update_shape(document, input, layer, responses),
|
||||
}
|
||||
|
||||
// Auto-panning
|
||||
@@ -814,6 +823,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
tool_data.data.cleanup(responses);
|
||||
tool_data.current_shape = shape;
|
||||
|
||||
responses.add(ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::ShapeType(shape)));
|
||||
ShapeToolFsmState::Ready(shape)
|
||||
}
|
||||
(_, ShapeToolMessage::HideShapeTypeWidget(hide)) => {
|
||||
@@ -853,6 +863,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
HintInfo::keys([Key::Shift], "Constrain Square").prepend_plus(),
|
||||
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
|
||||
])],
|
||||
ShapeType::Circle => vec![HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw Circle")])],
|
||||
};
|
||||
HintData(hint_groups)
|
||||
}
|
||||
@@ -867,6 +878,7 @@ impl Fsm for ShapeToolFsmState {
|
||||
HintInfo::keys([Key::Alt], "From Center"),
|
||||
HintInfo::keys([Key::Control], "Lock Angle"),
|
||||
]),
|
||||
ShapeType::Circle => HintGroup(vec![]),
|
||||
};
|
||||
|
||||
common_hint_group.push(tool_hint_group);
|
||||
|
||||
Reference in New Issue
Block a user