|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
|
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
|
|
|
|
use super::document::utility_types::network_interface;
|
|
|
|
|
use super::utility_types::{PanelType, PersistentData, WorkspacePanelLayout};
|
|
|
|
|
use super::utility_types::{PanelLayoutSubdivision, PanelType, PersistentData, WorkspacePanelLayout};
|
|
|
|
|
use crate::application::{Editor, generate_uuid};
|
|
|
|
|
use crate::consts::{DEFAULT_DOCUMENT_NAME, DEFAULT_STROKE_WIDTH, FILE_EXTENSION};
|
|
|
|
|
use crate::messages::animation::TimingInformation;
|
|
|
|
@@ -57,7 +57,6 @@ pub struct PortfolioMessageHandler {
|
|
|
|
|
pub executor: NodeGraphExecutor,
|
|
|
|
|
pub selection_mode: SelectionMode,
|
|
|
|
|
pub reset_node_definitions_on_open: bool,
|
|
|
|
|
pub focus_document: bool,
|
|
|
|
|
pub workspace_panel_layout: WorkspacePanelLayout,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -88,9 +87,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
current_tool,
|
|
|
|
|
preferences,
|
|
|
|
|
viewport,
|
|
|
|
|
data_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Data) && !self.focus_document,
|
|
|
|
|
layers_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.focus_document,
|
|
|
|
|
properties_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Properties) && !self.focus_document,
|
|
|
|
|
data_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Data) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
layers_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
properties_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Properties) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
};
|
|
|
|
|
document.process_message(message, responses, document_inputs)
|
|
|
|
|
}
|
|
|
|
@@ -105,6 +104,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
|
|
|
|
|
// Tell frontend to load persistent preferences
|
|
|
|
|
responses.add(FrontendMessage::TriggerLoadPreferences);
|
|
|
|
|
responses.add(FrontendMessage::TriggerLoadWorkspaceLayout);
|
|
|
|
|
|
|
|
|
|
// Before loading any documents, initially prepare the welcome screen buttons layout
|
|
|
|
|
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
|
|
|
@@ -155,9 +155,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
current_tool,
|
|
|
|
|
preferences,
|
|
|
|
|
viewport,
|
|
|
|
|
data_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Data) && !self.focus_document,
|
|
|
|
|
layers_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.focus_document,
|
|
|
|
|
properties_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Properties) && !self.focus_document,
|
|
|
|
|
data_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Data) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
layers_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
properties_panel_open: self.workspace_panel_layout.is_panel_visible(PanelType::Properties) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
};
|
|
|
|
|
document.process_message(message, responses, document_inputs)
|
|
|
|
|
}
|
|
|
|
@@ -445,6 +445,17 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
document.load_layer_resources(responses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::LoadWorkspaceLayout { layout } => {
|
|
|
|
|
self.workspace_panel_layout = layout;
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
|
|
|
|
|
// Refresh all visible panels since the layout may have changed
|
|
|
|
|
for group_id in self.workspace_panel_layout.root.all_group_ids() {
|
|
|
|
|
if let Some(panel_type) = self.workspace_panel_layout.panel_group(group_id).and_then(|g| g.active_panel_type()) {
|
|
|
|
|
self.refresh_panel_content(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::NewDocumentWithName { name } => {
|
|
|
|
|
let mut new_document = DocumentMessageHandler::default();
|
|
|
|
|
new_document.name = name;
|
|
|
|
@@ -507,6 +518,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
|
|
|
|
|
// Refresh the new active tab
|
|
|
|
|
if let Some(panel_type) = self.workspace_panel_layout.panel_group(target_group).and_then(|g| g.active_panel_type()) {
|
|
|
|
@@ -556,6 +568,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
|
|
|
|
|
// Refresh the moved panel's content in its new location
|
|
|
|
|
self.refresh_panel_content(panel_type, responses);
|
|
|
|
@@ -1190,6 +1203,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::RequestWelcomeScreenButtonsLayout => {
|
|
|
|
@@ -1269,6 +1283,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
|
|
|
|
|
// Send the layout update first so the frontend mounts the new panel component before it receives content
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
|
|
|
|
|
if let Some(panel_type) = self.workspace_panel_layout.panel_group(group).and_then(|g| g.active_panel_type()) {
|
|
|
|
|
self.refresh_panel_content(panel_type, responses);
|
|
|
|
@@ -1303,6 +1318,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
|
|
|
|
|
// Refresh the new panel group's active tab
|
|
|
|
|
if let Some(panel_type) = self.workspace_panel_layout.panel_group(new_id).and_then(|g| g.active_panel_type()) {
|
|
|
|
@@ -1465,43 +1481,25 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::ToggleFocusDocument => {
|
|
|
|
|
self.focus_document = !self.focus_document;
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
self.workspace_panel_layout.focus_document = !self.workspace_panel_layout.focus_document;
|
|
|
|
|
|
|
|
|
|
let properties_present = self.workspace_panel_layout.is_panel_present(PanelType::Properties);
|
|
|
|
|
let layers_present = self.workspace_panel_layout.is_panel_present(PanelType::Layers);
|
|
|
|
|
let data_present = self.workspace_panel_layout.is_panel_present(PanelType::Data);
|
|
|
|
|
|
|
|
|
|
if self.focus_document {
|
|
|
|
|
if properties_present {
|
|
|
|
|
Self::destroy_panel_layouts(PanelType::Properties, responses);
|
|
|
|
|
}
|
|
|
|
|
if layers_present {
|
|
|
|
|
Self::destroy_panel_layouts(PanelType::Layers, responses);
|
|
|
|
|
}
|
|
|
|
|
if data_present {
|
|
|
|
|
Self::destroy_panel_layouts(PanelType::Data, responses);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Run the graph to grab the data
|
|
|
|
|
if properties_present || layers_present || data_present {
|
|
|
|
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if properties_present {
|
|
|
|
|
responses.add(PropertiesPanelMessage::Refresh);
|
|
|
|
|
}
|
|
|
|
|
if layers_present && self.active_document_id.is_some() {
|
|
|
|
|
responses.add(DeferMessage::AfterGraphRun {
|
|
|
|
|
messages: vec![NodeGraphMessage::UpdateLayerPanel.into(), DocumentMessage::DocumentStructureChanged.into()],
|
|
|
|
|
});
|
|
|
|
|
// Destroy or refresh non-document panel layouts based on focus mode
|
|
|
|
|
for &panel_type in PanelType::non_document_panels() {
|
|
|
|
|
if self.workspace_panel_layout.is_panel_present(panel_type) {
|
|
|
|
|
if self.workspace_panel_layout.focus_document {
|
|
|
|
|
Self::destroy_panel_layouts(panel_type, responses);
|
|
|
|
|
} else {
|
|
|
|
|
self.refresh_panel_content(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::TogglePropertiesPanelOpen => {
|
|
|
|
|
if self.focus_document {
|
|
|
|
|
if self.workspace_panel_layout.focus_document {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1509,7 +1507,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
self.toggle_dockable_panel(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::ToggleLayersPanelOpen => {
|
|
|
|
|
if self.focus_document {
|
|
|
|
|
if self.workspace_panel_layout.focus_document {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1517,7 +1515,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
self.toggle_dockable_panel(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::ToggleDataPanelOpen => {
|
|
|
|
|
if self.focus_document {
|
|
|
|
|
if self.workspace_panel_layout.focus_document {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1538,11 +1536,72 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::UpdateWorkspacePanelLayout => {
|
|
|
|
|
let panel_layout = match self.workspace_panel_layout.focus_document {
|
|
|
|
|
true => self.workspace_panel_layout.document_only_layout(),
|
|
|
|
|
false => self.workspace_panel_layout.clone(),
|
|
|
|
|
};
|
|
|
|
|
responses.add(FrontendMessage::UpdateWorkspacePanelLayout { panel_layout });
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::SaveWorkspaceLayout => {
|
|
|
|
|
responses.add(FrontendMessage::TriggerSaveWorkspaceLayout {
|
|
|
|
|
workspace_layout: self.workspace_panel_layout.clone(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::ResetWorkspaceLayout => {
|
|
|
|
|
// Destroy layouts for all currently visible non-document panels
|
|
|
|
|
for &panel_type in PanelType::non_document_panels() {
|
|
|
|
|
if self.workspace_panel_layout.is_panel_present(panel_type) {
|
|
|
|
|
Self::destroy_panel_layouts(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Replace layout with the default and recalculate sizes
|
|
|
|
|
self.workspace_panel_layout = WorkspacePanelLayout::default();
|
|
|
|
|
self.workspace_panel_layout.recalculate_default_sizes();
|
|
|
|
|
|
|
|
|
|
responses.add(FrontendMessage::UpdateWorkspacePanelLayout {
|
|
|
|
|
panel_layout: self.workspace_panel_layout.clone(),
|
|
|
|
|
});
|
|
|
|
|
// Refresh all visible panels since the layout has been completely replaced
|
|
|
|
|
for group_id in self.workspace_panel_layout.root.all_group_ids() {
|
|
|
|
|
if let Some(panel_type) = self.workspace_panel_layout.panel_group(group_id).and_then(|g| g.active_panel_type()) {
|
|
|
|
|
self.refresh_panel_content(panel_type, responses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::ResetPanelGroupSizes { split_path } => {
|
|
|
|
|
// Walk the tree to the target split node using the path
|
|
|
|
|
let mut node = &mut self.workspace_panel_layout.root;
|
|
|
|
|
for &index in &split_path {
|
|
|
|
|
let PanelLayoutSubdivision::Split { children } = node else { return };
|
|
|
|
|
let Some(child) = children.get_mut(index) else { return };
|
|
|
|
|
node = &mut child.subdivision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recalculate default sizes for this split node
|
|
|
|
|
node.recalculate_default_sizes();
|
|
|
|
|
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::SetPanelGroupSizes { split_path, sizes } => {
|
|
|
|
|
// Walk the tree to the target split node using the path
|
|
|
|
|
let mut node = &mut self.workspace_panel_layout.root;
|
|
|
|
|
for &index in &split_path {
|
|
|
|
|
let PanelLayoutSubdivision::Split { children } = node else { return };
|
|
|
|
|
let Some(child) = children.get_mut(index) else { return };
|
|
|
|
|
node = &mut child.subdivision;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply the new sizes to the split's children
|
|
|
|
|
if let PanelLayoutSubdivision::Split { children } = node {
|
|
|
|
|
for (child, &size) in children.iter_mut().zip(sizes.iter()) {
|
|
|
|
|
child.size = size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
}
|
|
|
|
|
PortfolioMessage::UpdateOpenDocumentsList => {
|
|
|
|
|
// Send the list of document tab names
|
|
|
|
@@ -1602,7 +1661,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extend with actions that are disabled when focusing the document
|
|
|
|
|
if !self.focus_document {
|
|
|
|
|
if !self.workspace_panel_layout.focus_document {
|
|
|
|
|
common.extend(actions!(PortfolioMessageDiscriminant;
|
|
|
|
|
TogglePropertiesPanelOpen,
|
|
|
|
|
ToggleLayersPanelOpen,
|
|
|
|
@@ -1696,8 +1755,14 @@ impl PortfolioMessageHandler {
|
|
|
|
|
} else {
|
|
|
|
|
self.document_ids.push_back(document_id);
|
|
|
|
|
}
|
|
|
|
|
new_document.update_layers_panel_control_bar_widgets(self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.focus_document, responses);
|
|
|
|
|
new_document.update_layers_panel_bottom_bar_widgets(self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.focus_document, responses);
|
|
|
|
|
new_document.update_layers_panel_control_bar_widgets(
|
|
|
|
|
self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
responses,
|
|
|
|
|
);
|
|
|
|
|
new_document.update_layers_panel_bottom_bar_widgets(
|
|
|
|
|
self.workspace_panel_layout.is_panel_visible(PanelType::Layers) && !self.workspace_panel_layout.focus_document,
|
|
|
|
|
responses,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
self.documents.insert(document_id, new_document);
|
|
|
|
|
|
|
|
|
@@ -1744,7 +1809,7 @@ impl PortfolioMessageHandler {
|
|
|
|
|
/// Get the ID of the selected node that should be used as the current source for the Data panel.
|
|
|
|
|
pub fn node_to_inspect(&self) -> Option<NodeId> {
|
|
|
|
|
// Skip if the Data panel is not open
|
|
|
|
|
if !self.workspace_panel_layout.is_panel_visible(PanelType::Data) || self.focus_document {
|
|
|
|
|
if !self.workspace_panel_layout.is_panel_visible(PanelType::Data) || self.workspace_panel_layout.focus_document {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1794,6 +1859,7 @@ impl PortfolioMessageHandler {
|
|
|
|
|
|
|
|
|
|
responses.add(MenuBarMessage::SendLayout);
|
|
|
|
|
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
|
|
|
|
|
responses.add(PortfolioMessage::SaveWorkspaceLayout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Destroy the stored layout for a panel that is no longer the active tab.
|
|
|
|
|