Skip to content
Draft
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
6 changes: 6 additions & 0 deletions editor/src/messages/layout/utility_types/layout_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ pub enum LayoutGroup {
description: String,
visible: bool,
pinned: bool,
expanded: bool,
id: u64,
layout: Layout,
},
Expand Down Expand Up @@ -439,6 +440,7 @@ impl Diffable for LayoutGroup {
description: current_description,
visible: current_visible,
pinned: current_pinned,
expanded: current_expanded,
id: current_id,
layout: current_layout,
},
Expand All @@ -447,6 +449,7 @@ impl Diffable for LayoutGroup {
description: new_description,
visible: new_visible,
pinned: new_pinned,
expanded: new_expanded,
id: new_id,
layout: new_layout,
},
Expand All @@ -458,13 +461,15 @@ impl Diffable for LayoutGroup {
|| *current_description != new_description
|| *current_visible != new_visible
|| *current_pinned != new_pinned
|| *current_expanded != new_expanded
|| *current_id != new_id
{
// Update self to reflect new changes
current_name.clone_from(&new_name);
current_description.clone_from(&new_description);
*current_visible = new_visible;
*current_pinned = new_pinned;
*current_expanded = new_expanded;
*current_id = new_id;
current_layout.clone_from(&new_layout);

Expand All @@ -474,6 +479,7 @@ impl Diffable for LayoutGroup {
description: new_description,
visible: new_visible,
pinned: new_pinned,
expanded: new_expanded,
id: new_id,
layout: new_layout,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pub struct DocumentMessageHandler {
/// List of the [`LayerNodeIdentifier`]s that are currently collapsed by the user in the Layers panel.
/// Collapsed means that the expansion arrow isn't set to show the children of these layers.
pub collapsed: CollapsedLayers,

/// The full Git commit hash of the Graphite repository that was used to build the editor.
/// We save this to provide a hint about which version of the editor was used to create the document.
pub commit_hash: String,
Expand Down Expand Up @@ -159,6 +160,7 @@ impl Default for DocumentMessageHandler {
// ============================================
network_interface: default_document_network_interface(),
collapsed: CollapsedLayers::default(),

commit_hash: GRAPHITE_GIT_COMMIT_HASH.to_string(),
document_ptz: PTZ::default(),
render_mode: RenderMode::default(),
Expand Down Expand Up @@ -229,6 +231,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
document_name: self.name.as_str(),
executor,
persistent_data,

properties_panel_open,
};
self.properties_panel_message_handler.process_message(message, responses, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
let new_merge_node = resolve_network_node_type("Merge").expect("Merge node").default_node_template();
self.network_interface.insert_node(new_id, new_merge_node, &[]);
self.responses.add(PropertiesPanelMessage::SetSectionExpanded { node_id: new_id.0, expanded: false });
LayerNodeIdentifier::new(new_id, self.network_interface)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use graphene_std::*;
use serde_json::Value;
use std::collections::{HashMap, VecDeque};

pub const MERGE_NODE_IDENTIFIER: &str = "Merge";

pub struct NodePropertiesContext<'a> {
pub persistent_data: &'a PersistentData,
pub responses: &'a mut VecDeque<Message>,
Expand Down Expand Up @@ -213,7 +215,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
properties: None,
},
DocumentNodeDefinition {
identifier: "Merge",
identifier: MERGE_NODE_IDENTIFIER,
category: "General",
node_template: NodeTemplate {
document_node: DocumentNode {
Expand Down Expand Up @@ -2710,10 +2712,17 @@ impl DocumentNodeDefinition {
}
populate_input_properties(&mut template, Vec::new());

if let DocumentNodeImplementation::Network(_) = &template.document_node.implementation {
let network = template.persistent_node_metadata.network_metadata.get_or_insert_with(NodeNetworkMetadata::default);
network.persistent_metadata.reference = Some(self.identifier.to_string());
}
if self.identifier == MERGE_NODE_IDENTIFIER {
template.persistent_node_metadata.collapsed = true;
}

template
}

/// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], completely default.
pub fn default_node_template(&self) -> NodeTemplate {
self.node_template_input_override(self.node_template.document_node.inputs.clone().into_iter().map(Some))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ pub enum NodeGraphMessage {
node_id: NodeId,
pinned: bool,
},
SetCollapsed {
node_id: NodeId,
collapsed: bool,
},
SetVisibility {
node_id: NodeId,
visible: bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1904,6 +1904,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
NodeGraphMessage::SetPinned { node_id, pinned } => {
network_interface.set_pinned(&node_id, selection_network_path, pinned);
}
NodeGraphMessage::SetCollapsed { node_id, collapsed } => {
network_interface.set_collapsed(&node_id, selection_network_path, collapsed);
}
NodeGraphMessage::SetVisibility { node_id, visible } => {
network_interface.set_visibility(&node_id, selection_network_path, visible);
}
Expand All @@ -1913,6 +1916,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}
responses.add(NodeGraphMessage::UpdateActionButtons);
responses.add(NodeGraphMessage::SendGraph);
responses.add(NodeGraphMessage::UpdateLayerPanel);
responses.add(PortfolioMessage::AutoSaveActiveDocument);

responses.add(PropertiesPanelMessage::Refresh);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1830,7 +1830,17 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
if layout.is_empty() {
layout = node_no_properties(node_id, context);
}
let name = context.network_interface.implementation_name(&node_id, context.selection_network_path);
let mut name = context.network_interface.implementation_name(&node_id, context.selection_network_path);
if name == "Custom Node" {
if let Some(display_name) = context
.network_interface
.node_metadata(&node_id, context.selection_network_path)
.map(|metadata| metadata.persistent_metadata.display_name.clone())
.filter(|name| !name.is_empty())
{
name = display_name;
}
}

let description = context
.network_interface
Expand All @@ -1843,12 +1853,15 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper

let visible = context.network_interface.is_visible(&node_id, context.selection_network_path);
let pinned = context.network_interface.is_pinned(&node_id, context.selection_network_path);
let collapsed = context.network_interface.is_collapsed(&node_id, context.selection_network_path);
let expanded = !collapsed;

LayoutGroup::Section {
name,
description,
visible,
pinned,
expanded,
id: node_id.0,
layout: Layout(layout),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ pub enum PropertiesPanelMessage {
// Messages
Clear,
Refresh,
SetAllSectionsExpanded { expanded: bool },
SetSectionExpanded { node_id: u64, expanded: bool },
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,59 @@ impl MessageHandler<PropertiesPanelMessage, PropertiesPanelMessageContext<'_>> f
layout_target: LayoutTarget::PropertiesPanel,
});
}
PropertiesPanelMessage::SetAllSectionsExpanded { expanded } => {
let mut layout = {
let mut node_properties_context = NodePropertiesContext {
persistent_data,
responses,
network_interface,
selection_network_path,
document_name,
executor,
};
Layout(NodeGraphMessageHandler::collate_properties(&mut node_properties_context))
};

responses.add(DocumentMessage::AddTransaction);
let node_ids = Self::update_all_section_expansion_recursive(&mut layout.0, expanded, responses);
if !node_ids.is_empty() {
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids });
}

responses.add(LayoutMessage::SendLayout {
layout,
layout_target: LayoutTarget::PropertiesPanel,
});
}
PropertiesPanelMessage::SetSectionExpanded { node_id, expanded } => {
let node_id = NodeId(node_id);
responses.add(DocumentMessage::AddTransaction);
responses.add(NodeGraphMessage::SetCollapsed { node_id, collapsed: !expanded });
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids: vec![node_id] });
}
}
}

