Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 12 additions & 19 deletions editor/src/messages/portfolio/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2414,22 +2414,26 @@ impl DocumentMessageHandler {
self.drive_storage_undo_redo(document_id, resource_storage, legacy_applied, true, responses);
}

pub fn undo(&mut self, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) -> Option<NodeNetworkInterface> {
// If there is no history return and don't broadcast SelectionChanged
let mut network_interface = self.history.pop_undo()?;

/// Installs a history snapshot as the active network interface, carrying over the current view state and structure load, and returns the replaced interface.
fn install_history_snapshot(&mut self, mut network_interface: NodeNetworkInterface, viewport: &ViewportMessageHandler) -> NodeNetworkInterface {
// Set the previous network navigation metadata to the current navigation metadata
network_interface.copy_all_navigation_metadata(&self.network_interface);
std::mem::swap(&mut network_interface.resolved_types, &mut self.network_interface.resolved_types);

//Update the metadata transform based on document PTZ
// Update the metadata transform based on document PTZ
let transform = self.navigation_handler.calculate_offset_transform(viewport.center_in_viewport_space().into(), &self.document_ptz);
network_interface.set_document_to_viewport_transform(transform);

// Ensure document structure is loaded so that updating the selected nodes has the correct metadata
network_interface.load_structure();

let previous_network = std::mem::replace(&mut self.network_interface, network_interface);
std::mem::replace(&mut self.network_interface, network_interface)
}

pub fn undo(&mut self, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) -> Option<NodeNetworkInterface> {
// If there is no history return and don't broadcast SelectionChanged
let network_interface = self.history.pop_undo()?;
let previous_network = self.install_history_snapshot(network_interface, viewport);

// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
Expand All @@ -2454,20 +2458,9 @@ impl DocumentMessageHandler {

pub fn redo(&mut self, viewport: &ViewportMessageHandler, responses: &mut VecDeque<Message>) -> Option<NodeNetworkInterface> {
// If there is no history return and don't broadcast SelectionChanged
let mut network_interface = self.history.pop_redo()?;

// Set the previous network navigation metadata to the current navigation metadata
network_interface.copy_all_navigation_metadata(&self.network_interface);
std::mem::swap(&mut network_interface.resolved_types, &mut self.network_interface.resolved_types);

//Update the metadata transform based on document PTZ
let transform = self.navigation_handler.calculate_offset_transform(viewport.center_in_viewport_space().into(), &self.document_ptz);
network_interface.set_document_to_viewport_transform(transform);

// Ensure document structure is loaded so that updating the selected nodes has the correct metadata
network_interface.load_structure();
let network_interface = self.history.pop_redo()?;
let previous_network = self.install_history_snapshot(network_interface, viewport);

let previous_network = std::mem::replace(&mut self.network_interface, network_interface);
// Push the UpdateOpenDocumentsList message to the bus in order to update the save status of the open documents
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
responses.add(NodeGraphMessage::SelectedNodesUpdated);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub struct NodeNetworkInterface {
network: MemoNetwork,
/// Stores all editor information for a NodeNetwork. Should automatically kept in sync by the setter methods when changes to the document network are made.
network_metadata: NodeNetworkMetadata,
// TODO: Wrap in TransientMetadata Option
// TODO: Wrap in a TransientCache
/// Stores the document network's structural topology. Should automatically kept in sync by the setter methods when changes to the document network are made.
#[serde(skip)]
document_metadata: DocumentMetadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl NodeNetworkInterface {
}

/// Reads the stack dependents through &self if they are already loaded.
pub(crate) fn with_stack_dependents<R>(&self, network_path: &[NodeId], read: impl FnOnce(&HashMap<NodeId, LayerOwner>) -> R) -> Option<R> {
pub(crate) fn with_stack_dependents_if_loaded<R>(&self, network_path: &[NodeId], read: impl FnOnce(&HashMap<NodeId, LayerOwner>) -> R) -> Option<R> {
self.network_metadata(network_path)?.transient_metadata.stack_dependents.with_loaded(read)
}

Expand Down Expand Up @@ -454,7 +454,7 @@ impl NodeNetworkInterface {
}

/// Reads the owned nodes of a layer through &self if they are loaded.
pub(crate) fn with_owned_nodes<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&HashSet<NodeId>) -> R) -> Option<R> {
pub(crate) fn with_owned_nodes_if_loaded<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&HashSet<NodeId>) -> R) -> Option<R> {
let layer_node = self.node_metadata(node_id, network_path)?;
if !layer_node.persistent_metadata.is_layer() {
return None;
Expand Down Expand Up @@ -679,38 +679,20 @@ impl NodeNetworkInterface {
}

pub fn get_input_center(&self, input: &InputConnector, network_path: &[NodeId]) -> Option<DVec2> {
fn port_center(ports: &Ports, index: usize) -> Option<DVec2> {
ports
.input_ports
.iter()
.find_map(|(input_index, click_target)| if index == *input_index { click_target.bounding_box_center() } else { None })
}

match input {
InputConnector::Node { node_id, input_index } => {
self.try_load_node_click_targets(node_id, network_path);
self.with_node_click_targets(node_id, network_path, |click_targets| port_center(&click_targets.port_click_targets, *input_index))
.flatten()
}
InputConnector::Export(export_index) => self.with_import_export_ports(network_path, |ports| port_center(ports, *export_index)).flatten(),
InputConnector::Node { node_id, input_index } => self
.with_node_click_targets(node_id, network_path, |click_targets| click_targets.port_click_targets.input_port_position(*input_index))
.flatten(),
InputConnector::Export(export_index) => self.with_import_export_ports(network_path, |ports| ports.input_port_position(*export_index)).flatten(),
}
}

pub fn get_output_center(&self, output: &OutputConnector, network_path: &[NodeId]) -> Option<DVec2> {
fn port_center(ports: &Ports, index: usize) -> Option<DVec2> {
ports
.output_ports
.iter()
.find_map(|(output_index, click_target)| if index == *output_index { click_target.bounding_box_center() } else { None })
}

match output {
OutputConnector::Node { node_id, output_index } => {
self.try_load_node_click_targets(node_id, network_path);
self.with_node_click_targets(node_id, network_path, |click_targets| port_center(&click_targets.port_click_targets, *output_index))
.flatten()
}
OutputConnector::Import(import_index) => self.with_import_export_ports(network_path, |ports| port_center(ports, *import_index)).flatten(),
OutputConnector::Node { node_id, output_index } => self
.with_node_click_targets(node_id, network_path, |click_targets| click_targets.port_click_targets.output_port_position(*output_index))
.flatten(),
OutputConnector::Import(import_index) => self.with_import_export_ports(network_path, |ports| ports.output_port_position(*import_index)).flatten(),
}
}

Expand Down Expand Up @@ -938,25 +920,29 @@ impl NodeNetworkInterface {
}

/// Loads the node click targets if needed, then reads them through &self.
pub(crate) fn with_loaded_node_click_targets<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&DocumentNodeClickTargets) -> R) -> Option<R> {
pub(crate) fn with_node_click_targets<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&DocumentNodeClickTargets) -> R) -> Option<R> {
self.try_load_node_click_targets(node_id, network_path);
self.with_node_click_targets(node_id, network_path, read)
self.with_node_click_targets_if_loaded(node_id, network_path, read)
}

/// Reads the modify import/export click targets through &self, loading them first if needed.
pub(crate) fn with_modify_import_export<R>(&self, network_path: &[NodeId], read: impl FnOnce(&ModifyImportExportClickTarget) -> R) -> Option<R> {
self.try_load_modify_import_export(network_path);
self.network_metadata(network_path)?.transient_metadata.modify_import_export.with_loaded(read)
}

fn try_load_modify_import_export(&self, network_path: &[NodeId]) {
let Some(network_metadata) = self.network_metadata(network_path) else {
log::error!("Could not get nested network_metadata in modify_import_export");
return None;
return;
};
if !network_metadata.transient_metadata.modify_import_export.is_loaded() {
self.load_modify_import_export(network_path);
}
self.network_metadata(network_path)?.transient_metadata.modify_import_export.with_loaded(read)
}

/// Reads the node click targets through &self if they are already loaded.
pub(crate) fn with_node_click_targets<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&DocumentNodeClickTargets) -> R) -> Option<R> {
pub(crate) fn with_node_click_targets_if_loaded<R>(&self, node_id: &NodeId, network_path: &[NodeId], read: impl FnOnce(&DocumentNodeClickTargets) -> R) -> Option<R> {
let node_metadata = self.node_metadata(node_id, network_path)?;
let result = node_metadata.transient_metadata.click_targets.with_loaded(read);
if result.is_none() {
Expand Down Expand Up @@ -1095,8 +1081,8 @@ impl NodeNetworkInterface {
let name_left = node_top_left.x + NAME_LEFT_OFFSET;
let icons_reserve = VISIBILITY_INSET_FROM_LAYER_RIGHT + icons_width + GRIP_WIDTH;
let name_right_max = node_top_left.x + width as f64 - icons_reserve;
let text_w = text_width(&display_name, FONT_SIZE);
let name_right = (name_left + text_w).min(name_right_max);
let name_width = text_width(&display_name, FONT_SIZE);
let name_right = (name_left + name_width).min(name_right_max);
if name_right > name_left {
// The 1-grid-tall name strip is centered vertically in the 2-grid-tall layer.
let name_top = node_top_left.y + HALF_GRID_SIZE as f64;
Expand Down Expand Up @@ -1142,7 +1128,7 @@ impl NodeNetworkInterface {
}

pub fn try_get_node_bounding_box(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<[DVec2; 2]> {
self.with_node_click_targets(node_id, network_path, |click_targets| click_targets.node_click_target.bounding_box())
self.with_node_click_targets_if_loaded(node_id, network_path, |click_targets| click_targets.node_click_target.bounding_box())
.flatten()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl NodeNetworkInterface {
}
});
nodes.into_iter().for_each(|node_id| {
self.with_loaded_node_click_targets(&node_id, network_path, |node_click_targets| {
self.with_node_click_targets(&node_id, network_path, |node_click_targets| {
let mut node_path = String::new();

if let ClickTargetType::Subpath(subpath) = node_click_targets.node_click_target.target_type() {
Expand Down Expand Up @@ -146,7 +146,7 @@ impl NodeNetworkInterface {
let clicked_nodes = nodes
.iter()
.filter(|node_id| {
self.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
self.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
transient_node_metadata.node_click_target.intersect_point_no_stroke(point)
}) == Some(true)
})
Expand Down Expand Up @@ -181,7 +181,7 @@ impl NodeNetworkInterface {
node_ids
.iter()
.filter_map(|node_id| {
self.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
self.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
if let NodeTypeClickTargets::Layer(layer) = &transient_node_metadata.node_type_metadata {
match click_target_type {
LayerClickTargetTypes::Visibility => layer.visibility_click_target.intersect_point_no_stroke(point).then_some(*node_id),
Expand Down Expand Up @@ -216,7 +216,7 @@ impl NodeNetworkInterface {
.collect::<Vec<_>>()
.iter()
.filter_map(|node_id| {
self.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
self.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
transient_node_metadata
.port_click_targets
.clicked_input_port_from_point(point)
Expand Down Expand Up @@ -246,7 +246,7 @@ impl NodeNetworkInterface {
nodes
.iter()
.filter_map(|node_id| {
self.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
self.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
transient_node_metadata
.port_click_targets
.clicked_output_port_from_point(point)
Expand All @@ -266,7 +266,7 @@ impl NodeNetworkInterface {
pub fn input_position(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<DVec2> {
match input_connector {
InputConnector::Node { node_id, input_index } => self
.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
transient_node_metadata.port_click_targets.input_port_position(*input_index)
})
.flatten(),
Expand All @@ -279,7 +279,7 @@ impl NodeNetworkInterface {
pub fn output_position(&self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<DVec2> {
match output_connector {
OutputConnector::Node { node_id, output_index } => self
.with_loaded_node_click_targets(node_id, network_path, |transient_node_metadata| {
.with_node_click_targets(node_id, network_path, |transient_node_metadata| {
transient_node_metadata.port_click_targets.output_port_position(*output_index)
})
.flatten(),
Expand Down
Loading
Loading