Skip to content

Commit cd8beb5

Browse files
committed
Extract drag state to new file
1 parent ba1ea6a commit cd8beb5

File tree

5 files changed

+120
-94
lines changed

5 files changed

+120
-94
lines changed

editor/src/messages/portfolio/document/utility_types/document_metadata.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,19 @@ impl LayerNodeIdentifier {
451451
}
452452
}
453453

454+
impl PartialEq<NodeId> for LayerNodeIdentifier {
455+
fn eq(&self, other: &NodeId) -> bool {
456+
self.to_node() == *other
457+
}
458+
}
459+
460+
// Implement <BookFormat> == <Book> comparisons
461+
impl PartialEq<LayerNodeIdentifier> for NodeId {
462+
fn eq(&self, other: &LayerNodeIdentifier) -> bool {
463+
other.to_node() == *self
464+
}
465+
}
466+
454467
// ========
455468
// AxisIter
456469
// ========

editor/src/messages/portfolio/document/utility_types/network_interface.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,15 +1317,11 @@ impl NodeNetworkInterface {
13171317
/// Layers excluding ones that are children of other layers in the list in layer tree order.
13181318
// TODO: Cache this
13191319
// Now allocation free!
1320-
pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> ShallowestSelectionIter<'_> {
1320+
pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> ShallowestSelectionIter<'_, NodeId> {
13211321
// Avoids the clone and filtering from from the selected_nodes_in_nested_network.
13221322
let metadata = self.network_metadata(network_path);
13231323
let selection = metadata.and_then(|metadata| metadata.persistent_metadata.selection_undo_history.back());
1324-
ShallowestSelectionIter {
1325-
selection: selection.map_or([].as_slice(), |selection| selection.0.as_slice()),
1326-
next: Some(LayerNodeIdentifier::ROOT_PARENT),
1327-
metadata: self.document_metadata(),
1328-
}
1324+
ShallowestSelectionIter::new(self.document_metadata(), selection.map_or([].as_slice(), |selection| selection.0.as_slice()))
13291325
}
13301326

13311327
/// 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 {
69976993

69986994
/// Iterate through the shallowest selected layers without allocating
69996995
#[derive(Clone)]
7000-
pub struct ShallowestSelectionIter<'a> {
6996+
pub struct ShallowestSelectionIter<'a, T: PartialEq<LayerNodeIdentifier>> {
70016997
next: Option<LayerNodeIdentifier>,
7002-
selection: &'a [NodeId], // TODO: should be HashSet to avoid duplicates.
6998+
selection: &'a [T], // TODO: should be HashSet to avoid duplicates.
70036999
metadata: &'a DocumentMetadata,
70047000
}
70057001

7006-
impl Iterator for ShallowestSelectionIter<'_> {
7002+
impl<'a, T: PartialEq<LayerNodeIdentifier>> ShallowestSelectionIter<'a, T> {
7003+
pub fn new(metadata: &'a DocumentMetadata, selection: &'a [T]) -> Self {
7004+
ShallowestSelectionIter {
7005+
selection,
7006+
next: Some(LayerNodeIdentifier::ROOT_PARENT),
7007+
metadata,
7008+
}
7009+
}
7010+
}
7011+
7012+
impl<T: PartialEq<LayerNodeIdentifier>> Iterator for ShallowestSelectionIter<'_, T> {
70077013
type Item = LayerNodeIdentifier;
70087014

