Disable the Path tool's "Colinear Handles" checkbox when no interior anchors are selected (#2339)
* disable "Colinear Handles" checkbox when only endpoint or its handle is selected * small refactor * ignore endpoints when calculating multiple selected points colinearity --------- Co-authored-by: indierusty <priyaayadav@gmail.com> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
381dcbf17f
commit
0a91dd2141
|
|
@ -575,7 +575,7 @@ impl ShapeState {
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the selected manipulator groups, returning whether their handles have mixed, colinear, or free angles.
|
/// Iterates over the selected manipulator groups exluding endpoints, returning whether their handles have mixed, colinear, or free angles.
|
||||||
/// If there are no points selected this function returns mixed.
|
/// If there are no points selected this function returns mixed.
|
||||||
pub fn selected_manipulator_angles(&self, network_interface: &NodeNetworkInterface) -> ManipulatorAngle {
|
pub fn selected_manipulator_angles(&self, network_interface: &NodeNetworkInterface) -> ManipulatorAngle {
|
||||||
// This iterator contains a bool indicating whether or not selected points' manipulator groups have colinear handles.
|
// This iterator contains a bool indicating whether or not selected points' manipulator groups have colinear handles.
|
||||||
|
|
@ -583,7 +583,13 @@ impl ShapeState {
|
||||||
.selected_shape_state
|
.selected_shape_state
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(&layer, selection_state)| (network_interface.compute_modified_vector(layer), selection_state))
|
.map(|(&layer, selection_state)| (network_interface.compute_modified_vector(layer), selection_state))
|
||||||
.flat_map(|(data, selection_state)| selection_state.selected_points.iter().map(move |&point| data.as_ref().is_some_and(|data| data.colinear(point))));
|
.flat_map(|(data, selection_state)| {
|
||||||
|
selection_state.selected_points.iter().filter_map(move |&point| {
|
||||||
|
let Some(data) = &data else { return None };
|
||||||
|
let Some(_) = point.get_handle_pair(&data) else { return None }; // ignores the endpoints.
|
||||||
|
Some(data.colinear(point))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let Some(first_is_colinear) = points_colinear_status.next() else { return ManipulatorAngle::Mixed };
|
let Some(first_is_colinear) = points_colinear_status.next() else { return ManipulatorAngle::Mixed };
|
||||||
if points_colinear_status.any(|point| first_is_colinear != point) {
|
if points_colinear_status.any(|point| first_is_colinear != point) {
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ impl LayoutHolder for PathTool {
|
||||||
// TODO: Remove `unwrap_or_default` once checkboxes are capable of displaying a mixed state
|
// TODO: Remove `unwrap_or_default` once checkboxes are capable of displaying a mixed state
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let colinear_handle_checkbox = CheckboxInput::new(colinear_handles_state)
|
let colinear_handle_checkbox = CheckboxInput::new(colinear_handles_state)
|
||||||
.disabled(self.tool_data.selection_status.is_none())
|
.disabled(!self.tool_data.can_toggle_colinearity)
|
||||||
.on_update(|&CheckboxInput { checked, .. }| {
|
.on_update(|&CheckboxInput { checked, .. }| {
|
||||||
if checked {
|
if checked {
|
||||||
PathToolMessage::ManipulatorMakeHandlesColinear.into()
|
PathToolMessage::ManipulatorMakeHandlesColinear.into()
|
||||||
|
|
@ -186,7 +186,7 @@ impl LayoutHolder for PathTool {
|
||||||
.tooltip(colinear_handles_tooltip)
|
.tooltip(colinear_handles_tooltip)
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
let colinear_handles_label = TextLabel::new("Colinear Handles")
|
let colinear_handles_label = TextLabel::new("Colinear Handles")
|
||||||
.disabled(self.tool_data.selection_status.is_none())
|
.disabled(!self.tool_data.can_toggle_colinearity)
|
||||||
.tooltip(colinear_handles_tooltip)
|
.tooltip(colinear_handles_tooltip)
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
|
||||||
|
|
@ -359,7 +359,10 @@ struct PathToolData {
|
||||||
opposing_handle_lengths: Option<OpposingHandleLengths>,
|
opposing_handle_lengths: Option<OpposingHandleLengths>,
|
||||||
/// Describes information about the selected point(s), if any, across one or multiple shapes and manipulator point types (anchor or handle).
|
/// Describes information about the selected point(s), if any, across one or multiple shapes and manipulator point types (anchor or handle).
|
||||||
/// The available information varies depending on whether `None`, `One`, or `Multiple` points are currently selected.
|
/// The available information varies depending on whether `None`, `One`, or `Multiple` points are currently selected.
|
||||||
|
/// NOTE: It must be updated using `update_selection_status` to ensure `can_toggle_colinearity` stays synchronized with the current selection.
|
||||||
selection_status: SelectionStatus,
|
selection_status: SelectionStatus,
|
||||||
|
/// `true` if we can change the current selection to colinear or not.
|
||||||
|
can_toggle_colinearity: bool,
|
||||||
segment: Option<ClosestSegment>,
|
segment: Option<ClosestSegment>,
|
||||||
snap_cache: SnapCache,
|
snap_cache: SnapCache,
|
||||||
double_click_handled: bool,
|
double_click_handled: bool,
|
||||||
|
|
@ -415,6 +418,20 @@ impl PathToolData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_selection_status(&mut self, shape_editor: &mut ShapeState, document: &DocumentMessageHandler) {
|
||||||
|
let selection_status = get_selection_status(&document.network_interface, shape_editor);
|
||||||
|
|
||||||
|
self.can_toggle_colinearity = match &selection_status {
|
||||||
|
SelectionStatus::None => false,
|
||||||
|
SelectionStatus::One(single_selected_point) => {
|
||||||
|
let vector_data = document.network_interface.compute_modified_vector(single_selected_point.layer).unwrap();
|
||||||
|
single_selected_point.id.get_handle_pair(&vector_data).is_some()
|
||||||
|
}
|
||||||
|
SelectionStatus::Multiple(_) => true,
|
||||||
|
};
|
||||||
|
self.selection_status = selection_status;
|
||||||
|
}
|
||||||
|
|
||||||
fn start_insertion(&mut self, responses: &mut VecDeque<Message>, segment: ClosestSegment) -> PathToolFsmState {
|
fn start_insertion(&mut self, responses: &mut VecDeque<Message>, segment: ClosestSegment) -> PathToolFsmState {
|
||||||
if self.segment.is_some() {
|
if self.segment.is_some() {
|
||||||
warn!("Segment was `Some(..)` before `start_insertion`")
|
warn!("Segment was `Some(..)` before `start_insertion`")
|
||||||
|
|
@ -1302,7 +1319,7 @@ impl Fsm for PathToolFsmState {
|
||||||
point_select_state: shape_editor.get_dragging_state(&document.network_interface),
|
point_select_state: shape_editor.get_dragging_state(&document.network_interface),
|
||||||
colinear,
|
colinear,
|
||||||
};
|
};
|
||||||
tool_data.selection_status = get_selection_status(&document.network_interface, shape_editor);
|
tool_data.update_selection_status(shape_editor, document);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, PathToolMessage::ManipulatorMakeHandlesColinear) => {
|
(_, PathToolMessage::ManipulatorMakeHandlesColinear) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue