void VisualShaderEditor::_update_graph() { if (updating) return; if (visual_shader.is_null()) return; graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE); VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); graph->clear_connections(); //erase all nodes for (int i = 0; i < graph->get_child_count(); i++) { if (Object::cast_to<GraphNode>(graph->get_child(i))) { memdelete(graph->get_child(i)); i--; } } static const Color type_color[3] = { Color::html("#61daf4"), Color::html("#d67dee"), Color::html("#f6a86e") }; List<VisualShader::Connection> connections; visual_shader->get_node_connections(type, &connections); Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1); Vector<int> nodes = visual_shader->get_node_list(type); for (int n_i = 0; n_i < nodes.size(); n_i++) { Vector2 position = visual_shader->get_node_position(type, nodes[n_i]); Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, nodes[n_i]); GraphNode *node = memnew(GraphNode); graph->add_child(node); /*if (!vsnode->is_connected("changed", this, "_node_changed")) { vsnode->connect("changed", this, "_node_changed", varray(vsnode->get_instance_id()), CONNECT_DEFERRED); }*/ node->set_offset(position); node->set_title(vsnode->get_caption()); node->set_name(itos(nodes[n_i])); if (nodes[n_i] >= 2) { node->set_show_close_button(true); node->connect("close_request", this, "_delete_request", varray(nodes[n_i]), CONNECT_DEFERRED); } node->connect("dragged", this, "_node_dragged", varray(nodes[n_i])); Control *custom_editor = NULL; int port_offset = 0; Ref<VisualShaderNodeUniform> uniform = vsnode; if (uniform.is_valid()) { LineEdit *uniform_name = memnew(LineEdit); uniform_name->set_text(uniform->get_uniform_name()); node->add_child(uniform_name); uniform_name->connect("text_entered", this, "_line_edit_changed", varray(uniform_name, nodes[n_i])); uniform_name->connect("focus_exited", this, "_line_edit_focus_out", varray(uniform_name, nodes[n_i])); if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") { //shortcut VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); continue; } port_offset++; } for (int i = 0; i < plugins.size(); i++) { custom_editor = plugins.write[i]->create_editor(vsnode); if (custom_editor) { break; } } if (custom_editor && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { //will be embedded in first port } else if (custom_editor) { port_offset++; node->add_child(custom_editor); custom_editor = NULL; } for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { if (vsnode->is_port_separator(i)) { node->add_child(memnew(HSeparator)); port_offset++; } bool valid_left = i < vsnode->get_input_port_count(); VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR; bool port_left_used = false; String name_left; if (valid_left) { name_left = vsnode->get_input_port_name(i); port_left = vsnode->get_input_port_type(i); for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { if (E->get().to_node == nodes[n_i] && E->get().to_port == i) { port_left_used = true; } } } bool valid_right = i < vsnode->get_output_port_count(); VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR; String name_right; if (valid_right) { name_right = vsnode->get_output_port_name(i); port_right = vsnode->get_output_port_type(i); } HBoxContainer *hb = memnew(HBoxContainer); Variant default_value; if (valid_left && !port_left_used) { default_value = vsnode->get_input_port_default_value(i); } if (default_value.get_type() != Variant::NIL) { // only a label Button *button = memnew(Button); hb->add_child(button); button->connect("pressed", this, "_edit_port_default_input", varray(button, nodes[n_i], i)); switch (default_value.get_type()) { case Variant::COLOR: { button->set_custom_minimum_size(Size2(30, 0) * EDSCALE); button->connect("draw", this, "_draw_color_over_button", varray(button, default_value)); } break; case Variant::INT: case Variant::REAL: { button->set_text(String::num(default_value, 4)); } break; case Variant::VECTOR3: { Vector3 v = default_value; button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3)); } break; default: {} } } if (i == 0 && custom_editor) { hb->add_child(custom_editor); custom_editor->set_h_size_flags(SIZE_EXPAND_FILL); } else { if (valid_left) { Label *label = memnew(Label); label->set_text(name_left); label->add_style_override("normal", label_style); //more compact hb->add_child(label); } hb->add_spacer(); if (valid_right) { Label *label = memnew(Label); label->set_text(name_right); label->set_align(Label::ALIGN_RIGHT); label->add_style_override("normal", label_style); //more compact hb->add_child(label); } } if (valid_right && edit_type->get_selected() == VisualShader::TYPE_FRAGMENT) { TextureButton *preview = memnew(TextureButton); preview->set_toggle_mode(true); preview->set_normal_texture(get_icon("GuiVisibilityHidden", "EditorIcons")); preview->set_pressed_texture(get_icon("GuiVisibilityVisible", "EditorIcons")); preview->set_v_size_flags(SIZE_SHRINK_CENTER); if (vsnode->get_output_port_for_preview() == i) { preview->set_pressed(true); } preview->connect("pressed", this, "_preview_select_port", varray(nodes[n_i], i), CONNECT_DEFERRED); hb->add_child(preview); } node->add_child(hb); node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode"); Color c = sb->get_border_color(MARGIN_TOP); Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0); mono_color.a = 0.85; c = mono_color; node->add_color_override("title_color", c); c.a = 0.7; node->add_color_override("close_color", c); } } if (vsnode->get_output_port_for_preview() >= 0) { VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); port_preview->setup(visual_shader, type, nodes[n_i], vsnode->get_output_port_for_preview()); port_preview->set_h_size_flags(SIZE_SHRINK_CENTER); node->add_child(port_preview); } String error = vsnode->get_warning(visual_shader->get_mode(), type); if (error != String()) { Label *error_label = memnew(Label); error_label->add_color_override("font_color", get_color("error_color", "Editor")); error_label->set_text(error); node->add_child(error_label); } } for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { int from = E->get().from_node; int from_idx = E->get().from_port; int to = E->get().to_node; int to_idx = E->get().to_port; graph->connect_node(itos(from), from_idx, itos(to), to_idx); } }
void AnimationNodeBlendTreeEditor::_update_graph() { if (updating) return; graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE); if (blend_tree->get_parent().is_valid()) { goto_parent->show(); } else { goto_parent->hide(); } graph->clear_connections(); //erase all nodes for (int i = 0; i < graph->get_child_count(); i++) { if (Object::cast_to<GraphNode>(graph->get_child(i))) { memdelete(graph->get_child(i)); i--; } } animations.clear(); List<StringName> nodes; blend_tree->get_node_list(&nodes); for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { GraphNode *node = memnew(GraphNode); graph->add_child(node); Ref<AnimationNode> agnode = blend_tree->get_node(E->get()); if (!agnode->is_connected("changed", this, "_node_changed")) { agnode->connect("changed", this, "_node_changed", varray(agnode->get_instance_id()), CONNECT_DEFERRED); } node->set_offset(agnode->get_position() * EDSCALE); node->set_title(agnode->get_caption()); node->set_name(E->get()); int base = 0; if (String(E->get()) != "output") { LineEdit *name = memnew(LineEdit); name->set_text(E->get()); name->set_expand_to_text_length(true); node->add_child(name); node->set_slot(0, false, 0, Color(), true, 0, get_color("font_color", "Label")); name->connect("text_entered", this, "_node_renamed", varray(agnode)); name->connect("focus_exited", this, "_node_renamed_focus_out", varray(name, agnode)); base = 1; node->set_show_close_button(true); node->connect("close_request", this, "_delete_request", varray(E->get()), CONNECT_DEFERRED); } for (int i = 0; i < agnode->get_input_count(); i++) { Label *in_name = memnew(Label); node->add_child(in_name); in_name->set_text(agnode->get_input_name(i)); node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color()); } node->connect("dragged", this, "_node_dragged", varray(agnode)); if (EditorNode::get_singleton()->item_has_editor(agnode.ptr())) { node->add_child(memnew(HSeparator)); Button *open_in_editor = memnew(Button); open_in_editor->set_text(TTR("Open Editor")); open_in_editor->set_icon(get_icon("Edit", "EditorIcons")); node->add_child(open_in_editor); open_in_editor->connect("pressed", this, "_open_in_editor", varray(E->get()), CONNECT_DEFERRED); open_in_editor->set_h_size_flags(SIZE_SHRINK_CENTER); } if (agnode->has_filter()) { node->add_child(memnew(HSeparator)); Button *edit_filters = memnew(Button); edit_filters->set_text(TTR("Edit Filters")); edit_filters->set_icon(get_icon("AnimationFilter", "EditorIcons")); node->add_child(edit_filters); edit_filters->connect("pressed", this, "_edit_filters", varray(E->get()), CONNECT_DEFERRED); edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER); } Ref<AnimationNodeAnimation> anim = agnode; if (anim.is_valid()) { MenuButton *mb = memnew(MenuButton); mb->set_text(anim->get_animation()); mb->set_icon(get_icon("Animation", "EditorIcons")); Array options; node->add_child(memnew(HSeparator)); node->add_child(mb); ProgressBar *pb = memnew(ProgressBar); AnimationTree *player = anim->get_tree(); if (player->has_node(player->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); if (ap) { List<StringName> anims; ap->get_animation_list(&anims); for (List<StringName>::Element *F = anims.front(); F; F = F->next()) { mb->get_popup()->add_item(F->get()); options.push_back(F->get()); } if (ap->has_animation(anim->get_animation())) { pb->set_max(ap->get_animation(anim->get_animation())->get_length()); } } } pb->set_percent_visible(false); animations[E->get()] = pb; node->add_child(pb); mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED); } Ref<AnimationNodeOneShot> oneshot = agnode; if (oneshot.is_valid()) { HBoxContainer *play_stop = memnew(HBoxContainer); play_stop->add_spacer(); Button *play = memnew(Button); play->set_icon(get_icon("Play", "EditorIcons")); play->connect("pressed", this, "_oneshot_start", varray(E->get()), CONNECT_DEFERRED); play_stop->add_child(play); Button *stop = memnew(Button); stop->set_icon(get_icon("Stop", "EditorIcons")); stop->connect("pressed", this, "_oneshot_stop", varray(E->get()), CONNECT_DEFERRED); play_stop->add_child(stop); play_stop->add_spacer(); node->add_child(play_stop); } } List<AnimationNodeBlendTree::NodeConnection> connections; blend_tree->get_node_connections(&connections); for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = connections.front(); E; E = E->next()) { StringName from = E->get().output_node; StringName to = E->get().input_node; int to_idx = E->get().input_index; graph->connect_node(from, 0, to, to_idx); } }