Remove update_dynamic_hints seperate function

This commit is contained in:
hypercube
2025-08-05 08:56:52 +01:00
parent 4421d04643
commit 5440f9605d
15 changed files with 336 additions and 358 deletions

View File

@@ -1596,7 +1596,7 @@ impl ShapeState {
}
pub fn find_nearest_visible_point_indices(
&mut self,
&self,
network_interface: &NodeNetworkInterface,
mouse_position: DVec2,
select_threshold: f64,

View File

@@ -528,7 +528,7 @@ impl Fsm for ArtboardToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
ArtboardToolFsmState::Ready { .. } => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw Artboard")]),
@@ -552,7 +552,7 @@ impl Fsm for ArtboardToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
if let Self::Ready { hovered: false } = self {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair });
} else {

View File

@@ -418,7 +418,7 @@ impl Fsm for BrushToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
BrushToolFsmState::Ready => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Draw")]),
@@ -430,7 +430,7 @@ impl Fsm for BrushToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -124,7 +124,7 @@ impl Fsm for EyedropperToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
EyedropperToolFsmState::Ready => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Sample to Primary"),
@@ -138,7 +138,7 @@ impl Fsm for EyedropperToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let cursor = match *self {
EyedropperToolFsmState::Ready => MouseCursorIcon::Default,
EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary => MouseCursorIcon::None,

View File

@@ -145,7 +145,7 @@ impl Fsm for FillToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
FillToolFsmState::Ready => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Fill with Primary"),
@@ -157,7 +157,7 @@ impl Fsm for FillToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -297,7 +297,7 @@ impl Fsm for FreehandToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
FreehandToolFsmState::Ready => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Polyline"),
@@ -310,7 +310,7 @@ impl Fsm for FreehandToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -519,7 +519,7 @@ impl Fsm for GradientToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
GradientToolFsmState::Ready => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Gradient"),
@@ -534,7 +534,7 @@ impl Fsm for GradientToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -145,7 +145,7 @@ impl Fsm for NavigateToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
NavigateToolFsmState::Ready | NavigateToolFsmState::ZoomOrClickZooming => HintData(vec![
HintGroup(vec![
@@ -169,7 +169,7 @@ impl Fsm for NavigateToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let cursor = match *self {
NavigateToolFsmState::Ready => MouseCursorIcon::ZoomIn,
NavigateToolFsmState::Tilting => MouseCursorIcon::Default,

View File

@@ -1505,9 +1505,9 @@ impl Fsm for PathToolFsmState {
tool_options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> Self {
let ToolActionMessageContext { document, input, shape_editor, .. } = tool_action_data;
self.update_hints(tool_data, tool_action_data, tool_options, responses);
update_dynamic_hints(self, responses, shape_editor, document, tool_data, tool_options, input.mouse.position);
let ToolActionMessageContext { document, input, shape_editor, .. } = tool_action_data;
let ToolMessage::Path(event) = event else { return self };
@@ -3040,11 +3040,218 @@ impl Fsm for PathToolFsmState {
}
}
fn update_hints(&self, _responses: &mut VecDeque<Message>) {
// Moved logic to update_dynamic_hints
fn update_hints(&self, tool_data: &Self::ToolData, ctx: &ToolActionMessageContext, tool_options: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let ToolActionMessageContext { document, shape_editor, input, .. } = ctx;
// Condinting based on currently selected segment if it has any one g1 continuous handle
let hint_data = match self {
PathToolFsmState::Ready => {
// Show point sliding hints only when there is an anchor with colinear handles selected
let single_anchor_selected = shape_editor.selected_points().count() == 1 && shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_)));
let at_least_one_anchor_selected = shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_)));
let at_least_one_point_selected = shape_editor.selected_points().count() >= 1;
let mut single_colinear_anchor_selected = false;
if single_anchor_selected {
if let (Some(anchor), Some(layer)) = (
shape_editor.selected_points().next(),
document.network_interface.selected_nodes().selected_layers(document.metadata()).next(),
) {
if let Some(vector) = document.network_interface.compute_modified_vector(layer) {
single_colinear_anchor_selected = vector.colinear(*anchor)
}
}
}
let mut drag_selected_hints = vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")];
let mut delete_selected_hints = vec![HintInfo::keys([Key::Delete], "Delete Selected")];
if at_least_one_anchor_selected {
delete_selected_hints.push(HintInfo::keys([Key::Accel], "No Dissolve").prepend_plus());
delete_selected_hints.push(HintInfo::keys([Key::Shift], "Cut Anchor").prepend_plus());
}
if single_colinear_anchor_selected {
drag_selected_hints.push(HintInfo::multi_keys([[Key::Control], [Key::Shift]], "Slide").prepend_plus());
}
let segment_edit = tool_options.path_editing_mode.segment_editing_mode;
let point_edit = tool_options.path_editing_mode.point_editing_mode;
let hovering_segment = tool_data.segment.is_some();
let hovering_point = shape_editor
.find_nearest_visible_point_indices(
&document.network_interface,
input.mouse.position,
SELECTION_THRESHOLD,
tool_options.path_overlay_mode,
&tool_data.frontier_handles_info,
)
.is_some();
let mut hint_data = if hovering_segment {
if segment_edit {
// Hovering a segment in segment editing mode
vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Select Segment"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Control], MouseMotion::Lmb, "Insert Point on Segment")]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Control], MouseMotion::LmbDrag, "Mold Segment")]),
]
} else {
// Hovering a segment in point editing mode
vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Insert Point on Segment")]),
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Mold Segment")]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "Delete Segment")]),
]
}
} else if hovering_point {
if point_edit {
// Hovering over a point in point editing mode
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Select Point"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
])]
} else {
// Hovering over a point in segment selection mode (will select a nearby segment)
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Select Segment"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
])]
}
} else {
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"),
HintInfo::keys([Key::Control], "Lasso").prepend_plus(),
])]
};
if at_least_one_anchor_selected {
// TODO: Dynamically show either "Smooth" or "Sharp" based on the current state
hint_data.push(HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDouble, "Convert Anchor Point"),
HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "To Sharp"),
HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "To Smooth"),
]));
}
if at_least_one_point_selected {
let mut groups = vec![
HintGroup(drag_selected_hints),
HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyR], [Key::KeyS]], "Grab/Rotate/Scale Selected")]),
HintGroup(vec![HintInfo::arrow_keys("Nudge Selected"), HintInfo::keys([Key::Shift], "10x").prepend_plus()]),
HintGroup(delete_selected_hints),
];
hint_data.append(&mut groups);
}
HintData(hint_data)
}
PathToolFsmState::Dragging(dragging_state) => {
let colinear = dragging_state.colinear;
let mut dragging_hint_data = HintData(Vec::new());
dragging_hint_data
.0
.push(HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]));
let drag_anchor = HintInfo::keys([Key::Space], "Drag Anchor");
let toggle_group = match dragging_state.point_select_state {
PointSelectState::HandleNoPair | PointSelectState::HandleWithPair => {
let mut hints = vec![HintInfo::keys([Key::Tab], "Swap Dragged Handle")];
hints.push(HintInfo::keys(
[Key::KeyC],
if colinear == ManipulatorAngle::Colinear {
"Break Colinear Handles"
} else {
"Make Handles Colinear"
},
));
hints
}
PointSelectState::Anchor => Vec::new(),
};
let hold_group = match dragging_state.point_select_state {
PointSelectState::HandleNoPair => {
let mut hints = vec![];
if colinear != ManipulatorAngle::Free {
hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles"));
}
hints.push(HintInfo::keys([Key::Shift], "15° Increments"));
hints.push(HintInfo::keys([Key::Control], "Lock Angle"));
hints.push(drag_anchor);
hints
}
PointSelectState::HandleWithPair => {
let mut hints = vec![];
if colinear != ManipulatorAngle::Free {
hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles"));
}
hints.push(HintInfo::keys([Key::Shift], "15° Increments"));
hints.push(HintInfo::keys([Key::Control], "Lock Angle"));
hints.push(drag_anchor);
hints
}
PointSelectState::Anchor => Vec::new(),
};
if !toggle_group.is_empty() {
dragging_hint_data.0.push(HintGroup(toggle_group));
}
if !hold_group.is_empty() {
dragging_hint_data.0.push(HintGroup(hold_group));
}
if tool_data.molding_segment {
let mut has_colinear_anchors = false;
if let Some(segment) = &tool_data.segment {
let handle1 = HandleId::primary(segment.segment());
let handle2 = HandleId::end(segment.segment());
if let Some(vector) = document.network_interface.compute_modified_vector(segment.layer()) {
let other_handle1 = vector.other_colinear_handle(handle1);
let other_handle2 = vector.other_colinear_handle(handle2);
if other_handle1.is_some() || other_handle2.is_some() {
has_colinear_anchors = true;
}
};
}
let handles_stored = if let Some(other_handles) = tool_data.temporary_adjacent_handles_while_molding {
other_handles[0].is_some() || other_handles[1].is_some()
} else {
false
};
let molding_disable_possible = has_colinear_anchors || handles_stored;
let mut molding_hints = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])];
if molding_disable_possible {
molding_hints.push(HintGroup(vec![HintInfo::keys([Key::Alt], "Break Colinear Handles")]));
}
HintData(molding_hints)
} else {
dragging_hint_data
}
}
PathToolFsmState::Drawing { .. } => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
HintInfo::keys([Key::Alt], "Subtract").prepend_plus(),
]),
]),
PathToolFsmState::SlidingPoint => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]),
};
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}
@@ -3260,220 +3467,3 @@ fn calculate_adjacent_anchor_tangent(currently_dragged_handle: ManipulatorPointI
_ => (None, None),
}
}
fn update_dynamic_hints(
state: PathToolFsmState,
responses: &mut VecDeque<Message>,
shape_editor: &mut ShapeState,
document: &DocumentMessageHandler,
tool_data: &PathToolData,
tool_options: &PathToolOptions,
position: DVec2,
) {
// Condinting based on currently selected segment if it has any one g1 continuous handle
let hint_data = match state {
PathToolFsmState::Ready => {
// Show point sliding hints only when there is an anchor with colinear handles selected
let single_anchor_selected = shape_editor.selected_points().count() == 1 && shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_)));
let at_least_one_anchor_selected = shape_editor.selected_points().any(|point| matches!(point, ManipulatorPointId::Anchor(_)));
let at_least_one_point_selected = shape_editor.selected_points().count() >= 1;
let mut single_colinear_anchor_selected = false;
if single_anchor_selected {
if let (Some(anchor), Some(layer)) = (
shape_editor.selected_points().next(),
document.network_interface.selected_nodes().selected_layers(document.metadata()).next(),
) {
if let Some(vector) = document.network_interface.compute_modified_vector(layer) {
single_colinear_anchor_selected = vector.colinear(*anchor)
}
}
}
let mut drag_selected_hints = vec![HintInfo::mouse(MouseMotion::LmbDrag, "Drag Selected")];
let mut delete_selected_hints = vec![HintInfo::keys([Key::Delete], "Delete Selected")];
if at_least_one_anchor_selected {
delete_selected_hints.push(HintInfo::keys([Key::Accel], "No Dissolve").prepend_plus());
delete_selected_hints.push(HintInfo::keys([Key::Shift], "Cut Anchor").prepend_plus());
}
if single_colinear_anchor_selected {
drag_selected_hints.push(HintInfo::multi_keys([[Key::Control], [Key::Shift]], "Slide").prepend_plus());
}
let segment_edit = tool_options.path_editing_mode.segment_editing_mode;
let point_edit = tool_options.path_editing_mode.point_editing_mode;
let hovering_segment = tool_data.segment.is_some();
let hovering_point = shape_editor
.find_nearest_visible_point_indices(
&document.network_interface,
position,
SELECTION_THRESHOLD,
tool_options.path_overlay_mode,
&tool_data.frontier_handles_info,
)
.is_some();
let mut hint_data = if hovering_segment {
if segment_edit {
// Hovering a segment in segment editing mode
vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Select Segment"), HintInfo::keys([Key::Shift], "Extend").prepend_plus()]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Control], MouseMotion::Lmb, "Insert Point on Segment")]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Control], MouseMotion::LmbDrag, "Mold Segment")]),
]
} else {
// Hovering a segment in point editing mode
vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Insert Point on Segment")]),
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Mold Segment")]),
HintGroup(vec![HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "Delete Segment")]),
]
}
} else if hovering_point {
if point_edit {
// Hovering over a point in point editing mode
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Select Point"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
])]
} else {
// Hovering over a point in segment selection mode (will select a nearby segment)
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Select Segment"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
])]
}
} else {
vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"),
HintInfo::keys([Key::Control], "Lasso").prepend_plus(),
])]
};
if at_least_one_anchor_selected {
// TODO: Dynamically show either "Smooth" or "Sharp" based on the current state
hint_data.push(HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDouble, "Convert Anchor Point"),
HintInfo::keys_and_mouse([Key::Alt], MouseMotion::Lmb, "To Sharp"),
HintInfo::keys_and_mouse([Key::Alt], MouseMotion::LmbDrag, "To Smooth"),
]));
}
if at_least_one_point_selected {
let mut groups = vec![
HintGroup(drag_selected_hints),
HintGroup(vec![HintInfo::multi_keys([[Key::KeyG], [Key::KeyR], [Key::KeyS]], "Grab/Rotate/Scale Selected")]),
HintGroup(vec![HintInfo::arrow_keys("Nudge Selected"), HintInfo::keys([Key::Shift], "10x").prepend_plus()]),
HintGroup(delete_selected_hints),
];
hint_data.append(&mut groups);
}
HintData(hint_data)
}
PathToolFsmState::Dragging(dragging_state) => {
let colinear = dragging_state.colinear;
let mut dragging_hint_data = HintData(Vec::new());
dragging_hint_data
.0
.push(HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]));
let drag_anchor = HintInfo::keys([Key::Space], "Drag Anchor");
let toggle_group = match dragging_state.point_select_state {
PointSelectState::HandleNoPair | PointSelectState::HandleWithPair => {
let mut hints = vec![HintInfo::keys([Key::Tab], "Swap Dragged Handle")];
hints.push(HintInfo::keys(
[Key::KeyC],
if colinear == ManipulatorAngle::Colinear {
"Break Colinear Handles"
} else {
"Make Handles Colinear"
},
));
hints
}
PointSelectState::Anchor => Vec::new(),
};
let hold_group = match dragging_state.point_select_state {
PointSelectState::HandleNoPair => {
let mut hints = vec![];
if colinear != ManipulatorAngle::Free {
hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles"));
}
hints.push(HintInfo::keys([Key::Shift], "15° Increments"));
hints.push(HintInfo::keys([Key::Control], "Lock Angle"));
hints.push(drag_anchor);
hints
}
PointSelectState::HandleWithPair => {
let mut hints = vec![];
if colinear != ManipulatorAngle::Free {
hints.push(HintInfo::keys([Key::Alt], "Equidistant Handles"));
}
hints.push(HintInfo::keys([Key::Shift], "15° Increments"));
hints.push(HintInfo::keys([Key::Control], "Lock Angle"));
hints.push(drag_anchor);
hints
}
PointSelectState::Anchor => Vec::new(),
};
if !toggle_group.is_empty() {
dragging_hint_data.0.push(HintGroup(toggle_group));
}
if !hold_group.is_empty() {
dragging_hint_data.0.push(HintGroup(hold_group));
}
if tool_data.molding_segment {
let mut has_colinear_anchors = false;
if let Some(segment) = &tool_data.segment {
let handle1 = HandleId::primary(segment.segment());
let handle2 = HandleId::end(segment.segment());
if let Some(vector) = document.network_interface.compute_modified_vector(segment.layer()) {
let other_handle1 = vector.other_colinear_handle(handle1);
let other_handle2 = vector.other_colinear_handle(handle2);
if other_handle1.is_some() || other_handle2.is_some() {
has_colinear_anchors = true;
}
};
}
let handles_stored = if let Some(other_handles) = tool_data.temporary_adjacent_handles_while_molding {
other_handles[0].is_some() || other_handles[1].is_some()
} else {
false
};
let molding_disable_possible = has_colinear_anchors || handles_stored;
let mut molding_hints = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])];
if molding_disable_possible {
molding_hints.push(HintGroup(vec![HintInfo::keys([Key::Alt], "Break Colinear Handles")]));
}
HintData(molding_hints)
} else {
dragging_hint_data
}
}
PathToolFsmState::Drawing { .. } => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Select Area"),
HintInfo::keys([Key::Shift], "Extend").prepend_plus(),
HintInfo::keys([Key::Alt], "Subtract").prepend_plus(),
]),
]),
PathToolFsmState::SlidingPoint => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]),
};
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}

