Skip to content

Commit 9a2cd93

Browse files
committed
Merge branch 'master' into foo
2 parents 1a31ef2 + 41fe465 commit 9a2cd93

File tree

8 files changed

+131
-72
lines changed

8 files changed

+131
-72
lines changed

editor/src/messages/portfolio/document/document_message.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,14 @@ pub enum DocumentMessage {
159159
SetViewMode {
160160
view_mode: ViewMode,
161161
},
162+
AddTransaction,
162163
StartTransaction,
163164
EndTransaction,
164165
CommitTransaction,
165166
AbortTransaction,
166167
RepeatedAbortTransaction {
167168
undo_count: usize,
168169
},
169-
AddTransaction,
170170
ToggleLayerExpansion {
171171
id: NodeId,
172172
recursive: bool,

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,11 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
11551155
self.view_mode = view_mode;
11561156
responses.add_front(NodeGraphMessage::RunDocumentGraph);
11571157
}
1158+
DocumentMessage::AddTransaction => {
1159+
// Reverse order since they are added to the front
1160+
responses.add_front(DocumentMessage::CommitTransaction);
1161+
responses.add_front(DocumentMessage::StartTransaction);
1162+
}
11581163
// Note: A transaction should never be started in a scope that mutates the network interface, since it will only be run after that scope ends.
11591164
DocumentMessage::StartTransaction => {
11601165
self.network_interface.start_transaction();
@@ -1198,11 +1203,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
11981203
self.network_interface.finish_transaction();
11991204
responses.add(OverlaysMessage::Draw);
12001205
}
1201-
DocumentMessage::AddTransaction => {
1202-
// Reverse order since they are added to the front
1203-
responses.add_front(DocumentMessage::CommitTransaction);
1204-
responses.add_front(DocumentMessage::StartTransaction);
1205-
}
12061206
DocumentMessage::ToggleLayerExpansion { id, recursive } => {
12071207
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]);
12081208
let metadata = self.metadata();

