diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index 3d1d6b20..82265d33 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -21,6 +21,12 @@ const char *VoxelGraphEditor::SIGNAL_NODE_SELECTED = "node_selected"; const char *VoxelGraphEditor::SIGNAL_NOTHING_SELECTED = "nothing_selected"; const char *VoxelGraphEditor::SIGNAL_NODES_DELETED = "nodes_deleted"; +static NodePath to_node_path(StringName sn) { + Vector path; + path.push_back(sn); + return NodePath(path, false); +} + VoxelGraphEditor::VoxelGraphEditor() { VBoxContainer *vbox_container = memnew(VBoxContainer); vbox_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); @@ -174,15 +180,14 @@ void VoxelGraphEditor::_process(float delta) { } } - // When an input is left unconnected, it picks a default value. Input hints show this value. - // It is otherwise shown in the inspector when the node is selected, but seeing them at a glance helps. - // I decided to do by polling so all the code is here and there is no faffing around with signals. + // I decided to do by polling to display some things on graph nodes, so all the code is here and there is no faffing + // around with signals. if (_graph.is_valid() && is_visible_in_tree()) { for (int child_node_index = 0; child_node_index < _graph_edit->get_child_count(); ++child_node_index) { Node *node = _graph_edit->get_child(child_node_index); VoxelGraphEditorNode *node_view = Object::cast_to(node); if (node_view != nullptr) { - node_view->poll_default_inputs(**_graph); + node_view->poll(**_graph); } } } @@ -236,6 +241,7 @@ void VoxelGraphEditor::build_gui_from_graph() { ERR_FAIL_COND(to_node_view == nullptr); const Error err = _graph_edit->connect_node( from_node_name, con.src.port_index, to_node_view->get_name(), con.dst.port_index); + ERR_FAIL_COND(err != OK); } } @@ -268,12 +274,6 @@ void remove_connections_from_and_to(GraphEdit &graph_edit, StringName node_name) } } -static NodePath to_node_path(StringName sn) { - Vector path; - path.push_back(sn); - return NodePath(path, false); -} - void VoxelGraphEditor::remove_node_gui(StringName gui_node_name) { // Remove connections from the UI, because GraphNode doesn't do it... remove_connections_from_and_to(*_graph_edit, gui_node_name); @@ -312,7 +312,7 @@ void VoxelGraphEditor::update_node_layout(uint32_t node_id) { for (List::Element *e = old_connections.front(); e; e = e->next()) { const GraphEdit::Connection &con = e->get(); - NodePath to = to_node_path(con.to); + const NodePath to = to_node_path(con.to); const VoxelGraphEditorNode *to_view = Object::cast_to(graph_edit.get_node(to)); if (to_view == nullptr) { continue; @@ -334,8 +334,10 @@ void VoxelGraphEditor::update_node_layout(uint32_t node_id) { // TODO Optimize: the graph stores an adjacency list, we could use that std::vector connections; _graph->get_connections(connections); + for (size_t i = 0; i < connections.size(); ++i) { const ProgramGraph::Connection &con = connections[i]; + if (con.dst.node_id == node_id) { graph_edit.connect_node(node_to_gui_name(con.src.node_id), con.src.port_index, node_to_gui_name(con.dst.node_id), con.dst.port_index); @@ -653,7 +655,7 @@ void VoxelGraphEditor::update_range_analysis_previews() { // Highlight only nodes that will actually run Span execution_map = VoxelGeneratorGraph::get_last_execution_map_debug_from_current_thread(); for (unsigned int i = 0; i < execution_map.size(); ++i) { - String node_view_path = node_to_gui_name(execution_map[i]); + const String node_view_path = node_to_gui_name(execution_map[i]); VoxelGraphEditorNode *node_view = Object::cast_to(_graph_edit->get_node(node_view_path)); node_view->set_modulate(Color(1, 1, 1)); } @@ -693,7 +695,7 @@ void VoxelGraphEditor::update_slice_previews() { // Gather preview nodes for (int i = 0; i < _graph_edit->get_child_count(); ++i) { - VoxelGraphEditorNode *node = Object::cast_to(_graph_edit->get_child(i)); + const VoxelGraphEditorNode *node = Object::cast_to(_graph_edit->get_child(i)); if (node == nullptr || node->get_preview() == nullptr) { continue; } @@ -817,7 +819,9 @@ void VoxelGraphEditor::_on_graph_node_name_changed(int node_id) { VoxelGraphEditorNode *node_view = Object::cast_to(_graph_edit->get_node(ui_node_name)); ERR_FAIL_COND(node_view == nullptr); - node_view->update_title(node_name, node_type_name); + if (node_type_id != VoxelGeneratorGraph::NODE_EXPRESSION) { + node_view->update_title(node_name, node_type_name); + } } void VoxelGraphEditor::_on_update_previews_button_pressed() { diff --git a/editor/graph/voxel_graph_editor_node.cpp b/editor/graph/voxel_graph_editor_node.cpp index 15cd2949..dc10883e 100644 --- a/editor/graph/voxel_graph_editor_node.cpp +++ b/editor/graph/voxel_graph_editor_node.cpp @@ -20,7 +20,9 @@ VoxelGraphEditorNode *VoxelGraphEditorNode::create(const VoxelGeneratorGraph &gr node_view->update_title(node_name, node_type.name); node_view->_node_id = node_id; - //node_view.resizable = true + // Some nodes can have variable size title and layout. The node can get larger automatically, but doesn't shrink. + // So for now we make them resizable so users can adjust them. + node_view->set_resizable(node_type_id == VoxelGeneratorGraph::NODE_EXPRESSION); //node_view.rect_size = Vector2(200, 100) node_view->update_layout(graph); @@ -30,9 +32,17 @@ VoxelGraphEditorNode *VoxelGraphEditorNode::create(const VoxelGeneratorGraph &gr node_view->add_child(node_view->_preview); } + if (node_view->is_resizable()) { + node_view->connect("resize_request", callable_mp(node_view, &VoxelGraphEditorNode::_on_resize_request)); + } + return node_view; } +void VoxelGraphEditorNode::_on_resize_request(Vector2 new_size) { + set_size(new_size); +} + void VoxelGraphEditorNode::update_layout(const VoxelGeneratorGraph &graph) { const uint32_t node_type_id = graph.get_node_type_id(_node_id); const VoxelGraphNodeDB::NodeType &node_type = VoxelGraphNodeDB::get_singleton()->get_type(node_type_id); @@ -87,16 +97,16 @@ void VoxelGraphEditorNode::update_layout(const VoxelGeneratorGraph &graph) { _input_hints.clear(); // Add inputs and outputs - for (unsigned int i = 0; i < row_count; ++i) { - const bool has_left = i < inputs.size(); - const bool has_right = (i < outputs.size()) && !hide_outputs; + for (unsigned int slot_index = 0; slot_index < row_count; ++slot_index) { + const bool has_left = slot_index < inputs.size(); + const bool has_right = (slot_index < outputs.size()) && !hide_outputs; HBoxContainer *property_control = memnew(HBoxContainer); property_control->set_custom_minimum_size(Vector2(0, 24 * EDSCALE)); if (has_left) { Label *label = memnew(Label); - label->set_text(inputs[i].name); + label->set_text(inputs[slot_index].name); property_control->add_child(label); Label *hint_label = memnew(Label); @@ -119,7 +129,7 @@ void VoxelGraphEditorNode::update_layout(const VoxelGeneratorGraph &graph) { } Label *label = memnew(Label); - label->set_text(outputs[i].name); + label->set_text(outputs[slot_index].name); // Pass filter is required to allow tooltips to work label->set_mouse_filter(Control::MOUSE_FILTER_PASS); property_control->add_child(label); @@ -128,7 +138,7 @@ void VoxelGraphEditorNode::update_layout(const VoxelGeneratorGraph &graph) { } add_child(property_control); - set_slot(i, has_left, Variant::FLOAT, port_color, has_right, Variant::FLOAT, port_color); + set_slot(slot_index, has_left, Variant::FLOAT, port_color, has_right, Variant::FLOAT, port_color); _rows.push_back(property_control); } @@ -146,6 +156,13 @@ void VoxelGraphEditorNode::update_title(StringName node_name, String node_type_n } } +void VoxelGraphEditorNode::poll(const VoxelGeneratorGraph &graph) { + poll_default_inputs(graph); + poll_params(graph); +} + +// When an input is left unconnected, it picks a default value. Input hints show this value. +// It is otherwise shown in the inspector when the node is selected, but seeing them at a glance helps. void VoxelGraphEditorNode::poll_default_inputs(const VoxelGeneratorGraph &graph) { ProgramGraph::PortLocation src_loc_unused; const String prefix = ": "; @@ -173,6 +190,13 @@ void VoxelGraphEditorNode::poll_default_inputs(const VoxelGeneratorGraph &graph) } } +void VoxelGraphEditorNode::poll_params(const VoxelGeneratorGraph &graph) { + if (graph.get_node_type_id(_node_id) == VoxelGeneratorGraph::NODE_EXPRESSION) { + const String code = graph.get_node_param(_node_id, 0); + set_title(code); + } +} + void VoxelGraphEditorNode::update_range_analysis_tooltips( const VoxelGeneratorGraph &graph, const VoxelGraphRuntime::State &state) { for (unsigned int port_index = 0; port_index < _output_labels.size(); ++port_index) { diff --git a/editor/graph/voxel_graph_editor_node.h b/editor/graph/voxel_graph_editor_node.h index 77425648..982e5466 100644 --- a/editor/graph/voxel_graph_editor_node.h +++ b/editor/graph/voxel_graph_editor_node.h @@ -18,7 +18,7 @@ public: static VoxelGraphEditorNode *create(const VoxelGeneratorGraph &graph, uint32_t node_id); void update_title(StringName node_name, String node_type_name); - void poll_default_inputs(const VoxelGeneratorGraph &graph); + void poll(const VoxelGeneratorGraph &graph); void update_range_analysis_tooltips(const VoxelGeneratorGraph &graph, const VoxelGraphRuntime::State &state); void clear_range_analysis_tooltips(); @@ -33,11 +33,15 @@ public: return _node_id; } - inline VoxelGraphEditorNodePreview *get_preview() { + inline VoxelGraphEditorNodePreview *get_preview() const { return _preview; } private: + void poll_default_inputs(const VoxelGeneratorGraph &graph); + void poll_params(const VoxelGeneratorGraph &graph); + void _on_resize_request(Vector2 new_size); + uint32_t _node_id = 0; VoxelGraphEditorNodePreview *_preview = nullptr; std::vector _output_labels;