Show expression code in the node's title

This commit is contained in:
Marc Gilleron 2022-04-05 22:26:26 +01:00
parent 092fc6db9e
commit 0629566330
3 changed files with 55 additions and 23 deletions

View File

@ -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<StringName> 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<VoxelGraphEditorNode>(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<StringName> 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<GraphEdit::Connection>::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<VoxelGraphEditorNode>(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<ProgramGraph::Connection> 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<const uint32_t> 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<VoxelGraphEditorNode>(_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<VoxelGraphEditorNode>(_graph_edit->get_child(i));
const VoxelGraphEditorNode *node = Object::cast_to<VoxelGraphEditorNode>(_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<VoxelGraphEditorNode>(_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() {

View File

@ -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) {

View File

@ -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<Control *> _output_labels;