mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 16:58:11 +08:00
Improve expose input and remove cancel/commit transaction messages
This commit is contained in:
@@ -182,8 +182,6 @@ pub enum DocumentMessage {
|
|||||||
AddTransaction,
|
AddTransaction,
|
||||||
StartTransaction,
|
StartTransaction,
|
||||||
EndTransaction,
|
EndTransaction,
|
||||||
CommitTransaction,
|
|
||||||
CancelTransaction,
|
|
||||||
AbortTransaction,
|
AbortTransaction,
|
||||||
RepeatedAbortTransaction {
|
RepeatedAbortTransaction {
|
||||||
undo_count: usize,
|
undo_count: usize,
|
||||||
|
|||||||
@@ -1292,46 +1292,28 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
DocumentMessage::AddTransaction => {
|
DocumentMessage::AddTransaction => {
|
||||||
// Reverse order since they are added to the front
|
self.start_transaction(responses);
|
||||||
responses.add_front(DocumentMessage::CommitTransaction);
|
self.commit_transaction(responses);
|
||||||
responses.add_front(DocumentMessage::StartTransaction);
|
|
||||||
}
|
}
|
||||||
// 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.
|
// 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.
|
||||||
DocumentMessage::StartTransaction => {
|
DocumentMessage::StartTransaction => {
|
||||||
self.network_interface.start_transaction();
|
self.start_transaction(responses);
|
||||||
let network_interface_clone = self.network_interface.clone();
|
|
||||||
self.document_undo_history.push_back(network_interface_clone);
|
|
||||||
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
|
||||||
self.document_undo_history.pop_front();
|
|
||||||
}
|
|
||||||
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
|
|
||||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
|
||||||
}
|
}
|
||||||
// Commits the transaction if the network was mutated since the transaction started, otherwise it cancels the transaction
|
// Commits the transaction if the network was mutated since the transaction started, otherwise it cancels the transaction
|
||||||
DocumentMessage::EndTransaction => match self.network_interface.transaction_status() {
|
DocumentMessage::EndTransaction => match self.network_interface.transaction_status() {
|
||||||
TransactionStatus::Started => {
|
TransactionStatus::Started => {
|
||||||
responses.add_front(DocumentMessage::CancelTransaction);
|
self.network_interface.finish_transaction();
|
||||||
|
self.document_undo_history.pop_back();
|
||||||
}
|
}
|
||||||
TransactionStatus::Modified => {
|
TransactionStatus::Modified => {
|
||||||
responses.add_front(DocumentMessage::CommitTransaction);
|
self.commit_transaction(responses);
|
||||||
}
|
}
|
||||||
TransactionStatus::Finished => {}
|
TransactionStatus::Finished => {}
|
||||||
},
|
},
|
||||||
DocumentMessage::CancelTransaction => {
|
|
||||||
self.network_interface.finish_transaction();
|
|
||||||
self.document_undo_history.pop_back();
|
|
||||||
}
|
|
||||||
DocumentMessage::CommitTransaction => {
|
|
||||||
if self.network_interface.transaction_status() == TransactionStatus::Finished {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.network_interface.finish_transaction();
|
|
||||||
self.document_redo_history.clear();
|
|
||||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
|
||||||
}
|
|
||||||
DocumentMessage::AbortTransaction => match self.network_interface.transaction_status() {
|
DocumentMessage::AbortTransaction => match self.network_interface.transaction_status() {
|
||||||
TransactionStatus::Started => {
|
TransactionStatus::Started => {
|
||||||
responses.add_front(DocumentMessage::CancelTransaction);
|
self.network_interface.finish_transaction();
|
||||||
|
self.document_undo_history.pop_back();
|
||||||
}
|
}
|
||||||
TransactionStatus::Modified => {
|
TransactionStatus::Modified => {
|
||||||
responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 });
|
responses.add(DocumentMessage::RepeatedAbortTransaction { undo_count: 1 });
|
||||||
@@ -1829,6 +1811,26 @@ impl DocumentMessageHandler {
|
|||||||
val.unwrap()
|
val.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn start_transaction(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
|
self.network_interface.start_transaction();
|
||||||
|
let network_interface_clone = self.network_interface.clone();
|
||||||
|
self.document_undo_history.push_back(network_interface_clone);
|
||||||
|
if self.document_undo_history.len() > crate::consts::MAX_UNDO_HISTORY_LEN {
|
||||||
|
self.document_undo_history.pop_front();
|
||||||
|
}
|
||||||
|
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
|
||||||
|
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit_transaction(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
|
if self.network_interface.transaction_status() == TransactionStatus::Finished {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.network_interface.finish_transaction();
|
||||||
|
self.document_redo_history.clear();
|
||||||
|
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deserialize_document(serialized_content: &str) -> Result<Self, EditorError> {
|
pub fn deserialize_document(serialized_content: &str) -> Result<Self, EditorError> {
|
||||||
let document_message_handler = serde_json::from_str::<DocumentMessageHandler>(serialized_content)
|
let document_message_handler = serde_json::from_str::<DocumentMessageHandler>(serialized_content)
|
||||||
.or_else(|e| {
|
.or_else(|e| {
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ pub enum NodeGraphMessage {
|
|||||||
EnterNestedNetwork,
|
EnterNestedNetwork,
|
||||||
DuplicateSelectedNodes,
|
DuplicateSelectedNodes,
|
||||||
ExposeInput {
|
ExposeInput {
|
||||||
input_connector: InputConnector,
|
node_id: NodeId,
|
||||||
set_to_exposed: bool,
|
input_index: usize,
|
||||||
start_transaction: bool,
|
exposed: bool,
|
||||||
},
|
},
|
||||||
ExposeEncapsulatingPrimaryInput {
|
ExposeEncapsulatingPrimaryInput {
|
||||||
exposed: bool,
|
exposed: bool,
|
||||||
|
|||||||
@@ -403,15 +403,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
responses.add(DocumentMessage::EnterNestedNetwork { node_id });
|
responses.add(DocumentMessage::EnterNestedNetwork { node_id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ExposeInput {
|
NodeGraphMessage::ExposeInput { node_id, input_index, exposed } => {
|
||||||
input_connector,
|
|
||||||
set_to_exposed,
|
|
||||||
start_transaction,
|
|
||||||
} => {
|
|
||||||
let InputConnector::Node { node_id, input_index } = input_connector else {
|
|
||||||
log::error!("Cannot expose/hide export");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(node) = network_interface.document_node(&node_id, selection_network_path) else {
|
let Some(node) = network_interface.document_node(&node_id, selection_network_path) else {
|
||||||
log::error!("Could not find node {node_id} in NodeGraphMessage::ExposeInput");
|
log::error!("Could not find node {node_id} in NodeGraphMessage::ExposeInput");
|
||||||
return;
|
return;
|
||||||
@@ -421,38 +413,19 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we're un-exposing an input that is not a value, then disconnect it. This will convert it to a value input,
|
responses.add(DocumentMessage::AddTransaction);
|
||||||
// so we can come back to handle this message again to set the exposed value in the second run-through.
|
|
||||||
if !set_to_exposed && node_input.as_value().is_none() {
|
|
||||||
// Reversed order because we are pushing front
|
|
||||||
responses.add_front(NodeGraphMessage::ExposeInput {
|
|
||||||
input_connector,
|
|
||||||
set_to_exposed,
|
|
||||||
start_transaction: false,
|
|
||||||
});
|
|
||||||
responses.add_front(NodeGraphMessage::DisconnectInput { input_connector });
|
|
||||||
responses.add_front(DocumentMessage::StartTransaction);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
let new_exposed = exposed;
|
||||||
if start_transaction {
|
|
||||||
responses.add_front(DocumentMessage::StartTransaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this node's input is a value type, we set its chosen exposed state
|
|
||||||
if let NodeInput::Value { exposed, .. } = &mut node_input {
|
if let NodeInput::Value { exposed, .. } = &mut node_input {
|
||||||
*exposed = set_to_exposed;
|
*exposed = new_exposed;
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SetInput {
|
responses.add(NodeGraphMessage::SetInput {
|
||||||
input_connector: InputConnector::node(node_id, input_index),
|
input_connector: InputConnector::node(node_id, input_index),
|
||||||
input: node_input,
|
input: node_input,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Finish the history step
|
// Update the graph UI and re-render if the graph is open, if the graph is closed then open the graph and zoom in on the input
|
||||||
responses.add(DocumentMessage::CommitTransaction);
|
|
||||||
|
|
||||||
// Update the graph UI and re-render
|
|
||||||
if graph_view_overlay_open {
|
if graph_view_overlay_open {
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub fn commit_value<T>(_: &T) -> Message {
|
|||||||
DocumentMessage::AddTransaction.into()
|
DocumentMessage::AddTransaction.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphDataType, exposed: bool) -> WidgetInstance {
|
pub fn expose_widget(node_id: NodeId, input_index: usize, data_type: FrontendGraphDataType, exposed: bool) -> WidgetInstance {
|
||||||
ParameterExposeButton::new()
|
ParameterExposeButton::new()
|
||||||
.exposed(exposed)
|
.exposed(exposed)
|
||||||
.data_type(data_type)
|
.data_type(data_type)
|
||||||
@@ -58,9 +58,9 @@ pub fn expose_widget(node_id: NodeId, index: usize, data_type: FrontendGraphData
|
|||||||
})
|
})
|
||||||
.on_update(move |_parameter| Message::Batched {
|
.on_update(move |_parameter| Message::Batched {
|
||||||
messages: Box::new([NodeGraphMessage::ExposeInput {
|
messages: Box::new([NodeGraphMessage::ExposeInput {
|
||||||
input_connector: InputConnector::node(node_id, index),
|
node_id,
|
||||||
set_to_exposed: !exposed,
|
input_index,
|
||||||
start_transaction: true,
|
exposed: !exposed,
|
||||||
}
|
}
|
||||||
.into()]),
|
.into()]),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3800,8 +3800,8 @@ impl NodeNetworkInterface {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// When changing a NodeInput::Node to a NodeInput::Node, the input should first be disconnected to ensure proper side effects
|
// When changing a NodeInput::Node to another input, the input should first be disconnected to ensure proper side effects
|
||||||
if (matches!(previous_input, NodeInput::Node { .. }) && matches!(new_input, NodeInput::Node { .. })) {
|
if matches!(previous_input, NodeInput::Node { .. }) {
|
||||||
self.disconnect_input(input_connector, network_path);
|
self.disconnect_input(input_connector, network_path);
|
||||||
self.set_input(input_connector, new_input, network_path);
|
self.set_input(input_connector, new_input, network_path);
|
||||||
return;
|
return;
|
||||||
@@ -3856,7 +3856,7 @@ impl NodeNetworkInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is necessary to ensure the grpah is acyclic before calling `self.position` as it sometimes crashes with cyclic graphs #3227
|
// It is necessary to ensure the graph is acyclic before calling `self.position` as it sometimes crashes with cyclic graphs #3227
|
||||||
let previous_metadata = match &previous_input {
|
let previous_metadata = match &previous_input {
|
||||||
NodeInput::Node { node_id, .. } => self.position(node_id, network_path).map(|position| (*node_id, position)),
|
NodeInput::Node { node_id, .. } => self.position(node_id, network_path).map(|position| (*node_id, position)),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ impl ToolTransition for FreehandTool {
|
|||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct FreehandToolData {
|
struct FreehandToolData {
|
||||||
end_point: Option<(DVec2, PointId)>,
|
end_point: Option<(DVec2, PointId)>,
|
||||||
dragged: bool,
|
|
||||||
weight: f64,
|
weight: f64,
|
||||||
layer: Option<LayerNodeIdentifier>,
|
layer: Option<LayerNodeIdentifier>,
|
||||||
}
|
}
|
||||||
@@ -250,7 +249,6 @@ impl Fsm for FreehandToolFsmState {
|
|||||||
(FreehandToolFsmState::Ready, FreehandToolMessage::DragStart { append_to_selected }) => {
|
(FreehandToolFsmState::Ready, FreehandToolMessage::DragStart { append_to_selected }) => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
|
|
||||||
tool_data.dragged = false;
|
|
||||||
tool_data.end_point = None;
|
tool_data.end_point = None;
|
||||||
tool_data.weight = tool_options.line_weight;
|
tool_data.weight = tool_options.line_weight;
|
||||||
|
|
||||||
@@ -307,11 +305,7 @@ impl Fsm for FreehandToolFsmState {
|
|||||||
FreehandToolFsmState::Drawing
|
FreehandToolFsmState::Drawing
|
||||||
}
|
}
|
||||||
(FreehandToolFsmState::Drawing, FreehandToolMessage::DragStop) => {
|
(FreehandToolFsmState::Drawing, FreehandToolMessage::DragStop) => {
|
||||||
if tool_data.dragged {
|
responses.add(DocumentMessage::EndTransaction);
|
||||||
responses.add(DocumentMessage::CommitTransaction);
|
|
||||||
} else {
|
|
||||||
responses.add(DocumentMessage::EndTransaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
tool_data.end_point = None;
|
tool_data.end_point = None;
|
||||||
tool_data.layer = None;
|
tool_data.layer = None;
|
||||||
@@ -380,7 +374,6 @@ fn extend_path_with_next_segment(tool_data: &mut FreehandToolData, position: DVe
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tool_data.dragged = true;
|
|
||||||
tool_data.end_point = Some((position, id));
|
tool_data.end_point = Some((position, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user