View File

@@ -2164,7 +2164,7 @@ impl Fsm for PenToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
PenToolFsmState::Ready | PenToolFsmState::GRSHandle => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Draw Path"),
@@ -2226,7 +2226,7 @@ impl Fsm for PenToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -1650,22 +1650,7 @@ impl Fsm for SelectToolFsmState {
}
}
fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque<Message>) -> bool {
// Check for standard hits or cursor events
match message {
ToolMessage::UpdateHints => {
self.update_hints(responses);
true
}
ToolMessage::UpdateCursor => {
self.update_cursor(responses);
true
}
_ => false,
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
match self {
SelectToolFsmState::Ready { selection } => {
let hint_data = HintData(vec![
@@ -1752,7 +1737,7 @@ impl Fsm for SelectToolFsmState {
}
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -233,7 +233,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for Shap
}
}
update_dynamic_hints(&self.fsm_state, responses, &self.tool_data);
self.fsm_state.update_hints(&self.tool_data, context, &self.options, responses);
self.send_layout(responses, LayoutTarget::ToolOptions);
}
@@ -914,100 +914,96 @@ impl Fsm for ShapeToolFsmState {
}
}
fn update_hints(&self, _responses: &mut VecDeque<Message>) {
// Moved logic to update_dynamic_hints
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair });
}
}
fn update_dynamic_hints(state: &ShapeToolFsmState, responses: &mut VecDeque<Message>, tool_data: &ShapeToolData) {
let hint_data = match state {
ShapeToolFsmState::Ready(_) => {
let hint_groups = match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star => vec![
HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Polygon"),
HintInfo::keys([Key::Shift], "Constrain Regular").prepend_plus(),
fn update_hints(&self, tool_data: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
ShapeToolFsmState::Ready(_) => {
let hint_groups = match tool_data.current_shape {
ShapeType::Polygon | ShapeType::Star => vec![
HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Polygon"),
HintInfo::keys([Key::Shift], "Constrain Regular").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
]),
HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")]),
],
ShapeType::Ellipse => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Ellipse"),
HintInfo::keys([Key::Shift], "Constrain Circular").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Line => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Line"),
HintInfo::keys([Key::Shift], "15° Increments").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
HintInfo::keys([Key::Control], "Lock Angle").prepend_plus(),
])],
ShapeType::Rectangle => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Rectangle"),
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"),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Arc => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Arc"),
HintInfo::keys([Key::Shift], "Constrain Arc").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
};
HintData(hint_groups)
}
ShapeToolFsmState::Drawing(shape) => {
let mut common_hint_group = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])];
let tool_hint_group = match shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Arc => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Regular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Rectangle => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Ellipse => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Circular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Line => HintGroup(vec![
HintInfo::keys([Key::Shift], "15° Increments"),
HintInfo::keys([Key::Alt], "From Center"),
HintInfo::keys([Key::Control], "Lock Angle"),
]),
HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")]),
],
ShapeType::Ellipse => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Ellipse"),
HintInfo::keys([Key::Shift], "Constrain Circular").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Line => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Line"),
HintInfo::keys([Key::Shift], "15° Increments").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
HintInfo::keys([Key::Control], "Lock Angle").prepend_plus(),
])],
ShapeType::Rectangle => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Rectangle"),
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"),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
ShapeType::Arc => vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::LmbDrag, "Draw Arc"),
HintInfo::keys([Key::Shift], "Constrain Arc").prepend_plus(),
HintInfo::keys([Key::Alt], "From Center").prepend_plus(),
])],
};
HintData(hint_groups)
}
ShapeToolFsmState::Drawing(shape) => {
let mut common_hint_group = vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])];
let tool_hint_group = match shape {
ShapeType::Polygon | ShapeType::Star | ShapeType::Arc => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Regular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Rectangle => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Square"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Ellipse => HintGroup(vec![HintInfo::keys([Key::Shift], "Constrain Circular"), HintInfo::keys([Key::Alt], "From Center")]),
ShapeType::Line => HintGroup(vec![
ShapeType::Circle => HintGroup(vec![HintInfo::keys([Key::Alt], "From Center")]),
};
if !tool_hint_group.0.is_empty() {
common_hint_group.push(tool_hint_group);
}
if matches!(shape, ShapeType::Polygon | ShapeType::Star) {
common_hint_group.push(HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")]));
}
HintData(common_hint_group)
}
ShapeToolFsmState::DraggingLineEndpoints => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![
HintInfo::keys([Key::Shift], "15° Increments"),
HintInfo::keys([Key::Alt], "From Center"),
HintInfo::keys([Key::Control], "Lock Angle"),
]),
ShapeType::Circle => HintGroup(vec![HintInfo::keys([Key::Alt], "From Center")]),
};
if !tool_hint_group.0.is_empty() {
common_hint_group.push(tool_hint_group);
}
if matches!(shape, ShapeType::Polygon | ShapeType::Star) {
common_hint_group.push(HintGroup(vec![HintInfo::multi_keys([[Key::BracketLeft], [Key::BracketRight]], "Decrease/Increase Sides")]));
}
HintData(common_hint_group)
}
ShapeToolFsmState::DraggingLineEndpoints => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![
HintInfo::keys([Key::Shift], "15° Increments"),
HintInfo::keys([Key::Alt], "From Center"),
HintInfo::keys([Key::Control], "Lock Angle"),
]),
]),
ShapeToolFsmState::ResizingBounds => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Alt], "From Pivot"), HintInfo::keys([Key::Shift], "Preserve Aspect Ratio")]),
]),
ShapeToolFsmState::RotatingBounds => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]),
]),
ShapeToolFsmState::SkewingBounds { .. } => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Control], "Unlock Slide")]),
]),
ShapeToolFsmState::ModifyingGizmo => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]),
};
responses.add(FrontendMessage::UpdateInputHints { hint_data });
ShapeToolFsmState::ResizingBounds => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Alt], "From Pivot"), HintInfo::keys([Key::Shift], "Preserve Aspect Ratio")]),
]),
ShapeToolFsmState::RotatingBounds => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments")]),
]),
ShapeToolFsmState::SkewingBounds { .. } => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()]),
HintGroup(vec![HintInfo::keys([Key::Control], "Unlock Slide")]),
]),
ShapeToolFsmState::ModifyingGizmo => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]),
};
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Crosshair });
}
}