editor/src/messages/portfolio/document/node_graph/node_graph_message.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ pub enum NodeGraphMessage {
5858
DuplicateSelectedNodes,
5959
ExposeInput {
6060
input_connector: InputConnector,
61-
new_exposed: bool,
61+
set_to_exposed: bool,
62+
start_transaction: bool,
6263
},
6364
InsertNode {
6465
node_id: NodeId,

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,11 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
315315
responses.add(DocumentMessage::EnterNestedNetwork { node_id });
316316
}
317317
}
318-
NodeGraphMessage::ExposeInput { input_connector, new_exposed } => {
318+
NodeGraphMessage::ExposeInput {
319+
input_connector,
320+
set_to_exposed,
321+
start_transaction,
322+
} => {
319323
let InputConnector::Node { node_id, input_index } = input_connector else {
320324
log::error!("Cannot expose/hide export");
321325
return;
@@ -324,26 +328,43 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
324328
log::error!("Could not find node {node_id} in NodeGraphMessage::ExposeInput");
325329
return;
326330
};
327-
let Some(mut input) = node.inputs.get(input_index).cloned() else {
331+
let Some(mut node_input) = node.inputs.get(input_index).cloned() else {
328332
log::error!("Could not find input {input_index} in NodeGraphMessage::ExposeInput");
329333
return;
330334
};
331-
if let NodeInput::Value { exposed, .. } = &mut input {
332-
*exposed = new_exposed;
333-
} else if !new_exposed {
334-
// If hiding an input that is not a value, then disconnect it. This will convert it to a value input.
335-
responses.add(NodeGraphMessage::DisconnectInput { input_connector });
336-
responses.add(NodeGraphMessage::ExposeInput { input_connector, new_exposed });
335+
336+
// If we're un-exposing an input that is not a value, then disconnect it. This will convert it to a value input,
337+
// so we can come back to handle this message again to set the exposed value in the second run-through.
338+
if !set_to_exposed && node_input.as_value().is_none() {
339+
// Reversed order because we are pushing front
340+
responses.add_front(NodeGraphMessage::ExposeInput {
341+
input_connector,
342+
set_to_exposed,
343+
start_transaction: false,
344+
});
345+
responses.add_front(NodeGraphMessage::DisconnectInput { input_connector });
346+
responses.add_front(DocumentMessage::StartTransaction);
337347
return;
338348
}
339349

340-
responses.add(DocumentMessage::AddTransaction);
350+
// Add a history step, but only do so if we didn't already start a transaction in the first run-through of this message in the above code
351+
if start_transaction {
352+
responses.add_front(DocumentMessage::StartTransaction);
353+
}
341354

355+
// If this node's input is a value type, we set its chosen exposed state
356+
if let NodeInput::Value { exposed, .. } = &mut node_input {
357+
*exposed = set_to_exposed;
358+
}
342359
responses.add(NodeGraphMessage::SetInput {
343360
input_connector: InputConnector::node(node_id, input_index),
344-
input,
361+
input: node_input,
345362
});
346363

364+
// Finish the history step
365+
responses.add(DocumentMessage::CommitTransaction);
366+
367+
// Update the graph UI and re-render
347368
responses.add(PropertiesPanelMessage::Refresh);
348369
responses.add(NodeGraphMessage::SendGraph);
349370
responses.add(NodeGraphMessage::RunDocumentGraph);

editor/src/messages/portfolio/document/node_graph/node_properties.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ pub fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphData
5252
ParameterExposeButton::new()
5353
.exposed(exposed)
5454
.data_type(data_type)
55-
.tooltip("Expose this parameter input in node graph")
55+
.tooltip("Expose this parameter as a node input in the graph")
5656
.on_update(move |_parameter| {
5757
NodeGraphMessage::ExposeInput {
5858
input_connector: InputConnector::node(node_id, index),
59-
new_exposed: !exposed,
59+
set_to_exposed: !exposed,
60+
start_transaction: true,
6061
}
6162
.into()
6263
})

editor/src/messages/tool/common_functionality/shape_editor.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,37 @@ impl ShapeState {
388388
None
389389
}
390390

391+
pub fn get_point_selection_state(&mut self, network_interface: &NodeNetworkInterface, mouse_position: DVec2, select_threshold: f64) -> Option<(bool, Option<SelectedPointsInfo>)> {
392+
if self.selected_shape_state.is_empty() {
393+
return None;
394+
}
395+
396+
if let Some((layer, manipulator_point_id)) = self.find_nearest_point_indices(network_interface, mouse_position, select_threshold) {
397+
let vector_data = network_interface.compute_modified_vector(layer)?;
398+
let point_position = manipulator_point_id.get_position(&vector_data)?;
399+
400+
let selected_shape_state = self.selected_shape_state.get(&layer)?;
401+
let already_selected = selected_shape_state.is_selected(manipulator_point_id);
402+
403+
// Offset to snap the selected point to the cursor
404+
let offset = mouse_position - network_interface.document_metadata().transform_to_viewport(layer).transform_point2(point_position);
405+
406+
// Gather current selection information
407+
let points = self
408+
.selected_shape_state
409+
.iter()
410+
.flat_map(|(layer, state)| state.selected_points.iter().map(|&point_id| ManipulatorPointInfo { layer: *layer, point_id }))
411+
.collect();
412+
413+
let selection_info = SelectedPointsInfo { points, offset, vector_data };
414+
415+
// Return the current selection state and info
416+
return Some((already_selected, Some(selection_info)));
417+
}
418+
419+
None
420+
}
421+
391422
pub fn select_anchor_point_by_id(&mut self, layer: LayerNodeIdentifier, id: PointId, extend_selection: bool) {
392423
if !extend_selection {
393424
self.deselect_all_points();

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

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ struct PathToolData {
375375
current_selected_handle_id: Option<ManipulatorPointId>,
376376
angle: f64,
377377
opposite_handle_position: Option<DVec2>,
378+
last_clicked_point_was_selected: bool,
378379
snapping_axis: Option<Axis>,
379380
alt_clicked_on_anchor: bool,
380381
alt_dragging_from_anchor: bool,
@@ -501,11 +502,21 @@ impl PathToolData {
501502

502503
let old_selection = shape_editor.selected_points().cloned().collect::<Vec<_>>();
503504

504-
// Select the first point within the threshold (in pixels)
505-
if let Some(selected_points) = shape_editor.change_point_selection(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD, extend_selection) {
505+
// Check if the point is already selected; if not, select the first point within the threshold (in pixels)
506+
if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) {
506507
responses.add(DocumentMessage::StartTransaction);
507508

508-
if let Some(selected_points) = selected_points {
509+
self.last_clicked_point_was_selected = already_selected;
510+
511+
// If the point is already selected and shift (`extend_selection`) is used, keep the selection unchanged.
512+
// Otherwise, select the first point within the threshold.
513+
if !(already_selected && extend_selection) {
514+
if let Some(updated_selection_info) = shape_editor.change_point_selection(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD, extend_selection) {
515+
selection_info = updated_selection_info;
516+
}
517+
}
518+
519+
if let Some(selected_points) = selection_info {
509520
self.drag_start_pos = input.mouse.position;
510521

511522
// If selected points contain only handles and there was some selection before, then it is stored and becomes restored upon release
@@ -1386,7 +1397,23 @@ impl Fsm for PathToolFsmState {
13861397
PathToolFsmState::Ready
13871398
}
13881399
(_, PathToolMessage::DragStop { extend_selection, .. }) => {
1389-
if tool_data.handle_drag_toggle && tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD {
1400+
let extend_selection = input.keyboard.get(extend_selection as usize);
1401+
let drag_occurred = tool_data.drag_start_pos.distance(input.mouse.position) > DRAG_THRESHOLD;
1402+
let nearest_point = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD);
1403+
1404+
if let Some((layer, nearest_point)) = nearest_point {
1405+
if !drag_occurred && extend_selection {
1406+
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == point);
1407+
if clicked_selected && tool_data.last_clicked_point_was_selected {
1408+
shape_editor.selected_shape_state.entry(layer).or_default().deselect_point(nearest_point);
1409+
} else {
1410+
shape_editor.selected_shape_state.entry(layer).or_default().select_point(nearest_point);
1411+
}
1412+
responses.add(OverlaysMessage::Draw);
1413+
}
1414+
}
1415+
1416+
if tool_data.handle_drag_toggle && drag_occurred {
13901417
shape_editor.deselect_all_points();
13911418
shape_editor.select_points_by_manipulator_id(&tool_data.saved_points_before_handle_drag);
13921419

@@ -1404,12 +1431,8 @@ impl Fsm for PathToolFsmState {
14041431
tool_data.select_anchor_toggled = false;
14051432
}
14061433

1407-
let extend_selection = input.keyboard.get(extend_selection as usize);
1408-
1409-
let nearest_point = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD);
1410-
14111434
if let Some((layer, nearest_point)) = nearest_point {
1412-
if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !extend_selection {
1435+
if !drag_occurred && !extend_selection {
14131436
let clicked_selected = shape_editor.selected_points().any(|&point| nearest_point == point);
14141437
if clicked_selected {
14151438
shape_editor.deselect_all_points();

frontend/src/components/widgets/buttons/ParameterExposeButton.svelte

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,23 @@
1919
title={tooltip}
2020
tabindex="-1"
2121
>
22-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">
23-
<path class="interior" d="M0,7.882c0,1.832,1.325,2.63,2.945,1.772L8.785,6.56c1.62-.858,1.62-2.262,0-3.12L2.945.345C1.325-.512,0,.285,0,2.118Z" />
24-
<path
25-
class="outline"
26-
d="M 1.705180287361145 9.999852180480957 L 1.705180287361145 8.999852180480957 C 1.9275803565979 8.999852180480957 2.194530248641968 8.920772552490234 2.476730346679688
27-
8.771392822265625 L 8.31682014465332 5.67636251449585 C 8.788760185241699 5.426312446594238 9 5.156492233276367 9 5.000002384185791 C 9 4.843512535095215 8.788760185241699
28-
4.573692321777344 8.316730499267578 4.323602199554443 L 2.477190256118774 1.228852391242981 C 2.194520235061646 1.079232335090637 1.927510380744934 1.000152349472046 1.70503032207489
29-
1.000152349472046 C 1.091590285301208 1.000152349472046 1.000000357627869 1.700212359428406 1.000000357627869 2.117512464523315 L 1.000000357627869 7.882492542266846 C
30-
1.000000357627869 8.299762725830078 1.091610312461853 8.999792098999023 1.705130338668823 8.999852180480957 L 1.705180287361145 9.999852180480957 M 1.705027341842651 9.999849319458008
31-
C 0.7003514766693115 9.999751091003418 0 9.214582443237305 0 7.882492542266846 L 0 2.117512464523315 C 0 0.2850223779678345 1.325000405311584 -0.512467622756958 2.945000410079956
32-
0.3450223803520203 L 8.785000801086426 3.440012454986572 C 10.40500068664551 4.298342227935791 10.40500068664551 5.701662540435791 8.785000801086426 6.55999231338501 L
33-
2.945000410079956 9.654982566833496 C 2.502624750137329 9.889138221740723 2.082434415817261 9.999885559082031 1.705027341842651 9.999849319458008 Z"
34-
/>
35-
</svg>
22+
{#if !exposed}
23+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
24+
<circle class="interior" r="3" cx="4" cy="4" />
25+
<path
26+
class="outline"
27+
d="M4,1C5.656,1 7,2.344 7,4C7,5.656 5.656,7 4,7C2.344,7 1,5.656 1,4C1,2.344 2.344,1 4,1ZM4,2C2.896,2 2,2.896 2,4C2,5.104 2.896,6 4,6C5.104,6 6,5.104 6,4C6,2.896 5.104,2 4,2z"
28+
/>
29+
</svg>
30+
{:else}
31+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
32+
<path class="interior" d="M0,6.306L0,1.694C0,0.228 1.06,-0.41 2.356,0.276L7.028,2.752C8.324,3.438 8.324,4.562 7.028,5.248L2.356,7.723C1.06,8.41 0,7.771 0,6.306z" />
33+
<path
34+
class="outline"
35+
d="M1.364,8C0.56,8 0,7.372 0,6.306L0,1.694C0,0.228 1.06,-0.41 2.356,0.276L7.028,2.752C8.324,3.439 8.324,4.561 7.028,5.248L2.356,7.724C2.002,7.911 1.666,8 1.364,8ZM1.364,7.2C1.542,7.2 1.756,7.137 1.981,7.017L6.653,4.541C7.031,4.341 7.2,4.125 7.2,4C7.2,3.875 7.031,3.659 6.653,3.459L1.982,0.983C1.756,0.863 1.542,0.8 1.364,0.8C0.873,0.8 0.8,1.36 0.8,1.694L0.8,6.306C0.8,6.64 0.873,7.2 1.364,7.2z"
36+
/>
37+
</svg>
38+
{/if}
3639
</button>
3740
</LayoutRow>
3841

@@ -54,42 +57,21 @@
5457
fill: none;
5558
stroke: none;
5659
57-
svg {
58-
width: 10px;
59-
height: 10px;
60-
margin-top: -1px;
61-
margin-left: -1px;
60+
.outline {
61+
fill: none;
6262
}
6363
64-
&:not(.exposed) {
65-
&:not(:hover) {
66-
.outline {
67-
fill: var(--data-type-color-dim);
68-
}
69-
}
70-
71-
&:hover {
72-
.outline {
73-
fill: var(--data-type-color);
74-
}
75-
}
64+
.interior {
65+
fill: var(--data-type-color);
7666
}
7767
78-
&.exposed {
79-
&:not(:hover) {
80-
.interior {
81-
fill: var(--data-type-color);
82-
}
68+
&:hover {
69+
.outline {
70+
fill: var(--data-type-color);
8371
}
8472
85-
&:hover {
86-
.outline {
87-
fill: var(--data-type-color);
88-
}
89-
90-
.interior {
91-
fill: var(--data-type-color-dim);
92-
}
73+
.interior {
74+
fill: var(--data-type-color-dim);
9375
}
9476
}
9577
}

0 commit comments

Comments
 (0)