diff options
Diffstat (limited to 'editor/plugins')
49 files changed, 1990 insertions, 626 deletions
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 41e2062ab2..4a4e7f25b8 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -201,6 +201,8 @@ void AbstractPolygon2DEditor::_notification(int p_what) { case NOTIFICATION_READY: { + disable_polygon_editing(false, String()); + button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons")); button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons")); button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons")); @@ -275,9 +277,30 @@ void AbstractPolygon2DEditor::_wip_close() { selected_point = Vertex(); } +void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_reason) { + + _polygon_editing_enabled = !p_disable; + + button_create->set_disabled(p_disable); + button_edit->set_disabled(p_disable); + button_delete->set_disabled(p_disable); + + if (p_disable) { + + button_create->set_tooltip(p_reason); + button_edit->set_tooltip(p_reason); + button_delete->set_tooltip(p_reason); + } else { + + button_create->set_tooltip(TTR("Create points.")); + button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); + button_delete->set_tooltip(TTR("Erase points.")); + } +} + bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { - if (!_get_node()) + if (!_get_node() || !_polygon_editing_enabled) return false; Ref<InputEventMouseButton> mb = p_event; @@ -324,16 +347,16 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return true; } else { - Vector<Vector2> vertices = _get_polygon(insert.polygon); - pre_move_edit = vertices; + Vector<Vector2> vertices2 = _get_polygon(insert.polygon); + pre_move_edit = vertices2; printf("setting pre_move_edit\n"); edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); - vertices.insert(edited_point.vertex, edited_point.pos); + vertices2.insert(edited_point.vertex, edited_point.pos); selected_point = edited_point; edge_point = PosVertex(); undo_redo->create_action(TTR("Insert Point")); - _action_set_polygon(insert.polygon, vertices); + _action_set_polygon(insert.polygon, vertices2); _commit_action(); return true; } @@ -615,6 +638,13 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl const Color modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1); p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate); + + if (vertex == hover_point) { + Ref<Font> font = get_font("font", "Label"); + String num = String::num(vertex.vertex); + Size2 num_size = font->get_string_size(num); + p_overlay->draw_string(font, point - num_size * 0.5, num, Color(1.0, 1.0, 1.0, 0.5)); + } } } @@ -627,9 +657,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl void AbstractPolygon2DEditor::edit(Node *p_polygon) { - if (!canvas_item_editor) { + if (!canvas_item_editor) canvas_item_editor = CanvasItemEditor::get_singleton(); - } if (p_polygon) { @@ -648,7 +677,6 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) { selected_point = Vertex(); canvas_item_editor->update_viewport(); - } else { _set_node(NULL); @@ -783,19 +811,16 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi add_child(button_create); button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE)); button_create->set_toggle_mode(true); - button_create->set_tooltip(TTR("Create points.")); button_edit = memnew(ToolButton); add_child(button_edit); button_edit->connect("pressed", this, "_menu_option", varray(MODE_EDIT)); button_edit->set_toggle_mode(true); - button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); button_delete = memnew(ToolButton); add_child(button_delete); button_delete->connect("pressed", this, "_menu_option", varray(MODE_DELETE)); button_delete->set_toggle_mode(true); - button_delete->set_tooltip(TTR("Erase points.")); create_resource = memnew(ConfirmationDialog); add_child(create_resource); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 289c2785b1..97244fa4e9 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -81,6 +81,8 @@ class AbstractPolygon2DEditor : public HBoxContainer { bool wip_active; bool wip_destructive; + bool _polygon_editing_enabled; + CanvasItemEditor *canvas_item_editor; EditorNode *editor; Panel *panel; @@ -135,6 +137,8 @@ protected: virtual void _create_resource(); public: + void disable_polygon_editing(bool p_disable, String p_reason); + bool forward_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 3029ad978a..2ae39d90de 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -142,7 +142,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven } updating = true; - undo_redo->create_action("Move Node Point"); + undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); undo_redo->add_do_method(this, "_update_space"); @@ -325,7 +325,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) { return; updating = true; - undo_redo->create_action("Change BlendSpace1D Limits"); + undo_redo->create_action(TTR("Change BlendSpace1D Limits")); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value()); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value()); @@ -345,7 +345,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { return; updating = true; - undo_redo->create_action("Change BlendSpace1D Labels", UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label()); undo_redo->add_do_method(this, "_update_space"); @@ -401,7 +401,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { } updating = true; - undo_redo->create_action("Add Node Point"); + undo_redo->create_action(TTR("Add Node Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); undo_redo->add_do_method(this, "_update_space"); @@ -419,7 +419,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { anim->set_animation(animations_to_add[p_index]); updating = true; - undo_redo->create_action("Add Animation Point"); + undo_redo->create_action(TTR("Add Animation Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); undo_redo->add_do_method(this, "_update_space"); @@ -489,7 +489,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() { if (selected_point != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace1D Point"); + undo_redo->create_action(TTR("Remove BlendSpace1D Point")); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point); undo_redo->add_do_method(this, "_update_space"); @@ -507,7 +507,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { return; updating = true; - undo_redo->create_action("Move BlendSpace1D Node Point"); + undo_redo->create_action(TTR("Move BlendSpace1D Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value()); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); undo_redo->add_do_method(this, "_update_space"); diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 038e2d0b3e..918f3a2149 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -200,7 +200,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } updating = true; - undo_redo->create_action("Add Triangle"); + undo_redo->create_action(TTR("Add Triangle")); undo_redo->add_do_method(blend_space.ptr(), "add_triangle", making_triangle[0], making_triangle[1], making_triangle[2]); undo_redo->add_undo_method(blend_space.ptr(), "remove_triangle", blend_space->get_triangle_count()); undo_redo->add_do_method(this, "_update_space"); @@ -225,7 +225,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } updating = true; - undo_redo->create_action("Move Node Point"); + undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); undo_redo->add_do_method(this, "_update_space"); @@ -333,7 +333,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { } updating = true; - undo_redo->create_action("Add Node Point"); + undo_redo->create_action(TTR("Add Node Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); undo_redo->add_do_method(this, "_update_space"); @@ -352,7 +352,7 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { anim->set_animation(animations_to_add[p_index]); updating = true; - undo_redo->create_action("Add Animation Point"); + undo_redo->create_action(TTR("Add Animation Point")); undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); undo_redo->add_do_method(this, "_update_space"); @@ -639,7 +639,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) { return; updating = true; - undo_redo->create_action("Change BlendSpace2D Limits"); + undo_redo->create_action(TTR("Change BlendSpace2D Limits")); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value())); @@ -661,7 +661,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { return; updating = true; - undo_redo->create_action("Change BlendSpace2D Labels", UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label()); undo_redo->add_do_method(blend_space.ptr(), "set_y_label", label_y->get_text()); @@ -677,7 +677,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { if (selected_point != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace2D Point"); + undo_redo->create_action(TTR("Remove BlendSpace2D Point")); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point); @@ -700,7 +700,7 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { } else if (selected_triangle != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace2D Triangle"); + undo_redo->create_action(TTR("Remove BlendSpace2D Triangle")); undo_redo->add_do_method(blend_space.ptr(), "remove_triangle", selected_triangle); undo_redo->add_undo_method(blend_space.ptr(), "add_triangle", blend_space->get_triangle_point(selected_triangle, 0), blend_space->get_triangle_point(selected_triangle, 1), blend_space->get_triangle_point(selected_triangle, 2), selected_triangle); @@ -737,7 +737,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { if (updating) return; updating = true; - undo_redo->create_action("Move Node Point"); + undo_redo->create_action(TTR("Move Node Point")); undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); undo_redo->add_do_method(this, "_update_space"); @@ -814,7 +814,7 @@ void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { - undo_redo->create_action("Toggle Auto Triangles"); + undo_redo->create_action(TTR("Toggle Auto Triangles")); undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed()); undo_redo->add_undo_method(blend_space.ptr(), "set_auto_triangles", blend_space->get_auto_triangles()); undo_redo->add_do_method(this, "_update_space"); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 13c80e5394..c5dfba6b06 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -91,7 +91,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree(); updating = true; - undo_redo->create_action("Parameter Changed: " + String(p_property), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Parameter Changed") + ": " + String(p_property), UndoRedo::MERGE_ENDS); undo_redo->add_do_property(tree, p_property, p_value); undo_redo->add_undo_property(tree, p_property, tree->get(p_property)); undo_redo->add_do_method(this, "_update_graph"); @@ -231,6 +231,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { } pb->set_percent_visible(false); + pb->set_custom_minimum_size(Vector2(0, 14) * EDSCALE); animations[E->get()] = pb; node->add_child(pb); @@ -239,7 +240,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { 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 c = sb->get_border_color(); 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; @@ -325,7 +326,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { name = base_name + " " + itos(base); } - undo_redo->create_action("Add Node to BlendTree"); + undo_redo->create_action(TTR("Add Node to BlendTree")); undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE); undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name); undo_redo->add_do_method(this, "_update_graph"); @@ -336,7 +337,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) { updating = true; - undo_redo->create_action("Node Moved"); + undo_redo->create_action(TTR("Node Moved")); undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE); undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE); undo_redo->add_do_method(this, "_update_graph"); @@ -354,7 +355,7 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int return; } - undo_redo->create_action("Nodes Connected"); + undo_redo->create_action(TTR("Nodes Connected")); undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); undo_redo->add_do_method(this, "_update_graph"); @@ -367,7 +368,7 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, graph->disconnect_node(p_from, p_from_index, p_to, p_to_index); updating = true; - undo_redo->create_action("Nodes Disconnected"); + undo_redo->create_action(TTR("Nodes Disconnected")); undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index); undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from); undo_redo->add_do_method(this, "_update_graph"); @@ -383,7 +384,7 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node); ERR_FAIL_COND(!anim.is_valid()); - undo_redo->create_action("Set Animation"); + undo_redo->create_action(TTR("Set Animation")); undo_redo->add_do_method(anim.ptr(), "set_animation", option); undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation()); undo_redo->add_do_method(this, "_update_graph"); @@ -393,7 +394,7 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { - undo_redo->create_action("Delete Node"); + undo_redo->create_action(TTR("Delete Node")); undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which); undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which)); @@ -434,7 +435,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) { void AnimationNodeBlendTreeEditor::_filter_toggled() { updating = true; - undo_redo->create_action("Toggle filter on/off"); + undo_redo->create_action(TTR("Toggle Filter On/Off")); undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_enabled", filter_enabled->is_pressed()); undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_enabled", _filter_edit->is_filter_enabled()); undo_redo->add_do_method(this, "_update_filters", _filter_edit); @@ -452,7 +453,7 @@ void AnimationNodeBlendTreeEditor::_filter_edited() { bool filtered = edited->is_checked(0); updating = true; - undo_redo->create_action("Change filter"); + undo_redo->create_action(TTR("Change Filter")); undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", edited_path, filtered); undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", edited_path, _filter_edit->is_path_filtered(edited_path)); undo_redo->add_do_method(this, "_update_filters", _filter_edit); @@ -769,7 +770,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima String base_path = AnimationTreeEditor::get_singleton()->get_base_path(); updating = true; - undo_redo->create_action("Node Renamed"); + undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name); @@ -785,8 +786,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima for (int i = 0; i < visible_properties.size(); i++) { String pname = visible_properties[i]->get_edited_property().operator String(); if (pname.begins_with(base_path + prev_name)) { - String new_name = pname.replace_first(base_path + prev_name, base_path + name); - visible_properties[i]->set_object_and_property(visible_properties[i]->get_edited_object(), new_name); + String new_name2 = pname.replace_first(base_path + prev_name, base_path + name); + visible_properties[i]->set_object_and_property(visible_properties[i]->get_edited_object(), new_name2); } } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index b32b537d3d..bbaf41e3cc 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1160,22 +1160,22 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { return; } - String current = animation->get_item_text(animation->get_selected()); - Ref<Animation> anim = player->get_animation(current); - //editor->edit_resource(anim); - EditorSettings::get_singleton()->set_resource_clipboard(anim); + String current2 = animation->get_item_text(animation->get_selected()); + Ref<Animation> anim2 = player->get_animation(current2); + //editor->edit_resource(anim2); + EditorSettings::get_singleton()->set_resource_clipboard(anim2); } break; case TOOL_PASTE_ANIM: { - Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard(); - if (!anim.is_valid()) { + Ref<Animation> anim2 = EditorSettings::get_singleton()->get_resource_clipboard(); + if (!anim2.is_valid()) { error_dialog->set_text(TTR("No animation resource on clipboard!")); error_dialog->popup_centered_minsize(); return; } - String name = anim->get_name(); + String name = anim2->get_name(); if (name == "") { name = TTR("Pasted Animation"); } @@ -1189,7 +1189,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { } undo_redo->create_action(TTR("Paste Animation")); - undo_redo->add_do_method(player, "add_animation", name, anim); + undo_redo->add_do_method(player, "add_animation", name, anim2); undo_redo->add_undo_method(player, "remove_animation", name); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); @@ -1206,9 +1206,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { return; } - String current = animation->get_item_text(animation->get_selected()); - Ref<Animation> anim = player->get_animation(current); - editor->edit_resource(anim); + String current2 = animation->get_item_text(animation->get_selected()); + Ref<Animation> anim2 = player->get_animation(current2); + editor->edit_resource(anim2); } break; } diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 197ee77254..cb3e5a8129 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -226,7 +226,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv Ref<AnimationNode> an = state_machine->get_node(selected_node); updating = true; - undo_redo->create_action("Move Node"); + undo_redo->create_action(TTR("Move Node")); undo_redo->add_do_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node) + drag_ofs / EDSCALE); undo_redo->add_undo_method(state_machine.ptr(), "set_node_position", selected_node, state_machine->get_node_position(selected_node)); undo_redo->add_do_method(this, "_update_graph"); @@ -271,7 +271,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); updating = true; - undo_redo->create_action("Add Transition"); + undo_redo->create_action(TTR("Add Transition")); undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr); undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node); undo_redo->add_do_method(this, "_update_graph"); @@ -463,7 +463,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } updating = true; - undo_redo->create_action("Add Node"); + undo_redo->create_action(TTR("Add Node")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); undo_redo->add_do_method(this, "_update_graph"); @@ -490,7 +490,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { } updating = true; - undo_redo->create_action("Add Node"); + undo_redo->create_action(TTR("Add Node")); undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos); undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); undo_redo->add_do_method(this, "_update_graph"); @@ -714,12 +714,12 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { tl.to += offset; } - for (int i = 0; i < node_rects.size(); i++) { - if (node_rects[i].node_name == tl.from_node) { - _clip_src_line_to_rect(tl.from, tl.to, node_rects[i].node); + for (int j = 0; j < node_rects.size(); j++) { + if (node_rects[j].node_name == tl.from_node) { + _clip_src_line_to_rect(tl.from, tl.to, node_rects[j].node); } - if (node_rects[i].node_name == tl.to_node) { - _clip_dst_line_to_rect(tl.from, tl.to, node_rects[i].node); + if (node_rects[j].node_name == tl.to_node) { + _clip_dst_line_to_rect(tl.from, tl.to, node_rects[j].node); } } @@ -1088,7 +1088,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { } updating = true; - undo_redo->create_action("Node Renamed"); + undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name); undo_redo->add_do_method(this, "_update_graph"); @@ -1119,7 +1119,7 @@ void AnimationNodeStateMachineEditor::_erase_selected() { if (selected_node != StringName() && state_machine->has_node(selected_node)) { updating = true; - undo_redo->create_action("Node Removed"); + undo_redo->create_action(TTR("Node Removed")); undo_redo->add_do_method(state_machine.ptr(), "remove_node", selected_node); undo_redo->add_undo_method(state_machine.ptr(), "add_node", selected_node, state_machine->get_node(selected_node), state_machine->get_node_position(selected_node)); for (int i = 0; i < state_machine->get_transition_count(); i++) { @@ -1143,7 +1143,7 @@ void AnimationNodeStateMachineEditor::_erase_selected() { Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to)); updating = true; - undo_redo->create_action("Transition Removed"); + undo_redo->create_action(TTR("Transition Removed")); undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to); undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr); undo_redo->add_do_method(this, "_update_graph"); @@ -1169,7 +1169,7 @@ void AnimationNodeStateMachineEditor::_autoplay_selected() { } updating = true; - undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->create_action(TTR("Set Start Node (Autoplay)")); undo_redo->add_do_method(state_machine.ptr(), "set_start_node", new_start_node); undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", state_machine->get_start_node()); undo_redo->add_do_method(this, "_update_graph"); @@ -1192,7 +1192,7 @@ void AnimationNodeStateMachineEditor::_end_selected() { } updating = true; - undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->create_action(TTR("Set Start Node (Autoplay)")); undo_redo->add_do_method(state_machine.ptr(), "set_end_node", new_end_node); undo_redo->add_undo_method(state_machine.ptr(), "set_end_node", state_machine->get_end_node()); undo_redo->add_do_method(this, "_update_graph"); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index c68023ee9b..6d2cdfc583 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -177,6 +177,8 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const thumbnail = thumbnail->duplicate(); Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2); + // Overlay and thumbnail need the same format for `blend_rect` to work. + thumbnail->convert(Image::FORMAT_RGBA8); thumbnail->lock(); thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos); thumbnail->unlock(); @@ -816,7 +818,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons _image_update(p_code == HTTPClient::RESPONSE_NOT_MODIFIED, true, p_data, p_queue_id); } else { - // WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url); + WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url); Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target); if (obj) { obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("DefaultProjectIcon", "EditorIcons")); @@ -1338,6 +1340,7 @@ void EditorAssetLibrary::_bind_methods() { EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { + requesting = REQUESTING_NONE; templates_only = p_templates_only; VBoxContainer *library_main = memnew(VBoxContainer); diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h index e60bf6a38f..12e4faef94 100644 --- a/editor/plugins/audio_stream_editor_plugin.h +++ b/editor/plugins/audio_stream_editor_plugin.h @@ -33,7 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/audio/audio_player.h" +#include "scene/audio/audio_stream_player.h" #include "scene/gui/color_rect.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index b2d2704f07..11eec528c7 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -42,9 +42,9 @@ #include "scene/2d/light_2d.h" #include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" -#include "scene/2d/screen_button.h" #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite.h" +#include "scene/2d/touch_screen_button.h" #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" #include "scene/main/canvas_layer.h" @@ -398,10 +398,10 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li // Expand with the other ones for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) { - CanvasItem *canvas_item = E->get(); - Transform2D xform = canvas_item->get_global_transform_with_canvas(); + CanvasItem *canvas_item2 = E->get(); + Transform2D xform = canvas_item2->get_global_transform_with_canvas(); - Rect2 current_rect = canvas_item->_edit_get_rect(); + Rect2 current_rect = canvas_item2->_edit_get_rect(); rect.expand_to(xform.xform(current_rect.position)); rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0))); rect.expand_to(xform.xform(current_rect.position + current_rect.size)); @@ -816,10 +816,10 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state); if (commit_bones) { - for (List<Dictionary>::Element *E = se->pre_drag_bones_undo_state.front(); E; E = E->next()) { + for (List<Dictionary>::Element *F = se->pre_drag_bones_undo_state.front(); F; F = F->next()) { canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent()); undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state()); - undo_redo->add_undo_method(canvas_item, "_edit_set_state", E->get()); + undo_redo->add_undo_method(canvas_item, "_edit_set_state", F->get()); } } } @@ -1921,9 +1921,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if (drag_selection.size() == 1) { Node2D *node_2d = Object::cast_to<Node2D>(drag_selection[0]); if (node_2d && move_local_base_rotated) { - Transform2D m; - m.rotate(node_2d->get_rotation()); - new_pos += m.xform(drag_to); + Transform2D m2; + m2.rotate(node_2d->get_rotation()); + new_pos += m2.xform(drag_to); } else if (move_local_base) { new_pos += drag_to; } else { @@ -2065,18 +2065,18 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Start dragging if (still_selected) { // Drag the node(s) if requested - List<CanvasItem *> selection = _get_edited_canvas_items(); + List<CanvasItem *> selection2 = _get_edited_canvas_items(); // Remove not movable nodes - for (int i = 0; i < selection.size(); i++) { - if (!_is_node_movable(selection[i], true)) { - selection.erase(selection[i]); + for (int i = 0; i < selection2.size(); i++) { + if (!_is_node_movable(selection2[i], true)) { + selection2.erase(selection2[i]); } } - if (selection.size() > 0) { + if (selection2.size() > 0) { drag_type = DRAG_MOVE; - drag_selection = selection; + drag_selection = selection2; drag_from = click; _save_canvas_item_state(drag_selection); } @@ -2261,6 +2261,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { break; case DRAG_PAN: c = CURSOR_DRAG; + break; default: break; } @@ -2597,6 +2598,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_TOP_LEFT: case DRAG_BOTTOM_LEFT: _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); + FALLTHROUGH; case DRAG_MOVE: start = Vector2(node_pos_in_parent[0], Math::lerp(node_pos_in_parent[1], node_pos_in_parent[3], ratio)); end = start - Vector2(control->get_margin(MARGIN_LEFT), 0); @@ -2611,6 +2613,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_TOP_RIGHT: case DRAG_BOTTOM_RIGHT: _draw_margin_at_position(control->get_size().width, parent_transform.xform(Vector2((node_pos_in_parent[0] + node_pos_in_parent[2]) / 2, node_pos_in_parent[3])) + Vector2(0, 5), MARGIN_BOTTOM); + FALLTHROUGH; case DRAG_MOVE: start = Vector2(node_pos_in_parent[2], Math::lerp(node_pos_in_parent[3], node_pos_in_parent[1], ratio)); end = start - Vector2(control->get_margin(MARGIN_RIGHT), 0); @@ -2625,6 +2628,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_TOP_LEFT: case DRAG_TOP_RIGHT: _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2)) + Vector2(5, 0), MARGIN_RIGHT); + FALLTHROUGH; case DRAG_MOVE: start = Vector2(Math::lerp(node_pos_in_parent[0], node_pos_in_parent[2], ratio), node_pos_in_parent[1]); end = start - Vector2(0, control->get_margin(MARGIN_TOP)); @@ -2639,6 +2643,7 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { case DRAG_BOTTOM_LEFT: case DRAG_BOTTOM_RIGHT: _draw_margin_at_position(control->get_size().height, parent_transform.xform(Vector2(node_pos_in_parent[2], (node_pos_in_parent[1] + node_pos_in_parent[3]) / 2) + Vector2(5, 0)), MARGIN_RIGHT); + FALLTHROUGH; case DRAG_MOVE: start = Vector2(Math::lerp(node_pos_in_parent[2], node_pos_in_parent[0], ratio), node_pos_in_parent[3]); end = start - Vector2(0, control->get_margin(MARGIN_BOTTOM)); @@ -2828,13 +2833,20 @@ void CanvasItemEditor::_draw_selection() { Point2 bsfrom = transform.xform(drag_from); Point2 bsto = transform.xform(box_selecting_to); - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(bsfrom, bsto - bsfrom), Color(0.7, 0.7, 1.0, 0.3)); + VisualServer::get_singleton()->canvas_item_add_rect( + ci, + Rect2(bsfrom, bsto - bsfrom), + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); } - Color rotate_color(0.4, 0.7, 1.0, 0.8); if (drag_type == DRAG_ROTATE) { // Draw the line when rotating a node - viewport->draw_line(transform.xform(drag_rotation_center), transform.xform(drag_to), rotate_color); + viewport->draw_line( + transform.xform(drag_rotation_center), + transform.xform(drag_to), + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6), + Math::round(2 * EDSCALE), + true); } } @@ -3288,7 +3300,7 @@ void CanvasItemEditor::_notification(int p_what) { Control *control = Object::cast_to<Control>(E->get()); if (!control || Object::cast_to<Container>(control->get_parent())) { presets_menu->set_disabled(true); - presets_menu->set_tooltip(TTR("A child of a container gets its anchors and margins values overriden by its parent.")); + presets_menu->set_tooltip(TTR("Children of containers have their anchors and margins values overridden by their parent.")); break; } } @@ -4144,6 +4156,14 @@ void CanvasItemEditor::_popup_callback(int p_op) { _focus_selection(p_op); } break; + case PREVIEW_CANVAS_SCALE: { + + bool preview = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE)); + preview = !preview; + VS::get_singleton()->canvas_set_disable_scale(!preview); + view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(PREVIEW_CANVAS_SCALE), preview); + + } break; case SKELETON_MAKE_BONES: { Map<Node *, Object *> &selection = editor_selection->get_selection(); @@ -4162,6 +4182,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (!skeleton_show_bones) skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); } + _queue_update_bone_list(); viewport->update(); } break; @@ -4181,6 +4202,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { if (!skeleton_show_bones) skeleton_menu->get_popup()->activate_item(skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES)); } + _queue_update_bone_list(); viewport->update(); } break; @@ -4559,6 +4581,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_grid = true; snap_guides = true; snap_rotation = false; + snap_relative = false; snap_pixel = false; skeleton_show_bones = true; @@ -4816,6 +4839,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION); + p->add_separator(); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE); presets_menu = memnew(MenuButton); presets_menu->set_text(TTR("Layout")); @@ -4921,7 +4946,6 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) { canvas_item_editor->show(); canvas_item_editor->set_physics_process(true); VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false); - canvas_item_editor->viewport->grab_focus(); } else { @@ -5414,6 +5438,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte label_desc->add_constant_override("line_spacing", 0); label_desc->hide(); editor->get_gui_base()->add_child(label_desc); + VS::get_singleton()->canvas_set_disable_scale(true); } CanvasItemEditorViewport::~CanvasItemEditorViewport() { diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 7b6563944e..4d8c0282fd 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -171,6 +171,7 @@ private: ANIM_CLEAR_POSE, VIEW_CENTER_TO_SELECTION, VIEW_FRAME_TO_SELECTION, + PREVIEW_CANVAS_SCALE, SKELETON_MAKE_BONES, SKELETON_CLEAR_BONES, SKELETON_SHOW_BONES, diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index fc572f54e1..10023d88bf 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -35,9 +35,9 @@ #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/line_shape_2d.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" -#include "scene/resources/shape_line_2d.h" Variant CollisionShape2DEditor::get_handle_value(int idx) const { diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp new file mode 100644 index 0000000000..559558cdb8 --- /dev/null +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -0,0 +1,307 @@ +/*************************************************************************/ +/* cpu_particles_2d_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "cpu_particles_2d_editor_plugin.h" + +#include "canvas_item_editor_plugin.h" +#include "core/io/image_loader.h" +#include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/separator.h" +#include "scene/resources/particles_material.h" + +void CPUParticles2DEditorPlugin::edit(Object *p_object) { + + particles = Object::cast_to<CPUParticles2D>(p_object); +} + +bool CPUParticles2DEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("CPUParticles2D"); +} + +void CPUParticles2DEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + + toolbar->show(); + } else { + + toolbar->hide(); + } +} + +void CPUParticles2DEditorPlugin::_file_selected(const String &p_file) { + + source_emission_file = p_file; + emission_mask->popup_centered_minsize(); +} + +void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) { + + switch (p_idx) { + case MENU_LOAD_EMISSION_MASK: { + + file->popup_centered_ratio(); + + } break; + case MENU_CLEAR_EMISSION_MASK: { + + emission_mask->popup_centered_minsize(); + } break; + } +} + +void CPUParticles2DEditorPlugin::_generate_emission_mask() { + + Ref<Image> img; + img.instance(); + Error err = ImageLoader::load_image(source_emission_file, img); + ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); + ERR_FAIL_COND(err != OK); + + if (img->is_compressed()) { + img->decompress(); + } + img->convert(Image::FORMAT_RGBA8); + ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8); + Size2i s = Size2(img->get_width(), img->get_height()); + ERR_FAIL_COND(s.width == 0 || s.height == 0); + + Vector<Point2> valid_positions; + Vector<Point2> valid_normals; + Vector<uint8_t> valid_colors; + + valid_positions.resize(s.width * s.height); + + EmissionMode emode = (EmissionMode)emission_mask_mode->get_selected(); + + if (emode == EMISSION_MODE_BORDER_DIRECTED) { + valid_normals.resize(s.width * s.height); + } + + bool capture_colors = emission_colors->is_pressed(); + + if (capture_colors) { + valid_colors.resize(s.width * s.height * 4); + } + + int vpc = 0; + + { + PoolVector<uint8_t> data = img->get_data(); + PoolVector<uint8_t>::Read r = data.read(); + + for (int i = 0; i < s.width; i++) { + for (int j = 0; j < s.height; j++) { + + uint8_t a = r[(j * s.width + i) * 4 + 3]; + + if (a > 128) { + + if (emode == EMISSION_MODE_SOLID) { + + if (capture_colors) { + valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; + valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; + valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; + valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; + } + valid_positions.write[vpc++] = Point2(i, j); + + } else { + + bool on_border = false; + for (int x = i - 1; x <= i + 1; x++) { + for (int y = j - 1; y <= j + 1; y++) { + + if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { + on_border = true; + break; + } + } + + if (on_border) + break; + } + + if (on_border) { + valid_positions.write[vpc] = Point2(i, j); + + if (emode == EMISSION_MODE_BORDER_DIRECTED) { + Vector2 normal; + for (int x = i - 2; x <= i + 2; x++) { + for (int y = j - 2; y <= j + 2; y++) { + + if (x == i && y == j) + continue; + + if (x < 0 || y < 0 || x >= s.width || y >= s.height || r[(y * s.width + x) * 4 + 3] <= 128) { + normal += Vector2(x - i, y - j).normalized(); + } + } + } + + normal.normalize(); + valid_normals.write[vpc] = normal; + } + + if (capture_colors) { + valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; + valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; + valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; + valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; + } + + vpc++; + } + } + } + } + } + } + + valid_positions.resize(vpc); + if (valid_normals.size()) { + valid_normals.resize(vpc); + } + + ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); + ERR_FAIL_COND(valid_positions.size() == 0); + + if (capture_colors) { + PoolColorArray pca; + pca.resize(vpc); + PoolColorArray::Write pcaw = pca.write(); + for (int i = 0; i < vpc; i += 1) { + Color color; + color.r = valid_colors[i * 4 + 0] / 255.0f; + color.g = valid_colors[i * 4 + 1] / 255.0f; + color.b = valid_colors[i * 4 + 2] / 255.0f; + color.a = valid_colors[i * 4 + 3] / 255.0f; + pcaw[i] = color; + } + particles->set_emission_colors(pca); + } + + if (valid_normals.size()) { + particles->set_emission_shape(CPUParticles2D::EMISSION_SHAPE_DIRECTED_POINTS); + PoolVector2Array norms; + norms.resize(valid_normals.size()); + PoolVector2Array::Write normsw = norms.write(); + for (int i = 0; i < valid_normals.size(); i += 1) { + normsw[i] = valid_normals[i]; + } + particles->set_emission_normals(norms); + } else { + particles->set_emission_shape(CPUParticles2D::EMISSION_SHAPE_POINTS); + } + + { + PoolVector2Array points; + points.resize(valid_positions.size()); + PoolVector2Array::Write pointsw = points.write(); + for (int i = 0; i < valid_positions.size(); i += 1) { + pointsw[i] = valid_positions[i]; + } + particles->set_emission_points(points); + } +} + +void CPUParticles2DEditorPlugin::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + menu->get_popup()->connect("id_pressed", this, "_menu_callback"); + menu->set_icon(menu->get_popup()->get_icon("Particles2D", "EditorIcons")); + file->connect("file_selected", this, "_file_selected"); + } +} + +void CPUParticles2DEditorPlugin::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_menu_callback"), &CPUParticles2DEditorPlugin::_menu_callback); + ClassDB::bind_method(D_METHOD("_file_selected"), &CPUParticles2DEditorPlugin::_file_selected); + ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &CPUParticles2DEditorPlugin::_generate_emission_mask); +} + +CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { + + particles = NULL; + editor = p_node; + undo_redo = editor->get_undo_redo(); + + toolbar = memnew(HBoxContainer); + add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar); + toolbar->hide(); + + toolbar->add_child(memnew(VSeparator)); + + menu = memnew(MenuButton); + menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); + // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK); + menu->set_text(TTR("Particles")); + toolbar->add_child(menu); + + file = memnew(EditorFileDialog); + List<String> ext; + ImageLoader::get_recognized_extensions(&ext); + for (List<String>::Element *E = ext.front(); E; E = E->next()) { + file->add_filter("*." + E->get() + "; " + E->get().to_upper()); + } + file->set_mode(EditorFileDialog::MODE_OPEN_FILE); + toolbar->add_child(file); + + epoints = memnew(SpinBox); + epoints->set_min(1); + epoints->set_max(8192); + epoints->set_step(1); + epoints->set_value(512); + file->get_vbox()->add_margin_child(TTR("Generated Point Count:"), epoints); + + emission_mask = memnew(ConfirmationDialog); + emission_mask->set_title(TTR("Load Emission Mask")); + VBoxContainer *emvb = memnew(VBoxContainer); + emission_mask->add_child(emvb); + emission_mask_mode = memnew(OptionButton); + emvb->add_margin_child(TTR("Emission Mask"), emission_mask_mode); + emission_mask_mode->add_item("Solid Pixels", EMISSION_MODE_SOLID); + emission_mask_mode->add_item("Border Pixels", EMISSION_MODE_BORDER); + emission_mask_mode->add_item("Directed Border Pixels", EMISSION_MODE_BORDER_DIRECTED); + emission_colors = memnew(CheckBox); + emission_colors->set_text(TTR("Capture from Pixel")); + emvb->add_margin_child(TTR("Emission Colors"), emission_colors); + + toolbar->add_child(emission_mask); + + emission_mask->connect("confirmed", this, "_generate_emission_mask"); +} + +CPUParticles2DEditorPlugin::~CPUParticles2DEditorPlugin() { +} diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h new file mode 100644 index 0000000000..f715abd87b --- /dev/null +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* cpu_particles_2d_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CPU_PARTICLES_2D_EDITOR_PLUGIN_H +#define CPU_PARTICLES_2D_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/2d/collision_polygon_2d.h" +#include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/box_container.h" +#include "scene/gui/file_dialog.h" + +class CPUParticles2DEditorPlugin : public EditorPlugin { + + GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin); + + enum { + MENU_LOAD_EMISSION_MASK, + MENU_CLEAR_EMISSION_MASK + }; + + enum EmissionMode { + EMISSION_MODE_SOLID, + EMISSION_MODE_BORDER, + EMISSION_MODE_BORDER_DIRECTED + }; + + CPUParticles2D *particles; + + EditorFileDialog *file; + EditorNode *editor; + + HBoxContainer *toolbar; + MenuButton *menu; + + SpinBox *epoints; + + ConfirmationDialog *emission_mask; + OptionButton *emission_mask_mode; + CheckBox *emission_colors; + + String source_emission_file; + + UndoRedo *undo_redo; + void _file_selected(const String &p_file); + void _menu_callback(int p_idx); + void _generate_emission_mask(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + virtual String get_name() const { return "CPUParticles2D"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + CPUParticles2DEditorPlugin(EditorNode *p_node); + ~CPUParticles2DEditorPlugin(); +}; + +#endif // CPU_PARTICLES_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 0c0cc9d635..58d7968723 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -36,7 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "scene/resources/bit_mask.h" +#include "scene/resources/bit_map.h" #include "scene/resources/dynamic_font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" @@ -92,7 +92,12 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 if (!tex.is_valid()) { return Ref<Texture>(); } + Ref<Image> atlas = tex->get_data(); + if (!atlas.is_valid()) { + return Ref<Texture>(); + } + img = atlas->get_rect(atex->get_region()); } else if (ltex.is_valid()) { img = ltex->to_image(); @@ -845,15 +850,16 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c font->draw(canvas_item, pos, sampled_text); - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture - preview_done = false; + VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); } + VS::get_singleton()->canvas_item_clear(canvas_item); + Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); @@ -878,7 +884,11 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 p_size) const { - return generate_from_path(p_from->get_path(), p_size); + String path = p_from->get_path(); + if (!FileAccess::exists(path)) { + return Ref<Texture>(); + } + return generate_from_path(path, p_size); } EditorFontPreviewPlugin::EditorFontPreviewPlugin() { diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 62a9ce719b..e85c475ad7 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -51,7 +51,7 @@ void GradientEditor::_ramp_changed() { editing = true; UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); - undo_redo->create_action("Gradient Edited"); + undo_redo->create_action(TTR("Gradient Edited")); undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets()); diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index db0816064c..b3f3ccf501 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -353,6 +353,7 @@ void ItemListEditor::_bind_methods() { ItemListEditor::ItemListEditor() { selected_idx = -1; + item_list = NULL; toolbar_button = memnew(ToolButton); toolbar_button->set_text(TTR("Items")); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index ce8cc77802..ebacccb03c 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -32,6 +32,210 @@ #include "scene/resources/particles_material.h" +void MaterialEditor::_notification(int p_what) { + + if (p_what == NOTIFICATION_PHYSICS_PROCESS) { + } + + if (p_what == NOTIFICATION_READY) { + + //get_scene()->connect("node_removed",this,"_node_removed"); + + if (first_enter) { + //it's in propertyeditor so.. could be moved around + + light_1_switch->set_normal_texture(get_icon("MaterialPreviewLight1", "EditorIcons")); + light_1_switch->set_pressed_texture(get_icon("MaterialPreviewLight1Off", "EditorIcons")); + light_2_switch->set_normal_texture(get_icon("MaterialPreviewLight2", "EditorIcons")); + light_2_switch->set_pressed_texture(get_icon("MaterialPreviewLight2Off", "EditorIcons")); + + sphere_switch->set_normal_texture(get_icon("MaterialPreviewSphereOff", "EditorIcons")); + sphere_switch->set_pressed_texture(get_icon("MaterialPreviewSphere", "EditorIcons")); + box_switch->set_normal_texture(get_icon("MaterialPreviewCubeOff", "EditorIcons")); + box_switch->set_pressed_texture(get_icon("MaterialPreviewCube", "EditorIcons")); + + first_enter = false; + } + } + + if (p_what == NOTIFICATION_DRAW) { + + Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons"); + Size2 size = get_size(); + + draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + } +} + +void MaterialEditor::edit(Ref<Material> p_material, const Ref<Environment> &p_env) { + + material = p_material; + camera->set_environment(p_env); + if (!material.is_null()) { + sphere_instance->set_material_override(material); + box_instance->set_material_override(material); + } else { + + hide(); + } +} + +void MaterialEditor::_button_pressed(Node *p_button) { + + if (p_button == light_1_switch) { + light1->set_visible(!light_1_switch->is_pressed()); + } + + if (p_button == light_2_switch) { + light2->set_visible(!light_2_switch->is_pressed()); + } + + if (p_button == box_switch) { + box_instance->show(); + sphere_instance->hide(); + box_switch->set_pressed(true); + sphere_switch->set_pressed(false); + } + + if (p_button == sphere_switch) { + box_instance->hide(); + sphere_instance->show(); + box_switch->set_pressed(false); + sphere_switch->set_pressed(true); + } +} + +void MaterialEditor::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed); +} + +MaterialEditor::MaterialEditor() { + + vc = memnew(ViewportContainer); + vc->set_stretch(true); + add_child(vc); + vc->set_anchors_and_margins_preset(PRESET_WIDE); + viewport = memnew(Viewport); + Ref<World> world; + world.instance(); + viewport->set_world(world); //use own world + vc->add_child(viewport); + viewport->set_disable_input(true); + viewport->set_transparent_background(true); + viewport->set_msaa(Viewport::MSAA_4X); + + camera = memnew(Camera); + camera->set_transform(Transform(Basis(), Vector3(0, 0, 3))); + camera->set_perspective(45, 0.1, 10); + camera->make_current(); + viewport->add_child(camera); + + light1 = memnew(DirectionalLight); + light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + viewport->add_child(light1); + + light2 = memnew(DirectionalLight); + light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + light2->set_color(Color(0.7, 0.7, 0.7)); + viewport->add_child(light2); + + sphere_instance = memnew(MeshInstance); + viewport->add_child(sphere_instance); + + box_instance = memnew(MeshInstance); + viewport->add_child(box_instance); + + Transform box_xform; + box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0)); + box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0)); + box_xform.basis.scale(Vector3(0.8, 0.8, 0.8)); + box_xform.origin.y = 0.2; + box_instance->set_transform(box_xform); + + sphere_mesh.instance(); + sphere_instance->set_mesh(sphere_mesh); + box_mesh.instance(); + box_instance->set_mesh(box_mesh); + box_instance->hide(); + + set_custom_minimum_size(Size2(1, 150) * EDSCALE); + + HBoxContainer *hb = memnew(HBoxContainer); + add_child(hb); + hb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 2); + + VBoxContainer *vb_shape = memnew(VBoxContainer); + hb->add_child(vb_shape); + + sphere_switch = memnew(TextureButton); + sphere_switch->set_toggle_mode(true); + sphere_switch->set_pressed(true); + vb_shape->add_child(sphere_switch); + sphere_switch->connect("pressed", this, "_button_pressed", varray(sphere_switch)); + + box_switch = memnew(TextureButton); + box_switch->set_toggle_mode(true); + box_switch->set_pressed(false); + vb_shape->add_child(box_switch); + box_switch->connect("pressed", this, "_button_pressed", varray(box_switch)); + + hb->add_spacer(); + + VBoxContainer *vb_light = memnew(VBoxContainer); + hb->add_child(vb_light); + + light_1_switch = memnew(TextureButton); + light_1_switch->set_toggle_mode(true); + vb_light->add_child(light_1_switch); + light_1_switch->connect("pressed", this, "_button_pressed", varray(light_1_switch)); + + light_2_switch = memnew(TextureButton); + light_2_switch->set_toggle_mode(true); + vb_light->add_child(light_2_switch); + light_2_switch->connect("pressed", this, "_button_pressed", varray(light_2_switch)); + + first_enter = true; +} + +/////////////////////// + +bool EditorInspectorPluginMaterial::can_handle(Object *p_object) { + + Material *material = Object::cast_to<Material>(p_object); + if (!material) + return false; + + return material->get_shader_mode() == Shader::MODE_SPATIAL; +} + +void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { + + Material *material = Object::cast_to<Material>(p_object); + if (!material) { + return; + } + Ref<Material> m(material); + + MaterialEditor *editor = memnew(MaterialEditor); + editor->edit(m, env); + add_custom_control(editor); +} + +EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() { + env.instance(); + Ref<ProceduralSky> proc_sky = memnew(ProceduralSky(true)); + env->set_sky(proc_sky); + env->set_background(Environment::BG_COLOR_SKY); +} + +MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) { + + Ref<EditorInspectorPluginMaterial> plugin; + plugin.instance(); + add_inspector_plugin(plugin); +} + String SpatialMaterialConversionPlugin::converts_to() const { return "ShaderMaterial"; diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 39935d3e12..c3f14c27e5 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -32,6 +32,71 @@ #define MATERIAL_EDITOR_PLUGIN_H #include "editor/property_editor.h" +#include "scene/resources/primitive_meshes.h" + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/3d/camera.h" +#include "scene/3d/light.h" +#include "scene/3d/mesh_instance.h" +#include "scene/resources/material.h" + +class MaterialEditor : public Control { + + GDCLASS(MaterialEditor, Control); + + ViewportContainer *vc; + Viewport *viewport; + MeshInstance *sphere_instance; + MeshInstance *box_instance; + DirectionalLight *light1; + DirectionalLight *light2; + Camera *camera; + + Ref<SphereMesh> sphere_mesh; + Ref<CubeMesh> box_mesh; + + TextureButton *sphere_switch; + TextureButton *box_switch; + + TextureButton *light_1_switch; + TextureButton *light_2_switch; + + Ref<Material> material; + + void _button_pressed(Node *p_button); + bool first_enter; + +protected: + void _notification(int p_what); + + static void _bind_methods(); + +public: + void edit(Ref<Material> p_material, const Ref<Environment> &p_env); + MaterialEditor(); +}; + +class EditorInspectorPluginMaterial : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginMaterial, EditorInspectorPlugin) + Ref<Environment> env; + +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + + EditorInspectorPluginMaterial(); +}; + +class MaterialEditorPlugin : public EditorPlugin { + + GDCLASS(MaterialEditorPlugin, EditorPlugin); + +public: + virtual String get_name() const { return "Material"; } + + MaterialEditorPlugin(EditorNode *p_node); +}; class SpatialMaterialConversionPlugin : public EditorResourceConversionPlugin { GDCLASS(SpatialMaterialConversionPlugin, EditorResourceConversionPlugin) diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index fcf515e3fc..6203035e25 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -80,26 +80,21 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) { mesh = p_mesh; mesh_instance->set_mesh(mesh); - if (mesh.is_null()) { - - hide(); - } else { - rot_x = 0; - rot_y = 0; - _update_rotation(); - - AABB aabb = mesh->get_aabb(); - Vector3 ofs = aabb.position + aabb.size * 0.5; - float m = aabb.get_longest_axis_size(); - if (m != 0) { - m = 1.0 / m; - m *= 0.5; - Transform xform; - xform.basis.scale(Vector3(m, m, m)); - xform.origin = -xform.basis.xform(ofs); //-ofs*m; - //xform.origin.z -= aabb.get_longest_axis_size() * 2; - mesh_instance->set_transform(xform); - } + rot_x = Math::deg2rad(-15.0); + rot_y = Math::deg2rad(30.0); + _update_rotation(); + + AABB aabb = mesh->get_aabb(); + Vector3 ofs = aabb.position + aabb.size * 0.5; + float m = aabb.get_longest_axis_size(); + if (m != 0) { + m = 1.0 / m; + m *= 0.5; + Transform xform; + xform.basis.scale(Vector3(m, m, m)); + xform.origin = -xform.basis.xform(ofs); //-ofs*m; + //xform.origin.z -= aabb.get_longest_axis_size() * 2; + mesh_instance->set_transform(xform); } } @@ -128,8 +123,8 @@ MeshEditor::MeshEditor() { viewport->set_world(world); //use own world add_child(viewport); viewport->set_disable_input(true); + viewport->set_msaa(Viewport::MSAA_2X); set_stretch(true); - camera = memnew(Camera); camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1))); camera->set_perspective(45, 0.1, 10); @@ -176,39 +171,29 @@ MeshEditor::MeshEditor() { rot_y = 0; } -void MeshEditorPlugin::edit(Object *p_object) { - - Mesh *s = Object::cast_to<Mesh>(p_object); - if (!s) - return; - - mesh_editor->edit(Ref<Mesh>(s)); -} +/////////////////////// -bool MeshEditorPlugin::handles(Object *p_object) const { +bool EditorInspectorPluginMesh::can_handle(Object *p_object) { - return p_object->is_class("Mesh"); + return Object::cast_to<Mesh>(p_object) != NULL; } -void MeshEditorPlugin::make_visible(bool p_visible) { +void EditorInspectorPluginMesh::parse_begin(Object *p_object) { - if (p_visible) { - mesh_editor->show(); - //mesh_editor->set_process(true); - } else { - - mesh_editor->hide(); - //mesh_editor->set_process(false); + Mesh *mesh = Object::cast_to<Mesh>(p_object); + if (!mesh) { + return; } + Ref<Mesh> m(mesh); + + MeshEditor *editor = memnew(MeshEditor); + editor->edit(m); + add_custom_control(editor); } MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) { - editor = p_node; - mesh_editor = memnew(MeshEditor); - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, mesh_editor); - mesh_editor->hide(); -} - -MeshEditorPlugin::~MeshEditorPlugin() { + Ref<EditorInspectorPluginMesh> plugin; + plugin.instance(); + add_inspector_plugin(plugin); } diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h index 0275f45be9..8ada2dac90 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -72,22 +72,21 @@ public: MeshEditor(); }; +class EditorInspectorPluginMesh : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginMesh, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); +}; + class MeshEditorPlugin : public EditorPlugin { GDCLASS(MeshEditorPlugin, EditorPlugin); - MeshEditor *mesh_editor; - EditorNode *editor; - public: virtual String get_name() const { return "Mesh"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); MeshEditorPlugin(EditorNode *p_node); - ~MeshEditorPlugin(); }; #endif diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 40ec03bc96..3e10cdbbfa 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -198,14 +198,14 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_UV2: { - Ref<ArrayMesh> mesh = node->get_mesh(); - if (!mesh.is_valid()) { + Ref<ArrayMesh> mesh2 = node->get_mesh(); + if (!mesh2.is_valid()) { err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh.")); err_dialog->popup_centered_minsize(); return; } - Error err = mesh->lightmap_unwrap(node->get_global_transform()); + Error err = mesh2->lightmap_unwrap(node->get_global_transform()); if (err != OK) { err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?")); err_dialog->popup_centered_minsize(); @@ -214,8 +214,8 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; case MENU_OPTION_DEBUG_UV1: { - Ref<Mesh> mesh = node->get_mesh(); - if (!mesh.is_valid()) { + Ref<Mesh> mesh2 = node->get_mesh(); + if (!mesh2.is_valid()) { err_dialog->set_text(TTR("No mesh to debug.")); err_dialog->popup_centered_minsize(); return; @@ -223,8 +223,8 @@ void MeshInstanceEditor::_menu_option(int p_option) { _create_uv_lines(0); } break; case MENU_OPTION_DEBUG_UV2: { - Ref<Mesh> mesh = node->get_mesh(); - if (!mesh.is_valid()) { + Ref<Mesh> mesh2 = node->get_mesh(); + if (!mesh2.is_valid()) { err_dialog->set_text(TTR("No mesh to debug.")); err_dialog->popup_centered_minsize(); return; diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index aedac7b45d..89eb253afe 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -127,7 +127,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, continue; MeshLibrary::ShapeData shape_data; shape_data.shape = collision; - shape_data.local_transform = sb->shape_owner_get_transform(E->get()); + shape_data.local_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get()); collisions.push_back(shape_data); } } @@ -136,17 +136,20 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, p_library->set_item_shapes(id, collisions); Ref<NavigationMesh> navmesh; + Transform navmesh_transform; for (int j = 0; j < mi->get_child_count(); j++) { Node *child2 = mi->get_child(j); if (!Object::cast_to<NavigationMeshInstance>(child2)) continue; NavigationMeshInstance *sb = Object::cast_to<NavigationMeshInstance>(child2); navmesh = sb->get_navigation_mesh(); + navmesh_transform = sb->get_transform(); if (!navmesh.is_null()) break; } if (!navmesh.is_null()) { p_library->set_item_navmesh(id, navmesh); + p_library->set_item_navmesh_transform(id, navmesh_transform); } } diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index a944674cbd..70d4919e9f 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -91,6 +91,7 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { cpu_particles->set_transform(particles->get_transform()); cpu_particles->set_visible(particles->is_visible()); cpu_particles->set_pause_mode(particles->get_pause_mode()); + cpu_particles->set_z_index(particles->get_z_index()); EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(particles, cpu_particles, false); @@ -132,7 +133,10 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { particles->set_emitting(false); } - particles->set_visibility_rect(rect); + undo_redo->create_action(TTR("Generate Visibility Rect")); + undo_redo->add_do_method(particles, "set_visibility_rect", rect); + undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect()); + undo_redo->commit_action(); } void Particles2DEditorPlugin::_generate_emission_mask() { @@ -404,7 +408,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { generate_visibility_rect->connect("confirmed", this, "_generate_visibility_rect"); emission_mask = memnew(ConfirmationDialog); - emission_mask->set_title(TTR("Generate Visibility Rect")); + emission_mask->set_title(TTR("Load Emission Mask")); VBoxContainer *emvb = memnew(VBoxContainer); emission_mask->add_child(emvb); emission_mask_mode = memnew(OptionButton); diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 95828064ac..0032850535 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -353,7 +353,11 @@ void ParticlesEditor::_generate_aabb() { node->set_emitting(false); } - node->set_visibility_aabb(rect); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Generate Visibility AABB")); + ur->add_do_method(node, "set_visibility_aabb", rect); + ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb()); + ur->commit_action(); } void ParticlesEditor::edit(Particles *p_particles) { diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 354475d268..a10eddb131 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -180,11 +180,11 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for segment split. if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mode == MODE_EDIT && on_edge == true) { - Vector2 gpoint = mb->get_position(); + Vector2 gpoint2 = mb->get_position(); Ref<Curve2D> curve = node->get_curve(); int insertion_point = -1; - float mbLength = curve->get_closest_offset(xform.affine_inverse().xform(gpoint)); + float mbLength = curve->get_closest_offset(xform.affine_inverse().xform(gpoint2)); int len = curve->get_point_count(); for (int i = 0; i < len - 1; i++) { float compareLength = curve->get_closest_offset(curve->get_point_position(i + 1)); @@ -195,7 +195,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { insertion_point = curve->get_point_count() - 2; undo_redo->create_action(TTR("Split Curve")); - undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint), Vector2(0, 0), Vector2(0, 0), insertion_point + 1); + undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1); undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); @@ -204,7 +204,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { action = ACTION_MOVING_POINT; action_point = insertion_point + 1; moving_from = curve->get_point_position(action_point); - moving_screen_from = gpoint; + moving_screen_from = gpoint2; canvas_item_editor->update_viewport(); diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 6efa76ef80..88dc258c5f 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -638,6 +638,10 @@ String PathSpatialGizmoPlugin::get_name() const { return "Path"; } +int PathSpatialGizmoPlugin::get_priority() const { + return -1; +} + PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h index ce3d3799d4..5482d09377 100644 --- a/editor/plugins/path_editor_plugin.h +++ b/editor/plugins/path_editor_plugin.h @@ -62,6 +62,7 @@ protected: public: String get_name() const; + int get_priority() const; PathSpatialGizmoPlugin(); }; diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 1d7b4ffa41..0dbbaf4177 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -45,6 +45,7 @@ Node2D *Polygon2DEditor::_get_node() const { void Polygon2DEditor::_set_node(Node *p_polygon) { node = Object::cast_to<Polygon2D>(p_polygon); + _update_polygon_editing_state(); } Vector2 Polygon2DEditor::_get_offset(int p_idx) const { @@ -53,6 +54,7 @@ Vector2 Polygon2DEditor::_get_offset(int p_idx) const { } int Polygon2DEditor::_get_polygon_count() const { + if (node->get_internal_vertex_count() > 0) { return 0; //do not edit if internal vertices exist } else { @@ -365,6 +367,8 @@ void Polygon2DEditor::_cancel_editing() { node->set_vertex_colors(uv_create_colors_prev); node->call("_set_bones", uv_create_bones_prev); node->set_polygons(polygons_prev); + + _update_polygon_editing_state(); } else if (uv_drag) { uv_drag = false; if (uv_edit_mode[0]->is_pressed()) { // Edit UV. @@ -377,9 +381,20 @@ void Polygon2DEditor::_cancel_editing() { polygon_create.clear(); } +void Polygon2DEditor::_update_polygon_editing_state() { + + if (!_get_node()) + return; + + if (node->get_internal_vertex_count() > 0) + disable_polygon_editing(true, TTR("Polygon 2D has internal vertices, so it can no longer be edited in the viewport.")); + else + disable_polygon_editing(false, String()); +} + void Polygon2DEditor::_commit_action() { - // Makes that undo/redoing actions made outside of the UV editor still affects its polygon. + // Makes that undo/redoing actions made outside of the UV editor still affect its polygon. undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport"); @@ -480,6 +495,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create_colors_prev = node->get_vertex_colors(); uv_create_bones_prev = node->call("_get_bones"); polygons_prev = node->get_polygons(); + disable_polygon_editing(false, String()); node->set_polygon(points_prev); node->set_uv(points_prev); node->set_internal_vertex_count(0); @@ -501,6 +517,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(node, "set_vertex_colors", uv_create_colors_prev); undo_redo->add_do_method(node, "clear_bones"); undo_redo->add_undo_method(node, "_set_bones", uv_create_bones_prev); + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -552,7 +570,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(node, "set_internal_vertex_count", internal_vertices + 1); undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); - + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -606,7 +625,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(node, "set_internal_vertex_count", internal_vertices - 1); undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); - + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -1028,6 +1048,9 @@ void Polygon2DEditor::_uv_draw() { Ref<Texture> internal_handle = get_icon("EditorInternalHandle", "EditorIcons"); Color poly_line_color = Color(0.9, 0.5, 0.5); + if (polygons.size() || polygon_create.size()) { + poly_line_color.a *= 0.25; + } Color polygon_line_color = Color(0.5, 0.5, 0.9); Vector<Color> polygon_fill_color; { @@ -1041,14 +1064,38 @@ void Polygon2DEditor::_uv_draw() { int uv_draw_max = uvs.size(); + uv_draw_max -= node->get_internal_vertex_count(); + if (uv_draw_max < 0) { + uv_draw_max = 0; + } + + for (int i = 0; i < uvs.size(); i++) { + + int next = uv_draw_max > 0 ? (i + 1) % uv_draw_max : 0; + + if (i < uv_draw_max && uv_drag && uv_move_current == UV_MODE_EDIT_POINT && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) { + uv_edit_draw->draw_line(mtx.xform(points_prev[i]), mtx.xform(points_prev[next]), prev_color, 2 * EDSCALE); + } + + Vector2 next_point = uvs[next]; + if (uv_create && i == uvs.size() - 1) { + next_point = uv_create_to; + } + if (i < uv_draw_max /*&& polygons.size() == 0 && polygon_create.size() == 0*/) { //if using or creating polygons, do not show outline (will show polygons instead) + uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), poly_line_color, 2 * EDSCALE); + } + + rect.expand_to(mtx.basis_xform(uvs[i])); + } + for (int i = 0; i < polygons.size(); i++) { PoolVector<int> points = polygons[i]; Vector<Vector2> polypoints; - for (int i = 0; i < points.size(); i++) { - int next = (i + 1) % points.size(); + for (int j = 0; j < points.size(); j++) { + int next = (j + 1) % points.size(); - int idx = points[i]; + int idx = points[j]; int idx_next = points[next]; if (idx < 0 || idx >= uvs.size()) continue; @@ -1063,27 +1110,8 @@ void Polygon2DEditor::_uv_draw() { } } - uv_draw_max -= node->get_internal_vertex_count(); - if (uv_draw_max < 0) { - uv_draw_max = 0; - } - for (int i = 0; i < uvs.size(); i++) { - int next = uv_draw_max > 0 ? (i + 1) % uv_draw_max : 0; - - if (i < uv_draw_max && uv_drag && uv_move_current == UV_MODE_EDIT_POINT && EDITOR_DEF("editors/poly_editor/show_previous_outline", true)) { - uv_edit_draw->draw_line(mtx.xform(points_prev[i]), mtx.xform(points_prev[next]), prev_color, 2 * EDSCALE); - } - - Vector2 next_point = uvs[next]; - if (uv_create && i == uvs.size() - 1) { - next_point = uv_create_to; - } - if (i < uv_draw_max && polygons.size() == 0 && polygon_create.size() == 0) { //if using or creating polygons, do not show outline (will show polygons instead) - uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), poly_line_color, 2 * EDSCALE); - } - if (weight_r.ptr()) { Vector2 draw_pos = mtx.xform(uvs[i]); float weight = weight_r[i]; @@ -1095,14 +1123,13 @@ void Polygon2DEditor::_uv_draw() { uv_edit_draw->draw_texture(internal_handle, mtx.xform(uvs[i]) - internal_handle->get_size() * 0.5); } } - rect.expand_to(mtx.basis_xform(uvs[i])); } if (polygon_create.size()) { for (int i = 0; i < polygon_create.size(); i++) { Vector2 from = uvs[polygon_create[i]]; Vector2 to = (i + 1) < polygon_create.size() ? uvs[polygon_create[i + 1]] : uv_create_to; - uv_edit_draw->draw_line(mtx.xform(from), mtx.xform(to), poly_line_color, 2); + uv_edit_draw->draw_line(mtx.xform(from), mtx.xform(to), polygon_line_color, 2); } } @@ -1216,6 +1243,7 @@ void Polygon2DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_uv_edit_popup_hide"), &Polygon2DEditor::_uv_edit_popup_hide); ClassDB::bind_method(D_METHOD("_sync_bones"), &Polygon2DEditor::_sync_bones); ClassDB::bind_method(D_METHOD("_update_bone_list"), &Polygon2DEditor::_update_bone_list); + ClassDB::bind_method(D_METHOD("_update_polygon_editing_state"), &Polygon2DEditor::_update_polygon_editing_state); ClassDB::bind_method(D_METHOD("_bone_paint_selected"), &Polygon2DEditor::_bone_paint_selected); } diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index d1849dd09b..24ca2ea3f4 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -128,6 +128,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { virtual void _menu_option(int p_option); void _cancel_editing(); + void _update_polygon_editing_state(); void _uv_scroll_changed(float); void _uv_input(const Ref<InputEvent> &p_input); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 9e65d9de10..42aba78e96 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -849,8 +849,7 @@ void ScriptEditor::_file_dialog_action(String p_file) { } file->close(); memdelete(file); - - // fallthrough to open the file. + FALLTHROUGH; } case FILE_OPEN: { @@ -979,6 +978,10 @@ void ScriptEditor::_menu_option(int p_option) { OS::get_singleton()->shell_open("https://docs.godotengine.org/"); } break; + case REQUEST_DOCS: { + + OS::get_singleton()->shell_open("https://github.com/godotengine/godot-docs/issues/new"); + } break; case WINDOW_NEXT: { @@ -1308,6 +1311,7 @@ void ScriptEditor::_notification(int p_what) { EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); help_search->set_icon(get_icon("HelpSearch", "EditorIcons")); site_search->set_icon(get_icon("Instance", "EditorIcons")); + request_docs->set_icon(get_icon("Issue", "EditorIcons")); script_forward->set_icon(get_icon("Forward", "EditorIcons")); script_back->set_icon(get_icon("Back", "EditorIcons")); @@ -1951,8 +1955,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if (is_visible_in_tree()) se->ensure_focus(); - if (p_line >= 0) + if (p_line > 0) { se->goto_line(p_line - 1); + } } return true; } @@ -2012,8 +2017,9 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra _test_script_times_on_disk(p_resource); _update_modified_scripts_for_external_editor(p_resource); - if (p_line >= 0) + if (p_line > 0) { se->goto_line(p_line - 1); + } notify_script_changed(p_resource); _add_recent_script(p_resource->get_path()); @@ -2206,6 +2212,9 @@ void ScriptEditor::_script_split_dragged(float) { Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + if (tab_container->get_child_count() == 0) + return Variant(); + Node *cur_node = tab_container->get_child(tab_container->get_current_tab()); HBoxContainer *drag_preview = memnew(HBoxContainer); @@ -3074,7 +3083,13 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { site_search->set_text(TTR("Online Docs")); site_search->connect("pressed", this, "_menu_option", varray(SEARCH_WEBSITE)); menu_hb->add_child(site_search); - site_search->set_tooltip(TTR("Open Godot online documentation")); + site_search->set_tooltip(TTR("Open Godot online documentation.")); + + request_docs = memnew(ToolButton); + request_docs->set_text(TTR("Request Docs")); + request_docs->connect("pressed", this, "_menu_option", varray(REQUEST_DOCS)); + menu_hb->add_child(request_docs); + request_docs->set_tooltip(TTR("Help improve the Godot documentation by giving feedback.")); help_search = memnew(ToolButton); help_search->set_text(TTR("Search Help")); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 11f4589f00..954b014935 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -157,6 +157,7 @@ class ScriptEditor : public PanelContainer { DEBUG_WITH_EXTERNAL_EDITOR, SEARCH_HELP, SEARCH_WEBSITE, + REQUEST_DOCS, HELP_SEARCH_FIND, HELP_SEARCH_FIND_NEXT, WINDOW_MOVE_UP, @@ -200,6 +201,7 @@ class ScriptEditor : public PanelContainer { Button *help_search; Button *site_search; + Button *request_docs; EditorHelpSearch *help_search_dialog; ItemList *script_list; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 60dc156782..9fc42e3862 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -273,18 +273,12 @@ void ScriptTextEditor::_set_theme_for_script() { } } -void ScriptTextEditor::_toggle_warning_pannel(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - warnings_panel->set_visible(!warnings_panel->is_visible()); - } +void ScriptTextEditor::_show_warnings_panel(bool p_show) { + warnings_panel->set_visible(p_show); } -void ScriptTextEditor::_error_pressed(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - code_editor->goto_error(); - } +void ScriptTextEditor::_error_pressed() { + code_editor->goto_error(); } void ScriptTextEditor::_warning_clicked(Variant p_line) { @@ -468,7 +462,7 @@ void ScriptTextEditor::_validate_script() { } } - code_editor->get_warning_count_label()->set_text(itos(warnings.size())); + code_editor->set_warning_nb(warnings.size()); warnings_panel->clear(); warnings_panel->push_table(3); for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { @@ -626,7 +620,9 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c } ScriptLanguage::LookupResult result; - if (p_symbol.is_resource_file()) { + if (ScriptServer::is_global_class(p_symbol)) { + EditorNode::get_singleton()->load_resource(ScriptServer::get_global_class_path(p_symbol)); + } else if (p_symbol.is_resource_file()) { List<String> scene_extensions; ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions); @@ -800,92 +796,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TOGGLE_COMMENT: { - Ref<Script> scr = script; - if (scr.is_null()) - return; - - String delimiter = "#"; - List<String> comment_delimiters; - scr->get_language()->get_comment_delimiters(&comment_delimiters); - - for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) { - String script_delimiter = E->get(); - if (script_delimiter.find(" ") == -1) { - delimiter = script_delimiter; - break; - } - } - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int begin = tx->get_selection_from_line(); - int end = tx->get_selection_to_line(); - - // End of selection ends on the first column of the last line, ignore it. - if (tx->get_selection_to_column() == 0) - end -= 1; - - int col_to = tx->get_selection_to_column(); - int cursor_pos = tx->cursor_get_column(); - - // Check if all lines in the selected block are commented - bool is_commented = true; - for (int i = begin; i <= end; i++) { - if (!tx->get_line(i).begins_with(delimiter)) { - is_commented = false; - break; - } - } - for (int i = begin; i <= end; i++) { - String line_text = tx->get_line(i); - - if (line_text.strip_edges().empty()) { - line_text = delimiter; - } else { - if (is_commented) { - line_text = line_text.substr(delimiter.length(), line_text.length()); - } else { - line_text = delimiter + line_text; - } - } - tx->set_line(i, line_text); - } - - // Adjust selection & cursor position. - int offset = is_commented ? -1 : 1; - int col_from = tx->get_selection_from_column() > 0 ? tx->get_selection_from_column() + offset : 0; - - if (is_commented && tx->cursor_get_column() == tx->get_line(tx->cursor_get_line()).length() + 1) - cursor_pos += 1; - - if (tx->get_selection_to_column() != 0 && col_to != tx->get_line(tx->get_selection_to_line()).length() + 1) - col_to += offset; - - if (tx->cursor_get_column() != 0) - cursor_pos += offset; - - tx->select(begin, col_from, tx->get_selection_to_line(), col_to); - tx->cursor_set_column(cursor_pos); - - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - - int col = tx->cursor_get_column(); - if (line_text.begins_with(delimiter)) { - line_text = line_text.substr(delimiter.length(), line_text.length()); - col -= 1; - } else { - line_text = delimiter + line_text; - col += 1; - } - - tx->set_line(begin, line_text); - tx->cursor_set_column(col); - } - tx->end_complex_operation(); - tx->update(); - + _edit_option_toggle_inline_comment(); } break; case EDIT_COMPLETE: { @@ -999,7 +910,7 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); } - } + } break; case DEBUG_GOTO_NEXT_BREAKPOINT: { List<int> bpoints; @@ -1072,6 +983,25 @@ void ScriptTextEditor::_edit_option(int p_op) { } } +void ScriptTextEditor::_edit_option_toggle_inline_comment() { + if (script.is_null()) + return; + + String delimiter = "#"; + List<String> comment_delimiters; + script->get_language()->get_comment_delimiters(&comment_delimiters); + + for (List<String>::Element *E = comment_delimiters.front(); E; E = E->next()) { + String script_delimiter = E->get(); + if (script_delimiter.find(" ") == -1) { + delimiter = script_delimiter; + break; + } + } + + code_editor->toggle_inline_comment(delimiter); +} + void ScriptTextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) { highlighters[p_highlighter->get_name()] = p_highlighter; highlighter_menu->add_radio_check_item(p_highlighter->get_name()); @@ -1107,7 +1037,7 @@ void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line); ClassDB::bind_method("_lookup_symbol", &ScriptTextEditor::_lookup_symbol); ClassDB::bind_method("_text_edit_gui_input", &ScriptTextEditor::_text_edit_gui_input); - ClassDB::bind_method("_toggle_warning_pannel", &ScriptTextEditor::_toggle_warning_pannel); + ClassDB::bind_method("_show_warnings_panel", &ScriptTextEditor::_show_warnings_panel); ClassDB::bind_method("_error_pressed", &ScriptTextEditor::_error_pressed); ClassDB::bind_method("_warning_clicked", &ScriptTextEditor::_warning_clicked); ClassDB::bind_method("_color_changed", &ScriptTextEditor::_color_changed); @@ -1427,7 +1357,7 @@ ScriptTextEditor::ScriptTextEditor() { code_editor = memnew(CodeTextEditor); editor_box->add_child(code_editor); - code_editor->add_constant_override("separation", 0); + code_editor->add_constant_override("separation", 2); code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); code_editor->connect("validate_script", this, "_validate_script"); code_editor->connect("load_theme_settings", this, "_load_theme_settings"); @@ -1445,9 +1375,8 @@ ScriptTextEditor::ScriptTextEditor() { warnings_panel->set_focus_mode(FOCUS_CLICK); warnings_panel->hide(); - code_editor->get_error_label()->connect("gui_input", this, "_error_pressed"); - code_editor->get_warning_label()->connect("gui_input", this, "_toggle_warning_pannel"); - code_editor->get_warning_count_label()->connect("gui_input", this, "_toggle_warning_pannel"); + code_editor->connect("error_pressed", this, "_error_pressed"); + code_editor->connect("show_warnings_panel", this, "_show_warnings_panel"); warnings_panel->connect("meta_clicked", this, "_warning_clicked"); update_settings(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 856e442d82..b081a31c18 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -125,8 +125,8 @@ protected: void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force); void _load_theme_settings(); void _set_theme_for_script(); - void _toggle_warning_pannel(const Ref<InputEvent> &p_event); - void _error_pressed(const Ref<InputEvent> &p_event); + void _show_warnings_panel(bool p_show); + void _error_pressed(); void _warning_clicked(Variant p_line); void _notification(int p_what); @@ -136,6 +136,7 @@ protected: void _change_syntax_highlighter(int p_idx); void _edit_option(int p_op); + void _edit_option_toggle_inline_comment(); void _make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition); void _text_edit_gui_input(const Ref<InputEvent> &ev); void _color_changed(const Color &p_color); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index cc2e65cf6d..d39e521113 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -47,12 +47,16 @@ Ref<Shader> ShaderTextEditor::get_edited_shader() const { } void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) { + if (shader == p_shader) { + return; + } shader = p_shader; _load_theme_settings(); get_text_edit()->set_text(p_shader->get_code()); + _validate_script(); _line_col_changed(); } @@ -244,19 +248,19 @@ void ShaderEditor::_menu_option(int p_option) { } break; case EDIT_INDENT_LEFT: { - TextEdit *tx = shader_editor->get_text_edit(); if (shader.is_null()) return; + TextEdit *tx = shader_editor->get_text_edit(); tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { - TextEdit *tx = shader_editor->get_text_edit(); if (shader.is_null()) return; + TextEdit *tx = shader_editor->get_text_edit(); tx->indent_right(); } break; @@ -268,54 +272,10 @@ void ShaderEditor::_menu_option(int p_option) { } break; case EDIT_TOGGLE_COMMENT: { - TextEdit *tx = shader_editor->get_text_edit(); if (shader.is_null()) return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int begin = tx->get_selection_from_line(); - int end = tx->get_selection_to_line(); - - // End of selection ends on the first column of the last line, ignore it. - if (tx->get_selection_to_column() == 0) - end -= 1; - - // Check if all lines in the selected block are commented - bool is_commented = true; - for (int i = begin; i <= end; i++) { - if (!tx->get_line(i).begins_with("//")) { - is_commented = false; - break; - } - } - for (int i = begin; i <= end; i++) { - String line_text = tx->get_line(i); - - if (line_text.strip_edges().empty()) { - line_text = "//"; - } else { - if (is_commented) { - line_text = line_text.substr(2, line_text.length()); - } else { - line_text = "//" + line_text; - } - } - tx->set_line(i, line_text); - } - } else { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - - if (line_text.begins_with("//")) - line_text = line_text.substr(2, line_text.length()); - else - line_text = "//" + line_text; - tx->set_line(begin, line_text); - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); + shader_editor->toggle_inline_comment("//"); } break; case EDIT_COMPLETE: { @@ -351,8 +311,8 @@ void ShaderEditor::_menu_option(int p_option) { void ShaderEditor::_notification(int p_what) { if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) - shader_editor->get_text_edit()->grab_focus(); + //if (is_visible_in_tree()) + // shader_editor->get_text_edit()->grab_focus(); } } @@ -414,6 +374,9 @@ void ShaderEditor::edit(const Ref<Shader> &p_shader) { if (p_shader.is_null() || !p_shader->is_text_shader()) return; + if (shader == p_shader) + return; + shader = p_shader; shader_editor->set_edited_shader(p_shader); @@ -437,8 +400,12 @@ void ShaderEditor::save_external_data() { void ShaderEditor::apply_shaders() { if (shader.is_valid()) { - shader->set_code(shader_editor->get_text_edit()->get_text()); - shader->set_edited(true); + String shader_code = shader->get_code(); + String editor_code = shader_editor->get_text_edit()->get_text(); + if (shader_code != editor_code) { + shader->set_code(editor_code); + shader->set_edited(true); + } } } diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 619d54b202..ef3e17279c 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -63,7 +63,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action("Create Rest Pose from Bones"); + ur->create_action(TTR("Create Rest Pose from Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); ur->add_do_method(bone, "set_rest", bone->get_transform()); @@ -79,7 +79,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action("Set Rest Pose to Bones"); + ur->create_action(TTR("Set Rest Pose to Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); ur->add_do_method(bone, "set_transform", bone->get_rest()); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 9ece812c49..f48887d342 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -35,7 +35,7 @@ #include "core/os/keyboard.h" #include "core/print_string.h" #include "core/project_settings.h" -#include "core/sort.h" +#include "core/sort_array.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/plugins/animation_player_editor_plugin.h" @@ -1021,7 +1021,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } _edit.mouse_pos = b->get_position(); - _edit.snap = false; + _edit.snap = spatial_editor->is_snap_enabled(); _edit.mode = TRANSFORM_NONE; //gizmo has priority over everything @@ -1772,7 +1772,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { if (_edit.mode != TRANSFORM_NONE) { - _edit.snap = true; + _edit.snap = !_edit.snap; } } if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) { @@ -2108,9 +2108,11 @@ void SpatialEditorViewport::_notification(int p_what) { set_process(visible); - if (visible) + if (visible) { _update_camera(0); - + } else { + set_freelook_active(false); + } call_deferred("update_transform_gizmo_view"); } @@ -2262,7 +2264,7 @@ void SpatialEditorViewport::_notification(int p_what) { if (show_fps) { String text; const float temp_fps = Engine::get_singleton()->get_frames_per_second(); - text += TTR("FPS") + ": " + itos(temp_fps) + " (" + String::num(1000.0f / temp_fps, 2) + " ms)"; + text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2))); fps_label->set_text(text); } @@ -2380,7 +2382,10 @@ void SpatialEditorViewport::_draw() { if (cursor.region_select) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), Color(0.7, 0.7, 1.0, 0.3)); + VisualServer::get_singleton()->canvas_item_add_rect( + ci, + Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); } if (message_time > 0) { @@ -2394,7 +2399,13 @@ void SpatialEditorViewport::_draw() { if (_edit.mode == TRANSFORM_ROTATE) { Point2 center = _point_to_screen(_edit.center); - VisualServer::get_singleton()->canvas_item_add_line(ci, _edit.mouse_pos, center, Color(0.4, 0.7, 1.0, 0.8)); + VisualServer::get_singleton()->canvas_item_add_line( + ci, + _edit.mouse_pos, + center, + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6), + Math::round(2 * EDSCALE), + true); } if (previewing) { @@ -2546,7 +2557,7 @@ void SpatialEditorViewport::_menu_option(int p_option) { List<Node *> &selection = editor_selection->get_selected_node_list(); - undo_redo->create_action(TTR("Align with view")); + undo_redo->create_action(TTR("Align with View")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Spatial *sp = Object::cast_to<Spatial>(E->get()); @@ -2999,7 +3010,7 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { previewing = Object::cast_to<Camera>(pv); previewing->connect("tree_exiting", this, "_preview_exited_scene"); VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace - view_menu->hide(); + view_menu->set_disabled(true); surface->update(); preview_camera->set_pressed(true); preview_camera->show(); @@ -3554,6 +3565,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE); fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE); fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN); + fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance.")); + fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show. surface->add_child(fps_label); fps_label->hide(); @@ -4113,10 +4126,10 @@ Dictionary SpatialEditor::get_state() const { d["zfar"] = get_zfar(); Dictionary gizmos_status; - for (int i = 0; i < gizmo_plugins.size(); i++) { - if (!gizmo_plugins[i]->can_be_hidden()) continue; + for (int i = 0; i < gizmo_plugins_by_name.size(); i++) { + if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue; int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i)); - String name = gizmo_plugins[i]->get_name(); + String name = gizmo_plugins_by_name[i]->get_name(); gizmos_status[name] = state; } @@ -4166,9 +4179,13 @@ void SpatialEditor::set_state(const Dictionary &p_state) { if (d.has("viewports")) { Array vp = d["viewports"]; - ERR_FAIL_COND(vp.size() > 4); + uint32_t vp_size = static_cast<uint32_t>(vp.size()); + if (vp_size > VIEWPORTS_COUNT) { + WARN_PRINT("Ignoring superfluous viewport settings from spatial editor state.") + vp_size = VIEWPORTS_COUNT; + } - for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { + for (uint32_t i = 0; i < vp_size; i++) { viewports[i]->set_state(vp[i]); } } @@ -4201,32 +4218,19 @@ void SpatialEditor::set_state(const Dictionary &p_state) { List<Variant> keys; gizmos_status.get_key_list(&keys); - for (int j = 0; j < gizmo_plugins.size(); ++j) { - if (!gizmo_plugins[j]->can_be_hidden()) continue; - int state = EditorSpatialGizmoPlugin::ON_TOP; + for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) { + if (!gizmo_plugins_by_name[j]->can_be_hidden()) continue; + int state = EditorSpatialGizmoPlugin::VISIBLE; for (int i = 0; i < keys.size(); i++) { - if (gizmo_plugins.write[j]->get_name() == keys[i]) { + if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) { state = gizmos_status[keys[i]]; + break; } } - const int idx = gizmos_menu->get_item_index(j); - - gizmos_menu->set_item_multistate(idx, state); - gizmo_plugins.write[j]->set_state(state); - - switch (state) { - case EditorSpatialGizmoPlugin::VISIBLE: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); - break; - case EditorSpatialGizmoPlugin::ON_TOP: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); - break; - case EditorSpatialGizmoPlugin::HIDDEN: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); - break; - } + gizmo_plugins_by_name.write[j]->set_state(state); } + _update_gizmos_menu(); } } @@ -4340,7 +4344,7 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) { break; } - gizmo_plugins.write[p_option]->set_state(state); + gizmo_plugins_by_name.write[p_option]->set_state(state); update_all_gizmos(); } @@ -4693,10 +4697,10 @@ void SpatialEditor::_init_indicators() { plane_mat->set_on_top_of_alpha(); plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); - Color col; - col[i] = 1.0; - col.a = gizmo_alph; - plane_mat->set_albedo(col); + Color col2; + col2[i] = 1.0; + col2.a = gizmo_alph; + plane_mat->set_albedo(col2); plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides surftool->set_material(plane_mat); surftool->commit(move_plane_gizmo[i]); @@ -4822,10 +4826,10 @@ void SpatialEditor::_init_indicators() { plane_mat->set_on_top_of_alpha(); plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); - Color col; - col[i] = 1.0; - col.a = gizmo_alph; - plane_mat->set_albedo(col); + Color col2; + col2[i] = 1.0; + col2.a = gizmo_alph; + plane_mat->set_albedo(col2); plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides surftool->set_material(plane_mat); surftool->commit(scale_plane_gizmo[i]); @@ -4836,23 +4840,46 @@ void SpatialEditor::_init_indicators() { _generate_selection_box(); } -struct _GizmoPluginComparator { - - bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { - return p_a->get_name() < p_b->get_name(); - } -}; - void SpatialEditor::_update_gizmos_menu() { gizmos_menu->clear(); - gizmo_plugins.sort_custom<_GizmoPluginComparator>(); - for (int i = 0; i < gizmo_plugins.size(); ++i) { - if (!gizmo_plugins[i]->can_be_hidden()) continue; - String plugin_name = gizmo_plugins[i]->get_name(); - gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::VISIBLE, i); - gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible")); + for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) { + if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue; + String plugin_name = gizmo_plugins_by_name[i]->get_name(); + const int plugin_state = gizmo_plugins_by_name[i]->get_state(); + gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i); + const int idx = gizmos_menu->get_item_index(i); + switch (plugin_state) { + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + break; + } + } +} + +void SpatialEditor::_update_gizmos_menu_theme() { + for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) { + if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue; + const int plugin_state = gizmo_plugins_by_name[i]->get_state(); + const int idx = gizmos_menu->get_item_index(i); + switch (plugin_state) { + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + break; + } } } @@ -5046,7 +5073,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { Array keys = snap_data.keys(); if (keys.size()) { - undo_redo->create_action("Snap Nodes To Floor"); + undo_redo->create_action(TTR("Snap Nodes To Floor")); for (int i = 0; i < keys.size(); i++) { Node *node = keys[i]; @@ -5145,20 +5172,17 @@ void SpatialEditor::_notification(int p_what) { get_tree()->connect("node_removed", this, "_node_removed"); EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons"); editor_selection->connect("selection_changed", this, "_refresh_menu_icons"); - } - - if (p_what == NOTIFICATION_ENTER_TREE) { + } else if (p_what == NOTIFICATION_ENTER_TREE) { _register_all_gizmos(); _update_gizmos_menu(); _init_indicators(); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { + } else if (p_what == NOTIFICATION_THEME_CHANGED) { + _update_gizmos_menu_theme(); + } else if (p_what == NOTIFICATION_EXIT_TREE) { _finish_indicators(); - } - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { + } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons")); @@ -5217,8 +5241,8 @@ void SpatialEditor::_request_gizmo(Object *p_obj) { Ref<EditorSpatialGizmo> seg; - for (int i = 0; i < gizmo_plugins.size(); ++i) { - seg = gizmo_plugins.write[i]->get_gizmo(sp); + for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) { + seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp); if (seg.is_valid()) { sp->set_gizmo(seg); @@ -5743,15 +5767,39 @@ void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) { spatial_editor->snap_cursor_to_plane(p_plane); } +struct _GizmoPluginPriorityComparator { + + bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { + if (p_a->get_priority() == p_b->get_priority()) { + return p_a->get_name() < p_b->get_name(); + } + return p_a->get_priority() > p_b->get_priority(); + } +}; + +struct _GizmoPluginNameComparator { + + bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { + return p_a->get_name() < p_b->get_name(); + } +}; + void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) { ERR_FAIL_NULL(p_plugin.ptr()); - gizmo_plugins.push_back(p_plugin); + + gizmo_plugins_by_priority.push_back(p_plugin); + gizmo_plugins_by_priority.sort_custom<_GizmoPluginPriorityComparator>(); + + gizmo_plugins_by_name.push_back(p_plugin); + gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>(); + _update_gizmos_menu(); SpatialEditor::get_singleton()->update_all_gizmos(); } void SpatialEditor::remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) { - gizmo_plugins.erase(p_plugin); + gizmo_plugins_by_priority.erase(p_plugin); + gizmo_plugins_by_name.erase(p_plugin); _update_gizmos_menu(); } @@ -5904,6 +5952,13 @@ String EditorSpatialGizmoPlugin::get_name() const { return TTR("Nameless gizmo"); } +int EditorSpatialGizmoPlugin::get_priority() const { + if (get_script_instance() && get_script_instance()->has_method("get_priority")) { + return get_script_instance()->call("get_priority"); + } + return 0; +} + Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) { if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) { @@ -5936,6 +5991,7 @@ void EditorSpatialGizmoPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorSpatialGizmoPlugin::get_material); //, DEFVAL(Ref<EditorSpatialGizmo>())); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "get_priority")); BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden")); BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden")); @@ -6035,6 +6091,10 @@ void EditorSpatialGizmoPlugin::set_state(int p_state) { } } +int EditorSpatialGizmoPlugin::get_state() const { + return current_state; +} + void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) { current_gizmos.erase(p_gizmo); } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 2dc627cb27..4a9d34a7f7 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -60,6 +60,7 @@ public: RID instance; Ref<ArrayMesh> mesh; + Ref<Material> material; RID skeleton; bool billboard; bool unscaled; @@ -103,7 +104,7 @@ protected: public: void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); - void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); + void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID(), const Ref<Material> &p_material = Ref<Material>()); void add_collision_segments(const Vector<Vector3> &p_lines); void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); @@ -618,6 +619,7 @@ private: void _instance_scene(); void _init_indicators(); void _update_gizmos_menu(); + void _update_gizmos_menu_theme(); void _init_grid(); void _finish_indicators(); void _finish_grid(); @@ -637,7 +639,8 @@ private: static SpatialEditor *singleton; void _node_removed(Node *p_node); - Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins; + Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_priority; + Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_name; void _register_all_gizmos(); @@ -780,6 +783,7 @@ public: Ref<SpatialMaterial> get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo = Ref<EditorSpatialGizmo>()); virtual String get_name() const; + virtual int get_priority() const; virtual bool can_be_hidden() const; virtual bool is_selectable_when_hidden() const; @@ -792,6 +796,7 @@ public: Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial); void set_state(int p_state); + int get_state() const; void unregister_gizmo(EditorSpatialGizmo *p_gizmo); EditorSpatialGizmoPlugin(); diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index c1718dd8bf..3854d27567 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -91,6 +91,8 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float Vector<Vector2> outPoints; ClipperLib::PolyNode *p2 = out.GetFirst(); + ERR_FAIL_COND_V(!p2, points); + while (p2->IsHole()) { p2 = p2->GetNext(); } diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index b712cfc9d3..5ba2fde763 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -40,10 +40,8 @@ void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { void SpriteFramesEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { - } - if (p_what == NOTIFICATION_ENTER_TREE) { + load->set_icon(get_icon("Load", "EditorIcons")); copy->set_icon(get_icon("ActionCopy", "EditorIcons")); paste->set_icon(get_icon("ActionPaste", "EditorIcons")); @@ -54,14 +52,9 @@ void SpriteFramesEditor::_notification(int p_what) { _delete->set_icon(get_icon("Remove", "EditorIcons")); new_anim->set_icon(get_icon("New", "EditorIcons")); remove_anim->set_icon(get_icon("Remove", "EditorIcons")); - } - - if (p_what == NOTIFICATION_READY) { - - //NodePath("/root")->connect("node_removed", this,"_node_removed",Vector<Variant>(),true); - } + } else if (p_what == NOTIFICATION_READY) { - if (p_what == NOTIFICATION_DRAW) { + add_constant_override("autohide", 1); // Fixes the dragger always showing up. } } @@ -354,9 +347,6 @@ void SpriteFramesEditor::_animation_name_edited() { for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) { String current = E->get()->call("get_animation"); - if (current != edited_anim) - continue; - undo_redo->add_do_method(E->get(), "set_animation", name); undo_redo->add_undo_method(E->get(), "set_animation", edited_anim); } @@ -389,9 +379,6 @@ void SpriteFramesEditor::_animation_add() { for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) { String current = E->get()->call("get_animation"); - if (frames->has_animation(current)) - continue; - undo_redo->add_do_method(E->get(), "set_animation", name); undo_redo->add_undo_method(E->get(), "set_animation", current); } @@ -649,7 +636,6 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da void SpriteFramesEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &SpriteFramesEditor::_gui_input); ClassDB::bind_method(D_METHOD("_load_pressed"), &SpriteFramesEditor::_load_pressed); ClassDB::bind_method(D_METHOD("_empty_pressed"), &SpriteFramesEditor::_empty_pressed); ClassDB::bind_method(D_METHOD("_empty2_pressed"), &SpriteFramesEditor::_empty2_pressed); @@ -673,31 +659,25 @@ void SpriteFramesEditor::_bind_methods() { SpriteFramesEditor::SpriteFramesEditor() { - //add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("panel","Panel")); - - split = memnew(HSplitContainer); - add_child(split); - VBoxContainer *vbc_animlist = memnew(VBoxContainer); - split->add_child(vbc_animlist); + add_child(vbc_animlist); vbc_animlist->set_custom_minimum_size(Size2(150, 0) * EDSCALE); - //vbc_animlist->set_v_size_flags(SIZE_EXPAND_FILL); VBoxContainer *sub_vb = memnew(VBoxContainer); - vbc_animlist->add_margin_child(TTR("Animations"), sub_vb, true); + vbc_animlist->add_margin_child(TTR("Animations:"), sub_vb, true); sub_vb->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *hbc_animlist = memnew(HBoxContainer); sub_vb->add_child(hbc_animlist); - new_anim = memnew(Button); - new_anim->set_flat(true); + new_anim = memnew(ToolButton); + new_anim->set_tooltip(TTR("New Animation")); hbc_animlist->add_child(new_anim); new_anim->set_h_size_flags(SIZE_EXPAND_FILL); new_anim->connect("pressed", this, "_animation_add"); - remove_anim = memnew(Button); - remove_anim->set_flat(true); + remove_anim = memnew(ToolButton); + remove_anim->set_tooltip(TTR("Remove Animation")); hbc_animlist->add_child(remove_anim); remove_anim->connect("pressed", this, "_animation_remove"); @@ -722,56 +702,47 @@ SpriteFramesEditor::SpriteFramesEditor() { anim_loop->connect("pressed", this, "_animation_loop_changed"); VBoxContainer *vbc = memnew(VBoxContainer); - split->add_child(vbc); + add_child(vbc); vbc->set_h_size_flags(SIZE_EXPAND_FILL); sub_vb = memnew(VBoxContainer); - vbc->add_margin_child(TTR("Animation Frames"), sub_vb, true); + vbc->add_margin_child(TTR("Animation Frames:"), sub_vb, true); HBoxContainer *hbc = memnew(HBoxContainer); sub_vb->add_child(hbc); - //animations = memnew( ItemList ); - - load = memnew(Button); - load->set_flat(true); + load = memnew(ToolButton); load->set_tooltip(TTR("Load Resource")); hbc->add_child(load); - copy = memnew(Button); - copy->set_flat(true); + copy = memnew(ToolButton); copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); - paste = memnew(Button); - paste->set_flat(true); + paste = memnew(ToolButton); paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); - empty = memnew(Button); - empty->set_flat(true); + empty = memnew(ToolButton); empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); - empty2 = memnew(Button); - empty2->set_flat(true); + empty2 = memnew(ToolButton); empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); hbc->add_spacer(false); - move_up = memnew(Button); - move_up->set_flat(true); + move_up = memnew(ToolButton); move_up->set_tooltip(TTR("Move (Before)")); hbc->add_child(move_up); - move_down = memnew(Button); - move_down->set_flat(true); + move_down = memnew(ToolButton); move_down->set_tooltip(TTR("Move (After)")); hbc->add_child(move_down); - _delete = memnew(Button); - _delete->set_flat(true); + _delete = memnew(ToolButton); + _delete->set_tooltip(TTR("Delete")); hbc->add_child(_delete); file = memnew(EditorFileDialog); @@ -787,7 +758,6 @@ SpriteFramesEditor::SpriteFramesEditor() { tree->set_fixed_column_width(thumbnail_size * 3 / 2); tree->set_max_text_lines(2); tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); - //tree->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); tree->set_drag_forwarding(this); sub_vb->add_child(tree); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 3ef4ba290b..55dd10074e 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -39,25 +39,25 @@ #include "scene/gui/split_container.h" #include "scene/gui/tree.h" -class SpriteFramesEditor : public PanelContainer { - - GDCLASS(SpriteFramesEditor, PanelContainer); - - Button *load; - Button *_delete; - Button *copy; - Button *paste; - Button *empty; - Button *empty2; - Button *move_up; - Button *move_down; +class SpriteFramesEditor : public HSplitContainer { + + GDCLASS(SpriteFramesEditor, HSplitContainer); + + ToolButton *load; + ToolButton *_delete; + ToolButton *copy; + ToolButton *paste; + ToolButton *empty; + ToolButton *empty2; + ToolButton *move_up; + ToolButton *move_down; ItemList *tree; bool loading_scene; int sel; HSplitContainer *split; - Button *new_anim; - Button *remove_anim; + ToolButton *new_anim; + ToolButton *remove_anim; Tree *animations; SpinBox *anim_speed; diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 0482ae86f3..0aa4a7662c 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -138,39 +138,33 @@ TextureEditor::TextureEditor() { set_custom_minimum_size(Size2(1, 150)); } -void TextureEditorPlugin::edit(Object *p_object) { - - Texture *s = Object::cast_to<Texture>(p_object); - if (!s) - return; - - texture_editor->edit(Ref<Texture>(s)); +TextureEditor::~TextureEditor() { + if (!texture.is_null()) { + texture->remove_change_receptor(this); + } } +// +bool EditorInspectorPluginTexture::can_handle(Object *p_object) { -bool TextureEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Texture"); + return Object::cast_to<ImageTexture>(p_object) != NULL || Object::cast_to<AtlasTexture>(p_object) != NULL || Object::cast_to<StreamTexture>(p_object) != NULL || Object::cast_to<LargeTexture>(p_object) != NULL || Object::cast_to<AnimatedTexture>(p_object) != NULL; } -void TextureEditorPlugin::make_visible(bool p_visible) { +void EditorInspectorPluginTexture::parse_begin(Object *p_object) { - if (p_visible) { - texture_editor->show(); - //texture_editor->set_process(true); - } else { - - texture_editor->hide(); - //texture_editor->set_process(false); + Texture *texture = Object::cast_to<Texture>(p_object); + if (!texture) { + return; } + Ref<Texture> m(texture); + + TextureEditor *editor = memnew(TextureEditor); + editor->edit(m); + add_custom_control(editor); } TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) { - editor = p_node; - texture_editor = memnew(TextureEditor); - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, texture_editor); - texture_editor->hide(); -} - -TextureEditorPlugin::~TextureEditorPlugin() { + Ref<EditorInspectorPluginTexture> plugin; + plugin.instance(); + add_inspector_plugin(plugin); } diff --git a/editor/plugins/texture_editor_plugin.h b/editor/plugins/texture_editor_plugin.h index 80ff4d6416..bcbda1fbd7 100644 --- a/editor/plugins/texture_editor_plugin.h +++ b/editor/plugins/texture_editor_plugin.h @@ -50,24 +50,24 @@ protected: public: void edit(Ref<Texture> p_texture); TextureEditor(); + ~TextureEditor(); +}; + +class EditorInspectorPluginTexture : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginTexture, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); }; class TextureEditorPlugin : public EditorPlugin { GDCLASS(TextureEditorPlugin, EditorPlugin); - TextureEditor *texture_editor; - EditorNode *editor; - public: virtual String get_name() const { return "Texture"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); TextureEditorPlugin(EditorNode *p_node); - ~TextureEditorPlugin(); }; #endif // TEXTURE_EDITOR_PLUGIN_H diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 3eeb871380..f741040fa8 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -64,7 +64,7 @@ void TextureRegionEditor::_region_draw() { return; Transform2D mtx; - mtx.elements[2] = -draw_ofs; + mtx.elements[2] = -draw_ofs * draw_zoom; mtx.scale_basis(Vector2(draw_zoom, draw_zoom)); VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx); @@ -128,7 +128,7 @@ void TextureRegionEditor::_region_draw() { }; for (int i = 0; i < 4; i++) { int next = (i + 1) % 4; - edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, Color(0.3, 0.7, 1, 1), 2); + edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, Color(0.3, 0.7, 1, 1), 2); } } } @@ -153,16 +153,16 @@ void TextureRegionEditor::_region_draw() { Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized(); ofs *= 1.4144 * (select_handle->get_size().width / 2); - edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, color, 2); + edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, color, 2); if (snap_mode != SNAP_AUTOSLICE) - edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs); + edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); ofs = (endpoints[next] - endpoints[i]) / 2; ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2); if (snap_mode != SNAP_AUTOSLICE) - edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs); + edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); scroll_rect.expand_to(endpoints[i]); } @@ -205,10 +205,10 @@ void TextureRegionEditor::_region_draw() { margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); } Vector2 pos[4] = { - mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y), - -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y), - mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x, 0), - -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x, 0) + mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y * draw_zoom), + -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y * draw_zoom), + mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x * draw_zoom, 0), + -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x * draw_zoom, 0) }; draw_margin_line(edit_draw, pos[0], pos[0] + Vector2(edit_draw->get_size().x, 0)); @@ -220,7 +220,7 @@ void TextureRegionEditor::_region_draw() { void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { Transform2D mtx; - mtx.elements[2] = -draw_ofs; + mtx.elements[2] = -draw_ofs * draw_zoom; mtx.scale_basis(Vector2(draw_zoom, draw_zoom)); Vector2 endpoints[8] = { @@ -255,10 +255,10 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT); } Vector2 pos[4] = { - mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs, - mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs, - mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs, - mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs + mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs * draw_zoom, + mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs * draw_zoom }; if (Math::abs(mb->get_position().y - pos[0].y) < 8) { edited_margin = 0; @@ -415,9 +415,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } } } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { - _zoom_in(); + _zoom_on_position(draw_zoom * ((0.95 + (0.05 * mb->get_factor())) / 0.95), mb->get_position()); } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { - _zoom_out(); + _zoom_on_position(draw_zoom * (1 - (0.05 * mb->get_factor())), mb->get_position()); } } @@ -427,7 +427,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - Vector2 draged(mm->get_relative().x, mm->get_relative().y); + Vector2 draged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom); hscroll->set_value(hscroll->get_value() - draged.x); vscroll->set_value(vscroll->get_value() - draged.y); @@ -578,25 +578,30 @@ void TextureRegionEditor::_set_snap_sep_y(float p_val) { edit_draw->update(); } +void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { + if (p_zoom < 0.25 || p_zoom > 8) + return; + + float prev_zoom = draw_zoom; + draw_zoom = p_zoom; + Point2 ofs = p_position; + ofs = ofs / prev_zoom - ofs / draw_zoom; + draw_ofs.x = Math::round(draw_ofs.x + ofs.x); + draw_ofs.y = Math::round(draw_ofs.y + ofs.y); + + edit_draw->update(); +} + void TextureRegionEditor::_zoom_in() { - if (draw_zoom < 8) { - draw_zoom *= 2; - edit_draw->update(); - } + _zoom_on_position(draw_zoom * 1.5, edit_draw->get_size() / 2.0); } void TextureRegionEditor::_zoom_reset() { - if (draw_zoom == 1) - return; - draw_zoom = 1; - edit_draw->update(); + _zoom_on_position(1.0, edit_draw->get_size() / 2.0); } void TextureRegionEditor::_zoom_out() { - if (draw_zoom > 0.25) { - draw_zoom /= 2; - edit_draw->update(); - } + _zoom_on_position(draw_zoom / 1.5, edit_draw->get_size() / 2.0); } void TextureRegionEditor::apply_rect(const Rect2 &p_rect) { @@ -743,6 +748,7 @@ void TextureRegionEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &TextureRegionEditor::_set_snap_step_y); ClassDB::bind_method(D_METHOD("_set_snap_sep_x"), &TextureRegionEditor::_set_snap_sep_x); ClassDB::bind_method(D_METHOD("_set_snap_sep_y"), &TextureRegionEditor::_set_snap_sep_y); + ClassDB::bind_method(D_METHOD("_zoom_on_position"), &TextureRegionEditor::_zoom_on_position); ClassDB::bind_method(D_METHOD("_zoom_in"), &TextureRegionEditor::_zoom_in); ClassDB::bind_method(D_METHOD("_zoom_reset"), &TextureRegionEditor::_zoom_reset); ClassDB::bind_method(D_METHOD("_zoom_out"), &TextureRegionEditor::_zoom_out); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 19eaef9bc3..a49e0fb96c 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -110,6 +110,7 @@ class TextureRegionEditor : public VBoxContainer { void _set_snap_step_y(float p_val); void _set_snap_sep_x(float p_val); void _set_snap_sep_y(float p_val); + void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); void _zoom_in(); void _zoom_reset(); void _zoom_out(); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index a967374eb9..8a18af7ae8 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -299,7 +299,11 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p } } - node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord); + Variant v_pos_x = p_pos.x, v_pos_y = p_pos.y, v_tile = p_value, v_flip_h = p_flip_h, v_flip_v = p_flip_v, v_transpose = p_transpose, v_autotile_coord = Vector2(p_autotile_coord.x, p_autotile_coord.y); + const Variant *args[7] = { &v_pos_x, &v_pos_y, &v_tile, &v_flip_h, &v_flip_v, &v_transpose, &v_autotile_coord }; + Variant::CallError ce; + node->call("set_cell", args, 7, ce); + if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) { if (current != -1) { node->set_cell_autotile_coord(p_pos.x, p_pos.y, position); @@ -477,17 +481,17 @@ void TileMapEditor::_update_palette() { if (sel_tile != TileMap::INVALID_CELL) { if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) { - const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile); + const Map<Vector2, uint16_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile); - Vector<Vector2> entries; - for (const Map<Vector2, uint16_t>::Element *E = tiles.front(); E; E = E->next()) { - entries.push_back(E->key()); + Vector<Vector2> entries2; + for (const Map<Vector2, uint16_t>::Element *E = tiles2.front(); E; E = E->next()) { + entries2.push_back(E->key()); } - entries.sort(); + entries2.sort(); Ref<Texture> tex = tileset->tile_get_texture(sel_tile); - for (int i = 0; i < entries.size(); i++) { + for (int i = 0; i < entries2.size(); i++) { manual_palette->add_item(String()); @@ -496,7 +500,7 @@ void TileMapEditor::_update_palette() { Rect2 region = tileset->tile_get_region(sel_tile); int spacing = tileset->autotile_get_spacing(sel_tile); region.size = tileset->autotile_get_size(sel_tile); // !! - region.position += (region.size + Vector2(spacing, spacing)) * entries[i]; + region.position += (region.size + Vector2(spacing, spacing)) * entries2[i]; if (!region.has_no_area()) manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); @@ -504,16 +508,16 @@ void TileMapEditor::_update_palette() { manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); } - manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries[i]); + manual_palette->set_item_metadata(manual_palette->get_item_count() - 1, entries2[i]); } } } if (manual_palette->get_item_count() > 0) { // Only show the manual palette if at least tile exists in it - int selected = manual_palette->get_current(); - if (selected == -1) selected = 0; - manual_palette->set_current(selected); + int selected2 = manual_palette->get_current(); + if (selected2 == -1) selected2 = 0; + manual_palette->set_current(selected2); manual_palette->show(); } @@ -1157,7 +1161,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (points.size() == 0) return false; - undo_redo->create_action("Bucket Fill"); + undo_redo->create_action(TTR("Bucket Fill")); undo_redo->add_do_method(this, "_erase_points", points); undo_redo->add_undo_method(this, "_fill_points", points, pop); @@ -1434,9 +1438,9 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { aabb.expand_to(node->world_to_map(xform_inv.xform(screen_size))); Rect2i si = aabb.grow(1.0); - if (node->get_half_offset() != TileMap::HALF_OFFSET_X) { + if (node->get_half_offset() != TileMap::HALF_OFFSET_X && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_X) { - int max_lines = 2000; //avoid crash if size too smal + int max_lines = 2000; //avoid crash if size too small for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) { @@ -1450,7 +1454,7 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } } else { - int max_lines = 10000; //avoid crash if size too smal + int max_lines = 10000; //avoid crash if size too small for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) { @@ -1458,23 +1462,26 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { Vector2 ofs; if (ABS(j) & 1) { - ofs = cell_xf[0] * 0.5; + ofs = cell_xf[0] * (node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5); } Vector2 from = xform.xform(node->map_to_world(Vector2(i, j), true) + ofs); Vector2 to = xform.xform(node->map_to_world(Vector2(i, j + 1), true) + ofs); + Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2); p_overlay->draw_line(from, to, col, 1); - if (max_lines-- == 0) + if (--max_lines == 0) break; } + if (max_lines == 0) + break; } } int max_lines = 10000; //avoid crash if size too smal - if (node->get_half_offset() != TileMap::HALF_OFFSET_Y) { + if (node->get_half_offset() != TileMap::HALF_OFFSET_Y && node->get_half_offset() != TileMap::HALF_OFFSET_NEGATIVE_Y) { for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) { @@ -1495,17 +1502,20 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { Vector2 ofs; if (ABS(j) & 1) { - ofs = cell_xf[1] * 0.5; + ofs = cell_xf[1] * (node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5); } Vector2 from = xform.xform(node->map_to_world(Vector2(j, i), true) + ofs); Vector2 to = xform.xform(node->map_to_world(Vector2(j + 1, i), true) + ofs); + Color col = i == 0 ? Color(1, 0.8, 0.2, 0.5) : Color(1, 0.3, 0.1, 0.2); p_overlay->draw_line(from, to, col, 1); - if (max_lines-- == 0) + if (--max_lines == 0) break; } + if (max_lines == 0) + break; } } } @@ -1533,8 +1543,12 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { for (int i = 0; i < 4; i++) { if (node->get_half_offset() == TileMap::HALF_OFFSET_X && ABS(over_tile.y) & 1) endpoints[i] += cell_xf[0] * 0.5; + if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_X && ABS(over_tile.y) & 1) + endpoints[i] += cell_xf[0] * -0.5; if (node->get_half_offset() == TileMap::HALF_OFFSET_Y && ABS(over_tile.x) & 1) endpoints[i] += cell_xf[1] * 0.5; + if (node->get_half_offset() == TileMap::HALF_OFFSET_NEGATIVE_Y && ABS(over_tile.x) & 1) + endpoints[i] += cell_xf[1] * -0.5; endpoints[i] = xform.xform(endpoints[i]); } Color col; diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 1a687a4009..54e6e5b154 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -201,11 +201,13 @@ void TileSetEditor::_bind_methods() { ClassDB::bind_method("_zoom_out", &TileSetEditor::_zoom_out); ClassDB::bind_method("_zoom_reset", &TileSetEditor::_zoom_reset); ClassDB::bind_method("_select_edited_shape_coord", &TileSetEditor::_select_edited_shape_coord); + ClassDB::bind_method("_sort_tiles", &TileSetEditor::_sort_tiles); ClassDB::bind_method("edit", &TileSetEditor::edit); ClassDB::bind_method("add_texture", &TileSetEditor::add_texture); ClassDB::bind_method("remove_texture", &TileSetEditor::remove_texture); ClassDB::bind_method("update_texture_list_icon", &TileSetEditor::update_texture_list_icon); + ClassDB::bind_method("update_workspace_minsize", &TileSetEditor::update_workspace_minsize); } void TileSetEditor::_notification(int p_what) { @@ -232,6 +234,9 @@ void TileSetEditor::_notification(int p_what) { tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); tools[BITMASK_CLEAR]->set_icon(get_icon("Clear", "EditorIcons")); tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); + tools[SHAPE_NEW_RECTANGLE]->set_icon(get_icon("CollisionShape2D", "EditorIcons")); + tools[SELECT_PREVIOUS]->set_icon(get_icon("ArrowLeft", "EditorIcons")); + tools[SELECT_NEXT]->set_icon(get_icon("ArrowRight", "EditorIcons")); tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); @@ -239,6 +244,7 @@ void TileSetEditor::_notification(int p_what) { tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons")); + _update_toggle_shape_button(); tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons")); tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons")); @@ -322,11 +328,29 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", varray(i)); tool_hb->add_child(tool_workspacemode[i]); } + Control *spacer = memnew(Control); spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); tool_hb->add_child(spacer); tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE); + tools[SELECT_NEXT] = memnew(ToolButton); + tool_hb->add_child(tools[SELECT_NEXT]); + tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE); + tools[SELECT_NEXT]->set_shortcut(ED_SHORTCUT("tileset_editor/next_shape", TTR("Next Coordinate"), KEY_PAGEDOWN)); + tools[SELECT_NEXT]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_NEXT)); + tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile.")); + tools[SELECT_PREVIOUS] = memnew(ToolButton); + tool_hb->add_child(tools[SELECT_PREVIOUS]); + tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE); + tools[SELECT_PREVIOUS]->set_shortcut(ED_SHORTCUT("tileset_editor/previous_shape", TTR("Previous Coordinate"), KEY_PAGEUP)); + tools[SELECT_PREVIOUS]->set_tooltip(TTR("Select the previous shape, subtile, or Tile.")); + tools[SELECT_PREVIOUS]->connect("pressed", this, "_on_tool_clicked", varray(SELECT_PREVIOUS)); + + VSeparator *separator_shape_selection = memnew(VSeparator); + tool_hb->add_child(separator_shape_selection); + tool_hb->move_child(separator_shape_selection, WORKSPACE_CREATE_SINGLE); + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); workspace_mode = WORKSPACE_EDIT; @@ -377,12 +401,24 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_CLEAR)); toolbar->add_child(tools[BITMASK_CLEAR]); + tools[SHAPE_NEW_RECTANGLE] = memnew(ToolButton); + toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]); + tools[SHAPE_NEW_RECTANGLE]->set_toggle_mode(true); + tools[SHAPE_NEW_RECTANGLE]->set_button_group(tg); + tools[SHAPE_NEW_RECTANGLE]->set_tooltip(TTR("Create a new rectangle.")); + tools[SHAPE_NEW_POLYGON] = memnew(ToolButton); toolbar->add_child(tools[SHAPE_NEW_POLYGON]); tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true); tools[SHAPE_NEW_POLYGON]->set_button_group(tg); tools[SHAPE_NEW_POLYGON]->set_tooltip(TTR("Create a new polygon.")); + separator_shape_toggle = memnew(VSeparator); + toolbar->add_child(separator_shape_toggle); + tools[SHAPE_TOGGLE_TYPE] = memnew(ToolButton); + tools[SHAPE_TOGGLE_TYPE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_TOGGLE_TYPE)); + toolbar->add_child(tools[SHAPE_TOGGLE_TYPE]); + separator_delete = memnew(VSeparator); toolbar->add_child(separator_delete); tools[SHAPE_DELETE] = memnew(ToolButton); @@ -583,16 +619,15 @@ void TileSetEditor::_on_texture_list_selected(int p_index) { if (get_current_texture().is_valid()) { current_item_index = p_index; preview->set_texture(get_current_texture()); - workspace->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); - workspace_container->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); - workspace_overlay->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); update_workspace_tile_mode(); + update_workspace_minsize(); } else { current_item_index = -1; preview->set_texture(NULL); workspace->set_custom_minimum_size(Size2i()); update_workspace_tile_mode(); } + set_current_tile(-1); workspace->update(); } @@ -637,6 +672,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_NEW_RECTANGLE]->hide(); if (workspace_mode == WORKSPACE_EDIT) { separator_delete->show(); @@ -666,6 +702,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->show(); + tools[SHAPE_NEW_RECTANGLE]->show(); separator_delete->show(); tools[SHAPE_DELETE]->show(); @@ -689,6 +726,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->show(); tools[BITMASK_CLEAR]->show(); tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_NEW_RECTANGLE]->hide(); separator_delete->hide(); tools[SHAPE_DELETE]->hide(); @@ -709,6 +747,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { tools[BITMASK_PASTE]->hide(); tools[BITMASK_CLEAR]->hide(); tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_NEW_RECTANGLE]->hide(); separator_delete->hide(); tools[SHAPE_DELETE]->hide(); @@ -733,6 +772,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { } break; default: {} } + _update_toggle_shape_button(); workspace->update(); } @@ -1071,7 +1111,23 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { undo_redo->create_action(TTR("Set Tile Region")); undo_redo->add_do_method(tileset.ptr(), "tile_set_region", get_current_tile(), edited_region); undo_redo->add_undo_method(tileset.ptr(), "tile_set_region", get_current_tile(), tileset->tile_get_region(get_current_tile())); + + Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2; + Size2 workspace_minsize = workspace->get_custom_minimum_size(); + if (tile_workspace_size.x > workspace_minsize.x && tile_workspace_size.y > workspace_minsize.y) { + undo_redo->add_do_method(workspace, "set_custom_minimum_size", tile_workspace_size); + undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize); + undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", tile_workspace_size); + undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize); + undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", tile_workspace_size); + undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize); + } else if (workspace_minsize.x > get_current_texture()->get_size().x + WORKSPACE_MARGIN.x * 2 || workspace_minsize.y > get_current_texture()->get_size().y + WORKSPACE_MARGIN.y * 2) { + undo_redo->add_do_method(this, "update_workspace_minsize"); + undo_redo->add_undo_method(this, "update_workspace_minsize"); + } + edited_region = Rect2(); + undo_redo->add_do_method(workspace, "update"); undo_redo->add_undo_method(workspace, "update"); undo_redo->add_do_method(workspace_overlay, "update"); @@ -1095,6 +1151,19 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); tool_editmode[EDITMODE_COLLISION]->set_pressed(true); edit_mode = EDITMODE_COLLISION; + + Size2 tile_workspace_size = edited_region.position + edited_region.size + WORKSPACE_MARGIN * 2; + Size2 workspace_minsize = workspace->get_custom_minimum_size(); + if (tile_workspace_size.x > workspace_minsize.x || tile_workspace_size.y > workspace_minsize.y) { + Size2 new_workspace_minsize = Size2(MAX(tile_workspace_size.x, workspace_minsize.x), MAX(tile_workspace_size.y, workspace_minsize.y)); + undo_redo->add_do_method(workspace, "set_custom_minimum_size", new_workspace_minsize); + undo_redo->add_undo_method(workspace, "set_custom_minimum_size", workspace_minsize); + undo_redo->add_do_method(workspace_container, "set_custom_minimum_size", new_workspace_minsize); + undo_redo->add_undo_method(workspace_container, "set_custom_minimum_size", workspace_minsize); + undo_redo->add_do_method(workspace_overlay, "set_custom_minimum_size", new_workspace_minsize); + undo_redo->add_undo_method(workspace_overlay, "set_custom_minimum_size", workspace_minsize); + } + edited_region = Rect2(); undo_redo->add_do_method(workspace, "update"); @@ -1335,8 +1404,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } undo_redo->create_action(TTR("Edit Collision Polygon")); - undo_redo->add_do_method(edited_collision_shape.ptr(), "set_points", points); - undo_redo->add_undo_method(edited_collision_shape.ptr(), "set_points", edited_collision_shape->get_points()); + _set_edited_shape_points(points); undo_redo->add_do_method(this, "_select_edited_shape_coord"); undo_redo->add_undo_method(this, "_select_edited_shape_coord"); undo_redo->commit_action(); @@ -1414,6 +1482,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { workspace->update(); } else { creating_shape = true; + _set_edited_collision_shape(Ref<ConvexPolygonShape2D>()); current_shape.resize(0); current_shape.push_back(snap_point(pos)); workspace->update(); @@ -1430,6 +1499,21 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { workspace->update(); } } + } else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + _set_edited_collision_shape(Ref<ConvexPolygonShape2D>()); + current_shape.resize(0); + current_shape.push_back(snap_point(shape_anchor)); + current_shape.push_back(snap_point(shape_anchor + Vector2(current_tile_region.size.x, 0))); + current_shape.push_back(snap_point(shape_anchor + current_tile_region.size)); + current_shape.push_back(snap_point(shape_anchor + Vector2(0, current_tile_region.size.y))); + close_shape(shape_anchor); + workspace->update(); + } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + workspace->update(); + } + } } } break; default: {} @@ -1463,6 +1547,49 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->add_do_method(workspace, "update"); undo_redo->add_undo_method(workspace, "update"); undo_redo->commit_action(); + } else if (p_tool == SHAPE_TOGGLE_TYPE) { + if (edited_collision_shape.is_valid()) { + Ref<ConvexPolygonShape2D> convex = edited_collision_shape; + Ref<ConcavePolygonShape2D> concave = edited_collision_shape; + Ref<Shape2D> previous_shape = edited_collision_shape; + Array sd = tileset->call("tile_get_shapes", get_current_tile()); + + if (convex.is_valid()) { + // Make concave + undo_redo->create_action(TTR("Make Polygon Concave")); + Ref<ConcavePolygonShape2D> _concave = memnew(ConcavePolygonShape2D); + edited_collision_shape = _concave; + _set_edited_shape_points(_get_collision_shape_points(convex)); + } else if (concave.is_valid()) { + // Make convex + undo_redo->create_action(TTR("Make Polygon Convex")); + Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D); + edited_collision_shape = _convex; + _set_edited_shape_points(_get_collision_shape_points(concave)); + } else { + // Shoudn't haphen + } + for (int i = 0; i < sd.size(); i++) { + if (sd[i].get("shape") == previous_shape) { + undo_redo->add_undo_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd.duplicate()); + sd.remove(i); + sd.insert(i, edited_collision_shape); + undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); + break; + } + } + _update_toggle_shape_button(); + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } + } else if (p_tool == SELECT_NEXT) { + _select_next_shape(); + } else if (p_tool == SELECT_PREVIOUS) { + _select_previous_shape(); } else if (p_tool == SHAPE_DELETE) { if (creating_shape) { creating_shape = false; @@ -1477,6 +1604,14 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->add_do_method(tileset.ptr(), "remove_tile", t_id); _undo_tile_removal(t_id); undo_redo->add_do_method(this, "_validate_current_tile_id"); + + Rect2 tile_region = tileset->tile_get_region(get_current_tile()); + Size2 tile_workspace_size = tile_region.position + tile_region.size; + if (tile_workspace_size.x > get_current_texture()->get_size().x || tile_workspace_size.y > get_current_texture()->get_size().y) { + undo_redo->add_do_method(this, "update_workspace_minsize"); + undo_redo->add_undo_method(this, "update_workspace_minsize"); + } + undo_redo->add_do_method(workspace, "update"); undo_redo->add_undo_method(workspace, "update"); undo_redo->add_do_method(workspace_overlay, "update"); @@ -1577,6 +1712,378 @@ void TileSetEditor::_on_grid_snap_toggled(bool p_val) { workspace->update(); } +Vector<Vector2> TileSetEditor::_get_collision_shape_points(const Ref<Shape2D> &p_shape) { + Ref<ConvexPolygonShape2D> convex = p_shape; + Ref<ConcavePolygonShape2D> concave = p_shape; + if (convex.is_valid()) { + return convex->get_points(); + } else if (concave.is_valid()) { + Vector<Vector2> points; + for (int i = 0; i < concave->get_segments().size(); i += 2) { + points.push_back(concave->get_segments()[i]); + } + return points; + } else { + return Vector<Vector2>(); + } +} + +Vector<Vector2> TileSetEditor::_get_edited_shape_points() { + return _get_collision_shape_points(edited_collision_shape); +} + +void TileSetEditor::_set_edited_shape_points(const Vector<Vector2> points) { + Ref<ConvexPolygonShape2D> convex = edited_collision_shape; + Ref<ConcavePolygonShape2D> concave = edited_collision_shape; + if (convex.is_valid()) { + undo_redo->add_do_method(convex.ptr(), "set_points", points); + undo_redo->add_undo_method(convex.ptr(), "set_points", _get_edited_shape_points()); + } else if (concave.is_valid()) { + PoolVector2Array segments; + for (int i = 0; i < points.size() - 1; i++) { + segments.push_back(points[i]); + segments.push_back(points[i + 1]); + } + segments.push_back(points[points.size() - 1]); + segments.push_back(points[0]); + concave->set_segments(segments); + undo_redo->add_do_method(concave.ptr(), "set_segments", segments); + undo_redo->add_undo_method(concave.ptr(), "set_segments", concave->get_segments()); + } else { + // Invalid shape + } +} + +void TileSetEditor::_update_tile_data() { + current_tile_data.clear(); + if (get_current_tile() < 0) + return; + + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + SubtileData data; + for (int i = 0; i < sd.size(); i++) { + data.collisions.push_back(sd[i].shape); + } + data.navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); + data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); + current_tile_data[Vector2i()] = data; + } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); + for (int y = 0; y < cell_count.y; y++) { + for (int x = 0; x < cell_count.x; x++) { + SubtileData data; + Vector2i coord(x, y); + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + data.collisions.push_back(sd[i].shape); + } + } + data.navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord); + data.occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); + current_tile_data[coord] = data; + } + } + } +} + +void TileSetEditor::_update_toggle_shape_button() { + Ref<ConvexPolygonShape2D> convex = edited_collision_shape; + Ref<ConcavePolygonShape2D> concave = edited_collision_shape; + separator_shape_toggle->show(); + tools[SHAPE_TOGGLE_TYPE]->show(); + if (edit_mode != EDITMODE_COLLISION || !edited_collision_shape.is_valid()) { + separator_shape_toggle->hide(); + tools[SHAPE_TOGGLE_TYPE]->hide(); + } else if (concave.is_valid()) { + tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConvexPolygonShape2D", "EditorIcons")); + tools[SHAPE_TOGGLE_TYPE]->set_text("Make Convex"); + } else if (convex.is_valid()) { + tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); + tools[SHAPE_TOGGLE_TYPE]->set_text("Make Concave"); + } else { + // Shoudn't happen + separator_shape_toggle->hide(); + tools[SHAPE_TOGGLE_TYPE]->hide(); + } +} + +void TileSetEditor::_select_next_tile() { + Array tiles = _get_tiles_in_current_texture(true); + if (tiles.size() == 0) { + set_current_tile(-1); + } else if (get_current_tile() == -1) { + set_current_tile(tiles[0]); + } else { + int index = tiles.find(get_current_tile()); + if (index < 0) { + set_current_tile(tiles[0]); + } else if (index == tiles.size() - 1) { + set_current_tile(tiles[0]); + } else { + set_current_tile(tiles[index + 1]); + } + } + if (get_current_tile() == -1) { + return; + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + return; + } else { + switch (edit_mode) { + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: + case EDITMODE_Z_INDEX: { + edited_shape_coord = Vector2(); + _select_edited_shape_coord(); + } break; + default: {} + } + } +} + +void TileSetEditor::_select_previous_tile() { + Array tiles = _get_tiles_in_current_texture(true); + if (tiles.size() == 0) { + set_current_tile(-1); + } else if (get_current_tile() == -1) { + set_current_tile(tiles[tiles.size() - 1]); + } else { + int index = tiles.find(get_current_tile()); + if (index <= 0) { + set_current_tile(tiles[tiles.size() - 1]); + } else { + set_current_tile(tiles[index - 1]); + } + } + if (get_current_tile() == -1) { + return; + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + return; + } else { + switch (edit_mode) { + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: + case EDITMODE_Z_INDEX: { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); + cell_count -= Vector2(1, 1); + edited_shape_coord = cell_count; + _select_edited_shape_coord(); + } break; + default: {} + } + } +} + +Array TileSetEditor::_get_tiles_in_current_texture(bool sorted) { + Array a; + List<int> all_tiles; + if (!get_current_texture().is_valid()) { + return a; + } + tileset->get_tile_list(&all_tiles); + for (int i = 0; i < all_tiles.size(); i++) { + if (tileset->tile_get_texture(all_tiles[i]) == get_current_texture()) { + a.push_back(all_tiles[i]); + } + } + if (sorted) { + a.sort_custom(this, "_sort_tiles"); + } + return a; +} + +bool TileSetEditor::_sort_tiles(Variant p_a, Variant p_b) { + int a = p_a; + int b = p_b; + + Vector2 pos_a = tileset->tile_get_region(a).position; + Vector2 pos_b = tileset->tile_get_region(b).position; + if (pos_a.y < pos_b.y) { + return true; + + } else if (pos_a.y == pos_b.y) { + if (pos_a.x < pos_b.x) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +void TileSetEditor::_select_next_subtile() { + if (get_current_tile() == -1) { + _select_next_tile(); + return; + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + _select_next_tile(); + } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { + _select_next_tile(); + } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); + if (edited_shape_coord.x >= cell_count.x - 1 && edited_shape_coord.y >= cell_count.y - 1) { + _select_next_tile(); + } else { + edited_shape_coord.x++; + if (edited_shape_coord.x >= cell_count.x) { + edited_shape_coord.x = 0; + edited_shape_coord.y++; + } + _select_edited_shape_coord(); + } + } +} + +void TileSetEditor::_select_previous_subtile() { + if (get_current_tile() == -1) { + _select_previous_tile(); + return; + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { + _select_previous_tile(); + } else if (edit_mode == EDITMODE_REGION || edit_mode == EDITMODE_BITMASK || edit_mode == EDITMODE_ICON) { + _select_previous_tile(); + } else { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->tile_get_region(get_current_tile()).size; + Vector2i cell_count = size / (tileset->autotile_get_size(get_current_tile()) + Vector2(spacing, spacing)); + if (edited_shape_coord.x <= 0 && edited_shape_coord.y <= 0) { + _select_previous_tile(); + } else { + edited_shape_coord.x--; + if (edited_shape_coord.x == -1) { + edited_shape_coord.x = cell_count.x - 1; + edited_shape_coord.y--; + } + _select_edited_shape_coord(); + } + } +} + +void TileSetEditor::_select_next_shape() { + if (get_current_tile() == -1) { + _select_next_subtile(); + } else if (edit_mode != EDITMODE_COLLISION) { + _select_next_subtile(); + } else { + Vector2i edited_coord = Vector2(); + if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { + edited_coord = edited_shape_coord; + } + SubtileData data = current_tile_data[edited_coord]; + if (data.collisions.size() == 0) { + _select_next_subtile(); + } else { + int index = data.collisions.find(edited_collision_shape); + if (index < 0) { + _set_edited_collision_shape(data.collisions[0]); + } else if (index == data.collisions.size() - 1) { + _select_next_subtile(); + } else { + _set_edited_collision_shape(data.collisions[index + 1]); + } + } + current_shape.resize(0); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; + + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Vector2 shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + current_tile_region.position += shape_anchor; + + if (edited_collision_shape.is_valid()) { + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); + } + } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } +} + +void TileSetEditor::_select_previous_shape() { + if (get_current_tile() == -1) { + _select_previous_subtile(); + if (get_current_tile() != -1 && edit_mode == EDITMODE_COLLISION) { + SubtileData data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); + } + } else { + return; + } + } else if (edit_mode != EDITMODE_COLLISION) { + _select_previous_subtile(); + } else { + Vector2i edited_coord = Vector2(); + if (tileset->tile_get_tile_mode(get_current_tile()) != TileSet::SINGLE_TILE) { + edited_coord = edited_shape_coord; + } + SubtileData data = current_tile_data[edited_coord]; + if (data.collisions.size() == 0) { + _select_previous_subtile(); + data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); + } + } else { + int index = data.collisions.find(edited_collision_shape); + if (index < 0) { + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); + } else if (index == 0) { + _select_previous_subtile(); + data = current_tile_data[Vector2i(edited_shape_coord)]; + if (data.collisions.size() > 1) { + _set_edited_collision_shape(data.collisions[data.collisions.size() - 1]); + } + } else { + _set_edited_collision_shape(data.collisions[index - 1]); + } + } + + current_shape.resize(0); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; + + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + Vector2 shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); + current_tile_region.position += shape_anchor; + + if (edited_collision_shape.is_valid()) { + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); + } + } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); + } +} + +void TileSetEditor::_set_edited_collision_shape(const Ref<Shape2D> &p_shape) { + edited_collision_shape = p_shape; + _update_toggle_shape_button(); +} + void TileSetEditor::_set_snap_step(Vector2 p_val) { snap_step.x = CLAMP(p_val.x, 0, 256); snap_step.y = CLAMP(p_val.y, 0, 256); @@ -1873,16 +2380,29 @@ void TileSetEditor::draw_polygon_shapes() { } anchor += WORKSPACE_MARGIN; anchor += tileset->tile_get_region(t_id).position; - Ref<ConvexPolygonShape2D> shape = sd[i].shape; + Ref<Shape2D> shape = sd[i].shape; if (shape.is_valid()) { Color c_bg; Color c_border; + Ref<ConvexPolygonShape2D> convex = shape; + bool is_convex = convex.is_valid(); if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || coord == edited_shape_coord) && sd[i].shape == edited_collision_shape) { - c_bg = Color(0, 1, 1, 0.5); - c_border = Color(0, 1, 1); + if (is_convex) { + c_bg = Color(0, 1, 1, 0.5); + c_border = Color(0, 1, 1); + } else { + c_bg = Color(0.8, 0, 1, 0.5); + c_border = Color(0.8, 0, 1); + } } else { - c_bg = Color(0.9, 0.7, 0.07, 0.5); - c_border = Color(0.9, 0.7, 0.07, 1); + if (is_convex) { + c_bg = Color(0.9, 0.7, 0.07, 0.5); + c_border = Color(0.9, 0.7, 0.07, 1); + + } else { + c_bg = Color(0.9, 0.45, 0.075, 0.5); + c_border = Color(0.9, 0.45, 0.075); + } } Vector<Vector2> polygon; Vector<Color> colors; @@ -1892,14 +2412,16 @@ void TileSetEditor::draw_polygon_shapes() { colors.push_back(c_bg); } } else { - for (int j = 0; j < shape->get_points().size(); j++) { - polygon.push_back(shape->get_points()[j] + anchor); + for (int j = 0; j < _get_collision_shape_points(shape).size(); j++) { + polygon.push_back(_get_collision_shape_points(shape)[j] + anchor); colors.push_back(c_bg); } } - if (polygon.size() > 2) { - workspace->draw_polygon(polygon, colors); - } + + if (polygon.size() < 3) + continue; + + workspace->draw_polygon(polygon, colors); if (coord == edited_shape_coord || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (!creating_shape) { @@ -1940,10 +2462,12 @@ void TileSetEditor::draw_polygon_shapes() { workspace->draw_polygon(polygon, colors); if (!creating_shape) { - for (int j = 0; j < polygon.size() - 1; j++) { - workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); + if (polygon.size() > 1) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1, true); + } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); } - workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1, true); } if (shape == edited_occlusion_shape) { draw_handles = true; @@ -2110,11 +2634,11 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { if (current_shape.size() >= 3) { Ref<ConvexPolygonShape2D> shape = memnew(ConvexPolygonShape2D); - Vector<Vector2> segments; + Vector<Vector2> points; float p_total = 0; for (int i = 0; i < current_shape.size(); i++) { - segments.push_back(current_shape[i] - shape_anchor); + points.push_back(current_shape[i] - shape_anchor); if (i != current_shape.size() - 1) p_total += ((current_shape[i + 1].x - current_shape[i].x) * (-current_shape[i + 1].y + (-current_shape[i].y))); @@ -2123,9 +2647,9 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } if (p_total < 0) - segments.invert(); + points.invert(); - shape->set_points(segments); + shape->set_points(points); undo_redo->create_action(TTR("Create Collision Polygon")); // Necessary to get the version that returns a Array instead of a Vector. @@ -2210,6 +2734,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } void TileSetEditor::select_coord(const Vector2 &coord) { + _update_tile_data(); current_shape = PoolVector2Array(); if (get_current_tile() == -1) return; @@ -2217,7 +2742,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_tile_region.position += WORKSPACE_MARGIN; if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) - edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0); + _set_edited_collision_shape(tileset->tile_get_shape(get_current_tile(), 0)); if (edited_occlusion_shape != tileset->tile_get_light_occluder(get_current_tile())) edited_occlusion_shape = tileset->tile_get_light_occluder(get_current_tile()); if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) @@ -2226,8 +2751,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { - for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); + for (int i = 0; i < _get_edited_shape_points().size(); i++) { + current_shape.push_back(_get_edited_shape_points()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_OCCLUSION) { @@ -2254,13 +2779,13 @@ void TileSetEditor::select_coord(const Vector2 &coord) { for (int i = 0; i < sd.size(); i++) { if (sd[i].autotile_coord == coord) { if (edited_collision_shape != sd[i].shape) - edited_collision_shape = sd[i].shape; + _set_edited_collision_shape(sd[i].shape); found_collision_shape = true; break; } } if (!found_collision_shape) - edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); + _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(NULL)); if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord)) edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), coord); if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord)) @@ -2275,8 +2800,8 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { - for (int j = 0; j < edited_collision_shape->get_points().size(); j++) { - current_shape.push_back(edited_collision_shape->get_points()[j] + shape_anchor); + for (int j = 0; j < _get_edited_shape_points().size(); j++) { + current_shape.push_back(_get_edited_shape_points()[j] + shape_anchor); } } } else if (edit_mode == EDITMODE_OCCLUSION) { @@ -2397,7 +2922,8 @@ void TileSetEditor::update_texture_list_icon() { for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) { RID rid = texture_list->get_item_metadata(current_idx); texture_list->set_item_icon(current_idx, texture_map[rid]); - texture_list->set_item_icon_region(current_idx, Rect2(0, 0, 150, 100)); + Size2 texture_size = texture_map[rid]->get_size(); + texture_list->set_item_icon_region(current_idx, Rect2(0, 0, MIN(texture_size.x, 150), MIN(texture_size.y, 100))); } texture_list->update(); } @@ -2410,10 +2936,14 @@ void TileSetEditor::update_workspace_tile_mode() { for (int i = 1; i < WORKSPACE_MODE_MAX; i++) { tool_workspacemode[i]->set_disabled(true); } + tools[SELECT_NEXT]->set_disabled(true); + tools[SELECT_PREVIOUS]->set_disabled(true); } else { for (int i = 1; i < WORKSPACE_MODE_MAX; i++) { tool_workspacemode[i]->set_disabled(false); } + tools[SELECT_NEXT]->set_disabled(false); + tools[SELECT_PREVIOUS]->set_disabled(false); } if (workspace_mode != WORKSPACE_EDIT) { @@ -2431,7 +2961,7 @@ void TileSetEditor::update_workspace_tile_mode() { for (int i = 0; i < EDITMODE_MAX; i++) { tool_editmode[i]->hide(); } - for (int i = 0; i < ZOOM_OUT; i++) { + for (int i = TOOL_SELECT; i < ZOOM_OUT; i++) { tools[i]->hide(); } @@ -2479,6 +3009,26 @@ void TileSetEditor::update_workspace_tile_mode() { _on_edit_mode_changed(edit_mode); } +void TileSetEditor::update_workspace_minsize() { + Size2 workspace_min_size = get_current_texture()->get_size(); + RID current_texture_rid = get_current_texture()->get_rid(); + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + if (tileset->tile_get_texture(E->get())->get_rid() == current_texture_rid) { + Rect2i region = tileset->tile_get_region(E->get()); + if (region.position.x + region.size.x > workspace_min_size.x) + workspace_min_size.x = region.position.x + region.size.x; + if (region.position.y + region.size.y > workspace_min_size.y) + workspace_min_size.y = region.position.y + region.size.y; + } + } + + workspace->set_custom_minimum_size(workspace_min_size + WORKSPACE_MARGIN * 2); + workspace_container->set_custom_minimum_size(workspace_min_size + WORKSPACE_MARGIN * 2); + workspace_overlay->set_custom_minimum_size(workspace_min_size + WORKSPACE_MARGIN * 2); +} + void TileSetEditor::update_edited_region(const Vector2 &end_point) { edited_region = Rect2(region_from, Size2()); if (tools[TOOL_GRID_SNAP]->is_pressed()) { @@ -2511,6 +3061,11 @@ void TileSetEditor::set_current_tile(int p_id) { helper->_change_notify(""); select_coord(Vector2(0, 0)); update_workspace_tile_mode(); + if (p_id == -1) { + editor->get_inspector()->edit(tileset.ptr()); + } else { + editor->get_inspector()->edit(helper); + } } } @@ -2548,20 +3103,20 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value tileset_editor->_set_snap_sep(snap); return true; } else if (p_name.operator String().left(5) == "tile_") { - String name = p_name.operator String().right(5); + String name2 = p_name.operator String().right(5); bool v = false; if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) return false; - if (name == "autotile_bitmask_mode") { + if (name2 == "autotile_bitmask_mode") { tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); - } else if (name == "subtile_size") { + } else if (name2 == "subtile_size") { tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v); - } else if (name == "subtile_spacing") { + } else if (name2 == "subtile_spacing") { tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v); } else { - tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, p_value, &v); + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name2, p_value, &v); } if (v) { tileset->_change_notify(""); @@ -2572,6 +3127,24 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value } else if (name == "tileset_script") { tileset->set_script(p_value); return true; + } else if (name == "selected_collision_one_way") { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); + for (int index = 0; index < sd.size(); index++) { + if (sd[index].shape == tileset_editor->edited_collision_shape) { + tileset->tile_set_shape_one_way(tileset_editor->get_current_tile(), index, p_value); + return true; + } + } + return false; + } else if (name == "selected_collision_one_way_margin") { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); + for (int index = 0; index < sd.size(); index++) { + if (sd[index].shape == tileset_editor->edited_collision_shape) { + tileset->tile_set_shape_one_way_margin(tileset_editor->get_current_tile(), index, p_value); + return true; + } + } + return false; } tileset_editor->err_dialog->set_text(TTR("This property can't be changed.")); @@ -2614,6 +3187,24 @@ bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const } else if (name == "selected_collision") { r_ret = tileset_editor->edited_collision_shape; v = true; + } else if (name == "selected_collision_one_way") { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); + for (int index = 0; index < sd.size(); index++) { + if (sd[index].shape == tileset_editor->edited_collision_shape) { + r_ret = sd[index].one_way_collision; + v = true; + break; + } + } + } else if (name == "selected_collision_one_way_margin") { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(tileset_editor->get_current_tile()); + for (int index = 0; index < sd.size(); index++) { + if (sd[index].shape == tileset_editor->edited_collision_shape) { + r_ret = sd[index].one_way_collision_margin; + v = true; + break; + } + } } else if (name == "selected_navigation") { r_ret = tileset_editor->edited_navigation_shape; v = true; @@ -2660,6 +3251,10 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const } if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) { p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class())); + if (tileset_editor->edited_collision_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "selected_collision_one_way", PROPERTY_HINT_NONE)); + p_list->push_back(PropertyInfo(Variant::REAL, "selected_collision_one_way_margin", PROPERTY_HINT_NONE)); + } } if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) { p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class())); @@ -2680,13 +3275,13 @@ void TilesetEditorContext::_bind_methods() { TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { tileset_editor = p_tileset_editor; + snap_options_visible = false; } void TileSetEditorPlugin::edit(Object *p_node) { if (Object::cast_to<TileSet>(p_node)) { tileset_editor->edit(Object::cast_to<TileSet>(p_node)); - editor->get_inspector()->edit(tileset_editor->helper); } } @@ -2715,6 +3310,7 @@ Dictionary TileSetEditorPlugin::get_state() const { state["snap_separation"] = tileset_editor->snap_separation; state["snap_enabled"] = tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->is_pressed(); state["keep_inside_tile"] = tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->is_pressed(); + state["show_information"] = tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->is_pressed(); return state; } @@ -2735,11 +3331,18 @@ void TileSetEditorPlugin::set_state(const Dictionary &p_state) { if (state.has("snap_enabled")) { tileset_editor->tools[TileSetEditor::TOOL_GRID_SNAP]->set_pressed(state["snap_enabled"]); + if (tileset_editor->helper) { + tileset_editor->_on_grid_snap_toggled(state["snap_enabled"]); + } } if (state.has("keep_inside_tile")) { tileset_editor->tools[TileSetEditor::SHAPE_KEEP_INSIDE_TILE]->set_pressed(state["keep_inside_tile"]); } + + if (state.has("show_information")) { + tileset_editor->tools[TileSetEditor::VISIBLE_INFO]->set_pressed(state["show_information"]); + } } TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 1a6b51cdd3..2827964592 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -34,6 +34,7 @@ #include "editor/editor_name_dialog.h" #include "editor/editor_node.h" #include "scene/2d/sprite.h" +#include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" @@ -76,11 +77,15 @@ class TileSetEditor : public HSplitContainer { }; enum TileSetTools { + SELECT_PREVIOUS, + SELECT_NEXT, TOOL_SELECT, BITMASK_COPY, BITMASK_PASTE, BITMASK_CLEAR, SHAPE_NEW_POLYGON, + SHAPE_NEW_RECTANGLE, + SHAPE_TOGGLE_TYPE, SHAPE_DELETE, SHAPE_KEEP_INSIDE_TILE, TOOL_GRID_SNAP, @@ -91,6 +96,12 @@ class TileSetEditor : public HSplitContainer { TOOL_MAX }; + struct SubtileData { + Array collisions; + Ref<OccluderPolygon2D> occlusion_shape; + Ref<NavigationPolygon> navigation_shape; + }; + Ref<TileSet> tileset; TilesetEditorContext *helper; EditorNode *editor; @@ -114,13 +125,14 @@ class TileSetEditor : public HSplitContainer { bool draw_edited_region; Vector2 edited_shape_coord; PoolVector2Array current_shape; + Map<Vector2i, SubtileData> current_tile_data; Map<Vector2, uint16_t> bitmask_map_copy; Vector2 snap_step; Vector2 snap_offset; Vector2 snap_separation; - Ref<ConvexPolygonShape2D> edited_collision_shape; + Ref<Shape2D> edited_collision_shape; Ref<OccluderPolygon2D> edited_occlusion_shape; Ref<NavigationPolygon> edited_navigation_shape; @@ -136,6 +148,7 @@ class TileSetEditor : public HSplitContainer { HSeparator *separator_editmode; HBoxContainer *toolbar; ToolButton *tools[TOOL_MAX]; + VSeparator *separator_shape_toggle; VSeparator *separator_bitmask; VSeparator *separator_delete; VSeparator *separator_grid; @@ -187,6 +200,20 @@ private: void _on_priority_changed(float val); void _on_z_index_changed(float val); void _on_grid_snap_toggled(bool p_val); + Vector<Vector2> _get_collision_shape_points(const Ref<Shape2D> &p_shape); + Vector<Vector2> _get_edited_shape_points(); + void _set_edited_shape_points(const Vector<Vector2> points); + void _update_tile_data(); + void _update_toggle_shape_button(); + void _select_next_tile(); + void _select_previous_tile(); + Array _get_tiles_in_current_texture(bool sorted = false); + bool _sort_tiles(Variant p_a, Variant p_b); + void _select_next_subtile(); + void _select_previous_subtile(); + void _select_next_shape(); + void _select_previous_shape(); + void _set_edited_collision_shape(const Ref<Shape2D> &p_shape); void _set_snap_step(Vector2 p_val); void _set_snap_off(Vector2 p_val); void _set_snap_sep(Vector2 p_val); @@ -209,6 +236,7 @@ private: void select_coord(const Vector2 &coord); Vector2 snap_point(const Vector2 &point); void update_workspace_tile_mode(); + void update_workspace_minsize(); void update_edited_region(const Vector2 &end_point); int get_current_tile() const; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 628c2f714c..4d8d81fb01 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -344,7 +344,7 @@ void VisualShaderEditor::_update_graph() { 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 c = sb->get_border_color(); 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; @@ -393,7 +393,7 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) { if (node->get_output_port_for_preview() == p_port) { p_port = -1; //toggle it } - undo_redo->create_action("Set Uniform Name"); + undo_redo->create_action(TTR("Set Uniform Name")); undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port); undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", node->get_output_port_for_preview()); undo_redo->add_do_method(this, "_update_graph"); @@ -411,7 +411,7 @@ void VisualShaderEditor::_line_edit_changed(const String &p_text, Object *line_e String validated_name = visual_shader->validate_uniform_name(p_text, node); updating = true; - undo_redo->create_action("Set Uniform Name"); + undo_redo->create_action(TTR("Set Uniform Name")); undo_redo->add_do_method(node.ptr(), "set_uniform_name", validated_name); undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name()); undo_redo->add_do_method(this, "_update_graph"); @@ -436,7 +436,7 @@ void VisualShaderEditor::_port_edited() { Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node); ERR_FAIL_COND(!vsn.is_valid()); - undo_redo->create_action("Set Input Default Port"); + undo_redo->create_action(TTR("Set Input Default Port")); undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value); undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port)); undo_redo->add_do_method(this, "_update_graph"); @@ -487,7 +487,7 @@ void VisualShaderEditor::_add_node(int p_idx) { int id_to_use = visual_shader->get_valid_node_id(type); - undo_redo->create_action("Add Node to Visual Shader"); + undo_redo->create_action(TTR("Add Node to Visual Shader")); undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use); undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use); undo_redo->add_do_method(this, "_update_graph"); @@ -500,7 +500,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); updating = true; - undo_redo->create_action("Node Moved"); + undo_redo->create_action(TTR("Node Moved")); undo_redo->add_do_method(visual_shader.ptr(), "set_node_position", type, p_node, p_to); undo_redo->add_undo_method(visual_shader.ptr(), "set_node_position", type, p_node, p_from); undo_redo->add_do_method(this, "_update_graph"); @@ -521,7 +521,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in return; } - undo_redo->create_action("Nodes Connected"); + undo_redo->create_action(TTR("Nodes Connected")); List<VisualShader::Connection> conns; visual_shader->get_node_connections(type, &conns); @@ -550,7 +550,7 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from int to = p_to.to_int(); //updating = true; seems graph edit can handle this, no need to protect - undo_redo->create_action("Nodes Disconnected"); + undo_redo->create_action(TTR("Nodes Disconnected")); undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->add_do_method(this, "_update_graph"); @@ -566,7 +566,7 @@ void VisualShaderEditor::_delete_request(int which) { VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); - undo_redo->create_action("Delete Node"); + undo_redo->create_action(TTR("Delete Node")); undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, which); undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, which), visual_shader->get_node_position(type, which), which); @@ -671,7 +671,7 @@ void VisualShaderEditor::_duplicate_nodes() { if (nodes.empty()) return; - undo_redo->create_action("Duplicate Nodes"); + undo_redo->create_action(TTR("Duplicate Nodes")); int base_id = visual_shader->get_valid_node_id(type); int id_from = base_id; @@ -732,7 +732,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St bool type_changed = input->get_input_type_by_name(name) != input->get_input_type_by_name(prev_name); UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); - undo_redo->create_action("Visual Shader Input Type Changed"); + undo_redo->create_action(TTR("Visual Shader Input Type Changed")); undo_redo->add_do_method(input.ptr(), "set_input_name", name); undo_redo->add_undo_method(input.ptr(), "set_input_name", prev_name); @@ -972,7 +972,7 @@ public: UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); updating = true; - undo_redo->create_action("Edit Visual Property: " + prop, UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Edit Visual Property") + ": " + prop, UndoRedo::MERGE_ENDS); undo_redo->add_do_property(node.ptr(), prop, p_value); undo_redo->add_undo_property(node.ptr(), prop, node->get(prop)); undo_redo->commit_action(); @@ -1093,7 +1093,7 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { return; UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); - undo_redo->create_action("Visual Shader Mode Changed"); + undo_redo->create_action(TTR("Visual Shader Mode Changed")); //do is easy undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which); undo_redo->add_undo_method(visual_shader.ptr(), "set_mode", visual_shader->get_mode()); @@ -1116,8 +1116,8 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { VisualShader::Type type = VisualShader::Type(i); Vector<int> nodes = visual_shader->get_node_list(type); - for (int i = 0; i < nodes.size(); i++) { - Ref<VisualShaderNodeInput> input = visual_shader->get_node(type, nodes[i]); + for (int j = 0; j < nodes.size(); j++) { + Ref<VisualShaderNodeInput> input = visual_shader->get_node(type, nodes[j]); if (!input.is_valid()) { continue; } |