View File

@@ -450,7 +450,7 @@ impl Fsm for SplineToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
SplineToolFsmState::Ready => HintData(vec![HintGroup(vec![
HintInfo::mouse(MouseMotion::Lmb, "Draw Spline"),
@@ -467,7 +467,7 @@ impl Fsm for SplineToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::Default });
}
}

View File

@@ -886,7 +886,7 @@ impl Fsm for TextToolFsmState {
}
}
fn update_hints(&self, responses: &mut VecDeque<Message>) {
fn update_hints(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let hint_data = match self {
TextToolFsmState::Ready => HintData(vec![
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Place Text")]),
@@ -915,7 +915,7 @@ impl Fsm for TextToolFsmState {
responses.add(FrontendMessage::UpdateInputHints { hint_data });
}
fn update_cursor(&self, responses: &mut VecDeque<Message>) {
fn update_cursor(&self, _: &Self::ToolData, _: &ToolActionMessageContext, _: &Self::ToolOptions, responses: &mut VecDeque<Message>) {
let cursor = match self {
TextToolFsmState::Placing => MouseCursorIcon::Crosshair,
_ => MouseCursorIcon::Text,

View File

@@ -56,20 +56,27 @@ pub trait Fsm {
fn transition(self, message: ToolMessage, tool_data: &mut Self::ToolData, transition_data: &mut ToolActionMessageContext, options: &Self::ToolOptions, responses: &mut VecDeque<Message>) -> Self;
/// Implementing this trait function lets a specific tool provide a list of hints (user input actions presently available) to draw in the footer bar.
fn update_hints(&self, responses: &mut VecDeque<Message>);
fn update_hints(&self, tool_data: &Self::ToolData, transition_data: &ToolActionMessageContext, options: &Self::ToolOptions, responses: &mut VecDeque<Message>);
/// Implementing this trait function lets a specific tool set the current mouse cursor icon.
fn update_cursor(&self, responses: &mut VecDeque<Message>);
fn update_cursor(&self, tool_data: &Self::ToolData, transition_data: &ToolActionMessageContext, options: &Self::ToolOptions, responses: &mut VecDeque<Message>);
/// If this message is a standard tool message, process it and return true. Standard tool messages are those which are common across every tool.
fn standard_tool_messages(&self, message: &ToolMessage, responses: &mut VecDeque<Message>) -> bool {
fn standard_tool_messages(
&self,
message: &ToolMessage,
tool_data: &Self::ToolData,
transition_data: &ToolActionMessageContext,
options: &Self::ToolOptions,
responses: &mut VecDeque<Message>,
) -> bool {
// Check for standard hits or cursor events
match message {
ToolMessage::UpdateHints => {
self.update_hints(responses);
self.update_hints(tool_data, transition_data, options, responses);
true
}
ToolMessage::UpdateCursor => {
self.update_cursor(responses);
self.update_cursor(tool_data, transition_data, options, responses);
true
}
_ => false,
@@ -90,7 +97,7 @@ pub trait Fsm {
Self: PartialEq + Sized + Copy,
{
// If this message is one of the standard tool messages, process it and exit early
if self.standard_tool_messages(&message, responses) {
if self.standard_tool_messages(&message, tool_data, transition_data, options, responses) {
return;
}
@@ -100,9 +107,9 @@ pub trait Fsm {
// Update state
if *self != new_state {
*self = new_state;
self.update_hints(responses);
self.update_hints(tool_data, transition_data, options, responses);
if update_cursor_on_transition {
self.update_cursor(responses);
self.update_cursor(tool_data, transition_data, options, responses);
}
}
}