70097015
fn next(&mut self) -> Option<Self::Item> {
@@ -7012,7 +7018,7 @@ impl Iterator for ShallowestSelectionIter<'_> {
70127018
let below_in_tree = || layer_node.ancestors(self.metadata).find_map(|ancestor| ancestor.next_sibling(self.metadata));
70137019

70147020
// If the current layer is selected, return it.
7015-
if layer_node != LayerNodeIdentifier::ROOT_PARENT && self.selection.contains(&layer_node.to_node()) {
7021+
if layer_node != LayerNodeIdentifier::ROOT_PARENT && self.selection.iter().any(|selection| *selection == layer_node) {
70167022
self.next = below_in_tree(); // Go straight to below and don't look at children
70177023
return Some(layer_node);
70187024
}

editor/src/messages/tool/tool_messages/select_tool.rs

Lines changed: 6 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
66
use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn;
77
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
88
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
9-
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
9+
use crate::messages::portfolio::document::utility_types::network_interface::{NodeNetworkInterface, ShallowestSelectionIter};
1010
use crate::messages::preferences::SelectionMode;
1111
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
1212
use crate::messages::tool::common_functionality::compass_rose::{Axis, CompassRose};
@@ -25,8 +25,10 @@ use graphene_std::renderer::Quad;
2525
use graphene_std::renderer::Rect;
2626
use graphene_std::transform::ReferencePoint;
2727

28+
mod drag_state;
2829
mod duplicate;
2930
pub mod options;
31+
use drag_state::*;
3032

3133
#[derive(Default, ExtractField)]
3234
pub struct SelectTool {
@@ -162,85 +164,6 @@ impl Default for SelectToolFsmState {
162164
}
163165
}
164166

165-
/// Represents the current drag in progress
166-
#[derive(Clone, Debug, Default)]
167-
struct DragState {
168-
pub start_document: DVec2,
169-
pub current_document: DVec2,
170-
/// Selection mode is set when the drag exceeds a certain distance. Once resolved, the selection mode cannot change.
171-
resolved_selection_mode: Option<SelectionMode>,
172-
}
173-
174-
impl DragState {
175-
pub fn new(input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) -> Self {
176-
let document_mouse = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
177-
Self {
178-
start_document: document_mouse,
179-
current_document: document_mouse,
180-
resolved_selection_mode: None,
181-
}
182-
}
183-
pub fn set_current(&mut self, input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) {
184-
self.current_document = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
185-
}
186-
187-
pub fn start_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
188-
metadata.document_to_viewport.transform_point2(self.start_document)
189-
}
190-
191-
pub fn current_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
192-
metadata.document_to_viewport.transform_point2(self.current_document)
193-
}
194-
195-
pub fn start_current_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
196-
[self.start_viewport(metadata), self.current_viewport(metadata)]
197-
}
198-
199-
pub fn total_drag_delta_document(&self) -> DVec2 {
200-
self.current_document - self.start_document
201-
}
202-
203-
pub fn total_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
204-
metadata.document_to_viewport.transform_vector2(self.total_drag_delta_document())
205-
}
206-
207-
pub fn inverse_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
208-
-self.total_drag_delta_viewport(metadata)
209-
}
210-
211-
fn update_selection_mode(&mut self, metadata: &DocumentMetadata, preferences: &PreferencesMessageHandler) -> SelectionMode {
212-
if let Some(resolved_selection_mode) = self.resolved_selection_mode {
213-
return resolved_selection_mode;
214-
}
215-
if preferences.get_selection_mode() != SelectionMode::Directional {
216-
self.resolved_selection_mode = Some(preferences.get_selection_mode());
217-
return preferences.get_selection_mode();
218-
}
219-
220-
let [start, current] = self.start_current_viewport(metadata);
221-
222-
// Drag direction cannot be resolved TODO: why not consider only X distance?
223-
if start.distance_squared(current) >= DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2) {
224-
let selection_mode = if current.x < start.x { SelectionMode::Touched } else { SelectionMode::Enclosed };
225-
self.resolved_selection_mode = Some(selection_mode);
226-
return selection_mode;
227-
}
228-
229-
SelectionMode::default()
230-
}
231-
232-
/// A viewport quad representing the drag bounds. Expanded if the start == end
233-
pub fn expanded_selection_box_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
234-
let [start, current] = self.start_current_viewport(metadata);
235-
if start == current {
236-
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
237-
[current - tolerance, current + tolerance]
238-
} else {
239-
[start, current]
240-
}
241-
}
242-
}
243-
244167
#[derive(Clone, Debug, Default)]
245168
struct SelectToolData {
246169
drag: DragState,
@@ -879,6 +802,7 @@ impl Fsm for SelectToolFsmState {
879802

880803
let snap_data = SnapData::ignore(document, input, ignore);
881804
let [start, current] = tool_data.drag.start_current_viewport(document.metadata());
805+
882806
let e0 = tool_data
883807
.bounding_box_manager
884808
.as_ref()
@@ -893,17 +817,16 @@ impl Fsm for SelectToolFsmState {
893817
};
894818

895819
// 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
896-
for layer in document.network_interface.shallowest_unique_layers(&[]) {
820+
for layer in ShallowestSelectionIter::new(document.metadata(), &tool_data.layers_dragging) {
897821
responses.add_front(GraphOperationMessage::TransformChange {
898822
layer,
899823
transform: DAffine2::from_translation(mouse_delta),
900824
transform_in: TransformIn::Viewport,
901825
skip_rerender: false,
902826
});
903827
}
904-
tool_data.drag.current_document += document.metadata().document_to_viewport.inverse().transform_vector2(mouse_delta);
905828

906-
info!("current {} mouse {}", tool_data.drag.current_viewport(document.metadata()), input.mouse.position);
829+
tool_data.drag.offset_viewport(mouse_delta, document.metadata());
907830

908831
// Auto-panning
909832
let messages = [
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::consts::{DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD, SELECTION_TOLERANCE};
2+
use crate::messages::{portfolio::document::utility_types::document_metadata::DocumentMetadata, preferences::SelectionMode, tool::tool_messages::tool_prelude::*};
3+
/// Represents the current drag in progress
4+
#[derive(Clone, Debug, Default)]
5+
pub struct DragState {
6+
pub start_document: DVec2,
7+
pub current_document: DVec2,
8+
/// Selection mode is set when the drag exceeds a certain distance. Once resolved, the selection mode cannot change.
9+
resolved_selection_mode: Option<SelectionMode>,
10+
}
11+
12+
impl DragState {
13+
pub fn new(input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) -> Self {
14+
let document_mouse = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
15+
Self {
16+
start_document: document_mouse,
17+
current_document: document_mouse,
18+
resolved_selection_mode: None,
19+
}
20+
}
21+
pub fn set_current(&mut self, input: &InputPreprocessorMessageHandler, metadata: &DocumentMetadata) {
22+
self.current_document = metadata.document_to_viewport.inverse().transform_point2(input.mouse.position);
23+
}
24+
25+
pub fn offset_viewport(&mut self, offset: DVec2, metadata: &DocumentMetadata) {
26+
self.current_document = self.current_document + metadata.document_to_viewport.inverse().transform_vector2(offset);
27+
}
28+
29+
pub fn start_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
30+
metadata.document_to_viewport.transform_point2(self.start_document)
31+
}
32+
33+
pub fn current_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
34+
metadata.document_to_viewport.transform_point2(self.current_document)
35+
}
36+
37+
pub fn start_current_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
38+
[self.start_viewport(metadata), self.current_viewport(metadata)]
39+
}
40+
41+
pub fn total_drag_delta_document(&self) -> DVec2 {
42+
self.current_document - self.start_document
43+
}
44+
45+
pub fn total_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
46+
metadata.document_to_viewport.transform_vector2(self.total_drag_delta_document())
47+
}
48+
49+
pub fn inverse_drag_delta_viewport(&self, metadata: &DocumentMetadata) -> DVec2 {
50+
-self.total_drag_delta_viewport(metadata)
51+
}
52+
53+
pub fn update_selection_mode(&mut self, metadata: &DocumentMetadata, preferences: &PreferencesMessageHandler) -> SelectionMode {
54+
if let Some(resolved_selection_mode) = self.resolved_selection_mode {
55+
return resolved_selection_mode;
56+
}
57+
if preferences.get_selection_mode() != SelectionMode::Directional {
58+
self.resolved_selection_mode = Some(preferences.get_selection_mode());
59+
return preferences.get_selection_mode();
60+
}
61+
62+
let [start, current] = self.start_current_viewport(metadata);
63+
64+
// Drag direction cannot be resolved TODO: why not consider only X distance?
65+
if start.distance_squared(current) >= DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD.powi(2) {
66+
let selection_mode = if current.x < start.x { SelectionMode::Touched } else { SelectionMode::Enclosed };
67+
self.resolved_selection_mode = Some(selection_mode);
68+
return selection_mode;
69+
}
70+
71+
SelectionMode::default()
72+
}
73+
74+
/// A viewport quad representing the drag bounds. Expanded if the start == end
75+
pub fn expanded_selection_box_viewport(&self, metadata: &DocumentMetadata) -> [DVec2; 2] {
76+
let [start, current] = self.start_current_viewport(metadata);
77+
if start == current {
78+
let tolerance = DVec2::splat(SELECTION_TOLERANCE);
79+
[current - tolerance, current + tolerance]
80+
} else {
81+
[start, current]
82+
}
83+
}
84+
}

editor/src/messages/tool/tool_messages/select_tool/duplicate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::super::tool_prelude::*;
2-
use super::DragState;
2+
use super::drag_state::DragState;
33
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, NodeTemplate};
44
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
55
use crate::messages::tool::tool_messages::select_tool::LayerNodeIdentifier;

0 commit comments

Comments
 (0)