From 07fd2c27827e4a91ad238d790d41396a33ef2389 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 7 May 2024 02:53:30 -0700 Subject: [PATCH] Add visibility and delete buttons to node sections in the Properties panel --- .../messages/layout/layout_message_handler.rs | 47 ++++++------ .../layout/utility_types/layout_widget.rs | 40 +++++++--- .../node_graph/node_graph_message_handler.rs | 4 + .../document/node_graph/node_properties.rs | 7 +- .../properties_panel_message_handler.rs | 2 +- frontend/src/components/panels/Layers.svelte | 6 +- frontend/src/components/views/Graph.svelte | 6 +- .../components/widgets/WidgetSection.svelte | 74 +++++++++++++------ frontend/src/wasm-communication/messages.ts | 4 +- frontend/wasm/src/editor_api.rs | 17 ++++- 10 files changed, 139 insertions(+), 68 deletions(-) diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 8664e75d..9ef27839 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -309,30 +309,35 @@ impl LayoutMessageHandler { responses: &mut VecDeque, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Vec, ) { - // We don't diff the menu bar layout yet. - if matches!(new_layout, Layout::MenuLayout(_)) { - // Skip update if the same - if self.layouts[layout_target as usize] == new_layout { - return; + match new_layout { + Layout::WidgetLayout(_) => { + let mut widget_diffs = Vec::new(); + self.layouts[layout_target as usize].diff(new_layout, &mut Vec::new(), &mut widget_diffs); + + // Skip sending if no diff. + if widget_diffs.is_empty() { + return; + } + + self.send_diff(widget_diffs, layout_target, responses, action_input_mapping); } - // Update the backend storage - self.layouts[layout_target as usize] = new_layout; - // Update the UI - responses.add(FrontendMessage::UpdateMenuBarLayout { - layout_target, - layout: self.layouts[layout_target as usize].clone().unwrap_menu_layout(action_input_mapping).layout, - }); - return; - } + // We don't diff the menu bar layout yet. + Layout::MenuLayout(_) => { + // Skip update if the same + if self.layouts[layout_target as usize] == new_layout { + return; + } - let mut widget_diffs = Vec::new(); - self.layouts[layout_target as usize].diff(new_layout, &mut Vec::new(), &mut widget_diffs); - // Skip sending if no diff. - if widget_diffs.is_empty() { - return; - } + // Update the backend storage + self.layouts[layout_target as usize] = new_layout; - self.send_diff(widget_diffs, layout_target, responses, action_input_mapping); + // Update the UI + responses.add(FrontendMessage::UpdateMenuBarLayout { + layout_target, + layout: self.layouts[layout_target as usize].clone().unwrap_menu_layout(action_input_mapping).layout, + }); + } + } } /// Send a diff to the frontend based on the layout target. diff --git a/editor/src/messages/layout/utility_types/layout_widget.rs b/editor/src/messages/layout/utility_types/layout_widget.rs index 6af30410..38669840 100644 --- a/editor/src/messages/layout/utility_types/layout_widget.rs +++ b/editor/src/messages/layout/utility_types/layout_widget.rs @@ -235,7 +235,7 @@ impl<'a> Iterator for WidgetIter<'a> { self.current_slice = Some(widgets); self.next() } - Some(LayoutGroup::Section { name: _, layout }) => { + Some(LayoutGroup::Section { layout, .. }) => { for layout_row in layout { self.stack.push(layout_row); } @@ -276,7 +276,7 @@ impl<'a> Iterator for WidgetIterMut<'a> { self.current_slice = Some(widgets); self.next() } - Some(LayoutGroup::Section { name: _, layout }) => { + Some(LayoutGroup::Section { layout, .. }) => { for layout_row in layout { self.stack.push(layout_row); } @@ -301,8 +301,9 @@ pub enum LayoutGroup { #[serde(rename = "rowWidgets")] widgets: Vec, }, + // TODO: Move this from being a child of `enum LayoutGroup` to being a child of `enum Layout` #[serde(rename = "section")] - Section { name: String, layout: SubLayout }, + Section { name: String, visible: bool, id: u64, layout: SubLayout }, } impl Default for LayoutGroup { @@ -378,28 +379,43 @@ impl LayoutGroup { ( Self::Section { name: current_name, + visible: current_visible, + id: current_id, layout: current_layout, }, - Self::Section { name: new_name, layout: new_layout }, + Self::Section { + name: new_name, + visible: new_visible, + id: new_id, + layout: new_layout, + }, ) => { - // If the lengths are different then resend the entire panel + // Resend the entire panel if the lengths, names, visibility, or node IDs are different // TODO: Diff insersion and deletion of items - if *current_name != new_name || current_layout.len() != new_layout.len() { + if current_layout.len() != new_layout.len() || *current_name != new_name || *current_visible != new_visible || *current_id != new_id { // Update self to reflect new changes *current_name = new_name.clone(); + *current_visible = new_visible; + *current_id = new_id; *current_layout = new_layout.clone(); // Push an update layout group to the diff - let new_value = DiffUpdate::LayoutGroup(Self::Section { name: new_name, layout: new_layout }); + let new_value = DiffUpdate::LayoutGroup(Self::Section { + name: new_name, + visible: new_visible, + id: new_id, + layout: new_layout, + }); let widget_path = widget_path.to_vec(); widget_diffs.push(WidgetDiff { widget_path, new_value }); - return; } // Diff all of the children - for (index, (current_child, new_child)) in current_layout.iter_mut().zip(new_layout).enumerate() { - widget_path.push(index); - current_child.diff(new_child, widget_path, widget_diffs); - widget_path.pop(); + else { + for (index, (current_child, new_child)) in current_layout.iter_mut().zip(new_layout).enumerate() { + widget_path.push(index); + current_child.diff(new_child, widget_path, widget_diffs); + widget_path.pop(); + } } } (current, new) => { diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 9b5485b7..e11df189 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -666,8 +666,12 @@ impl<'a> MessageHandler> for NodeGrap responses.add(NodeGraphMessage::RunDocumentGraph); } })(); + document_metadata.load_structure(document_network, selected_nodes); + self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses); + + responses.add(PropertiesPanelMessage::Refresh); } NodeGraphMessage::ToggleSelectedLocked => { responses.add(DocumentMessage::StartTransaction); diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 34d4c0fe..c841c830 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -2252,7 +2252,12 @@ pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, c Some(document_node_type) => (document_node_type.properties)(document_node, node_id, context), None => unknown_node_properties(document_node), }; - LayoutGroup::Section { name, layout } + LayoutGroup::Section { + name, + visible: document_node.visible, + id: node_id.0, + layout, + } } pub fn stroke_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs index 2f68e4da..57cccca2 100644 --- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs @@ -43,7 +43,7 @@ impl<'a> MessageHandler (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())} + action={(e) => (toggleNodeVisibility(listing.entry.id), e?.stopPropagation())} size={24} icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"} hoverIcon={listing.entry.visible ? "EyeHide" : "EyeShow"} diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 5d9d2f49..76385bc3 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -556,8 +556,8 @@ return selected.includes(node) || intersetNodeAABB(boxSelect, nodeIndex); } - function toggleLayerVisibility(id: bigint) { - editor.handle.toggleLayerVisibility(id); + function toggleNodeVisibility(id: bigint) { + editor.handle.toggleNodeVisibility(id); } function toggleLayerDisplay(displayAsLayer: boolean) { @@ -956,7 +956,7 @@ (toggleLayerVisibility(node.id), e?.stopPropagation())} + action={(e) => (toggleNodeVisibility(node.id), e?.stopPropagation())} size={24} icon={node.visible ? "EyeVisible" : "EyeHidden"} tooltip={node.visible ? "Visible" : "Hidden"} diff --git a/frontend/src/components/widgets/WidgetSection.svelte b/frontend/src/components/widgets/WidgetSection.svelte index 0775f60f..bfb61aeb 100644 --- a/frontend/src/components/widgets/WidgetSection.svelte +++ b/frontend/src/components/widgets/WidgetSection.svelte @@ -1,7 +1,11 @@ @@ -21,6 +27,25 @@ {#if expanded} @@ -53,12 +78,34 @@ align-items: center; display: flex; flex: 0 0 24px; - padding: 0 8px; + padding-left: 8px; + padding-right: 0; margin-bottom: 4px; border: 0; border-radius: 4px; background: var(--color-2-mildblack); + &.expanded { + border-radius: 4px 4px 0 0; + margin-bottom: 0; + + .expand-arrow::after { + transform: rotate(90deg); + } + } + + &:hover { + background: var(--color-4-dimgray); + + .expand-arrow::after { + background: var(--icon-expand-collapse-arrow-hover); + } + + + .body { + border: 1px solid var(--color-4-dimgray); + } + } + .expand-arrow { width: 8px; height: 8px; @@ -79,32 +126,15 @@ } } - &.expanded { - border-radius: 4px 4px 0 0; - margin-bottom: 0; - - .expand-arrow::after { - transform: rotate(90deg); - } - } - .text-label { height: 18px; margin-left: 8px; - display: inline-block; + flex: 1 1 100%; } + } - &:hover { - background: var(--color-4-dimgray); - - .expand-arrow::after { - background: var(--icon-expand-collapse-arrow-hover); - } - - + .body { - border: 1px solid var(--color-4-dimgray); - } - } + &:not(:hover) .header .show-only-on-hover { + display: none; } .body { diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 05c20363..5ad5c704 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -1176,7 +1176,7 @@ export function isWidgetSpanRow(layoutRow: LayoutGroup): layoutRow is WidgetSpan return Boolean((layoutRow as WidgetSpanRow)?.rowWidgets); } -export type WidgetSection = { name: string; layout: LayoutGroup[] }; +export type WidgetSection = { name: string; visible: boolean; id: bigint; layout: LayoutGroup[] }; export function isWidgetSection(layoutRow: LayoutGroup): layoutRow is WidgetSection { return Boolean((layoutRow as WidgetSection)?.layout); } @@ -1216,7 +1216,7 @@ function createLayoutGroup(layoutGroup: any): LayoutGroup { } if (layoutGroup.section) { - const result: WidgetSection = { name: layoutGroup.section.name, layout: layoutGroup.section.layout.map(createLayoutGroup) }; + const result: WidgetSection = { name: layoutGroup.section.name, visible: layoutGroup.section.visible, id: layoutGroup.section.id, layout: layoutGroup.section.layout.map(createLayoutGroup) }; return result; } diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index a104ad75..d190dff6 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -683,14 +683,25 @@ impl EditorHandle { self.dispatch(message); } - /// Toggle visibility of a layer from the layer list - #[wasm_bindgen(js_name = toggleLayerVisibility)] - pub fn toggle_layer_visibility(&self, id: u64) { + /// Toggle visibility of a layer or node given its node ID + #[wasm_bindgen(js_name = toggleNodeVisibility)] + pub fn toggle_node_visibility(&self, id: u64) { let node_id = NodeId(id); let message = NodeGraphMessage::ToggleVisibility { node_id }; self.dispatch(message); } + /// Delete a layer or node given its node ID + #[wasm_bindgen(js_name = deleteNode)] + pub fn delete_node(&self, id: u64) { + let message = DocumentMessage::StartTransaction; + self.dispatch(message); + + let id = NodeId(id); + let message = DocumentMessage::DeleteLayer { id }; + self.dispatch(message); + } + /// Toggle lock state of a layer from the layer list #[wasm_bindgen(js_name = toggleLayerLock)] pub fn toggle_layer_lock(&self, id: u64) {