mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 23:38:06 +08:00
Extract drag state to new file
This commit is contained in:
@@ -451,6 +451,19 @@ impl LayerNodeIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<NodeId> for LayerNodeIdentifier {
|
||||
fn eq(&self, other: &NodeId) -> bool {
|
||||
self.to_node() == *other
|
||||
}
|
||||
}
|
||||
|
||||
// Implement <BookFormat> == <Book> comparisons
|
||||
impl PartialEq<LayerNodeIdentifier> for NodeId {
|
||||
fn eq(&self, other: &LayerNodeIdentifier) -> bool {
|
||||
other.to_node() == *self
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// AxisIter
|
||||
// ========
|
||||
|
||||
@@ -1317,15 +1317,11 @@ impl NodeNetworkInterface {
|
||||
/// Layers excluding ones that are children of other layers in the list in layer tree order.
|
||||
// TODO: Cache this
|
||||
// Now allocation free!
|
||||
pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> ShallowestSelectionIter<'_> {
|
||||
pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> ShallowestSelectionIter<'_, NodeId> {
|
||||
// Avoids the clone and filtering from from the selected_nodes_in_nested_network.
|
||||
let metadata = self.network_metadata(network_path);
|
||||
let selection = metadata.and_then(|metadata| metadata.persistent_metadata.selection_undo_history.back());
|
||||
ShallowestSelectionIter {
|
||||
selection: selection.map_or([].as_slice(), |selection| selection.0.as_slice()),
|
||||
next: Some(LayerNodeIdentifier::ROOT_PARENT),
|
||||
metadata: self.document_metadata(),
|
||||
}
|
||||
ShallowestSelectionIter::new(self.document_metadata(), selection.map_or([].as_slice(), |selection| selection.0.as_slice()))
|
||||
}
|
||||
|
||||
/// Ancestor that is shared by all layers and that is deepest (more nested). Default may be the root. Skips selected non-folder, non-artboard layers
|
||||
@@ -6997,13 +6993,23 @@ pub enum TransactionStatus {
|
||||
|
||||
/// Iterate through the shallowest selected layers without allocating
|
||||
#[derive(Clone)]
|
||||
pub struct ShallowestSelectionIter<'a> {
|
||||
pub struct ShallowestSelectionIter<'a, T: PartialEq<LayerNodeIdentifier>> {
|
||||
next: Option<LayerNodeIdentifier>,
|
||||
selection: &'a [NodeId], // TODO: should be HashSet to avoid duplicates.
|
||||
selection: &'a [T], // TODO: should be HashSet to avoid duplicates.
|
||||
metadata: &'a DocumentMetadata,
|
||||
}
|
||||
|
||||
impl Iterator for ShallowestSelectionIter<'_> {
|
||||
impl<'a, T: PartialEq<LayerNodeIdentifier>> ShallowestSelectionIter<'a, T> {
|
||||
pub fn new(metadata: &'a DocumentMetadata, selection: &'a [T]) -> Self {
|
||||
ShallowestSelectionIter {
|
||||
selection,
|
||||
next: Some(LayerNodeIdentifier::ROOT_PARENT),
|
||||
metadata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq<LayerNodeIdentifier>> Iterator for ShallowestSelectionIter<'_, T> {
|
||||
type Item = LayerNodeIdentifier;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -7012,7 +7018,7 @@ impl Iterator for ShallowestSelectionIter<'_> {
|
||||
let below_in_tree = || layer_node.ancestors(self.metadata).find_map(|ancestor| ancestor.next_sibling(self.metadata));
|
||||
|
||||
// If the current layer is selected, return it.
|
||||
if layer_node != LayerNodeIdentifier::ROOT_PARENT && self.selection.contains(&layer_node.to_node()) {
|
||||
if layer_node != LayerNodeIdentifier::ROOT_PARENT && self.selection.iter().any(|selection| *selection == layer_node) {
|
||||
self.next = below_in_tree(); // Go straight to below and don't look at children
|
||||
return Some(layer_node);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
|
||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{NodeNetworkInterface, ShallowestSelectionIter};
|
||||
use crate::messages::preferences::SelectionMode;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose};
|
||||
@@ -25,8 +25,10 @@ use graphene_std::renderer::Quad;
|
||||
use graphene_std::renderer::Rect;
|
||||
use graphene_std::transform::ReferencePoint;
|
||||
|
||||
mod drag_state;
|
||||
mod duplicate;
|
||||
pub mod options;
|
||||
use drag_state::*;
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
pub struct SelectTool {
|
||||
@@ -162,85 +164,6 @@ impl Default for SelectToolFsmState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the current drag in progress
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct DragState {
|
||||
pub start_document: DVec2,
|
||||
pub current_document: DVec2,
|
||||
/// Selection mode is set when the drag exceeds a certain distance. Once resolved, the selection mode cannot change.
|
||||
resolved_selection_mode: Option<SelectionMode>,
|
||||
}
|
||||
|
||||
impl DragState {
|
||||
pub fn new(input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) -> Self {
|
||||
let document_mouse = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
Self {
|
||||
start_document: document_mouse,
|
||||
current_document: document_mouse,
|
||||
resolved_selection_mode: None,
|
||||
}
|
||||
}
|
||||
pub fn set_current(&mut self, input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) {
|
||||
self.current_document = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
}
|
||||
|
||||
pub fn start_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_point2(self.start_document)
|
||||
}
|
||||
|
||||
pub fn current_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_point2(self.current_document)
|
||||
}
|
||||
|
||||
pub fn start_current_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
|
||||
[self.start_viewport(metadata), self.current_viewport(metadata)]
|
||||
}
|
||||
|
||||
pub fn total_drag_delta_document(&self) -> DVec2 {
|
||||
self.current_document - self.start_document
|
||||
}
|
||||
|
||||
pub fn total_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_vector2(self.total_drag_delta_document())
|
||||
}
|
||||
|
||||
pub fn inverse_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
-self.total_drag_delta_viewport(metadata)
|
||||
}
|
||||
|
||||
fn update_selection_mode(&mut self, metadata: &DocumentMetadata, preferences: &PreferencesMessageHandler) -> SelectionMode {
|
||||
if let Some(resolved_selection_mode) = self.resolved_selection_mode {
|
||||
return resolved_selection_mode;
|
||||
}
|
||||
if preferences.get_selection_mode() != SelectionMode::Directional {
|
||||
self.resolved_selection_mode = Some(preferences.get_selection_mode());
|
||||
return preferences.get_selection_mode();
|
||||
}
|
||||
|
||||
let [start, current] = self.start_current_viewport(metadata);
|
||||
|
||||
// Drag direction cannot be resolved TODO: why not consider only X distance?
|
||||
if start.distance_squared(current) >= DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2) {
|
||||
let selection_mode = if current.x < start.x { SelectionMode::Touched } else { SelectionMode::Enclosed };
|
||||
self.resolved_selection_mode = Some(selection_mode);
|
||||
return selection_mode;
|
||||
}
|
||||
|
||||
SelectionMode::default()
|
||||
}
|
||||
|
||||
/// A viewport quad representing the drag bounds. Expanded if the start == end
|
||||
pub fn expanded_selection_box_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
|
||||
let [start, current] = self.start_current_viewport(metadata);
|
||||
if start == current {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
[current - tolerance, current + tolerance]
|
||||
} else {
|
||||
[start, current]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct SelectToolData {
|
||||
drag: DragState,
|
||||
@@ -879,6 +802,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
let snap_data = SnapData::ignore(document, input, ignore);
|
||||
let [start, current] = tool_data.drag.start_current_viewport(document.metadata());
|
||||
|
||||
let e0 = tool_data
|
||||
.bounding_box_manager
|
||||
.as_ref()
|
||||
@@ -893,7 +817,7 @@ impl Fsm for SelectToolFsmState {
|
||||
};
|
||||
|
||||
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
|
||||
for layer in document.network_interface.shallowest_unique_layers(&[]) {
|
||||
for layer in ShallowestSelectionIter::new(document.metadata(), &tool_data.layers_dragging) {
|
||||
responses.add_front(GraphOperationMessage::TransformChange {
|
||||
layer,
|
||||
transform: DAffine2::from_translation(mouse_delta),
|
||||
@@ -901,9 +825,8 @@ impl Fsm for SelectToolFsmState {
|
||||
skip_rerender: false,
|
||||
});
|
||||
}
|
||||
tool_data.drag.current_document += document.metadata().document_to_viewport.inverse().transform_vector2(mouse_delta);
|
||||
|
||||
info!("current {} mouse {}", tool_data.drag.current_viewport(document.metadata()), input.mouse.position);
|
||||
tool_data.drag.offset_viewport(mouse_delta, document.metadata());
|
||||
|
||||
// Auto-panning
|
||||
let messages = [
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
use crate::consts::{DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD, SELECTION_TOLERANCE};
|
||||
use crate::messages::{portfolio::document::utility_types::document_metadata::DocumentMetadata, preferences::SelectionMode, tool::tool_messages::tool_prelude::*};
|
||||
/// Represents the current drag in progress
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DragState {
|
||||
pub start_document: DVec2,
|
||||
pub current_document: DVec2,
|
||||
/// Selection mode is set when the drag exceeds a certain distance. Once resolved, the selection mode cannot change.
|
||||
resolved_selection_mode: Option<SelectionMode>,
|
||||
}
|
||||
|
||||
impl DragState {
|
||||
pub fn new(input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) -> Self {
|
||||
let document_mouse = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
Self {
|
||||
start_document: document_mouse,
|
||||
current_document: document_mouse,
|
||||
resolved_selection_mode: None,
|
||||
}
|
||||
}
|
||||
pub fn set_current(&mut self, input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) {
|
||||
self.current_document = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
|
||||
}
|
||||
|
||||
pub fn offset_viewport(&mut self, offset: DVec2, metadata: &DocumentMetadata) {
|
||||
self.current_document = self.current_document + metadata.document_to_viewport.inverse().transform_vector2(offset);
|
||||
}
|
||||
|
||||
pub fn start_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_point2(self.start_document)
|
||||
}
|
||||
|
||||
pub fn current_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_point2(self.current_document)
|
||||
}
|
||||
|
||||
pub fn start_current_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
|
||||
[self.start_viewport(metadata), self.current_viewport(metadata)]
|
||||
}
|
||||
|
||||
pub fn total_drag_delta_document(&self) -> DVec2 {
|
||||
self.current_document - self.start_document
|
||||
}
|
||||
|
||||
pub fn total_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
metadata.document_to_viewport.transform_vector2(self.total_drag_delta_document())
|
||||
}
|
||||
|
||||
pub fn inverse_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
|
||||
-self.total_drag_delta_viewport(metadata)
|
||||
}
|
||||
|
||||
pub fn update_selection_mode(&mut self, metadata: &DocumentMetadata, preferences: &PreferencesMessageHandler) -> SelectionMode {
|
||||
if let Some(resolved_selection_mode) = self.resolved_selection_mode {
|
||||
return resolved_selection_mode;
|
||||
}
|
||||
if preferences.get_selection_mode() != SelectionMode::Directional {
|
||||
self.resolved_selection_mode = Some(preferences.get_selection_mode());
|
||||
return preferences.get_selection_mode();
|
||||
}
|
||||
|
||||
let [start, current] = self.start_current_viewport(metadata);
|
||||
|
||||
// Drag direction cannot be resolved TODO: why not consider only X distance?
|
||||
if start.distance_squared(current) >= DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2) {
|
||||
let selection_mode = if current.x < start.x { SelectionMode::Touched } else { SelectionMode::Enclosed };
|
||||
self.resolved_selection_mode = Some(selection_mode);
|
||||
return selection_mode;
|
||||
}
|
||||
|
||||
SelectionMode::default()
|
||||
}
|
||||
|
||||
/// A viewport quad representing the drag bounds. Expanded if the start == end
|
||||
pub fn expanded_selection_box_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
|
||||
let [start, current] = self.start_current_viewport(metadata);
|
||||
if start == current {
|
||||
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
|
||||
[current - tolerance, current + tolerance]
|
||||
} else {
|
||||
[start, current]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::super::tool_prelude::*;
|
||||
use super::DragState;
|
||||
use super::drag_state::DragState;
|
||||
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeTemplate};
|
||||
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||
use crate::messages::tool::tool_messages::select_tool::LayerNodeIdentifier;
|
||||
|
||||
Reference in New Issue
Block a user