mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 01:38:12 +08:00
Add a node insertion button and layer renaming from the Properties panel (#2072)
* Add node button * Improve css a bit * Add layer renaming to the Properties panel and move New Layer to that, plus add unpinning to properties sections * Add tooltip * Re-add layer itself in listing * Final code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
3c839ffd2b
commit
5aa6716910
@@ -253,11 +253,6 @@ pub enum FrontendMessage {
|
||||
#[serde(rename = "openDocuments")]
|
||||
open_documents: Vec<FrontendDocumentDetails>,
|
||||
},
|
||||
UpdatePropertyPanelOptionsLayout {
|
||||
#[serde(rename = "layoutTarget")]
|
||||
layout_target: LayoutTarget,
|
||||
diff: Vec<WidgetDiff>,
|
||||
},
|
||||
UpdatePropertyPanelSectionsLayout {
|
||||
#[serde(rename = "layoutTarget")]
|
||||
layout_target: LayoutTarget,
|
||||
|
||||
@@ -214,6 +214,17 @@ impl LayoutMessageHandler {
|
||||
|
||||
responses.add(callback_message);
|
||||
}
|
||||
Widget::NodeCatalog(node_type_input) => match action {
|
||||
WidgetValueAction::Commit => {
|
||||
let callback_message = (node_type_input.on_commit.callback)(&());
|
||||
responses.add(callback_message);
|
||||
}
|
||||
WidgetValueAction::Update => {
|
||||
let value = value.as_str().expect("NodeCatalog update was not of type String").to_string();
|
||||
let callback_message = (node_type_input.on_update.callback)(&value);
|
||||
responses.add(callback_message);
|
||||
}
|
||||
},
|
||||
Widget::NumberInput(number_input) => match action {
|
||||
WidgetValueAction::Commit => {
|
||||
let callback_message = (number_input.on_commit.callback)(&());
|
||||
@@ -394,7 +405,6 @@ impl LayoutMessageHandler {
|
||||
LayoutTarget::LayersPanelOptions => FrontendMessage::UpdateLayersPanelOptionsLayout { layout_target, diff },
|
||||
LayoutTarget::MenuBar => unreachable!("Menu bar is not diffed"),
|
||||
LayoutTarget::NodeGraphBar => FrontendMessage::UpdateNodeGraphBarLayout { layout_target, diff },
|
||||
LayoutTarget::PropertiesOptions => FrontendMessage::UpdatePropertyPanelOptionsLayout { layout_target, diff },
|
||||
LayoutTarget::PropertiesSections => FrontendMessage::UpdatePropertyPanelSectionsLayout { layout_target, diff },
|
||||
LayoutTarget::ToolOptions => FrontendMessage::UpdateToolOptionsLayout { layout_target, diff },
|
||||
LayoutTarget::ToolShelf => FrontendMessage::UpdateToolShelfLayout { layout_target, diff },
|
||||
|
||||
@@ -38,8 +38,6 @@ pub enum LayoutTarget {
|
||||
MenuBar,
|
||||
/// Bar at the top of the node graph containing the location and the "Preview" and "Hide" buttons.
|
||||
NodeGraphBar,
|
||||
/// The bar at the top of the Properties panel containing the layer name and icon.
|
||||
PropertiesOptions,
|
||||
/// The body of the Properties panel containing many collapsable sections.
|
||||
PropertiesSections,
|
||||
/// The bar directly above the canvas, left-aligned and to the right of the document mode dropdown.
|
||||
@@ -303,7 +301,7 @@ pub enum LayoutGroup {
|
||||
},
|
||||
// TODO: Move this from being a child of `enum LayoutGroup` to being a child of `enum Layout`
|
||||
#[serde(rename = "section")]
|
||||
Section { name: String, visible: bool, id: u64, layout: SubLayout },
|
||||
Section { name: String, visible: bool, pinned: bool, id: u64, layout: SubLayout },
|
||||
}
|
||||
|
||||
impl Default for LayoutGroup {
|
||||
@@ -344,7 +342,7 @@ impl LayoutGroup {
|
||||
Widget::TextInput(x) => &mut x.tooltip,
|
||||
Widget::TextLabel(x) => &mut x.tooltip,
|
||||
Widget::BreadcrumbTrailButtons(x) => &mut x.tooltip,
|
||||
Widget::InvisibleStandinInput(_) | Widget::PivotInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) => continue,
|
||||
Widget::InvisibleStandinInput(_) | Widget::PivotInput(_) | Widget::RadioInput(_) | Widget::Separator(_) | Widget::WorkingColorsInput(_) | Widget::NodeCatalog(_) => continue,
|
||||
};
|
||||
if val.is_empty() {
|
||||
val.clone_from(&tooltip);
|
||||
@@ -385,22 +383,25 @@ impl LayoutGroup {
|
||||
Self::Section {
|
||||
name: current_name,
|
||||
visible: current_visible,
|
||||
pinned: current_pinned,
|
||||
id: current_id,
|
||||
layout: current_layout,
|
||||
},
|
||||
Self::Section {
|
||||
name: new_name,
|
||||
visible: new_visible,
|
||||
pinned: new_pinned,
|
||||
id: new_id,
|
||||
layout: new_layout,
|
||||
},
|
||||
) => {
|
||||
// Resend the entire panel if the lengths, names, visibility, or node IDs are different
|
||||
// TODO: Diff insersion and deletion of items
|
||||
if current_layout.len() != new_layout.len() || *current_name != new_name || *current_visible != new_visible || *current_id != new_id {
|
||||
if current_layout.len() != new_layout.len() || *current_name != new_name || *current_visible != new_visible || *current_pinned != new_pinned || *current_id != new_id {
|
||||
// Update self to reflect new changes
|
||||
current_name.clone_from(&new_name);
|
||||
*current_visible = new_visible;
|
||||
*current_pinned = new_pinned;
|
||||
*current_id = new_id;
|
||||
current_layout.clone_from(&new_layout);
|
||||
|
||||
@@ -408,6 +409,7 @@ impl LayoutGroup {
|
||||
let new_value = DiffUpdate::LayoutGroup(Self::Section {
|
||||
name: new_name,
|
||||
visible: new_visible,
|
||||
pinned: new_pinned,
|
||||
id: new_id,
|
||||
layout: new_layout,
|
||||
});
|
||||
@@ -504,6 +506,7 @@ pub enum Widget {
|
||||
IconLabel(IconLabel),
|
||||
ImageLabel(ImageLabel),
|
||||
InvisibleStandinInput(InvisibleStandinInput),
|
||||
NodeCatalog(NodeCatalog),
|
||||
NumberInput(NumberInput),
|
||||
ParameterExposeButton(ParameterExposeButton),
|
||||
PivotInput(PivotInput),
|
||||
@@ -580,6 +583,7 @@ impl DiffUpdate {
|
||||
| Widget::ImageLabel(_)
|
||||
| Widget::CurveInput(_)
|
||||
| Widget::InvisibleStandinInput(_)
|
||||
| Widget::NodeCatalog(_)
|
||||
| Widget::PivotInput(_)
|
||||
| Widget::RadioInput(_)
|
||||
| Widget::Separator(_)
|
||||
|
||||
@@ -274,6 +274,21 @@ pub enum NumberInputMode {
|
||||
Range,
|
||||
}
|
||||
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize, Derivative, WidgetBuilder, specta::Type)]
|
||||
#[derivative(Debug, PartialEq, Default)]
|
||||
pub struct NodeCatalog {
|
||||
pub disabled: bool,
|
||||
|
||||
// Callbacks
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_update: WidgetCallback<String>,
|
||||
|
||||
#[serde(skip)]
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||
pub on_commit: WidgetCallback<()>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder, specta::Type)]
|
||||
#[derivative(Debug, PartialEq)]
|
||||
pub struct RadioInput {
|
||||
|
||||
@@ -45,6 +45,9 @@ pub enum DocumentMessage {
|
||||
},
|
||||
CreateEmptyFolder,
|
||||
DebugPrintDocument,
|
||||
DeleteNode {
|
||||
node_id: NodeId,
|
||||
},
|
||||
DeleteSelectedLayers,
|
||||
DeselectAllLayers,
|
||||
DocumentHistoryBackward,
|
||||
@@ -128,6 +131,10 @@ pub enum DocumentMessage {
|
||||
SetBlendModeForSelectedLayers {
|
||||
blend_mode: BlendMode,
|
||||
},
|
||||
SetNodePinned {
|
||||
node_id: NodeId,
|
||||
pinned: bool,
|
||||
},
|
||||
SetOpacityForSelectedLayers {
|
||||
opacity: f64,
|
||||
},
|
||||
@@ -142,6 +149,10 @@ pub enum DocumentMessage {
|
||||
closure: Option<for<'a> fn(&'a mut SnappingState) -> &'a mut bool>,
|
||||
snapping_state: bool,
|
||||
},
|
||||
SetToNodeOrLayer {
|
||||
node_id: NodeId,
|
||||
is_layer: bool,
|
||||
},
|
||||
SetViewMode {
|
||||
view_mode: ViewMode,
|
||||
},
|
||||
|
||||
@@ -228,7 +228,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||
DocumentMessage::PropertiesPanel(message) => {
|
||||
let properties_panel_message_handler_data = PropertiesPanelMessageHandlerData {
|
||||
network_interface: &self.network_interface,
|
||||
selection_path: &self.selection_network_path,
|
||||
selection_network_path: &self.selection_network_path,
|
||||
document_name: self.name.as_str(),
|
||||
executor,
|
||||
};
|
||||
@@ -359,6 +359,17 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||
DocumentMessage::DebugPrintDocument => {
|
||||
info!("{:#?}", self.network_interface);
|
||||
}
|
||||
DocumentMessage::DeleteNode { node_id } => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
responses.add(NodeGraphMessage::DeleteNodes {
|
||||
node_ids: vec![node_id],
|
||||
delete_children: true,
|
||||
});
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
DocumentMessage::DeleteSelectedLayers => {
|
||||
responses.add(NodeGraphMessage::DeleteSelectedNodes { delete_children: true });
|
||||
}
|
||||
@@ -1008,6 +1019,13 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||
responses.add(GraphOperationMessage::BlendModeSet { layer, blend_mode });
|
||||
}
|
||||
}
|
||||
DocumentMessage::SetNodePinned { node_id, pinned } => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
responses.add(NodeGraphMessage::SetPinned { node_id, pinned });
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
}
|
||||
DocumentMessage::SetOpacityForSelectedLayers { opacity } => {
|
||||
let opacity = opacity.clamp(0., 1.);
|
||||
for layer in self.network_interface.selected_nodes(&[]).unwrap().selected_layers_except_artboards(&self.network_interface) {
|
||||
@@ -1027,6 +1045,10 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
|
||||
*closure(&mut self.snapping_state) = snapping_state;
|
||||
}
|
||||
}
|
||||
DocumentMessage::SetToNodeOrLayer { node_id, is_layer } => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
responses.add(NodeGraphMessage::SetToNodeOrLayer { node_id, is_layer });
|
||||
}
|
||||
DocumentMessage::SetViewMode { view_mode } => {
|
||||
self.view_mode = view_mode;
|
||||
responses.add_front(NodeGraphMessage::RunDocumentGraph);
|
||||
|
||||
@@ -268,17 +268,20 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
}
|
||||
|
||||
// Create a new node if the node does not exist and update its inputs
|
||||
existing_node_id.or_else(|| {
|
||||
let output_layer = self.get_output_layer()?;
|
||||
let Some(node_definition) = resolve_document_node_type(reference) else {
|
||||
log::error!("Node type {} does not exist in ModifyInputsContext::existing_node_id", reference);
|
||||
return None;
|
||||
};
|
||||
let node_id = NodeId::new();
|
||||
self.network_interface.insert_node(node_id, node_definition.default_node_template(), &[]);
|
||||
self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[]);
|
||||
Some(node_id)
|
||||
})
|
||||
existing_node_id.or_else(|| self.create_node(reference))
|
||||
}
|
||||
|
||||
/// Create a new node inside the layer
|
||||
pub fn create_node(&mut self, reference: &str) -> Option<NodeId> {
|
||||
let output_layer = self.get_output_layer()?;
|
||||
let Some(node_definition) = resolve_document_node_type(reference) else {
|
||||
log::error!("Node type {} does not exist in ModifyInputsContext::existing_node_id", reference);
|
||||
return None;
|
||||
};
|
||||
let node_id = NodeId::new();
|
||||
self.network_interface.insert_node(node_id, node_definition.default_node_template(), &[]);
|
||||
self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[]);
|
||||
Some(node_id)
|
||||
}
|
||||
|
||||
pub fn fill_set(&mut self, fill: Fill) {
|
||||
|
||||
@@ -35,6 +35,7 @@ pub struct NodePropertiesContext<'a> {
|
||||
pub executor: &'a mut NodeGraphExecutor,
|
||||
pub network_interface: &'a NodeNetworkInterface,
|
||||
pub selection_network_path: &'a [NodeId],
|
||||
pub document_name: &'a str,
|
||||
}
|
||||
|
||||
/// Acts as a description for a [DocumentNode] before it gets instantiated as one.
|
||||
|
||||
@@ -19,6 +19,14 @@ pub enum NodeGraphMessage {
|
||||
Init,
|
||||
SelectedNodesUpdated,
|
||||
Copy,
|
||||
CreateNodeInLayerNoTransaction {
|
||||
node_type: String,
|
||||
layer: LayerNodeIdentifier,
|
||||
},
|
||||
CreateNodeInLayerWithTransaction {
|
||||
node_type: String,
|
||||
layer: LayerNodeIdentifier,
|
||||
},
|
||||
CreateNodeFromContextMenu {
|
||||
node_id: Option<NodeId>,
|
||||
node_type: String,
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, Fron
|
||||
use super::{document_node_definitions, node_properties};
|
||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
|
||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
@@ -13,7 +14,7 @@ use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graphene_core::*;
|
||||
use renderer::{ClickTarget, Quad};
|
||||
use renderer::Quad;
|
||||
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
use std::cmp::Ordering;
|
||||
@@ -136,8 +137,20 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||
|
||||
responses.add(FrontendMessage::TriggerTextCopy { copy_text });
|
||||
}
|
||||
NodeGraphMessage::CreateNodeInLayerNoTransaction { node_type, layer } => {
|
||||
let Some(mut modify_inputs) = ModifyInputsContext::new_with_layer(layer, network_interface, responses) else {
|
||||
return;
|
||||
};
|
||||
modify_inputs.create_node(&node_type);
|
||||
}
|
||||
NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type, layer } => {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
responses.add(NodeGraphMessage::CreateNodeInLayerNoTransaction { node_type, layer });
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
NodeGraphMessage::CreateNodeFromContextMenu { node_id, node_type, x, y } => {
|
||||
let node_id = node_id.unwrap_or_else(|| NodeId::new());
|
||||
let node_id = node_id.unwrap_or_else(NodeId::new);
|
||||
|
||||
let Some(document_node_type) = document_node_definitions::resolve_document_node_type(&node_type) else {
|
||||
responses.add(DialogMessage::DisplayDialogError {
|
||||
@@ -429,31 +442,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
||||
.map(|selected_nodes| selected_nodes.selected_nodes().cloned().collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
// If the user is clicking on the create nodes list or context menu, break here
|
||||
if let Some(context_menu) = &self.context_menu {
|
||||
let context_menu_viewport = network_metadata
|
||||
.persistent_metadata
|
||||
.navigation_metadata
|
||||
.node_graph_to_viewport
|
||||
.transform_point2(DVec2::new(context_menu.context_menu_coordinates.0 as f64, context_menu.context_menu_coordinates.1 as f64));
|
||||
let (width, height) = if matches!(context_menu.context_menu_data, ContextMenuData::ToggleLayer { .. }) {
|
||||
// Height and width for toggle layer menu
|
||||
(173., 34.)
|
||||
} else {
|
||||
// Height and width for create node menu
|
||||
(180., 200.)
|
||||
};
|
||||
let context_menu_subpath = bezier_rs::Subpath::new_rounded_rect(
|
||||
DVec2::new(context_menu_viewport.x, context_menu_viewport.y),
|
||||
DVec2::new(context_menu_viewport.x + width, context_menu_viewport.y + height),
|
||||
[5.; 4],
|
||||
);
|
||||
let context_menu_click_target = ClickTarget::new(context_menu_subpath, 0.);
|
||||
if context_menu_click_target.intersect_point(click, DAffine2::IDENTITY) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Since the user is clicking elsewhere in the graph, ensure the add nodes list is closed
|
||||
if self.context_menu.is_some() {
|
||||
self.context_menu = None;
|
||||
@@ -1585,14 +1573,26 @@ impl NodeGraphMessageHandler {
|
||||
0 => {
|
||||
let selected_nodes = nodes
|
||||
.iter()
|
||||
.filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, context)))
|
||||
.filter_map(|node_id| network.nodes.get(node_id).map(|node| node_properties::generate_node_properties(node, *node_id, false, context)))
|
||||
.collect::<Vec<_>>();
|
||||
if !selected_nodes.is_empty() {
|
||||
return selected_nodes;
|
||||
}
|
||||
|
||||
let mut properties = vec![LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
IconLabel::new("File").tooltip("Name of the current document").widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
TextInput::new(context.document_name)
|
||||
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
],
|
||||
}];
|
||||
|
||||
// And if no nodes are selected, show properties for all pinned nodes
|
||||
network
|
||||
let pinned_node_properties = network
|
||||
.nodes
|
||||
.iter()
|
||||
.filter_map(|(node_id, node)| {
|
||||
@@ -1604,28 +1604,68 @@ impl NodeGraphMessageHandler {
|
||||
};
|
||||
|
||||
if pinned {
|
||||
Some(node_properties::generate_node_properties(node, *node_id, context))
|
||||
Some(node_properties::generate_node_properties(node, *node_id, true, context))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
properties.extend(pinned_node_properties);
|
||||
properties
|
||||
}
|
||||
// If one layer is selected, filter out all selected nodes that are not upstream of it. If there are no nodes left, show properties for the layer. Otherwise, show nothing.
|
||||
1 => {
|
||||
let layer = layers[0];
|
||||
let nodes_not_upstream_of_layer = nodes.into_iter().filter(|&selected_node_id| {
|
||||
!context
|
||||
.network_interface
|
||||
.is_node_upstream_of_another_by_horizontal_flow(layers[0], context.selection_network_path, selected_node_id)
|
||||
.is_node_upstream_of_another_by_horizontal_flow(layer, context.selection_network_path, selected_node_id)
|
||||
});
|
||||
if nodes_not_upstream_of_layer.count() > 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut layer_properties = vec![LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
IconLabel::new("Layer").tooltip("Name of the selected layer").widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
TextInput::new(context.document_name)
|
||||
.on_update(move |text_input| {
|
||||
NodeGraphMessage::SetDisplayName {
|
||||
node_id: layer,
|
||||
alias: text_input.value.clone(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
{
|
||||
let node_chooser = NodeCatalog::new()
|
||||
.on_update(move |node_type| {
|
||||
NodeGraphMessage::CreateNodeInLayerWithTransaction {
|
||||
node_type: node_type.clone(),
|
||||
layer: LayerNodeIdentifier::new_unchecked(layer),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
.widget_holder();
|
||||
let popover_layout = vec![LayoutGroup::Row { widgets: vec![node_chooser] }];
|
||||
PopoverButton::new()
|
||||
.icon(Some("Node".to_string()))
|
||||
.tooltip("Add an operation to the end of this layer's chain of nodes")
|
||||
.popover_layout(popover_layout)
|
||||
.widget_holder()
|
||||
},
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
],
|
||||
}];
|
||||
|
||||
// Iterate through all the upstream nodes, but stop when we reach another layer (since that's a point where we switch from horizontal to vertical flow)
|
||||
context
|
||||
let node_properties = context
|
||||
.network_interface
|
||||
.upstream_flow_back_from_nodes(vec![layers[0]], context.selection_network_path, network_interface::FlowType::HorizontalFlow)
|
||||
.upstream_flow_back_from_nodes(vec![layer], context.selection_network_path, network_interface::FlowType::HorizontalFlow)
|
||||
.enumerate()
|
||||
.take_while(|(i, node_id)| {
|
||||
if *i == 0 {
|
||||
@@ -1635,8 +1675,11 @@ impl NodeGraphMessageHandler {
|
||||
}
|
||||
})
|
||||
.filter_map(|(_, node_id)| network.nodes.get(&node_id).map(|node| (node, node_id)))
|
||||
.map(|(node, node_id)| node_properties::generate_node_properties(node, node_id, context))
|
||||
.collect()
|
||||
.map(|(node, node_id)| node_properties::generate_node_properties(node, node_id, false, context))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
layer_properties.extend(node_properties);
|
||||
layer_properties
|
||||
}
|
||||
// If multiple layers and/or nodes are selected, show nothing
|
||||
_ => Vec::new(),
|
||||
|
||||
@@ -2253,7 +2253,7 @@ pub(crate) fn index_properties(document_node: &DocumentNode, node_id: NodeId, _c
|
||||
vec![LayoutGroup::Row { widgets: index }]
|
||||
}
|
||||
|
||||
pub(crate) fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup {
|
||||
pub(crate) fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, pinned: bool, context: &mut NodePropertiesContext) -> LayoutGroup {
|
||||
let reference = context.network_interface.reference(&node_id, context.selection_network_path).clone();
|
||||
let layout = if let Some(ref reference) = reference {
|
||||
match super::document_node_definitions::resolve_document_node_type(reference) {
|
||||
@@ -2267,6 +2267,7 @@ pub(crate) fn generate_node_properties(document_node: &DocumentNode, node_id: No
|
||||
LayoutGroup::Section {
|
||||
name: reference.unwrap_or_default(),
|
||||
visible: document_node.visible,
|
||||
pinned,
|
||||
id: node_id.0,
|
||||
layout,
|
||||
}
|
||||
|
||||
+4
-22
@@ -11,17 +11,13 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
||||
fn process_message(&mut self, message: PropertiesPanelMessage, responses: &mut VecDeque<Message>, (persistent_data, data): (&PersistentData, PropertiesPanelMessageHandlerData)) {
|
||||
let PropertiesPanelMessageHandlerData {
|
||||
network_interface,
|
||||
selection_path,
|
||||
selection_network_path,
|
||||
document_name,
|
||||
executor,
|
||||
} = data;
|
||||
|
||||
match message {
|
||||
PropertiesPanelMessage::Clear => {
|
||||
responses.add(LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesOptions,
|
||||
});
|
||||
responses.add(LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(vec![])),
|
||||
layout_target: LayoutTarget::PropertiesSections,
|
||||
@@ -31,27 +27,13 @@ impl<'a> MessageHandler<PropertiesPanelMessage, (&PersistentData, PropertiesPane
|
||||
let mut context = NodePropertiesContext {
|
||||
persistent_data,
|
||||
responses,
|
||||
executor,
|
||||
network_interface,
|
||||
selection_network_path: selection_path,
|
||||
selection_network_path,
|
||||
document_name,
|
||||
executor,
|
||||
};
|
||||
|
||||
let properties_sections = NodeGraphMessageHandler::collate_properties(&mut context);
|
||||
|
||||
let options_bar = vec![LayoutGroup::Row {
|
||||
widgets: vec![
|
||||
IconLabel::new("File").tooltip("Document name").widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
TextInput::new(document_name)
|
||||
.on_update(|text_input| DocumentMessage::RenameDocument { new_name: text_input.value.clone() }.into())
|
||||
.widget_holder(),
|
||||
],
|
||||
}];
|
||||
|
||||
context.responses.add(LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(options_bar)),
|
||||
layout_target: LayoutTarget::PropertiesOptions,
|
||||
});
|
||||
context.responses.add(LayoutMessage::SendLayout {
|
||||
layout: Layout::WidgetLayout(WidgetLayout::new(properties_sections)),
|
||||
layout_target: LayoutTarget::PropertiesSections,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::node_graph_executor::NodeGraphExecutor;
|
||||
|
||||
pub struct PropertiesPanelMessageHandlerData<'a> {
|
||||
pub network_interface: &'a NodeNetworkInterface,
|
||||
pub selection_path: &'a [NodeId],
|
||||
pub selection_network_path: &'a [NodeId],
|
||||
pub document_name: &'a str,
|
||||
pub executor: &'a mut NodeGraphExecutor,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user