Fix Shape tool arc gizmo snap visualization and pointer cursor icon when hovering or dragging (#2957)
* fixed cursor,arc bugs * Update cursor icon * send pointer-move only when required * make it compile * Code review * remove repeated modifier key --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
3cc9dd79fb
commit
7e0a274bd1
|
|
@ -178,7 +178,7 @@ pub fn input_mappings() -> Mapping {
|
|||
entry!(KeyDown(Escape); action_dispatch=ShapeToolMessage::Abort),
|
||||
entry!(KeyDown(BracketLeft); action_dispatch=ShapeToolMessage::DecreaseSides),
|
||||
entry!(KeyDown(BracketRight); action_dispatch=ShapeToolMessage::IncreaseSides),
|
||||
entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove([Alt, Shift, Control, Shift])),
|
||||
entry!(PointerMove; refresh_keys=[Alt, Shift, Control], action_dispatch=ShapeToolMessage::PointerMove([Alt, Shift, Control])),
|
||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowLeft], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: -BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||
entry!(KeyDown(ArrowUp); modifiers=[Shift, ArrowRight], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: BIG_NUDGE_AMOUNT, delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||
entry!(KeyDown(ArrowUp); modifiers=[Shift], action_dispatch=ShapeToolMessage::NudgeSelectedLayers { delta_x: 0., delta_y: -BIG_NUDGE_AMOUNT, resize: Alt, resize_opposite_corner: Control }),
|
||||
|
|
|
|||
|
|
@ -423,11 +423,9 @@ impl OverlayContext {
|
|||
self.render_context.stroke();
|
||||
}
|
||||
|
||||
pub fn draw_arc_gizmo_angle(&mut self, pivot: DVec2, bold_radius: f64, dash_radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) {
|
||||
pub fn draw_arc_gizmo_angle(&mut self, pivot: DVec2, bold_radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) {
|
||||
let end_point1 = pivot + bold_radius * DVec2::from_angle(angle + offset_angle);
|
||||
let end_point2 = pivot + dash_radius * DVec2::from_angle(offset_angle);
|
||||
self.line(pivot, end_point1, None, None);
|
||||
self.dashed_line(pivot, end_point2, None, None, Some(2.), Some(2.), Some(0.5));
|
||||
self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle);
|
||||
}
|
||||
|
||||
|
|
@ -592,9 +590,9 @@ impl OverlayContext {
|
|||
self.end_dpi_aware_transform();
|
||||
}
|
||||
|
||||
pub fn arc_sweep_angle(&mut self, offset_angle: f64, angle: f64, end_point_position: DVec2, bold_radius: f64, dash_radius: f64, pivot: DVec2, text: &str, transform: DAffine2) {
|
||||
pub fn arc_sweep_angle(&mut self, offset_angle: f64, angle: f64, end_point_position: DVec2, bold_radius: f64, pivot: DVec2, text: &str, transform: DAffine2) {
|
||||
self.manipulator_handle(end_point_position, true, Some(COLOR_OVERLAY_RED));
|
||||
self.draw_arc_gizmo_angle(pivot, bold_radius, dash_radius, ARC_SWEEP_GIZMO_RADIUS, offset_angle, angle.to_radians());
|
||||
self.draw_arc_gizmo_angle(pivot, bold_radius, ARC_SWEEP_GIZMO_RADIUS, offset_angle, angle.to_radians());
|
||||
self.text(&text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -379,11 +379,9 @@ impl OverlayContext {
|
|||
self.scene.stroke(&kurbo::Stroke::new(1.0), self.get_transform(), Self::parse_color(COLOR_OVERLAY_BLUE), None, &path);
|
||||
}
|
||||
|
||||
pub fn draw_arc_gizmo_angle(&mut self, pivot: DVec2, bold_radius: f64, dash_radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) {
|
||||
pub fn draw_arc_gizmo_angle(&mut self, pivot: DVec2, bold_radius: f64, arc_radius: f64, offset_angle: f64, angle: f64) {
|
||||
let end_point1 = pivot + bold_radius * DVec2::from_angle(angle + offset_angle);
|
||||
let end_point2 = pivot + dash_radius * DVec2::from_angle(offset_angle);
|
||||
self.line(pivot, end_point1, None, None);
|
||||
self.dashed_line(pivot, end_point2, None, None, Some(2.), Some(2.), Some(0.5));
|
||||
self.draw_arc(pivot, arc_radius, offset_angle, (angle) % TAU + offset_angle);
|
||||
}
|
||||
|
||||
|
|
@ -542,9 +540,9 @@ impl OverlayContext {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn arc_sweep_angle(&mut self, offset_angle: f64, angle: f64, end_point_position: DVec2, bold_radius: f64, dash_radius: f64, pivot: DVec2, text: &str, transform: DAffine2) {
|
||||
pub fn arc_sweep_angle(&mut self, offset_angle: f64, angle: f64, end_point_position: DVec2, bold_radius: f64, pivot: DVec2, text: &str, transform: DAffine2) {
|
||||
self.manipulator_handle(end_point_position, true, Some(COLOR_OVERLAY_RED));
|
||||
self.draw_arc_gizmo_angle(pivot, bold_radius, dash_radius, ARC_SWEEP_GIZMO_RADIUS, offset_angle, angle.to_radians());
|
||||
self.draw_arc_gizmo_angle(pivot, bold_radius, ARC_SWEEP_GIZMO_RADIUS, offset_angle, angle.to_radians());
|
||||
self.text(text, COLOR_OVERLAY_BLUE, None, transform, 16., [Pivot::Middle, Pivot::Middle]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
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;
|
||||
|
|
@ -123,6 +124,15 @@ impl ShapeGizmoHandlers {
|
|||
Self::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gizmo_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
match self {
|
||||
Self::Star(h) => h.mouse_cursor_icon(),
|
||||
Self::Polygon(h) => h.mouse_cursor_icon(),
|
||||
Self::Arc(h) => h.mouse_cursor_icon(),
|
||||
Self::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Central manager that coordinates shape gizmo handlers for interactive editing on the canvas.
|
||||
|
|
@ -256,4 +266,12 @@ impl GizmoManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cursor icon to display when hovering or dragging a gizmo.
|
||||
///
|
||||
/// If a gizmo is active (hovered or being manipulated), it returns the cursor icon associated with that gizmo;
|
||||
/// otherwise, returns `None` to indicate the default crosshair cursor should be used.
|
||||
pub fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
self.active_shape_handler.as_ref().and_then(|h| h.gizmo_cursor_icon())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use crate::consts::{ARC_SNAP_THRESHOLD, COLOR_OVERLAY_RED, 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, FrontendMessage};
|
||||
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::tool_messages::tool_prelude::*;
|
||||
|
|
@ -57,7 +56,7 @@ 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, responses: &mut VecDeque<Message>) {
|
||||
pub fn handle_actions(&mut self, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, mouse_position: DVec2) {
|
||||
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 {
|
||||
|
|
@ -89,8 +88,6 @@ impl SweepAngleGizmo {
|
|||
self.snap_angles = Self::calculate_snap_angles();
|
||||
|
||||
self.update_state(SweepAngleGizmoState::Hover);
|
||||
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -127,6 +124,11 @@ impl SweepAngleGizmo {
|
|||
|
||||
// Depending on which endpoint is being dragged, draw guides relative to the static point
|
||||
let point = if self.endpoint == EndpointType::End { current_end } else { current_start };
|
||||
|
||||
// Draw the dashed line from center to drag start position
|
||||
overlay_context.dashed_line(self.position_before_rotation, viewport.transform_point2(DVec2::ZERO), None, None, Some(5.), Some(5.), Some(0.5));
|
||||
|
||||
// Draw the angle, text and the bold line
|
||||
self.dragging_snapping_overlays(self.position_before_rotation, point, tilt_offset, viewport, overlay_context);
|
||||
}
|
||||
SweepAngleGizmoState::Snapped => {
|
||||
|
|
@ -143,6 +145,9 @@ impl SweepAngleGizmo {
|
|||
// Draw lines from endpoints to the arc center
|
||||
overlay_context.line(start, center, Some(COLOR_OVERLAY_RED), Some(2.));
|
||||
overlay_context.line(end, center, Some(COLOR_OVERLAY_RED), Some(2.));
|
||||
|
||||
// Draw the line from drag start to arc center
|
||||
overlay_context.dashed_line(self.position_before_rotation, center, None, None, Some(5.), Some(5.), Some(0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +160,6 @@ impl SweepAngleGizmo {
|
|||
let final_vector = final_point - center;
|
||||
let offset_angle = initial_vector.to_angle() + tilt_offset;
|
||||
|
||||
let dash_radius = initial_point.distance(center);
|
||||
let bold_radius = final_point.distance(center);
|
||||
|
||||
let angle = initial_vector.angle_to(final_vector).to_degrees();
|
||||
|
|
@ -170,7 +174,7 @@ impl SweepAngleGizmo {
|
|||
|
||||
let transform = calculate_arc_text_transform(angle, offset_angle, center, text_texture_width);
|
||||
|
||||
overlay_context.arc_sweep_angle(offset_angle, angle, final_point, bold_radius, dash_radius, center, &text, transform);
|
||||
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>) {
|
||||
|
|
@ -209,12 +213,11 @@ impl SweepAngleGizmo {
|
|||
let wrapped = new_sweep_angle % 360.;
|
||||
self.total_angle_delta = -wrapped;
|
||||
|
||||
// Remaining drag gets passed to the ending endpoint
|
||||
let rest_angle = angle_delta + wrapped;
|
||||
self.endpoint = EndpointType::End;
|
||||
|
||||
self.initial_sweep_angle = 360.;
|
||||
self.initial_start_angle = current_start_angle + rest_angle;
|
||||
self.initial_start_angle = current_start_angle;
|
||||
self.update_state(SweepAngleGizmoState::Snapped);
|
||||
|
||||
self.apply_arc_update(node_id, self.initial_start_angle, self.initial_sweep_angle - wrapped, input, responses);
|
||||
}
|
||||
|
|
@ -288,12 +291,13 @@ impl SweepAngleGizmo {
|
|||
}
|
||||
// Clamp sweep angle above 360°, switch to start
|
||||
() if new_sweep_angle > 360. => {
|
||||
let delta = angle_delta - (360. - current_sweep_angle);
|
||||
let delta = angle_delta - (360. - new_sweep_angle);
|
||||
let sign = -delta.signum();
|
||||
|
||||
self.total_angle_delta = angle_delta;
|
||||
self.total_angle_delta = angle_delta - (360. - new_sweep_angle);
|
||||
self.initial_sweep_angle = 360.;
|
||||
self.endpoint = EndpointType::Start;
|
||||
self.update_state(SweepAngleGizmoState::Snapped);
|
||||
|
||||
self.apply_arc_update(node_id, self.initial_start_angle + angle_delta, self.initial_sweep_angle + angle_delta.abs() * sign, input, responses);
|
||||
}
|
||||
|
|
@ -339,7 +343,7 @@ impl SweepAngleGizmo {
|
|||
pub fn calculate_snap_angles() -> Vec<f64> {
|
||||
let mut snap_points = Vec::new();
|
||||
|
||||
for i in 0..8 {
|
||||
for i in 0..=8 {
|
||||
let snap_point = i as f64 * FRAC_PI_4;
|
||||
snap_points.push(snap_point.to_degrees());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ impl ArcGizmoHandler {
|
|||
}
|
||||
|
||||
impl ShapeGizmoHandler for ArcGizmoHandler {
|
||||
fn handle_state(&mut self, selected_shape_layers: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
self.sweep_angle_gizmo.handle_actions(selected_shape_layers, document, mouse_position, responses);
|
||||
fn handle_state(&mut self, selected_shape_layers: LayerNodeIdentifier, mouse_position: DVec2, document: &DocumentMessageHandler, _responses: &mut VecDeque<Message>) {
|
||||
self.sweep_angle_gizmo.handle_actions(selected_shape_layers, document, mouse_position);
|
||||
}
|
||||
|
||||
fn is_any_gizmo_hovered(&self) -> bool {
|
||||
|
|
@ -74,6 +74,14 @@ impl ShapeGizmoHandler for ArcGizmoHandler {
|
|||
arc_outline(selected_shape_layers.or(self.sweep_angle_gizmo.layer), document, overlay_context);
|
||||
}
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon> {
|
||||
if self.sweep_angle_gizmo.hovered() || self.sweep_angle_gizmo.is_dragging_or_snapped() {
|
||||
return Some(MouseCursorIcon::Default);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {
|
||||
self.sweep_angle_gizmo.cleanup();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl Ellipse {
|
|||
modifier: ShapeToolModifierKey,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let [center, lock_ratio, _, _] = modifier;
|
||||
let [center, lock_ratio, _] = modifier;
|
||||
|
||||
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
|
||||
let Some(node_id) = graph_modification_utils::get_ellipse_id(layer, &document.network_interface) else {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl Line {
|
|||
modifier: ShapeToolModifierKey,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let [center, _, lock_angle, snap_angle] = modifier;
|
||||
let [center, snap_angle, lock_angle] = modifier;
|
||||
|
||||
shape_tool_data.line_data.drag_current = ipp.mouse.position;
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,18 @@ 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() {
|
||||
return Some(MouseCursorIcon::EWResize);
|
||||
}
|
||||
|
||||
if self.point_radius_handle.is_dragging_or_snapped() || self.point_radius_handle.hovered() {
|
||||
return Some(MouseCursorIcon::Default);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {
|
||||
self.number_of_points_dial.cleanup();
|
||||
self.point_radius_handle.cleanup();
|
||||
|
|
@ -112,7 +124,7 @@ impl Polygon {
|
|||
modifier: ShapeToolModifierKey,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let [center, lock_ratio, _, _] = modifier;
|
||||
let [center, lock_ratio, _] = modifier;
|
||||
|
||||
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
|
||||
// TODO: We need to determine how to allow the polygon node to make irregular shapes
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl Rectangle {
|
|||
modifier: ShapeToolModifierKey,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let [center, lock_ratio, _, _] = modifier;
|
||||
let [center, lock_ratio, _] = modifier;
|
||||
|
||||
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
|
||||
let Some(node_id) = graph_modification_utils::get_rectangle_id(layer, &document.network_interface) else {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::ShapeToolData;
|
||||
use crate::consts::{ARC_SWEEP_GIZMO_RADIUS, ARC_SWEEP_GIZMO_TEXT_HEIGHT};
|
||||
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;
|
||||
|
|
@ -74,7 +75,7 @@ impl ShapeType {
|
|||
}
|
||||
}
|
||||
|
||||
pub type ShapeToolModifierKey = [Key; 4];
|
||||
pub type ShapeToolModifierKey = [Key; 3];
|
||||
|
||||
/// 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).
|
||||
|
|
@ -127,6 +128,8 @@ pub trait ShapeGizmoHandler {
|
|||
///
|
||||
/// For example, dragging states or hover flags should be cleared to avoid visual glitches when switching tools or shapes.
|
||||
fn cleanup(&mut self);
|
||||
|
||||
fn mouse_cursor_icon(&self) -> Option<MouseCursorIcon>;
|
||||
}
|
||||
|
||||
/// Center, Lock Ratio, Lock Angle, Snap Angle, Increase/Decrease Side
|
||||
|
|
|
|||
|
|
@ -90,6 +90,18 @@ impl ShapeGizmoHandler for StarGizmoHandler {
|
|||
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)]
|
||||
|
|
@ -114,7 +126,7 @@ impl Star {
|
|||
modifier: ShapeToolModifierKey,
|
||||
responses: &mut VecDeque<Message>,
|
||||
) {
|
||||
let [center, lock_ratio, _, _] = modifier;
|
||||
let [center, lock_ratio, _] = modifier;
|
||||
|
||||
if let Some([start, end]) = shape_tool_data.data.calculate_points(document, ipp, center, lock_ratio) {
|
||||
// TODO: We need to determine how to allow the polygon node to make irregular shapes
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ pub struct ShapeToolData {
|
|||
current_shape: ShapeType,
|
||||
|
||||
// Gizmos
|
||||
gizmo_manger: GizmoManager,
|
||||
gizmo_manager: GizmoManager,
|
||||
}
|
||||
|
||||
impl ShapeToolData {
|
||||
|
|
@ -351,6 +351,23 @@ impl ShapeToolData {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_cage_mouse_icon(&mut self, input: &InputPreprocessorMessageHandler) -> MouseCursorIcon {
|
||||
let dragging_bounds = self
|
||||
.bounding_box_manager
|
||||
.as_mut()
|
||||
.and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position))
|
||||
.is_some();
|
||||
|
||||
self.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Crosshair, |bounds| {
|
||||
let cursor_icon = bounds.get_cursor(input, true, dragging_bounds, Some(self.skew_edge));
|
||||
if cursor_icon == MouseCursorIcon::Default { MouseCursorIcon::Crosshair } else { cursor_icon }
|
||||
})
|
||||
}
|
||||
|
||||
fn shape_tool_modifier_keys() -> [Key; 3] {
|
||||
[Key::Alt, Key::Shift, Key::Control]
|
||||
}
|
||||
}
|
||||
|
||||
impl Fsm for ShapeToolFsmState {
|
||||
|
|
@ -388,30 +405,34 @@ impl Fsm for ShapeToolFsmState {
|
|||
.indicator_pos()
|
||||
.map(|pos| document.metadata().document_to_viewport.transform_point2(pos))
|
||||
.unwrap_or(input.mouse.position);
|
||||
let is_resizing_or_rotating = matches!(self, ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::SkewingBounds { .. } | ShapeToolFsmState::RotatingBounds);
|
||||
|
||||
if matches!(self, Self::Ready(_)) && !input.keyboard.key(Key::Control) {
|
||||
tool_data.gizmo_manger.handle_actions(mouse_position, document, responses);
|
||||
tool_data.gizmo_manger.overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
tool_data.gizmo_manager.handle_actions(mouse_position, document, responses);
|
||||
tool_data.gizmo_manager.overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
}
|
||||
|
||||
if matches!(self, ShapeToolFsmState::ModifyingGizmo) && !input.keyboard.key(Key::Control) {
|
||||
tool_data.gizmo_manger.dragging_overlays(document, input, shape_editor, mouse_position, &mut overlay_context);
|
||||
tool_data.gizmo_manager.dragging_overlays(document, input, shape_editor, mouse_position, &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 });
|
||||
}
|
||||
|
||||
let modifying_transform_cage = matches!(self, ShapeToolFsmState::ResizingBounds | ShapeToolFsmState::RotatingBounds | ShapeToolFsmState::SkewingBounds { .. });
|
||||
let hovering_over_gizmo = tool_data.gizmo_manger.hovering_over_gizmo();
|
||||
let hovering_over_gizmo = tool_data.gizmo_manager.hovering_over_gizmo();
|
||||
|
||||
if !is_resizing_or_rotating && !matches!(self, ShapeToolFsmState::ModifyingGizmo) && !modifying_transform_cage && !hovering_over_gizmo {
|
||||
if !matches!(self, ShapeToolFsmState::ModifyingGizmo) && !modifying_transform_cage && !hovering_over_gizmo {
|
||||
tool_data.data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
|
||||
}
|
||||
|
||||
if modifying_transform_cage && !matches!(self, ShapeToolFsmState::ModifyingGizmo) {
|
||||
transform_cage_overlays(document, tool_data, &mut overlay_context);
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: tool_data.cursor });
|
||||
}
|
||||
|
||||
if input.keyboard.key(Key::Control) && matches!(self, ShapeToolFsmState::Ready(_)) {
|
||||
anchor_overlays(document, &mut overlay_context);
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair });
|
||||
} else if matches!(self, ShapeToolFsmState::Ready(_)) {
|
||||
Line::overlays(document, tool_data, &mut overlay_context);
|
||||
|
||||
|
|
@ -433,7 +454,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
let edges = bounds.check_selected_edges(input.mouse.position);
|
||||
let is_skewing = matches!(self, ShapeToolFsmState::SkewingBounds { .. });
|
||||
let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge));
|
||||
if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating && !hovering_over_gizmo) {
|
||||
if is_skewing || (dragging_bounds && is_near_square && !hovering_over_gizmo) {
|
||||
bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge);
|
||||
}
|
||||
if !is_skewing && dragging_bounds && !hovering_over_gizmo {
|
||||
|
|
@ -442,6 +463,11 @@ impl Fsm for ShapeToolFsmState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cursor = tool_data.gizmo_manager.mouse_cursor_icon().unwrap_or_else(|| tool_data.transform_cage_mouse_icon(input));
|
||||
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
}
|
||||
|
||||
if matches!(self, ShapeToolFsmState::Drawing(_) | ShapeToolFsmState::DraggingLineEndpoints) {
|
||||
|
|
@ -562,8 +588,16 @@ impl Fsm for ShapeToolFsmState {
|
|||
|
||||
tool_data.line_data.drag_current = mouse_pos;
|
||||
|
||||
if tool_data.gizmo_manger.handle_click() {
|
||||
if tool_data.gizmo_manager.handle_click() && !input.keyboard.key(Key::Accel) {
|
||||
tool_data.data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(mouse_pos);
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let cursor = tool_data.gizmo_manager.mouse_cursor_icon().unwrap_or(MouseCursorIcon::Crosshair);
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
// Send a PointerMove message to refresh the cursor icon
|
||||
responses.add(ShapeToolMessage::PointerMove(ShapeToolData::shape_tool_modifier_keys()));
|
||||
|
||||
return ShapeToolFsmState::ModifyingGizmo;
|
||||
}
|
||||
|
||||
|
|
@ -584,17 +618,31 @@ impl Fsm for ShapeToolFsmState {
|
|||
let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, None);
|
||||
|
||||
if !input.keyboard.key(Key::Control) {
|
||||
// Helper function to update cursor and send pointer move message
|
||||
let update_cursor_and_pointer = |tool_data: &mut ShapeToolData, responses: &mut VecDeque<Message>| {
|
||||
let cursor = tool_data.transform_cage_mouse_icon(input);
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
responses.add(ShapeToolMessage::PointerMove(ShapeToolData::shape_tool_modifier_keys()));
|
||||
};
|
||||
|
||||
match (resize, rotate, skew) {
|
||||
(true, false, false) => {
|
||||
tool_data.get_snap_candidates(document, input);
|
||||
update_cursor_and_pointer(tool_data, responses);
|
||||
|
||||
return ShapeToolFsmState::ResizingBounds;
|
||||
}
|
||||
(false, true, false) => {
|
||||
tool_data.data.drag_start = mouse_pos;
|
||||
update_cursor_and_pointer(tool_data, responses);
|
||||
|
||||
return ShapeToolFsmState::RotatingBounds;
|
||||
}
|
||||
(false, false, true) => {
|
||||
tool_data.get_snap_candidates(document, input);
|
||||
update_cursor_and_pointer(tool_data, responses);
|
||||
|
||||
return ShapeToolFsmState::SkewingBounds { skew: Key::Control };
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -686,8 +734,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
self
|
||||
}
|
||||
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
tool_data.gizmo_manger.handle_update(tool_data.data.drag_start, document, input, responses);
|
||||
tool_data.gizmo_manager.handle_update(tool_data.data.drag_start, document, input, responses);
|
||||
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
|
|
@ -758,7 +805,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
if cursor == MouseCursorIcon::Default { MouseCursorIcon::Crosshair } else { cursor }
|
||||
});
|
||||
|
||||
if tool_data.cursor != cursor && !input.keyboard.key(Key::Control) && !all_selected_layers_line {
|
||||
if tool_data.cursor != cursor {
|
||||
tool_data.cursor = cursor;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor });
|
||||
}
|
||||
|
|
@ -797,7 +844,7 @@ impl Fsm for ShapeToolFsmState {
|
|||
input.mouse.finish_transaction(tool_data.data.drag_start, responses);
|
||||
tool_data.data.cleanup(responses);
|
||||
|
||||
tool_data.gizmo_manger.handle_cleanup();
|
||||
tool_data.gizmo_manager.handle_cleanup();
|
||||
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
bounds.original_transforms.clear();
|
||||
|
|
@ -822,12 +869,13 @@ impl Fsm for ShapeToolFsmState {
|
|||
tool_data.data.cleanup(responses);
|
||||
tool_data.line_data.dragging_endpoint = None;
|
||||
|
||||
tool_data.gizmo_manger.handle_cleanup();
|
||||
tool_data.gizmo_manager.handle_cleanup();
|
||||
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
bounds.original_transforms.clear();
|
||||
}
|
||||
|
||||
tool_data.cursor = MouseCursorIcon::Crosshair;
|
||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair });
|
||||
|
||||
ShapeToolFsmState::Ready(tool_data.current_shape)
|
||||
|
|
|
|||
Loading…
Reference in New Issue