fn actions(&self) -> ActionList {
actions!(PropertiesMessageDiscriminant;)
}
}

impl PropertiesPanelMessageHandler {
fn update_all_section_expansion_recursive(layout: &mut [LayoutGroup], expanded: bool, responses: &mut VecDeque<Message>) -> Vec<NodeId> {
let mut node_ids = Vec::new();
for group in layout {
if let LayoutGroup::Section {
id, layout, expanded: group_expanded, ..
} = group
{
*group_expanded = expanded;
let node_id = NodeId(*id);
node_ids.push(node_id);
responses.add(NodeGraphMessage::SetCollapsed { node_id, collapsed: !expanded });
node_ids.extend(Self::update_all_section_expansion_recursive(&mut layout.0, expanded, responses));
}
}
node_ids
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,14 @@ impl NodeNetworkInterface {
node_metadata.persistent_metadata.pinned
}

pub fn is_collapsed(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
let Some(node_metadata) = self.node_metadata(node_id, network_path) else {
log::error!("Could not get persistent node metadata in is_collapsed for node {node_id}");
return false;
};
node_metadata.persistent_metadata.collapsed
}

pub fn is_visible(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
let Some(node) = self.document_node(node_id, network_path) else {
log::error!("Could not get node in is_visible");
Expand Down Expand Up @@ -4487,6 +4495,16 @@ impl NodeNetworkInterface {
self.transaction_modified();
}

pub fn set_collapsed(&mut self, node_id: &NodeId, network_path: &[NodeId], collapsed: bool) {
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
log::error!("Could not get node {node_id} in set_collapsed");
return;
};

node_metadata.persistent_metadata.collapsed = collapsed;
self.transaction_modified();
}

pub fn set_visibility(&mut self, node_id: &NodeId, network_path: &[NodeId], is_visible: bool) {
let Some(network) = self.network_mut(network_path) else {
return;
Expand Down Expand Up @@ -6242,6 +6260,9 @@ pub struct DocumentNodePersistentMetadata {
/// Indicates that the node will be shown in the Properties panel when it would otherwise be empty, letting a user easily edit its properties by just deselecting everything.
#[serde(default)]
pub pinned: bool,
/// Whether the properties body is expanded or collapsed. Defaults to `false` when not specified.
#[serde(default)]
pub collapsed: bool,
/// Metadata that is specific to either nodes or layers, which are chosen states for displaying as a left-to-right node or bottom-to-top layer.
/// All fields in NodeTypePersistentMetadata should automatically be updated by using the network interface API
pub node_type_metadata: NodeTypePersistentMetadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ impl From<DocumentNodePersistentMetadataStringReference> for DocumentNodePersist
output_names: old.output_names,
locked: old.locked,
pinned: old.pinned,
collapsed: false,
node_type_metadata: old.node_type_metadata,
network_metadata: old.network_metadata,
}
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/components/widgets/WidgetSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import type { Editor } from "@graphite/editor";
import { isWidgetSpanRow, isWidgetSection, type WidgetSection as WidgetSectionFromJsMessages, type LayoutTarget } from "@graphite/messages";
import { operatingSystem } from "@graphite/utility-functions/platform";

import LayoutCol from "@graphite/components/layout/LayoutCol.svelte";
import IconButton from "@graphite/components/widgets/buttons/IconButton.svelte";
Expand All @@ -16,14 +17,24 @@
export { className as class };
export let classes: Record<string, boolean> = {};

let expanded = true;
$: expanded = widgetData.expanded;

const editor = getContext<Editor>("editor");
</script>

<!-- TODO: Implement collapsable sections with properties system -->
<LayoutCol class={`widget-section ${className}`.trim()} {classes}>
<button class="header" class:expanded on:click|stopPropagation={() => (expanded = !expanded)} tabindex="0">
<button
class="header"
class:expanded
on:click|stopPropagation={(e) => {
const accel = operatingSystem() === "Mac" ? e.metaKey : e.ctrlKey;
if (e.altKey || accel) {
editor.handle.setAllSectionsExpanded(!expanded);
} else {
editor.handle.setSectionExpanded(widgetData.id, !expanded);
}
}}
>
<div class="expand-arrow"></div>
<TextLabel tooltipLabel={widgetData.name} tooltipDescription={widgetData.description} bold={true}>{widgetData.name}</TextLabel>
<IconButton
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1587,7 +1587,7 @@ export function isWidgetTable(layoutTable: LayoutGroup): layoutTable is WidgetTa
return Boolean((layoutTable as WidgetTable)?.tableWidgets);
}

export type WidgetSection = { name: string; description: string; visible: boolean; pinned: boolean; id: bigint; layout: Layout };
export type WidgetSection = { name: string; description: string; visible: boolean; pinned: boolean; expanded: boolean; id: bigint; layout: Layout };
export function isWidgetSection(layoutRow: LayoutGroup): layoutRow is WidgetSection {
return Boolean((layoutRow as WidgetSection)?.layout);
}
Expand All @@ -1612,6 +1612,7 @@ function createLayoutGroup(layoutGroup: any): LayoutGroup {
description: layoutGroup.section.description,
visible: layoutGroup.section.visible,
pinned: layoutGroup.section.pinned,
expanded: layoutGroup.section.expanded,
id: layoutGroup.section.id,
layout: layoutGroup.section.layout.map(createLayoutGroup),
};
Expand Down
14 changes: 14 additions & 0 deletions frontend/wasm/src/editor_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,20 @@ impl EditorHandle {
self.dispatch(message);
}

/// Set section expanded state in the Properties panel
#[wasm_bindgen(js_name = setSectionExpanded)]
pub fn set_section_expanded(&self, node_id: u64, expanded: bool) {
let message = DocumentMessage::PropertiesPanel(PropertiesPanelMessage::SetSectionExpanded { node_id, expanded });
self.dispatch(message);
}

/// Set all sections expanded state in the Properties panel
#[wasm_bindgen(js_name = setAllSectionsExpanded)]
pub fn set_all_sections_expanded(&self, expanded: bool) {
let message = DocumentMessage::PropertiesPanel(PropertiesPanelMessage::SetAllSectionsExpanded { expanded });
self.dispatch(message);
}

/// Set the active panel to the most recently clicked panel
#[wasm_bindgen(js_name = setActivePanel)]
pub fn set_active_panel(&self, panel: String) {
Expand Down
Loading