mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 02:28:12 +08:00
Add the settings popover menu for the Overlays toggle (#2523)
* Added granular overlays control based on features * Added basic support for pivot, path, anchors and handles overlay settings * Added more overlay checks on anchors and handles * Add new settings over measurements, hover and selection overlays * Fix errors introduced while rebasing * Disable anchors and handles functionality with their overlays, extended selection outline check * Add check to enable/disable outlines on selected layers * Toggle handles checkbox in sync with anchors checkbox * Refactor overlays checks * Remove debug statements * Update select_tool.rs to resolve conflict * Minor fix to reflect anchor checkbox state on the handles * Minor fix to make anchors checkbox work * Rearrange menu items, and code review * Fix pivot dragging * Add handles overlay check when drawing with pen tool * Fix constrained dragging when transform cage is disabled * Fix deselecting user selection when anchors are disabled * Minor fix for disabling anchors * Remove All from OverlaysType * Remove debug statements * Fix editor crash when selecting other layers with path tool and anchors disabled * Minor fix on overlays check for all overlays * Add proper code formatting * Nits --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
1f7a9188ba
commit
1a81e45673
@@ -19,6 +19,8 @@ pub struct Pivot {
|
||||
pivot: Option<DVec2>,
|
||||
/// The old pivot position in the GUI, used to reduce refreshes of the document bar
|
||||
old_pivot_position: ReferencePoint,
|
||||
/// Used to enable and disable the pivot
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl Default for Pivot {
|
||||
@@ -28,6 +30,7 @@ impl Default for Pivot {
|
||||
transform_from_normalized: Default::default(),
|
||||
pivot: Default::default(),
|
||||
old_pivot_position: ReferencePoint::Center,
|
||||
active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +47,10 @@ impl Pivot {
|
||||
|
||||
/// Recomputes the pivot position and transform.
|
||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
let selected_nodes = document.network_interface.selected_nodes();
|
||||
let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface);
|
||||
let Some(first) = layers.next() else {
|
||||
@@ -82,6 +89,13 @@ impl Pivot {
|
||||
}
|
||||
|
||||
pub fn update_pivot(&mut self, document: &DocumentMessageHandler, overlay_context: &mut OverlayContext, draw_data: Option<(f64,)>) {
|
||||
if !overlay_context.visibility_settings.pivot() {
|
||||
self.active = false;
|
||||
return;
|
||||
} else {
|
||||
self.active = true;
|
||||
}
|
||||
|
||||
self.recalculate_pivot(document);
|
||||
if let (Some(pivot), Some(data)) = (self.pivot, draw_data) {
|
||||
overlay_context.pivot(pivot, data.0);
|
||||
@@ -90,6 +104,10 @@ impl Pivot {
|
||||
|
||||
/// Answers if the pivot widget has changed (so we should refresh the tool bar at the top of the canvas).
|
||||
pub fn should_refresh_pivot_position(&mut self) -> bool {
|
||||
if !self.active {
|
||||
return false;
|
||||
}
|
||||
|
||||
let new = self.to_pivot_position();
|
||||
let should_refresh = new != self.old_pivot_position;
|
||||
self.old_pivot_position = new;
|
||||
@@ -102,6 +120,10 @@ impl Pivot {
|
||||
|
||||
/// Sets the viewport position of the pivot for all selected layers.
|
||||
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
for layer in document.network_interface.selected_nodes().selected_visible_and_unlocked_layers(&document.network_interface) {
|
||||
let transform = Self::get_layer_pivot_transform(layer, document);
|
||||
// Only update the pivot when computed position is finite.
|
||||
@@ -115,11 +137,18 @@ impl Pivot {
|
||||
|
||||
/// Set the pivot using the normalized transform that is set above.
|
||||
pub fn set_normalized_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
self.set_viewport_position(self.transform_from_normalized.transform_point2(position), document, responses);
|
||||
}
|
||||
|
||||
/// Answers if the pointer is currently positioned over the pivot.
|
||||
pub fn is_over(&self, mouse: DVec2) -> bool {
|
||||
if !self.active {
|
||||
return false;
|
||||
}
|
||||
self.pivot.filter(|&pivot| mouse.distance_squared(pivot) < (PIVOT_DIAMETER / 2.).powi(2)).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ pub enum ManipulatorAngle {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SelectedLayerState {
|
||||
selected_points: HashSet<ManipulatorPointId>,
|
||||
ignore_handles: bool,
|
||||
ignore_anchors: bool,
|
||||
}
|
||||
|
||||
impl SelectedLayerState {
|
||||
@@ -52,12 +54,32 @@ impl SelectedLayerState {
|
||||
self.selected_points.contains(&point)
|
||||
}
|
||||
pub fn select_point(&mut self, point: ManipulatorPointId) {
|
||||
if (point.as_handle().is_some() && self.ignore_handles) || (point.as_anchor().is_some() && self.ignore_anchors) {
|
||||
return;
|
||||
}
|
||||
self.selected_points.insert(point);
|
||||
}
|
||||
pub fn deselect_point(&mut self, point: ManipulatorPointId) {
|
||||
if (point.as_handle().is_some() && self.ignore_handles) || (point.as_anchor().is_some() && self.ignore_anchors) {
|
||||
return;
|
||||
}
|
||||
self.selected_points.remove(&point);
|
||||
}
|
||||
pub fn set_handles_status(&mut self, ignore: bool) {
|
||||
self.ignore_handles = ignore;
|
||||
}
|
||||
pub fn set_anchors_status(&mut self, ignore: bool) {
|
||||
self.ignore_anchors = ignore;
|
||||
}
|
||||
pub fn clear_points_force(&mut self) {
|
||||
self.selected_points.clear();
|
||||
self.ignore_handles = false;
|
||||
self.ignore_anchors = false;
|
||||
}
|
||||
pub fn clear_points(&mut self) {
|
||||
if self.ignore_handles || self.ignore_anchors {
|
||||
return;
|
||||
}
|
||||
self.selected_points.clear();
|
||||
}
|
||||
pub fn selected_points_count(&self) -> usize {
|
||||
@@ -524,6 +546,52 @@ impl ShapeState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_selected_anchors(&mut self) {
|
||||
for state in self.selected_shape_state.values_mut() {
|
||||
state.set_anchors_status(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_selected_handles(&mut self) {
|
||||
for state in self.selected_shape_state.values_mut() {
|
||||
state.set_handles_status(false);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ignore_selected_anchors(&mut self) {
|
||||
for state in self.selected_shape_state.values_mut() {
|
||||
state.set_anchors_status(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ignore_selected_handles(&mut self) {
|
||||
for state in self.selected_shape_state.values_mut() {
|
||||
state.set_handles_status(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Deselects all the anchors across every selected layer.
|
||||
pub fn deselect_all_anchors(&mut self) {
|
||||
for (_, state) in self.selected_shape_state.iter_mut() {
|
||||
let selected_anchor_points: Vec<ManipulatorPointId> = state.selected_points.iter().filter(|selected_point| selected_point.as_anchor().is_some()).cloned().collect();
|
||||
|
||||
for point in selected_anchor_points {
|
||||
state.deselect_point(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Deselects all the handles across every selected layer.
|
||||
pub fn deselect_all_handles(&mut self) {
|
||||
for (_, state) in self.selected_shape_state.iter_mut() {
|
||||
let selected_handle_points: Vec<ManipulatorPointId> = state.selected_points.iter().filter(|selected_point| selected_point.as_handle().is_some()).cloned().collect();
|
||||
|
||||
for point in selected_handle_points {
|
||||
state.deselect_point(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the shapes we consider for selection, we will choose draggable manipulators from these shapes.
|
||||
pub fn set_selected_layers(&mut self, target_layers: Vec<LayerNodeIdentifier>) {
|
||||
self.selected_shape_state.retain(|layer_path, _| target_layers.contains(layer_path));
|
||||
@@ -632,7 +700,7 @@ impl ShapeState {
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Iterates over the selected manipulator groups exluding endpoints, returning whether their handles have mixed, colinear, or free angles.
|
||||
/// Iterates over the selected manipulator groups excluding endpoints, returning whether their handles have mixed, colinear, or free angles.
|
||||
/// If there are no points selected this function returns mixed.
|
||||
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.
|
||||
@@ -1495,7 +1563,7 @@ impl ShapeState {
|
||||
pub fn select_all_in_shape(&mut self, network_interface: &NodeNetworkInterface, selection_shape: SelectionShape, selection_change: SelectionChange) {
|
||||
for (&layer, state) in &mut self.selected_shape_state {
|
||||
if selection_change == SelectionChange::Clear {
|
||||
state.clear_points()
|
||||
state.clear_points_force()
|
||||
}
|
||||
|
||||
let vector_data = network_interface.compute_modified_vector(layer);
|
||||
|
||||
Reference in New Issue
Block a user