diff options
Diffstat (limited to 'editor/plugins')
128 files changed, 13920 insertions, 12598 deletions
diff --git a/editor/plugins/SCsub b/editor/plugins/SCsub index 2b1e889fb0..359d04e5df 100644 --- a/editor/plugins/SCsub +++ b/editor/plugins/SCsub @@ -1,5 +1,5 @@ #!/usr/bin/env python -Import('env') +Import("env") env.add_source_files(env.editor_sources, "*.cpp") diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index c8a36a3a99..7a3fb1ff52 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -31,135 +31,89 @@ #include "abstract_polygon_2d_editor.h" #include "canvas_item_editor_plugin.h" +#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" -AbstractPolygon2DEditor::Vertex::Vertex() : - polygon(-1), - vertex(-1) { - // invalid vertex -} - -AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex) : - polygon(-1), - vertex(p_vertex) { - // vertex p_vertex of current wip polygon -} - -AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex) : - polygon(p_polygon), - vertex(p_vertex) { - // vertex p_vertex of polygon p_polygon -} - bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const { - return polygon == p_vertex.polygon && vertex == p_vertex.vertex; } bool AbstractPolygon2DEditor::Vertex::operator!=(const AbstractPolygon2DEditor::Vertex &p_vertex) const { - return !(*this == p_vertex); } bool AbstractPolygon2DEditor::Vertex::valid() const { - return vertex >= 0; } -AbstractPolygon2DEditor::PosVertex::PosVertex() { - // invalid vertex -} - -AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) : - Vertex(p_vertex.polygon, p_vertex.vertex), - pos(p_pos) { -} - -AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) : - Vertex(p_polygon, p_vertex), - pos(p_pos) { -} - bool AbstractPolygon2DEditor::_is_empty() const { - - if (!_get_node()) + if (!_get_node()) { return true; + } const int n = _get_polygon_count(); for (int i = 0; i < n; i++) { - Vector<Vector2> vertices = _get_polygon(i); - if (vertices.size() != 0) + if (vertices.size() != 0) { return false; + } } return true; } bool AbstractPolygon2DEditor::_is_line() const { - return false; } bool AbstractPolygon2DEditor::_has_uv() const { - return false; } int AbstractPolygon2DEditor::_get_polygon_count() const { - return 1; } Variant AbstractPolygon2DEditor::_get_polygon(int p_idx) const { - return _get_node()->get("polygon"); } void AbstractPolygon2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { - _get_node()->set("polygon", p_polygon); } void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { - Node2D *node = _get_node(); undo_redo->add_do_method(node, "set_polygon", p_polygon); undo_redo->add_undo_method(node, "set_polygon", p_previous); } Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const { - return Vector2(0, 0); } void AbstractPolygon2DEditor::_commit_action() { - undo_redo->add_do_method(canvas_item_editor, "update_viewport"); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); undo_redo->commit_action(); } void AbstractPolygon2DEditor::_action_add_polygon(const Variant &p_polygon) { - _action_set_polygon(0, p_polygon); } void AbstractPolygon2DEditor::_action_remove_polygon(int p_idx) { - - _action_set_polygon(p_idx, _get_polygon(p_idx), PoolVector<Vector2>()); + _action_set_polygon(p_idx, _get_polygon(p_idx), Vector<Vector2>()); } void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_polygon) { - _action_set_polygon(p_idx, _get_polygon(p_idx), p_polygon); } bool AbstractPolygon2DEditor::_has_resource() const { - return true; } @@ -167,18 +121,14 @@ void AbstractPolygon2DEditor::_create_resource() { } void AbstractPolygon2DEditor::_menu_option(int p_option) { - switch (p_option) { - case MODE_CREATE: { - mode = MODE_CREATE; button_create->set_pressed(true); button_edit->set_pressed(false); button_delete->set_pressed(false); } break; case MODE_EDIT: { - _wip_close(); mode = MODE_EDIT; button_create->set_pressed(false); @@ -186,7 +136,6 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) { button_delete->set_pressed(false); } break; case MODE_DELETE: { - _wip_close(); mode = MODE_DELETE; button_create->set_pressed(false); @@ -197,28 +146,24 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) { } void AbstractPolygon2DEditor::_notification(int p_what) { - switch (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")); + button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons")); + button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons")); + button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons")); button_edit->set_pressed(true); - get_tree()->connect("node_removed", this, "_node_removed"); - create_resource->connect("confirmed", this, "_create_resource"); + get_tree()->connect("node_removed", callable_mp(this, &AbstractPolygon2DEditor::_node_removed)); + create_resource->connect("confirmed", callable_mp(this, &AbstractPolygon2DEditor::_create_resource)); } break; } } void AbstractPolygon2DEditor::_node_removed(Node *p_node) { - if (p_node == _get_node()) { - edit(NULL); + edit(nullptr); hide(); canvas_item_editor->update_viewport(); @@ -226,14 +171,12 @@ void AbstractPolygon2DEditor::_node_removed(Node *p_node) { } void AbstractPolygon2DEditor::_wip_changed() { - if (wip_active && _is_line()) { _set_polygon(0, wip); } } void AbstractPolygon2DEditor::_wip_cancel() { - wip.clear(); wip_active = false; @@ -245,23 +188,21 @@ void AbstractPolygon2DEditor::_wip_cancel() { } void AbstractPolygon2DEditor::_wip_close() { - if (!wip_active) + if (!wip_active) { return; + } if (_is_line()) { - _set_polygon(0, wip); } else if (wip.size() >= (_is_line() ? 2 : 3)) { - undo_redo->create_action(TTR("Create Polygon")); _action_add_polygon(wip); if (_has_uv()) { - undo_redo->add_do_method(_get_node(), "set_uv", PoolVector<Vector2>()); + undo_redo->add_do_method(_get_node(), "set_uv", Vector<Vector2>()); undo_redo->add_undo_method(_get_node(), "set_uv", _get_node()->get("uv")); } _commit_action(); } else { - return; } @@ -279,7 +220,6 @@ void AbstractPolygon2DEditor::_wip_close() { } void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_reason) { - _polygon_editing_enabled = !p_disable; button_create->set_disabled(p_disable); @@ -287,12 +227,10 @@ void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_r 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.")); @@ -300,27 +238,26 @@ void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_r } bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { - - if (!_get_node() || !_polygon_editing_enabled) + if (!_get_node() || !_polygon_editing_enabled) { return false; + } Ref<InputEventMouseButton> mb = p_event; if (!_has_resource()) { - if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { create_resource->set_text(String("No polygon resource on this node.\nCreate and assign one?")); - create_resource->popup_centered_minsize(); + create_resource->popup_centered(); } return (mb.is_valid() && mb->get_button_index() == 1); } CanvasItemEditor::Tool tool = CanvasItemEditor::get_singleton()->get_current_tool(); - if (tool != CanvasItemEditor::TOOL_SELECT) + if (tool != CanvasItemEditor::TOOL_SELECT) { return false; + } if (mb.is_valid()) { - Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); Vector2 gpoint = mb->get_position(); @@ -329,17 +266,16 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) { if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { - if (mb->get_control() || mb->get_shift() || mb->get_alt()) + if (mb->get_control() || mb->get_shift() || mb->get_alt()) { return false; + } const PosVertex insert = closest_edge_point(gpoint); if (insert.valid()) { - Vector<Vector2> vertices = _get_polygon(insert.polygon); if (vertices.size() < (_is_line() ? 2 : 3)) { - vertices.push_back(cpoint); undo_redo->create_action(TTR("Edit Polygon")); selected_point = Vertex(insert.polygon, vertices.size()); @@ -347,12 +283,11 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) _commit_action(); return true; } else { - Vector<Vector2> vertices2 = _get_polygon(insert.polygon); pre_move_edit = vertices2; edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos)); vertices2.insert(edited_point.vertex, edited_point.pos); - selected_point = edited_point; + selected_point = Vertex(edited_point.polygon, edited_point.vertex); edge_point = PosVertex(); undo_redo->create_action(TTR("Insert Point")); @@ -361,12 +296,10 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return true; } } else { - //look for points to move const PosVertex closest = closest_point(gpoint); if (closest.valid()) { - pre_move_edit = _get_polygon(closest.polygon); edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos)); selected_point = closest; @@ -374,14 +307,11 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) canvas_item_editor->update_viewport(); return true; } else { - selected_point = Vertex(); } } } else { - if (edited_point.valid()) { - //apply Vector<Vector2> vertices = _get_polygon(edited_point.polygon); @@ -397,23 +327,18 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) } } } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) { - const PosVertex closest = closest_point(gpoint); if (closest.valid()) { - remove_point(closest); return true; } } } else if (mode == MODE_DELETE) { - if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - const PosVertex closest = closest_point(gpoint); if (closest.valid()) { - remove_point(closest); return true; } @@ -421,11 +346,8 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) } if (mode == MODE_CREATE) { - if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - if (_is_line()) { - // for lines, we don't have a wip mode, and we can undo each single add point. Vector<Vector2> vertices = _get_polygon(0); vertices.push_back(cpoint); @@ -434,7 +356,6 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) _commit_action(); return true; } else if (!wip_active) { - wip.clear(); wip.push_back(cpoint); wip_active = true; @@ -446,16 +367,14 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) edge_point = PosVertex(); return true; } else { - const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); - if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) { + if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(xform.xform(cpoint)) < grab_threshold) { //wip closed _wip_close(); return true; } else { - //add wip point wip.push_back(cpoint); _wip_changed(); @@ -474,11 +393,9 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - Vector2 gpoint = mm->get_position(); if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) { - Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint))); //Move the point in a single axis. Should only work when editing a polygon and while holding shift. @@ -494,7 +411,6 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) edited_point = PosVertex(edited_point, cpoint); if (!wip_active) { - Vector<Vector2> vertices = _get_polygon(edited_point.polygon); ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false); vertices.write[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon); @@ -503,25 +419,20 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) canvas_item_editor->update_viewport(); } else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) { - const PosVertex onEdgeVertex = closest_edge_point(gpoint); if (onEdgeVertex.valid()) { - hover_point = Vertex(); edge_point = onEdgeVertex; canvas_item_editor->update_viewport(); } else { - if (edge_point.valid()) { - edge_point = PosVertex(); canvas_item_editor->update_viewport(); } const PosVertex new_hover_point = closest_point(gpoint); if (hover_point != new_hover_point) { - hover_point = new_hover_point; canvas_item_editor->update_viewport(); } @@ -532,13 +443,9 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Ref<InputEventKey> k = p_event; if (k.is_valid() && k->is_pressed()) { - - if (k->get_scancode() == KEY_DELETE || k->get_scancode() == KEY_BACKSPACE) { - + if (k->get_keycode() == KEY_DELETE || k->get_keycode() == KEY_BACKSPACE) { if (wip_active && selected_point.polygon == -1) { - if (wip.size() > selected_point.vertex) { - wip.remove(selected_point.vertex); _wip_changed(); selected_point = wip.size() - 1; @@ -546,19 +453,16 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) return true; } } else { - const Vertex active_point = get_active_point(); if (active_point.valid()) { - remove_point(active_point); return true; } } - } else if (wip_active && k->get_scancode() == KEY_ENTER) { - + } else if (wip_active && k->get_keycode() == KEY_ENTER) { _wip_close(); - } else if (wip_active && k->get_scancode() == KEY_ESCAPE) { + } else if (wip_active && k->get_keycode() == KEY_ESCAPE) { _wip_cancel(); } } @@ -567,44 +471,41 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) } void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - - if (!_get_node()) + if (!_get_node()) { return; + } Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); // All polygon points are sharp, so use the sharp handle icon - const Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); + const Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons"); const Vertex active_point = get_active_point(); const int n_polygons = _get_polygon_count(); const bool is_closed = !_is_line(); for (int j = -1; j < n_polygons; j++) { - - if (wip_active && wip_destructive && j != -1) + if (wip_active && wip_destructive && j != -1) { continue; + } - PoolVector<Vector2> points; + Vector<Vector2> points; Vector2 offset; if (wip_active && j == edited_point.polygon) { - points = Variant(wip); offset = Vector2(0, 0); } else { - - if (j == -1) + if (j == -1) { continue; + } points = _get_polygon(j); offset = _get_offset(j); } if (!wip_active && j == edited_point.polygon && EDITOR_GET("editors/poly_editor/show_previous_outline")) { - const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color(); const int n = pre_move_edit.size(); for (int i = 0; i < n - (is_closed ? 0 : 1); i++) { - Vector2 p, p2; p = pre_move_edit[i] + offset; p2 = pre_move_edit[(i + 1) % n] + offset; @@ -612,7 +513,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl Vector2 point = xform.xform(p); Vector2 next_point = xform.xform(p2); - p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE), true); + p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE)); } } @@ -620,28 +521,26 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl const Color col = Color(1, 0.3, 0.1, 0.8); for (int i = 0; i < n_points; i++) { - const Vertex vertex(j, i); const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset); const Vector2 point = xform.xform(p); if (is_closed || i < n_points - 1) { - Vector2 p2; if (j == edited_point.polygon && - ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex))) + ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex))) { p2 = edited_point.pos; - else + } else { p2 = points[(i + 1) % n_points] + offset; + } const Vector2 next_point = xform.xform(p2); - p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE), true); + p_overlay->draw_line(point, next_point, col, Math::round(2 * EDSCALE)); } } for (int i = 0; i < n_points; i++) { - const Vertex vertex(j, i); const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset); @@ -651,7 +550,7 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate); if (vertex == hover_point) { - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_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)); @@ -660,26 +559,25 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl } if (edge_point.valid()) { - - Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons"); + Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons"); p_overlay->draw_texture(add_handle, edge_point.pos - add_handle->get_size() * 0.5); } } void AbstractPolygon2DEditor::edit(Node *p_polygon) { - - if (!canvas_item_editor) + if (!canvas_item_editor) { canvas_item_editor = CanvasItemEditor::get_singleton(); + } if (p_polygon) { - _set_node(p_polygon); // Enable the pencil tool if the polygon is empty. - if (_is_empty()) + if (_is_empty()) { _menu_option(MODE_CREATE); - else + } else { _menu_option(MODE_EDIT); + } wip.clear(); wip_active = false; @@ -689,51 +587,43 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) { canvas_item_editor->update_viewport(); } else { - - _set_node(NULL); + _set_node(nullptr); } } void AbstractPolygon2DEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_node_removed"), &AbstractPolygon2DEditor::_node_removed); - ClassDB::bind_method(D_METHOD("_menu_option"), &AbstractPolygon2DEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_create_resource"), &AbstractPolygon2DEditor::_create_resource); } void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) { - - PoolVector<Vector2> vertices = _get_polygon(p_vertex.polygon); + Vector<Vector2> vertices = _get_polygon(p_vertex.polygon); if (vertices.size() > (_is_line() ? 2 : 3)) { - vertices.remove(p_vertex.vertex); undo_redo->create_action(TTR("Edit Polygon (Remove Point)")); _action_set_polygon(p_vertex.polygon, vertices); _commit_action(); } else { - undo_redo->create_action(TTR("Remove Polygon And Point")); _action_remove_polygon(p_vertex.polygon); _commit_action(); } - if (_is_empty()) + if (_is_empty()) { _menu_option(MODE_CREATE); + } hover_point = Vertex(); - if (selected_point == p_vertex) + if (selected_point == p_vertex) { selected_point = Vertex(); + } } AbstractPolygon2DEditor::Vertex AbstractPolygon2DEditor::get_active_point() const { - return hover_point.valid() ? hover_point : selected_point; } AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const Vector2 &p_pos) const { - const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); const int n_polygons = _get_polygon_count(); @@ -743,13 +633,11 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const real_t closest_dist = 1e10; for (int j = 0; j < n_polygons; j++) { - - PoolVector<Vector2> points = _get_polygon(j); + Vector<Vector2> points = _get_polygon(j); const Vector2 offset = _get_offset(j); const int n_points = points.size(); for (int i = 0; i < n_points; i++) { - Vector2 cp = xform.xform(points[i] + offset); real_t d = cp.distance_to(p_pos); @@ -764,7 +652,6 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_point(const } AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(const Vector2 &p_pos) const { - const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); const real_t eps = grab_threshold * 2; const real_t eps2 = eps * eps; @@ -776,21 +663,20 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c real_t closest_dist = 1e10; for (int j = 0; j < n_polygons; j++) { - - PoolVector<Vector2> points = _get_polygon(j); + Vector<Vector2> points = _get_polygon(j); const Vector2 offset = _get_offset(j); const int n_points = points.size(); const int n_segments = n_points - (_is_line() ? 1 : 0); for (int i = 0; i < n_segments; i++) { - Vector2 segment[2] = { xform.xform(points[i] + offset), xform.xform(points[(i + 1) % n_points] + offset) }; - Vector2 cp = Geometry::get_closest_point_to_segment_2d(p_pos, segment); + Vector2 cp = Geometry2D::get_closest_point_to_segment(p_pos, segment); - if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2) + if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2) { continue; //not valid to reuse point + } real_t d = cp.distance_to(p_pos); if (d < closest_dist && d < grab_threshold) { @@ -804,8 +690,7 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c } AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive) { - - canvas_item_editor = NULL; + canvas_item_editor = nullptr; editor = p_editor; undo_redo = EditorNode::get_undo_redo(); @@ -818,19 +703,22 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi edge_point = PosVertex(); add_child(memnew(VSeparator)); - button_create = memnew(ToolButton); + button_create = memnew(Button); + button_create->set_flat(true); add_child(button_create); - button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE)); + button_create->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_CREATE)); button_create->set_toggle_mode(true); - button_edit = memnew(ToolButton); + button_edit = memnew(Button); + button_edit->set_flat(true); add_child(button_edit); - button_edit->connect("pressed", this, "_menu_option", varray(MODE_EDIT)); + button_edit->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_EDIT)); button_edit->set_toggle_mode(true); - button_delete = memnew(ToolButton); + button_delete = memnew(Button); + button_delete->set_flat(true); add_child(button_delete); - button_delete->connect("pressed", this, "_menu_option", varray(MODE_DELETE)); + button_delete->connect("pressed", callable_mp(this, &AbstractPolygon2DEditor::_menu_option), varray(MODE_DELETE)); button_delete->set_toggle_mode(true); create_resource = memnew(ConfirmationDialog); @@ -841,24 +729,19 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi } void AbstractPolygon2DEditorPlugin::edit(Object *p_object) { - polygon_editor->edit(Object::cast_to<Node>(p_object)); } bool AbstractPolygon2DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class(klass); } void AbstractPolygon2DEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - polygon_editor->show(); } else { - polygon_editor->hide(); - polygon_editor->edit(NULL); + polygon_editor->edit(nullptr); } } diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 6ed6d0a257..527803150d 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -34,36 +34,41 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "scene/2d/polygon_2d.h" -#include "scene/gui/tool_button.h" class CanvasItemEditor; class AbstractPolygon2DEditor : public HBoxContainer { - GDCLASS(AbstractPolygon2DEditor, HBoxContainer); - ToolButton *button_create; - ToolButton *button_edit; - ToolButton *button_delete; + Button *button_create; + Button *button_edit; + Button *button_delete; struct Vertex { - Vertex(); - Vertex(int p_vertex); - Vertex(int p_polygon, int p_vertex); + Vertex() {} + Vertex(int p_vertex) : + vertex(p_vertex) {} + Vertex(int p_polygon, int p_vertex) : + polygon(p_polygon), + vertex(p_vertex) {} bool operator==(const Vertex &p_vertex) const; bool operator!=(const Vertex &p_vertex) const; bool valid() const; - int polygon; - int vertex; + int polygon = -1; + int vertex = -1; }; struct PosVertex : public Vertex { - PosVertex(); - PosVertex(const Vertex &p_vertex, const Vector2 &p_pos); - PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos); + PosVertex() {} + PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) : + Vertex(p_vertex.polygon, p_vertex.vertex), + pos(p_pos) {} + PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) : + Vertex(p_polygon, p_vertex), + pos(p_pos) {} Vector2 pos; }; @@ -144,7 +149,6 @@ public: }; class AbstractPolygon2DEditorPlugin : public EditorPlugin { - GDCLASS(AbstractPolygon2DEditorPlugin, EditorPlugin); AbstractPolygon2DEditor *polygon_editor; @@ -152,14 +156,14 @@ class AbstractPolygon2DEditorPlugin : public EditorPlugin { String klass; public: - virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return polygon_editor->forward_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { polygon_editor->forward_canvas_draw_over_viewport(p_overlay); } - - bool has_main_screen() const { return false; } - virtual String get_name() const { return klass; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); + virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return polygon_editor->forward_gui_input(p_event); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { polygon_editor->forward_canvas_draw_over_viewport(p_overlay); } + + bool has_main_screen() const override { return false; } + virtual String get_name() const override { return klass; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; AbstractPolygon2DEditorPlugin(EditorNode *p_node, AbstractPolygon2DEditor *p_polygon_editor, String p_class); ~AbstractPolygon2DEditorPlugin(); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index d743d1ac2f..d335b29c2f 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -42,7 +42,7 @@ StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; - if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) { if (selected_point != -1) { _erase_selected(); accept_event(); @@ -73,7 +73,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven ap->get_animation_list(&names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); + animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get()); animations_to_add.push_back(E->get()); } } @@ -81,8 +81,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { String name = String(E->get()).replace_first("AnimationNode", ""); - if (name == "Animation") + if (name == "Animation") { continue; + } int idx = menu->get_item_count(); menu->add_item(vformat("Add %s", name), idx); @@ -97,7 +98,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven menu->add_separator(); menu->add_item(TTR("Load..."), MENU_LOAD_FILE); - menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); + menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position())); menu->popup(); add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x; @@ -117,7 +118,6 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven _update_tool_erase(); for (int i = 0; i < points.size(); i++) { - if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) { selected_point = i; @@ -196,19 +196,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven } void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { - - Color linecolor = get_color("font_color", "Label"); + Color linecolor = get_theme_color("font_color", "Label"); Color linecolor_soft = linecolor; linecolor_soft.a *= 0.5; - Ref<Font> font = get_font("font", "Label"); - Ref<Texture> icon = get_icon("KeyValue", "EditorIcons"); - Ref<Texture> icon_selected = get_icon("KeySelected", "EditorIcons"); + Ref<Font> font = get_theme_font("font", "Label"); + Ref<Texture2D> icon = get_theme_icon("KeyValue", "EditorIcons"); + Ref<Texture2D> icon_selected = get_theme_icon("KeySelected", "EditorIcons"); Size2 s = blend_space_draw->get_size(); if (blend_space_draw->has_focus()) { - Color color = get_color("accent_color", "Editor"); + Color color = get_theme_color("accent_color", "Editor"); blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); } @@ -227,7 +226,6 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { } if (snap->is_pressed()) { - linecolor_soft.a = linecolor.a * 0.1; if (blend_space->get_snap() > 0) { @@ -280,7 +278,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { { Color color; if (tool_blend->is_pressed()) { - color = get_color("accent_color", "Editor"); + color = get_theme_color("accent_color", "Editor"); } else { color = linecolor; color.a *= 0.5; @@ -303,9 +301,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { } void AnimationNodeBlendSpace1DEditor::_update_space() { - - if (updating) + if (updating) { return; + } updating = true; @@ -322,8 +320,9 @@ void AnimationNodeBlendSpace1DEditor::_update_space() { } void AnimationNodeBlendSpace1DEditor::_config_changed(double) { - if (updating) + if (updating) { return; + } updating = true; undo_redo->create_action(TTR("Change BlendSpace1D Limits")); @@ -342,8 +341,9 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) { } void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { - if (updating) + if (updating) { return; + } updating = true; undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS); @@ -360,7 +360,6 @@ void AnimationNodeBlendSpace1DEditor::_snap_toggled() { } void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) { - file_loaded = ResourceLoader::load(p_file); if (file_loaded.is_valid()) { _add_menu_type(MENU_LOAD_FILE_CONFIRM); @@ -370,20 +369,18 @@ void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) { void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { Ref<AnimationRootNode> node; if (p_index == MENU_LOAD_FILE) { - open_file->clear_filters(); List<String> filters; ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); for (List<String>::Element *E = filters.front(); E; E = E->next()) { open_file->add_filter("*." + E->get()); } - open_file->popup_centered_ratio(); + open_file->popup_file_dialog(); return; } else if (p_index == MENU_LOAD_FILE_CONFIRM) { node = file_loaded; file_loaded.unref(); } else if (p_index == MENU_PASTE) { - node = EditorSettings::get_singleton()->get_resource_clipboard(); } else { String type = menu->get_item_metadata(p_index); @@ -432,7 +429,6 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { } void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { - if (p_tool == 0) { tool_erase->show(); tool_erase_sep->show(); @@ -446,8 +442,9 @@ void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { } void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { - if (updating) + if (updating) { return; + } if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { float pos = blend_space->get_blend_point_position(selected_point); @@ -467,7 +464,6 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { } void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { - bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count(); tool_erase->set_disabled(!point_valid); @@ -504,8 +500,9 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() { } void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { - if (updating) + if (updating) { return; + } updating = true; undo_redo->create_action(TTR("Move BlendSpace1D Node Point")); @@ -522,7 +519,6 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { } void AnimationNodeBlendSpace1DEditor::_open_editor() { - if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); ERR_FAIL_COND(an.is_null()); @@ -532,15 +528,15 @@ void AnimationNodeBlendSpace1DEditor::_open_editor() { void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); - panel->add_style_override("panel", get_stylebox("bg", "Tree")); - tool_blend->set_icon(get_icon("EditPivot", "EditorIcons")); - tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); - tool_create->set_icon(get_icon("EditKey", "EditorIcons")); - tool_erase->set_icon(get_icon("Remove", "EditorIcons")); - snap->set_icon(get_icon("SnapGrid", "EditorIcons")); - open_editor->set_icon(get_icon("Edit", "EditorIcons")); + error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); + panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + tool_blend->set_icon(get_theme_icon("EditPivot", "EditorIcons")); + tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_theme_icon("EditKey", "EditorIcons")); + tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons")); + snap->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); + open_editor->set_icon(get_theme_icon("Edit", "EditorIcons")); } if (p_what == NOTIFICATION_PROCESS) { @@ -568,35 +564,18 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { } void AnimationNodeBlendSpace1DEditor::_bind_methods() { - ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input); - ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace1DEditor::_blend_space_draw); - ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace1DEditor::_config_changed); - ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace1DEditor::_labels_changed); ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space); - ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace1DEditor::_snap_toggled); - ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace1DEditor::_tool_switch); - ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace1DEditor::_erase_selected); ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase); - ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace1DEditor::_edit_point_pos); - - ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace1DEditor::_add_menu_type); - ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace1DEditor::_add_animation_type); ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos); - - ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor); - - ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace1DEditor::_file_opened); } bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) { - Ref<AnimationNodeBlendSpace1D> b1d = p_node; return b1d.is_valid(); } void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) { - blend_space = p_node; if (!blend_space.is_null()) { @@ -604,7 +583,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) { } } -AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = NULL; +AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr; AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { singleton = this; @@ -616,43 +595,48 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { Ref<ButtonGroup> bg; bg.instance(); - tool_blend = memnew(ToolButton); + tool_blend = memnew(Button); + tool_blend->set_flat(true); tool_blend->set_toggle_mode(true); tool_blend->set_button_group(bg); top_hb->add_child(tool_blend); tool_blend->set_pressed(true); tool_blend->set_tooltip(TTR("Set the blending position within the space")); - tool_blend->connect("pressed", this, "_tool_switch", varray(3)); + tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(3)); - tool_select = memnew(ToolButton); + tool_select = memnew(Button); + tool_select->set_flat(true); tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); top_hb->add_child(tool_select); tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); - tool_select->connect("pressed", this, "_tool_switch", varray(0)); + tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(0)); - tool_create = memnew(ToolButton); + tool_create = memnew(Button); + tool_create->set_flat(true); tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); top_hb->add_child(tool_create); tool_create->set_tooltip(TTR("Create points.")); - tool_create->connect("pressed", this, "_tool_switch", varray(1)); + tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(1)); tool_erase_sep = memnew(VSeparator); top_hb->add_child(tool_erase_sep); - tool_erase = memnew(ToolButton); + tool_erase = memnew(Button); + tool_erase->set_flat(true); top_hb->add_child(tool_erase); tool_erase->set_tooltip(TTR("Erase points.")); - tool_erase->connect("pressed", this, "_erase_selected"); + tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected)); top_hb->add_child(memnew(VSeparator)); - snap = memnew(ToolButton); + snap = memnew(Button); + snap->set_flat(true); snap->set_toggle_mode(true); top_hb->add_child(snap); snap->set_pressed(true); snap->set_tooltip(TTR("Enable snap and show grid.")); - snap->connect("pressed", this, "_snap_toggled"); + snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled)); snap_value = memnew(SpinBox); top_hb->add_child(snap_value); @@ -670,12 +654,12 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { edit_value->set_min(-1000); edit_value->set_max(1000); edit_value->set_step(0.01); - edit_value->connect("value_changed", this, "_edit_point_pos"); + edit_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_pos)); open_editor = memnew(Button); edit_hb->add_child(open_editor); open_editor->set_text(TTR("Open Editor")); - open_editor->connect("pressed", this, "_open_editor", varray(), CONNECT_DEFERRED); + open_editor->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), varray(), CONNECT_DEFERRED); edit_hb->hide(); open_editor->hide(); @@ -691,8 +675,8 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { panel->set_v_size_flags(SIZE_EXPAND_FILL); blend_space_draw = memnew(Control); - blend_space_draw->connect("gui_input", this, "_blend_space_gui_input"); - blend_space_draw->connect("draw", this, "_blend_space_draw"); + blend_space_draw->connect("gui_input", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input)); + blend_space_draw->connect("draw", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_draw)); blend_space_draw->set_focus_mode(FOCUS_ALL); panel->add_child(blend_space_draw); @@ -724,10 +708,10 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { bottom_hb->add_child(max_value); } - snap_value->connect("value_changed", this, "_config_changed"); - min_value->connect("value_changed", this, "_config_changed"); - max_value->connect("value_changed", this, "_config_changed"); - label_value->connect("text_changed", this, "_labels_changed"); + snap_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed)); + min_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed)); + max_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed)); + label_value->connect("text_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_labels_changed)); error_panel = memnew(PanelContainer); add_child(error_panel); @@ -740,18 +724,18 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", this, "_add_menu_type"); + menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type)); animations_menu = memnew(PopupMenu); menu->add_child(animations_menu); animations_menu->set_name("animations"); - animations_menu->connect("index_pressed", this, "_add_animation_type"); + animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_animation_type)); open_file = memnew(EditorFileDialog); add_child(open_file); open_file->set_title(TTR("Open Animation Node")); - open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); - open_file->connect("file_selected", this, "_file_opened"); + open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened)); undo_redo = EditorNode::get_undo_redo(); selected_point = -1; diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index 346ad36cff..5ff5da47c0 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -42,21 +42,20 @@ #include "scene/gui/tree.h" class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { - GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendSpace1D> blend_space; HBoxContainer *goto_parent_hb; - ToolButton *goto_parent; + Button *goto_parent; PanelContainer *panel; - ToolButton *tool_blend; - ToolButton *tool_select; - ToolButton *tool_create; + Button *tool_blend; + Button *tool_select; + Button *tool_create; VSeparator *tool_erase_sep; - ToolButton *tool_erase; - ToolButton *snap; + Button *tool_erase; + Button *snap; SpinBox *snap_value; LineEdit *label_value; @@ -130,8 +129,8 @@ protected: public: static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; } - virtual bool can_edit(const Ref<AnimationNode> &p_node); - virtual void edit(const Ref<AnimationNode> &p_node); + virtual bool can_edit(const Ref<AnimationNode> &p_node) override; + virtual void edit(const Ref<AnimationNode> &p_node) override; AnimationNodeBlendSpace1DEditor(); }; diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index dc7754ba9a..805df0cbb9 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -30,9 +30,9 @@ #include "animation_blend_space_2d_editor.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" -#include "core/math/delaunay.h" -#include "core/os/input.h" +#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/editor_scale.h" @@ -40,10 +40,9 @@ #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) { - Ref<AnimationNodeBlendSpace2D> bs2d = p_node; return bs2d.is_valid(); } @@ -53,14 +52,13 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_changed() { } void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) { - if (blend_space.is_valid()) { - blend_space->disconnect("triangles_updated", this, "_blend_space_changed"); + blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed)); } blend_space = p_node; if (!blend_space.is_null()) { - blend_space->connect("triangles_updated", this, "_blend_space_changed"); + blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed)); _update_space(); } } @@ -71,9 +69,8 @@ StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const { } void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventKey> k = p_event; - if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) { if (selected_point != -1 || selected_triangle != -1) { _erase_selected(); accept_event(); @@ -100,17 +97,17 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven List<StringName> names; ap->get_animation_list(&names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); + animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get()); animations_to_add.push_back(E->get()); } } } for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { - String name = String(E->get()).replace_first("AnimationNode", ""); - if (name == "Animation") + if (name == "Animation") { continue; // nope + } int idx = menu->get_item_count(); menu->add_item(vformat("Add %s", name), idx); menu->set_item_metadata(idx, E->get()); @@ -124,7 +121,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven menu->add_separator(); menu->add_item(TTR("Load..."), MENU_LOAD_FILE); - menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); + menu->set_position(blend_space_draw->get_screen_transform().xform(mb->get_position())); menu->popup(); add_point_pos = (mb->get_position() / blend_space_draw->get_size()); add_point_pos.y = 1.0 - add_point_pos.y; @@ -138,7 +135,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - blend_space_draw->update(); //update anyway //try to see if a point can be selected selected_point = -1; @@ -146,7 +142,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven _update_tool_erase(); for (int i = 0; i < points.size(); i++) { - if (points[i].distance_to(mb->get_position()) < 10 * EDSCALE) { selected_point = i; Ref<AnimationNode> node = blend_space->get_blend_point_node(i); @@ -170,7 +165,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven triangle.push_back(points[idx]); } - if (Geometry::is_point_in_triangle(mb->get_position(), triangle[0], triangle[1], triangle[2])) { + if (Geometry2D::is_point_in_triangle(mb->get_position(), triangle[0], triangle[1], triangle[2])) { selected_triangle = i; _update_tool_erase(); return; @@ -180,15 +175,14 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - blend_space_draw->update(); //update anyway //try to see if a point can be selected selected_point = -1; for (int i = 0; i < points.size(); i++) { - - if (making_triangle.find(i) != -1) + if (making_triangle.find(i) != -1) { continue; + } if (points[i].distance_to(mb->get_position()) < 10 * EDSCALE) { making_triangle.push_back(i); @@ -243,7 +237,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - Vector2 blend_pos = (mb->get_position() / blend_space_draw->get_size()); blend_pos.y = 1.0 - blend_pos.y; blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); @@ -278,7 +271,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) { - Vector2 blend_pos = (mm->get_position() / blend_space_draw->get_size()); blend_pos.y = 1.0 - blend_pos.y; blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); @@ -291,7 +283,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven } void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) { - file_loaded = ResourceLoader::load(p_file); if (file_loaded.is_valid()) { _add_menu_type(MENU_LOAD_FILE_CONFIRM); @@ -299,23 +290,20 @@ void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) { } void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { - Ref<AnimationRootNode> node; if (p_index == MENU_LOAD_FILE) { - open_file->clear_filters(); List<String> filters; ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); for (List<String>::Element *E = filters.front(); E; E = E->next()) { open_file->add_filter("*." + E->get()); } - open_file->popup_centered_ratio(); + open_file->popup_file_dialog(); return; } else if (p_index == MENU_LOAD_FILE_CONFIRM) { node = file_loaded; file_loaded.unref(); } else if (p_index == MENU_PASTE) { - node = EditorSettings::get_singleton()->get_resource_clipboard(); } else { String type = menu->get_item_metadata(p_index); @@ -346,7 +334,6 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { } void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { - Ref<AnimationNodeAnimation> anim; anim.instance(); @@ -405,18 +392,17 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) { } void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { - - Color linecolor = get_color("font_color", "Label"); + Color linecolor = get_theme_color("font_color", "Label"); Color linecolor_soft = linecolor; linecolor_soft.a *= 0.5; - Ref<Font> font = get_font("font", "Label"); - Ref<Texture> icon = get_icon("KeyValue", "EditorIcons"); - Ref<Texture> icon_selected = get_icon("KeySelected", "EditorIcons"); + Ref<Font> font = get_theme_font("font", "Label"); + Ref<Texture2D> icon = get_theme_icon("KeyValue", "EditorIcons"); + Ref<Texture2D> icon_selected = get_theme_icon("KeySelected", "EditorIcons"); Size2 s = blend_space_draw->get_size(); if (blend_space_draw->has_focus()) { - Color color = get_color("accent_color", "Editor"); + Color color = get_theme_color("accent_color", "Editor"); blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); } blend_space_draw->draw_line(Point2(1, 0), Point2(1, s.height - 1), linecolor); @@ -438,14 +424,11 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } if (snap->is_pressed()) { - linecolor_soft.a = linecolor.a * 0.1; if (blend_space->get_snap().x > 0) { - int prev_idx = 0; for (int i = 0; i < s.x; i++) { - float v = blend_space->get_min_space().x + i * (blend_space->get_max_space().x - blend_space->get_min_space().x) / s.x; int idx = int(v / blend_space->get_snap().x); @@ -458,10 +441,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } if (blend_space->get_snap().y > 0) { - int prev_idx = 0; for (int i = 0; i < s.y; i++) { - float v = blend_space->get_max_space().y - i * (blend_space->get_max_space().y - blend_space->get_min_space().y) / s.y; int idx = int(v / blend_space->get_snap().y); @@ -476,7 +457,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { //triangles first for (int i = 0; i < blend_space->get_triangle_count(); i++) { - Vector<Vector2> points; points.resize(3); @@ -497,12 +477,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } for (int j = 0; j < 3; j++) { - blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, 1, true); + blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, 1); } Color color; if (i == selected_triangle) { - color = get_color("accent_color", "Editor"); + color = get_theme_color("accent_color", "Editor"); color.a *= 0.5; } else { color = linecolor; @@ -518,7 +498,6 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { points.clear(); for (int i = 0; i < blend_space->get_blend_point_count(); i++) { - Vector2 point = blend_space->get_blend_point_position(i); if (dragging_selected && selected_point == i) { point += drag_ofs; @@ -553,9 +532,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } for (int i = 0; i < points.size() - 1; i++) { - blend_space_draw->draw_line(points[i], points[i + 1], linecolor, 2, true); + blend_space_draw->draw_line(points[i], points[i + 1], linecolor, 2); } - blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, 2, true); + blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, 2); } ///draw cursor position @@ -563,7 +542,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { { Color color; if (tool_blend->is_pressed()) { - color = get_color("accent_color", "Editor"); + color = get_theme_color("accent_color", "Editor"); } else { color = linecolor; color.a *= 0.5; @@ -597,14 +576,13 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { } void AnimationNodeBlendSpace2DEditor::_snap_toggled() { - blend_space_draw->update(); } void AnimationNodeBlendSpace2DEditor::_update_space() { - - if (updating) + if (updating) { return; + } updating = true; @@ -636,8 +614,9 @@ void AnimationNodeBlendSpace2DEditor::_update_space() { } void AnimationNodeBlendSpace2DEditor::_config_changed(double) { - if (updating) + if (updating) { return; + } updating = true; undo_redo->create_action(TTR("Change BlendSpace2D Limits")); @@ -658,8 +637,9 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) { } void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { - if (updating) + if (updating) { return; + } updating = true; undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS); @@ -674,9 +654,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { } void AnimationNodeBlendSpace2DEditor::_erase_selected() { - if (selected_point != -1) { - updating = true; undo_redo->create_action(TTR("Remove BlendSpace2D Point")); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); @@ -699,7 +677,6 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { blend_space_draw->update(); } else if (selected_triangle != -1) { - updating = true; undo_redo->create_action(TTR("Remove BlendSpace2D Triangle")); undo_redo->add_do_method(blend_space.ptr(), "remove_triangle", selected_triangle); @@ -715,8 +692,9 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { } void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() { - if (updating) + if (updating) { return; + } if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Vector2 pos = blend_space->get_blend_point_position(selected_point); @@ -735,8 +713,9 @@ void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() { } void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { - if (updating) + if (updating) { return; + } updating = true; 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())); @@ -752,27 +731,25 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { } void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); - panel->add_style_override("panel", get_stylebox("bg", "Tree")); - tool_blend->set_icon(get_icon("EditPivot", "EditorIcons")); - tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); - tool_create->set_icon(get_icon("EditKey", "EditorIcons")); - tool_triangle->set_icon(get_icon("ToolTriangle", "EditorIcons")); - tool_erase->set_icon(get_icon("Remove", "EditorIcons")); - snap->set_icon(get_icon("SnapGrid", "EditorIcons")); - open_editor->set_icon(get_icon("Edit", "EditorIcons")); - auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons")); + error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); + panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + tool_blend->set_icon(get_theme_icon("EditPivot", "EditorIcons")); + tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_theme_icon("EditKey", "EditorIcons")); + tool_triangle->set_icon(get_theme_icon("ToolTriangle", "EditorIcons")); + tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons")); + snap->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); + open_editor->set_icon(get_theme_icon("Edit", "EditorIcons")); + auto_triangles->set_icon(get_theme_icon("AutoTriangle", "EditorIcons")); interpolation->clear(); - interpolation->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), "", 0); - interpolation->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), "", 1); - interpolation->add_icon_item(get_icon("TrackCapture", "EditorIcons"), "", 2); + interpolation->add_icon_item(get_theme_icon("TrackContinuous", "EditorIcons"), "", 0); + interpolation->add_icon_item(get_theme_icon("TrackDiscrete", "EditorIcons"), "", 1); + interpolation->add_icon_item(get_theme_icon("TrackCapture", "EditorIcons"), "", 2); } if (p_what == NOTIFICATION_PROCESS) { - String error; if (!AnimationTreeEditor::get_singleton()->get_tree()) { @@ -801,7 +778,6 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { } void AnimationNodeBlendSpace2DEditor::_open_editor() { - if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); ERR_FAIL_COND(an.is_null()); @@ -810,11 +786,10 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() { } void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { - EditorNode::get_singleton()->edit_item(NULL); + EditorNode::get_singleton()->edit_item(nullptr); } void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { - 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()); @@ -824,37 +799,17 @@ void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { } void AnimationNodeBlendSpace2DEditor::_bind_methods() { - - ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace2DEditor::_blend_space_gui_input); - ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace2DEditor::_blend_space_draw); - ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace2DEditor::_config_changed); - ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace2DEditor::_labels_changed); ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace2DEditor::_update_space); - ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace2DEditor::_snap_toggled); - ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace2DEditor::_tool_switch); - ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace2DEditor::_erase_selected); ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace2DEditor::_update_tool_erase); - ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace2DEditor::_edit_point_pos); - - ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace2DEditor::_add_menu_type); - ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace2DEditor::_add_animation_type); ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos); - ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor); - ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph); - - ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled); - ClassDB::bind_method("_blend_space_changed", &AnimationNodeBlendSpace2DEditor::_blend_space_changed); - - ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace2DEditor::_file_opened); } -AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL; +AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = nullptr; AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { - singleton = this; updating = false; @@ -864,59 +819,66 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { Ref<ButtonGroup> bg; bg.instance(); - tool_blend = memnew(ToolButton); + tool_blend = memnew(Button); + tool_blend->set_flat(true); tool_blend->set_toggle_mode(true); tool_blend->set_button_group(bg); top_hb->add_child(tool_blend); tool_blend->set_pressed(true); tool_blend->set_tooltip(TTR("Set the blending position within the space")); - tool_blend->connect("pressed", this, "_tool_switch", varray(3)); + tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(3)); - tool_select = memnew(ToolButton); + tool_select = memnew(Button); + tool_select->set_flat(true); tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); top_hb->add_child(tool_select); tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); - tool_select->connect("pressed", this, "_tool_switch", varray(0)); + tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(0)); - tool_create = memnew(ToolButton); + tool_create = memnew(Button); + tool_create->set_flat(true); tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); top_hb->add_child(tool_create); tool_create->set_tooltip(TTR("Create points.")); - tool_create->connect("pressed", this, "_tool_switch", varray(1)); + tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(1)); - tool_triangle = memnew(ToolButton); + tool_triangle = memnew(Button); + tool_triangle->set_flat(true); tool_triangle->set_toggle_mode(true); tool_triangle->set_button_group(bg); top_hb->add_child(tool_triangle); tool_triangle->set_tooltip(TTR("Create triangles by connecting points.")); - tool_triangle->connect("pressed", this, "_tool_switch", varray(2)); + tool_triangle->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch), varray(2)); tool_erase_sep = memnew(VSeparator); top_hb->add_child(tool_erase_sep); - tool_erase = memnew(ToolButton); + tool_erase = memnew(Button); + tool_erase->set_flat(true); top_hb->add_child(tool_erase); tool_erase->set_tooltip(TTR("Erase points and triangles.")); - tool_erase->connect("pressed", this, "_erase_selected"); + tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_erase_selected)); tool_erase->set_disabled(true); top_hb->add_child(memnew(VSeparator)); - auto_triangles = memnew(ToolButton); + auto_triangles = memnew(Button); + auto_triangles->set_flat(true); top_hb->add_child(auto_triangles); - auto_triangles->connect("pressed", this, "_auto_triangles_toggled"); + auto_triangles->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled)); auto_triangles->set_toggle_mode(true); auto_triangles->set_tooltip(TTR("Generate blend triangles automatically (instead of manually)")); top_hb->add_child(memnew(VSeparator)); - snap = memnew(ToolButton); + snap = memnew(Button); + snap->set_flat(true); snap->set_toggle_mode(true); top_hb->add_child(snap); snap->set_pressed(true); snap->set_tooltip(TTR("Enable snap and show grid.")); - snap->connect("pressed", this, "_snap_toggled"); + snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_snap_toggled)); snap_x = memnew(SpinBox); top_hb->add_child(snap_x); @@ -937,7 +899,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { top_hb->add_child(memnew(Label(TTR("Blend:")))); interpolation = memnew(OptionButton); top_hb->add_child(interpolation); - interpolation->connect("item_selected", this, "_config_changed"); + interpolation->connect("item_selected", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); edit_hb = memnew(HBoxContainer); top_hb->add_child(edit_hb); @@ -948,17 +910,17 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { edit_x->set_min(-1000); edit_x->set_step(0.01); edit_x->set_max(1000); - edit_x->connect("value_changed", this, "_edit_point_pos"); + edit_x->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_edit_point_pos)); edit_y = memnew(SpinBox); edit_hb->add_child(edit_y); edit_y->set_min(-1000); edit_y->set_step(0.01); edit_y->set_max(1000); - edit_y->connect("value_changed", this, "_edit_point_pos"); + edit_y->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_edit_point_pos)); open_editor = memnew(Button); edit_hb->add_child(open_editor); open_editor->set_text(TTR("Open Editor")); - open_editor->connect("pressed", this, "_open_editor", varray(), CONNECT_DEFERRED); + open_editor->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_open_editor), varray(), CONNECT_DEFERRED); edit_hb->hide(); open_editor->hide(); @@ -999,8 +961,8 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { panel->set_h_size_flags(SIZE_EXPAND_FILL); blend_space_draw = memnew(Control); - blend_space_draw->connect("gui_input", this, "_blend_space_gui_input"); - blend_space_draw->connect("draw", this, "_blend_space_draw"); + blend_space_draw->connect("gui_input", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_gui_input)); + blend_space_draw->connect("draw", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_draw)); blend_space_draw->set_focus_mode(FOCUS_ALL); panel->add_child(blend_space_draw); @@ -1029,14 +991,14 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { min_x_value->set_step(0.01); } - snap_x->connect("value_changed", this, "_config_changed"); - snap_y->connect("value_changed", this, "_config_changed"); - max_x_value->connect("value_changed", this, "_config_changed"); - min_x_value->connect("value_changed", this, "_config_changed"); - max_y_value->connect("value_changed", this, "_config_changed"); - min_y_value->connect("value_changed", this, "_config_changed"); - label_x->connect("text_changed", this, "_labels_changed"); - label_y->connect("text_changed", this, "_labels_changed"); + snap_x->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + snap_y->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + max_x_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + min_x_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + max_y_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + min_y_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed)); + label_x->connect("text_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_labels_changed)); + label_y->connect("text_changed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_labels_changed)); error_panel = memnew(PanelContainer); add_child(error_panel); @@ -1050,18 +1012,18 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", this, "_add_menu_type"); + menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_menu_type)); animations_menu = memnew(PopupMenu); menu->add_child(animations_menu); animations_menu->set_name("animations"); - animations_menu->connect("index_pressed", this, "_add_animation_type"); + animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_add_animation_type)); open_file = memnew(EditorFileDialog); add_child(open_file); open_file->set_title(TTR("Open Animation Node")); - open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); - open_file->connect("file_selected", this, "_file_opened"); + open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_file_opened)); undo_redo = EditorNode::get_undo_redo(); selected_point = -1; diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 50b0d9a06c..64885aeaca 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -42,24 +42,23 @@ #include "scene/gui/tree.h" class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { - GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendSpace2D> blend_space; PanelContainer *panel; - ToolButton *tool_blend; - ToolButton *tool_select; - ToolButton *tool_create; - ToolButton *tool_triangle; + Button *tool_blend; + Button *tool_select; + Button *tool_create; + Button *tool_triangle; VSeparator *tool_erase_sep; - ToolButton *tool_erase; - ToolButton *snap; + Button *tool_erase; + Button *snap; SpinBox *snap_x; SpinBox *snap_y; OptionButton *interpolation; - ToolButton *auto_triangles; + Button *auto_triangles; LineEdit *label_x; LineEdit *label_y; @@ -143,8 +142,8 @@ protected: public: static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; } - virtual bool can_edit(const Ref<AnimationNode> &p_node); - virtual void edit(const Ref<AnimationNode> &p_node); + virtual bool can_edit(const Ref<AnimationNode> &p_node) override; + virtual void edit(const Ref<AnimationNode> &p_node) override; AnimationNodeBlendSpace2DEditor(); }; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 2de224c043..6419f62343 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -30,8 +30,8 @@ #include "animation_blend_tree_editor_plugin.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/editor_inspector.h" @@ -40,10 +40,9 @@ #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" #include "scene/gui/progress_bar.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script) { - for (int i = 0; i < add_options.size(); i++) { ERR_FAIL_COND(add_options[i].script == p_script); } @@ -57,7 +56,6 @@ void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const R } void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_script) { - for (int i = 0; i < add_options.size(); i++) { if (add_options[i].script == p_script) { add_options.remove(i); @@ -69,7 +67,6 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip } void AnimationNodeBlendTreeEditor::_update_options_menu() { - add_node->get_popup()->clear(); for (int i = 0; i < add_options.size(); i++) { add_node->get_popup()->add_item(add_options[i].name, i); @@ -86,12 +83,10 @@ void AnimationNodeBlendTreeEditor::_update_options_menu() { } Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { - return Size2(10, 200); } void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { - AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_tree(); updating = true; undo_redo->create_action(TTR("Parameter Changed") + ": " + String(p_property), UndoRedo::MERGE_ENDS); @@ -104,9 +99,9 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert } void AnimationNodeBlendTreeEditor::_update_graph() { - - if (updating) + if (updating) { return; + } visible_properties.clear(); @@ -115,7 +110,6 @@ void AnimationNodeBlendTreeEditor::_update_graph() { graph->clear_connections(); //erase all nodes for (int i = 0; i < graph->get_child_count(); i++) { - if (Object::cast_to<GraphNode>(graph->get_child(i))) { memdelete(graph->get_child(i)); i--; @@ -128,7 +122,6 @@ void AnimationNodeBlendTreeEditor::_update_graph() { blend_tree->get_node_list(&nodes); for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { - GraphNode *node = memnew(GraphNode); graph->add_child(node); @@ -145,25 +138,24 @@ void AnimationNodeBlendTreeEditor::_update_graph() { name->set_text(E->get()); name->set_expand_to_text_length(true); node->add_child(name); - node->set_slot(0, false, 0, Color(), true, 0, get_color("font_color", "Label")); - name->connect("text_entered", this, "_node_renamed", varray(agnode)); - name->connect("focus_exited", this, "_node_renamed_focus_out", varray(name, agnode), CONNECT_DEFERRED); + node->set_slot(0, false, 0, Color(), true, 0, get_theme_color("font_color", "Label")); + name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode)); + name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED); base = 1; node->set_show_close_button(true); - node->connect("close_request", this, "_delete_request", varray(E->get()), CONNECT_DEFERRED); + node->connect("close_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_request), varray(E->get()), CONNECT_DEFERRED); } for (int i = 0; i < agnode->get_input_count(); i++) { Label *in_name = memnew(Label); node->add_child(in_name); in_name->set_text(agnode->get_input_name(i)); - node->set_slot(base + i, true, 0, get_color("font_color", "Label"), false, 0, Color()); + node->set_slot(base + i, true, 0, get_theme_color("font_color", "Label"), false, 0, Color()); } List<PropertyInfo> pinfo; agnode->get_parameter_list(&pinfo); for (List<PropertyInfo>::Element *F = pinfo.front(); F; F = F->next()) { - if (!(F->get().usage & PROPERTY_USAGE_EDITOR)) { continue; } @@ -173,41 +165,39 @@ void AnimationNodeBlendTreeEditor::_update_graph() { prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path); prop->update_property(); prop->set_name_split_ratio(0); - prop->connect("property_changed", this, "_property_changed"); + prop->connect("property_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_property_changed)); node->add_child(prop); visible_properties.push_back(prop); } } - node->connect("dragged", this, "_node_dragged", varray(E->get())); + node->connect("dragged", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_dragged), varray(E->get())); if (AnimationTreeEditor::get_singleton()->can_edit(agnode)) { node->add_child(memnew(HSeparator)); Button *open_in_editor = memnew(Button); open_in_editor->set_text(TTR("Open Editor")); - open_in_editor->set_icon(get_icon("Edit", "EditorIcons")); + open_in_editor->set_icon(get_theme_icon("Edit", "EditorIcons")); node->add_child(open_in_editor); - open_in_editor->connect("pressed", this, "_open_in_editor", varray(E->get()), CONNECT_DEFERRED); + open_in_editor->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_open_in_editor), varray(E->get()), CONNECT_DEFERRED); open_in_editor->set_h_size_flags(SIZE_SHRINK_CENTER); } if (agnode->has_filter()) { - node->add_child(memnew(HSeparator)); Button *edit_filters = memnew(Button); edit_filters->set_text(TTR("Edit Filters")); - edit_filters->set_icon(get_icon("AnimationFilter", "EditorIcons")); + edit_filters->set_icon(get_theme_icon("AnimationFilter", "EditorIcons")); node->add_child(edit_filters); - edit_filters->connect("pressed", this, "_edit_filters", varray(E->get()), CONNECT_DEFERRED); + edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters), varray(E->get()), CONNECT_DEFERRED); edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER); } Ref<AnimationNodeAnimation> anim = agnode; if (anim.is_valid()) { - MenuButton *mb = memnew(MenuButton); mb->set_text(anim->get_animation()); - mb->set_icon(get_icon("Animation", "EditorIcons")); + mb->set_icon(get_theme_icon("Animation", "EditorIcons")); Array options; node->add_child(memnew(HSeparator)); @@ -238,20 +228,20 @@ void AnimationNodeBlendTreeEditor::_update_graph() { animations[E->get()] = pb; node->add_child(pb); - mb->get_popup()->connect("index_pressed", this, "_anim_selected", varray(options, E->get()), CONNECT_DEFERRED); + mb->get_popup()->connect("index_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_anim_selected), varray(options, E->get()), CONNECT_DEFERRED); } if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { - Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode"); + Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode"); 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; - node->add_color_override("title_color", c); + node->add_theme_color_override("title_color", c); c.a = 0.7; - node->add_color_override("close_color", c); - node->add_color_override("resizer_color", c); + node->add_theme_color_override("close_color", c); + node->add_theme_color_override("resizer_color", c); } } @@ -259,7 +249,6 @@ void AnimationNodeBlendTreeEditor::_update_graph() { blend_tree->get_node_connections(&connections); for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = connections.front(); E; E = E->next()) { - StringName from = E->get().output_node; StringName to = E->get().input_node; int to_idx = E->get().input_index; @@ -269,7 +258,6 @@ void AnimationNodeBlendTreeEditor::_update_graph() { } void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) { - file_loaded = ResourceLoader::load(p_file); if (file_loaded.is_valid()) { _add_node(MENU_LOAD_FILE_CONFIRM); @@ -277,27 +265,24 @@ void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) { } void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { - Ref<AnimationNode> anode; String base_name; if (p_idx == MENU_LOAD_FILE) { - open_file->clear_filters(); List<String> filters; ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &filters); for (List<String>::Element *E = filters.front(); E; E = E->next()) { open_file->add_filter("*." + E->get()); } - open_file->popup_centered_ratio(); + open_file->popup_file_dialog(); return; } else if (p_idx == MENU_LOAD_FILE_CONFIRM) { anode = file_loaded; file_loaded.unref(); base_name = anode->get_class(); } else if (p_idx == MENU_PASTE) { - anode = EditorSettings::get_singleton()->get_resource_clipboard(); ERR_FAIL_COND(!anode.is_valid()); base_name = anode->get_class(); @@ -312,7 +297,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(base_type)); ERR_FAIL_COND(!an); anode = Ref<AnimationNode>(an); - anode->set_script(add_options[p_idx].script.get_ref_ptr()); + anode->set_script(add_options[p_idx].script); base_name = add_options[p_idx].name; } @@ -347,7 +332,6 @@ 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(TTR("Node Moved")); undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE); @@ -359,7 +343,6 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve } void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { - AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from); if (err != AnimationNodeBlendTree::CONNECTION_OK) { @@ -376,7 +359,6 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int } void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { - graph->disconnect_node(p_from, p_from_index, p_to, p_to_index); updating = true; @@ -390,7 +372,6 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, } void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, const String &p_node) { - String option = p_options[p_index]; Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node); @@ -405,7 +386,6 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options, } void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { - 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)); @@ -425,7 +405,6 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) { } void AnimationNodeBlendTreeEditor::_delete_nodes_request() { - List<StringName> to_erase; for (int i = 0; i < graph->get_child_count(); i++) { @@ -437,8 +416,9 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request() { } } - if (to_erase.empty()) + if (to_erase.empty()) { return; + } undo_redo->create_action(TTR("Delete Node(s)")); @@ -450,7 +430,6 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request() { } void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) { - _update_options_menu(); use_popup_menu_position = true; popup_menu_position = graph->get_local_mouse_position(); @@ -459,7 +438,6 @@ void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) { } void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { - GraphNode *gn = Object::cast_to<GraphNode>(p_node); ERR_FAIL_COND(!gn); @@ -472,14 +450,12 @@ void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { } void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) { - Ref<AnimationNode> an = blend_tree->get_node(p_which); ERR_FAIL_COND(!an.is_valid()); AnimationTreeEditor::get_singleton()->enter_editor(p_which); } void AnimationNodeBlendTreeEditor::_filter_toggled() { - updating = true; undo_redo->create_action(TTR("Toggle Filter On/Off")); undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_enabled", filter_enabled->is_pressed()); @@ -491,7 +467,6 @@ void AnimationNodeBlendTreeEditor::_filter_toggled() { } void AnimationNodeBlendTreeEditor::_filter_edited() { - TreeItem *edited = filters->get_edited(); ERR_FAIL_COND(!edited); @@ -509,9 +484,9 @@ void AnimationNodeBlendTreeEditor::_filter_edited() { } bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &anode) { - - if (updating || _filter_edit != anode) + if (updating || _filter_edit != anode) { return false; + } NodePath player_path = AnimationTreeEditor::get_singleton()->get_tree()->get_animation_player(); @@ -536,13 +511,12 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano updating = true; Set<String> paths; - HashMap<String, Set<String> > types; + HashMap<String, Set<String>> types; { List<StringName> animations; player->get_animation_list(&animations); for (List<StringName>::Element *E = animations.front(); E; E = E->next()) { - Ref<Animation> anim = player->get_animation(E->get()); for (int i = 0; i < anim->get_track_count(); i++) { String track_path = anim->track_get_path(i); @@ -577,9 +551,8 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano Map<String, TreeItem *> parenthood; for (Set<String>::Element *E = paths.front(); E; E = E->next()) { - NodePath path = E->get(); - TreeItem *ti = NULL; + TreeItem *ti = nullptr; String accum; for (int i = 0; i < path.get_name_count(); i++) { String name = path.get_name(i); @@ -608,18 +581,18 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano } } - Node *node = NULL; + Node *node = nullptr; if (base->has_node(accum)) { node = base->get_node(accum); } - if (!node) + if (!node) { continue; //no node, can't edit + } if (path.get_subname_count()) { - String concat = path.get_concatenated_subnames(); - Skeleton *skeleton = Object::cast_to<Skeleton>(node); + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); if (skeleton && skeleton->find_bone(concat) != -1) { //path in skeleton const String &bone = concat; @@ -643,7 +616,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano ti->set_text(0, F->get()); ti->set_selectable(0, false); ti->set_editable(0, false); - ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons")); } else { ti = parenthood[accum]; } @@ -654,7 +627,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, concat); ti->set_checked(0, anode->is_path_filtered(path)); - ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons")); ti->set_metadata(0, path); } else { @@ -697,36 +670,34 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano } void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) { - Ref<AnimationNode> anode = blend_tree->get_node(p_which); ERR_FAIL_COND(!anode.is_valid()); _filter_edit = anode; - if (!_update_filters(anode)) + if (!_update_filters(anode)) { return; + } - filter_dialog->popup_centered_minsize(Size2(500, 500) * EDSCALE); + filter_dialog->popup_centered(Size2(500, 500) * EDSCALE); } void AnimationNodeBlendTreeEditor::_removed_from_graph() { if (is_visible()) { - EditorNode::get_singleton()->edit_item(NULL); + EditorNode::get_singleton()->edit_item(nullptr); } } void AnimationNodeBlendTreeEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); - error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); - - if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) + if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) { _update_graph(); + } } if (p_what == NOTIFICATION_PROCESS) { - String error; if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) { @@ -756,7 +727,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_tree(); - AnimationPlayer *player = NULL; + AnimationPlayer *player = nullptr; if (graph_player->has_node(graph_player->get_animation_player())) { player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); } @@ -789,44 +760,22 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) { - if (updating) + if (updating) { return; + } updating = true; blend_tree->set_graph_offset(p_scroll / EDSCALE); updating = false; } void AnimationNodeBlendTreeEditor::_bind_methods() { - ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph); - ClassDB::bind_method("_add_node", &AnimationNodeBlendTreeEditor::_add_node); - ClassDB::bind_method("_node_dragged", &AnimationNodeBlendTreeEditor::_node_dragged); - ClassDB::bind_method("_node_renamed", &AnimationNodeBlendTreeEditor::_node_renamed); - ClassDB::bind_method("_node_renamed_focus_out", &AnimationNodeBlendTreeEditor::_node_renamed_focus_out); - ClassDB::bind_method("_connection_request", &AnimationNodeBlendTreeEditor::_connection_request); - ClassDB::bind_method("_disconnection_request", &AnimationNodeBlendTreeEditor::_disconnection_request); - ClassDB::bind_method("_node_selected", &AnimationNodeBlendTreeEditor::_node_selected); - ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor); - ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed); - ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request); - ClassDB::bind_method("_delete_nodes_request", &AnimationNodeBlendTreeEditor::_delete_nodes_request); - ClassDB::bind_method("_popup_request", &AnimationNodeBlendTreeEditor::_popup_request); - ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters); ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters); - ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited); - ClassDB::bind_method("_filter_toggled", &AnimationNodeBlendTreeEditor::_filter_toggled); - ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendTreeEditor::_removed_from_graph); - ClassDB::bind_method("_property_changed", &AnimationNodeBlendTreeEditor::_property_changed); - ClassDB::bind_method("_file_opened", &AnimationNodeBlendTreeEditor::_file_opened); - ClassDB::bind_method("_update_options_menu", &AnimationNodeBlendTreeEditor::_update_options_menu); - - ClassDB::bind_method("_anim_selected", &AnimationNodeBlendTreeEditor::_anim_selected); } -AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = NULL; +AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr; void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) { - String prev_name = blend_tree->get_node_name(p_node); ERR_FAIL_COND(prev_name == String()); GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(prev_name)); @@ -879,7 +828,6 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima blend_tree->get_node_connections(&connections); for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = connections.front(); E; E = E->next()) { - StringName from = E->get().output_node; StringName to = E->get().input_node; int to_idx = E->get().input_index; @@ -909,9 +857,8 @@ bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) { } void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { - if (blend_tree.is_valid()) { - blend_tree->disconnect("removed_from_graph", this, "_removed_from_graph"); + blend_tree->disconnect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph)); } blend_tree = p_node; @@ -919,14 +866,13 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) { if (blend_tree.is_null()) { hide(); } else { - blend_tree->connect("removed_from_graph", this, "_removed_from_graph"); + blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph)); _update_graph(); } } AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { - singleton = this; updating = false; use_popup_menu_position = false; @@ -936,12 +882,12 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->add_valid_right_disconnect_type(0); graph->add_valid_left_disconnect_type(0); graph->set_v_size_flags(SIZE_EXPAND_FILL); - graph->connect("connection_request", this, "_connection_request", varray(), CONNECT_DEFERRED); - graph->connect("disconnection_request", this, "_disconnection_request", varray(), CONNECT_DEFERRED); - graph->connect("node_selected", this, "_node_selected"); - graph->connect("scroll_offset_changed", this, "_scroll_changed"); - graph->connect("delete_nodes_request", this, "_delete_nodes_request"); - graph->connect("popup_request", this, "_popup_request"); + graph->connect("connection_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_request), varray(), CONNECT_DEFERRED); + graph->connect("disconnection_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_disconnection_request), varray(), CONNECT_DEFERRED); + graph->connect("node_selected", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_selected)); + graph->connect("scroll_offset_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_scroll_changed)); + graph->connect("delete_nodes_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_nodes_request)); + graph->connect("popup_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_request)); VSeparator *vs = memnew(VSeparator); graph->get_zoom_hbox()->add_child(vs); @@ -951,8 +897,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->get_zoom_hbox()->add_child(add_node); add_node->set_text(TTR("Add Node...")); graph->get_zoom_hbox()->move_child(add_node, 0); - add_node->get_popup()->connect("id_pressed", this, "_add_node"); - add_node->connect("about_to_show", this, "_update_options_menu"); + add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node)); + add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu)); add_options.push_back(AddOption("Animation", "AnimationNodeAnimation")); add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot")); @@ -984,19 +930,19 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { filter_enabled = memnew(CheckBox); filter_enabled->set_text(TTR("Enable Filtering")); - filter_enabled->connect("pressed", this, "_filter_toggled"); + filter_enabled->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_toggled)); filter_vbox->add_child(filter_enabled); filters = memnew(Tree); filter_vbox->add_child(filters); filters->set_v_size_flags(SIZE_EXPAND_FILL); filters->set_hide_root(true); - filters->connect("item_edited", this, "_filter_edited"); + filters->connect("item_edited", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_edited)); open_file = memnew(EditorFileDialog); add_child(open_file); open_file->set_title(TTR("Open Animation Node")); - open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); - open_file->connect("file_selected", this, "_file_opened"); + open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendTreeEditor::_file_opened)); undo_redo = EditorNode::get_undo_redo(); } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 4f5badea9f..3ebf623eef 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -44,7 +44,6 @@ class ProgressBar; class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { - GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeBlendTree> blend_tree; @@ -130,10 +129,10 @@ public: void add_custom_type(const String &p_name, const Ref<Script> &p_script); void remove_custom_type(const Ref<Script> &p_script); - virtual Size2 get_minimum_size() const; + virtual Size2 get_minimum_size() const override; - virtual bool can_edit(const Ref<AnimationNode> &p_node); - virtual void edit(const Ref<AnimationNode> &p_node); + virtual bool can_edit(const Ref<AnimationNode> &p_node) override; + virtual void edit(const Ref<AnimationNode> &p_node) override; AnimationNodeBlendTreeEditor(); }; diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5e69ce4e69..6e4a39d3f0 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -30,54 +30,48 @@ #include "animation_player_editor_plugin.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/animation_track_editor.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" - -// For onion skinning. -#include "editor/plugins/canvas_item_editor_plugin.h" -#include "editor/plugins/spatial_editor_plugin.h" -#include "scene/main/viewport.h" -#include "servers/visual_server.h" +#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning. +#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning. +#include "scene/main/window.h" +#include "servers/rendering_server.h" void AnimationPlayerEditor::_node_removed(Node *p_node) { - if (player && player == p_node) { - player = NULL; + player = nullptr; set_process(false); track_editor->set_animation(Ref<Animation>()); - track_editor->set_root(NULL); + track_editor->set_root(nullptr); track_editor->show_select_node_warning(true); _update_player(); } } void AnimationPlayerEditor::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_PROCESS: { - - if (!player) + if (!player) { return; + } updating = true; if (player->is_playing()) { - { String animname = player->get_assigned_animation(); if (player->has_animation(animname)) { Ref<Animation> anim = player->get_animation(animname); if (!anim.is_null()) { - frame->set_max(anim->get_length()); } } @@ -98,42 +92,39 @@ void AnimationPlayerEditor::_notification(int p_what) { updating = false; } break; case NOTIFICATION_ENTER_TREE: { + tool_anim->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu)); - tool_anim->get_popup()->connect("id_pressed", this, "_animation_tool_menu"); + onion_skinning->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu)); - onion_skinning->get_popup()->connect("id_pressed", this, "_onion_skinning_menu"); + blend_editor.next->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed)); - blend_editor.next->connect("item_selected", this, "_blend_editor_next_changed"); + get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed)); - get_tree()->connect("node_removed", this, "_node_removed"); - - add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel")); + add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("panel", "Panel")); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - - add_style_override("panel", editor->get_gui_base()->get_stylebox("panel", "Panel")); + add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("panel", "Panel")); } break; case NOTIFICATION_THEME_CHANGED: { + autoplay->set_icon(get_theme_icon("AutoPlay", "EditorIcons")); - autoplay->set_icon(get_icon("AutoPlay", "EditorIcons")); - - play->set_icon(get_icon("PlayStart", "EditorIcons")); - play_from->set_icon(get_icon("Play", "EditorIcons")); - play_bw->set_icon(get_icon("PlayStartBackwards", "EditorIcons")); - play_bw_from->set_icon(get_icon("PlayBackwards", "EditorIcons")); + play->set_icon(get_theme_icon("PlayStart", "EditorIcons")); + play_from->set_icon(get_theme_icon("Play", "EditorIcons")); + play_bw->set_icon(get_theme_icon("PlayStartBackwards", "EditorIcons")); + play_bw_from->set_icon(get_theme_icon("PlayBackwards", "EditorIcons")); - autoplay_icon = get_icon("AutoPlay", "EditorIcons"); - stop->set_icon(get_icon("Stop", "EditorIcons")); + autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons"); + stop->set_icon(get_theme_icon("Stop", "EditorIcons")); - onion_toggle->set_icon(get_icon("Onion", "EditorIcons")); - onion_skinning->set_icon(get_icon("GuiTabMenu", "EditorIcons")); + onion_toggle->set_icon(get_theme_icon("Onion", "EditorIcons")); + onion_skinning->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons")); - pin->set_icon(get_icon("Pin", "EditorIcons")); + pin->set_icon(get_theme_icon("Pin", "EditorIcons")); - tool_anim->add_style_override("normal", get_stylebox("normal", "Button")); - track_editor->get_edit_menu()->add_style_override("normal", get_stylebox("normal", "Button")); + tool_anim->add_theme_style_override("normal", get_theme_stylebox("normal", "Button")); + track_editor->get_edit_menu()->add_theme_style_override("normal", get_theme_stylebox("normal", "Button")); -#define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_icon(m_icon, "EditorIcons")) +#define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_theme_icon(m_icon, "EditorIcons")) ITEM_ICON(TOOL_NEW_ANIM, "New"); ITEM_ICON(TOOL_LOAD_ANIM, "Load"); @@ -149,9 +140,9 @@ void AnimationPlayerEditor::_notification(int p_what) { } void AnimationPlayerEditor::_autoplay_pressed() { - - if (updating) + if (updating) { return; + } if (animation->get_item_count() == 0) { return; } @@ -178,17 +169,15 @@ void AnimationPlayerEditor::_autoplay_pressed() { } void AnimationPlayerEditor::_play_pressed() { - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); } if (current != "") { - - if (current == player->get_assigned_animation()) + if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself + } player->play(current); } @@ -197,19 +186,15 @@ void AnimationPlayerEditor::_play_pressed() { } void AnimationPlayerEditor::_play_from_pressed() { - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); } if (current != "") { - float time = player->get_current_animation_position(); if (current == player->get_assigned_animation() && player->is_playing()) { - player->stop(); //so it won't blend with itself } @@ -222,17 +207,15 @@ void AnimationPlayerEditor::_play_from_pressed() { } void AnimationPlayerEditor::_play_bw_pressed() { - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); } if (current != "") { - - if (current == player->get_assigned_animation()) + if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself + } player->play(current, -1, -1, true); } @@ -241,18 +224,16 @@ void AnimationPlayerEditor::_play_bw_pressed() { } void AnimationPlayerEditor::_play_bw_from_pressed() { - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); } if (current != "") { - float time = player->get_current_animation_position(); - if (current == player->get_assigned_animation()) + if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself + } player->play(current, -1, -1, true); player->seek(time); @@ -261,8 +242,8 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { //unstop stop->set_pressed(false); } -void AnimationPlayerEditor::_stop_pressed() { +void AnimationPlayerEditor::_stop_pressed() { if (!player) { return; } @@ -273,24 +254,21 @@ void AnimationPlayerEditor::_stop_pressed() { } void AnimationPlayerEditor::_animation_selected(int p_which) { - - if (updating) + if (updating) { return; + } // when selecting an animation, the idea is that the only interesting behavior // ui-wise is that it should play/blend the next one if currently playing String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); } if (current != "") { - player->set_assigned_animation(current); Ref<Animation> anim = player->get_animation(current); { - track_editor->set_animation(anim); Node *root = player->get_node(player->get_root()); if (root) { @@ -301,7 +279,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { } else { track_editor->set_animation(Ref<Animation>()); - track_editor->set_root(NULL); + track_editor->set_root(nullptr); } autoplay->set_pressed(current == player->get_autoplay()); @@ -312,7 +290,6 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { } void AnimationPlayerEditor::_animation_new() { - renaming = false; name_title->set_text(TTR("New Animation Name:")); @@ -320,8 +297,9 @@ void AnimationPlayerEditor::_animation_new() { String base = TTR("New Anim"); while (true) { String attempt = base; - if (count > 1) + if (count > 1) { attempt += " (" + itos(count) + ")"; + } if (player->has_animation(attempt)) { count++; continue; @@ -335,10 +313,11 @@ void AnimationPlayerEditor::_animation_new() { name->select_all(); name->grab_focus(); } -void AnimationPlayerEditor::_animation_rename() { - if (animation->get_item_count() == 0) +void AnimationPlayerEditor::_animation_rename() { + if (animation->get_item_count() == 0) { return; + } int selected = animation->get_selected(); String selected_name = animation->get_item_text(selected); @@ -349,34 +328,33 @@ void AnimationPlayerEditor::_animation_rename() { name->select_all(); name->grab_focus(); } + void AnimationPlayerEditor::_animation_load() { ERR_FAIL_COND(!player); - file->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); file->clear_filters(); List<String> extensions; ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions); for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - file->add_filter("*." + E->get() + " ; " + E->get().to_upper()); } - file->popup_centered_ratio(); + file->popup_file_dialog(); current_option = RESOURCE_LOAD; } void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource> &p_resource, const String &p_path) { - int flg = 0; - if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) + if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) { flg |= ResourceSaver::FLAG_COMPRESS; + } String path = ProjectSettings::get_singleton()->localize_path(p_path); Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { - accept->set_text(TTR("Error saving resource!")); - accept->popup_centered_minsize(); + EditorNode::get_singleton()->show_warning(TTR("Error saving resource!")); return; } @@ -385,7 +363,6 @@ void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource> &p_resou } void AnimationPlayerEditor::_animation_save(const Ref<Resource> &p_resource) { - if (p_resource->get_path().is_resource_file()) { _animation_save_in_path(p_resource, p_resource->get_path()); } else { @@ -394,54 +371,51 @@ void AnimationPlayerEditor::_animation_save(const Ref<Resource> &p_resource) { } void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) { - - file->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); List<String> extensions; ResourceSaver::get_recognized_extensions(p_resource, &extensions); file->clear_filters(); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } + String path; //file->set_current_path(current_path); if (p_resource->get_path() != "") { - file->set_current_path(p_resource->get_path()); + path = p_resource->get_path(); if (extensions.size()) { - String ext = p_resource->get_path().get_extension().to_lower(); - if (extensions.find(ext) == NULL) { - file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get())); + if (extensions.find(p_resource->get_path().get_extension().to_lower()) == nullptr) { + path = p_resource->get_path().get_base_dir() + p_resource->get_name() + "." + extensions.front()->get(); } } } else { - - String existing; if (extensions.size()) { if (p_resource->get_name() != "") { - existing = p_resource->get_name() + "." + extensions.front()->get().to_lower(); + path = p_resource->get_name() + "." + extensions.front()->get().to_lower(); } else { - existing = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower(); + path = "new_" + p_resource->get_class().to_lower() + "." + extensions.front()->get().to_lower(); } } - file->set_current_path(existing); } - file->popup_centered_ratio(); + file->set_current_path(path); file->set_title(TTR("Save Resource As...")); + file->popup_file_dialog(); current_option = RESOURCE_SAVE; } void AnimationPlayerEditor::_animation_remove() { - - if (animation->get_item_count() == 0) + if (animation->get_item_count() == 0) { return; + } - delete_dialog->set_text(TTR("Delete Animation?")); - delete_dialog->popup_centered_minsize(); + String current = animation->get_item_text(animation->get_selected()); + + delete_dialog->set_text(vformat(TTR("Delete Animation '%s'?"), current)); + delete_dialog->popup_centered(); } void AnimationPlayerEditor::_animation_remove_confirmed() { - String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); @@ -464,12 +438,9 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { } void AnimationPlayerEditor::_select_anim_by_name(const String &p_anim) { - int idx = -1; for (int i = 0; i < animation->get_item_count(); i++) { - if (animation->get_item_text(i) == p_anim) { - idx = i; break; } @@ -483,7 +454,6 @@ void AnimationPlayerEditor::_select_anim_by_name(const String &p_anim) { } double AnimationPlayerEditor::_get_editor_step() const { - // Returns the effective snapping value depending on snapping modifiers, or 0 if snapping is disabled. if (track_editor->is_snap_enabled()) { const String current = player->get_assigned_animation(); @@ -498,13 +468,12 @@ double AnimationPlayerEditor::_get_editor_step() const { } void AnimationPlayerEditor::_animation_name_edited() { - player->stop(); String new_name = name->get_text(); if (new_name == "" || new_name.find(":") != -1 || new_name.find("/") != -1) { error_dialog->set_text(TTR("Invalid animation name!")); - error_dialog->popup_centered_minsize(); + error_dialog->popup_centered(); return; } @@ -515,7 +484,7 @@ void AnimationPlayerEditor::_animation_name_edited() { if (player->has_animation(new_name)) { error_dialog->set_text(TTR("Animation name already exists!")); - error_dialog->popup_centered_minsize(); + error_dialog->popup_centered(); return; } @@ -535,7 +504,6 @@ void AnimationPlayerEditor::_animation_name_edited() { _select_anim_by_name(new_name); } else { - Ref<Animation> new_anim = Ref<Animation>(memnew(Animation)); new_anim->set_name(new_name); @@ -557,9 +525,9 @@ void AnimationPlayerEditor::_animation_name_edited() { } void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) { - - if (animation->get_item_count() == 0) + if (animation->get_item_count() == 0) { return; + } String current = animation->get_item_text(animation->get_selected()); @@ -572,14 +540,15 @@ void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) { } void AnimationPlayerEditor::_animation_blend() { - - if (updating_blends) + if (updating_blends) { return; + } blend_editor.tree->clear(); - if (animation->get_item_count() == 0) + if (animation->get_item_count() == 0) { return; + } String current = animation->get_item_text(animation->get_selected()); @@ -600,7 +569,6 @@ void AnimationPlayerEditor::_animation_blend() { blend_editor.next->add_item("", i); for (List<StringName>::Element *E = anims.front(); E; E = E->next()) { - String to = E->get(); TreeItem *blend = blend_editor.tree->create_item(root); blend->set_editable(0, false); @@ -628,18 +596,20 @@ void AnimationPlayerEditor::_animation_blend() { } void AnimationPlayerEditor::_blend_edited() { - - if (updating_blends) + if (updating_blends) { return; + } - if (animation->get_item_count() == 0) + if (animation->get_item_count() == 0) { return; + } String current = animation->get_item_text(animation->get_selected()); TreeItem *selected = blend_editor.tree->get_edited(); - if (!selected) + if (!selected) { return; + } updating_blends = true; String to = selected->get_text(0); @@ -656,15 +626,14 @@ void AnimationPlayerEditor::_blend_edited() { } void AnimationPlayerEditor::ensure_visibility() { - - if (player && pin->is_pressed()) + if (player && pin->is_pressed()) { return; // another player is pinned, don't reset + } _animation_edit(); } Dictionary AnimationPlayerEditor::get_state() const { - Dictionary d; d["visible"] = is_visible_in_tree(); @@ -676,8 +645,8 @@ Dictionary AnimationPlayerEditor::get_state() const { return d; } -void AnimationPlayerEditor::set_state(const Dictionary &p_state) { +void AnimationPlayerEditor::set_state(const Dictionary &p_state) { if (!p_state.has("visible") || !p_state["visible"]) { return; } @@ -686,7 +655,6 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { } if (p_state.has("player")) { - Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]); if (Object::cast_to<AnimationPlayer>(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) { player = Object::cast_to<AnimationPlayer>(n); @@ -711,7 +679,6 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { } void AnimationPlayerEditor::_animation_resource_edit() { - if (animation->get_item_count()) { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); @@ -720,7 +687,6 @@ void AnimationPlayerEditor::_animation_resource_edit() { } void AnimationPlayerEditor::_animation_edit() { - if (animation->get_item_count()) { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); @@ -732,36 +698,30 @@ void AnimationPlayerEditor::_animation_edit() { } } else { track_editor->set_animation(Ref<Animation>()); - track_editor->set_root(NULL); + track_editor->set_root(nullptr); } } -void AnimationPlayerEditor::_dialog_action(String p_file) { - +void AnimationPlayerEditor::_dialog_action(String p_path) { switch (current_option) { case RESOURCE_LOAD: { ERR_FAIL_COND(!player); - Ref<Resource> res = ResourceLoader::load(p_file, "Animation"); - ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + p_file + "'."); - ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + p_file + "' is not Animation."); - if (p_file.find_last("/") != -1) { + Ref<Resource> res = ResourceLoader::load(p_path, "Animation"); + ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + p_path + "'."); + ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + p_path + "' is not Animation."); - p_file = p_file.substr(p_file.find_last("/") + 1, p_file.length()); + String anim_name = p_path.get_file(); + int ext_pos = anim_name.rfind("."); + if (ext_pos != -1) { + anim_name = anim_name.substr(0, ext_pos); } - if (p_file.find_last("\\") != -1) { - - p_file = p_file.substr(p_file.find_last("\\") + 1, p_file.length()); - } - - if (p_file.find(".") != -1) - p_file = p_file.substr(0, p_file.find(".")); undo_redo->create_action(TTR("Load Animation")); - undo_redo->add_do_method(player, "add_animation", p_file, res); - undo_redo->add_undo_method(player, "remove_animation", p_file); - if (player->has_animation(p_file)) { - undo_redo->add_undo_method(player, "add_animation", p_file, player->get_animation(p_file)); + undo_redo->add_do_method(player, "add_animation", anim_name, res); + undo_redo->add_undo_method(player, "remove_animation", anim_name); + if (player->has_animation(anim_name)) { + undo_redo->add_undo_method(player, "add_animation", anim_name, player->get_animation(anim_name)); } undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); @@ -769,7 +729,6 @@ void AnimationPlayerEditor::_dialog_action(String p_file) { break; } case RESOURCE_SAVE: { - String current = animation->get_item_text(animation->get_selected()); if (current != "") { Ref<Animation> anim = player->get_animation(current); @@ -778,31 +737,27 @@ void AnimationPlayerEditor::_dialog_action(String p_file) { RES current_res = RES(Object::cast_to<Resource>(*anim)); - _animation_save_in_path(current_res, p_file); + _animation_save_in_path(current_res, p_path); } } } } void AnimationPlayerEditor::_scale_changed(const String &p_scale) { - - player->set_speed_scale(p_scale.to_double()); + player->set_speed_scale(p_scale.to_float()); } void AnimationPlayerEditor::_update_animation() { - // the purpose of _update_animation is to reflect the current state // of the animation player in the current editor.. updating = true; if (player->is_playing()) { - play->set_pressed(true); stop->set_pressed(false); } else { - play->set_pressed(false); stop->set_pressed(true); } @@ -811,7 +766,6 @@ void AnimationPlayerEditor::_update_animation() { String current = player->get_assigned_animation(); for (int i = 0; i < animation->get_item_count(); i++) { - if (animation->get_item_text(i) == current) { animation->select(i); break; @@ -822,11 +776,11 @@ void AnimationPlayerEditor::_update_animation() { } void AnimationPlayerEditor::_update_player() { - updating = true; List<StringName> animlist; - if (player) + if (player) { player->get_animation_list(&animlist); + } animation->clear(); @@ -848,10 +802,10 @@ void AnimationPlayerEditor::_update_player() { frame->set_editable(animlist.size() != 0); animation->set_disabled(animlist.size() == 0); autoplay->set_disabled(animlist.size() == 0); - tool_anim->set_disabled(player == NULL); + tool_anim->set_disabled(player == nullptr); onion_toggle->set_disabled(animlist.size() == 0); onion_skinning->set_disabled(animlist.size() == 0); - pin->set_disabled(player == NULL); + pin->set_disabled(player == nullptr); if (!player) { AnimationPlayerEditor::singleton->get_track_editor()->update_keying(); @@ -861,14 +815,15 @@ void AnimationPlayerEditor::_update_player() { int active_idx = -1; for (List<StringName>::Element *E = animlist.front(); E; E = E->next()) { - - if (player->get_autoplay() == E->get()) + if (player->get_autoplay() == E->get()) { animation->add_icon_item(autoplay_icon, E->get()); - else + } else { animation->add_item(E->get()); + } - if (player->get_assigned_animation() == E->get()) + if (player->get_assigned_animation() == E->get()) { active_idx = animation->get_item_count() - 1; + } } updating = false; @@ -878,7 +833,6 @@ void AnimationPlayerEditor::_update_player() { _animation_selected(active_idx); } else if (animation->get_item_count() > 0) { - animation->select(0); autoplay->set_pressed(animation->get_item_text(0) == player->get_autoplay()); _animation_selected(0); @@ -900,38 +854,41 @@ void AnimationPlayerEditor::_update_player() { } void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { - - if (player && pin->is_pressed()) + if (player && pin->is_pressed()) { return; // Ignore, pinned. + } player = p_player; if (player) { _update_player(); if (onion.enabled) { - if (animation->get_item_count() > 0) + if (animation->get_item_count() > 0) { _start_onion_skinning(); - else + } else { _stop_onion_skinning(); + } } track_editor->show_select_node_warning(false); } else { - if (onion.enabled) + if (onion.enabled) { _stop_onion_skinning(); + } track_editor->show_select_node_warning(true); } } void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_overlay) { - - if (!onion.can_overlay) + if (!onion.can_overlay) { return; + } // Can happen on viewport resize, at least. - if (!_are_onion_layers_valid()) + if (!_are_onion_layers_valid()) { return; + } RID ci = p_overlay->get_canvas_item(); Rect2 src_rect = p_overlay->get_global_rect(); @@ -950,8 +907,8 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o alpha += alpha_step; if (onion.captures_valid[cidx]) { - VS::get_singleton()->canvas_item_add_texture_rect_region( - ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); + RS::get_singleton()->canvas_item_add_texture_rect_region( + ci, dst_rect, RS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); } cidx++; @@ -964,8 +921,8 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o alpha -= alpha_step; if (onion.captures_valid[cidx]) { - VS::get_singleton()->canvas_item_add_texture_rect_region( - ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); + RS::get_singleton()->canvas_item_add_texture_rect_region( + ci, dst_rect, RS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); } cidx++; @@ -974,22 +931,21 @@ void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_o } void AnimationPlayerEditor::_animation_duplicate() { - - if (!animation->get_item_count()) + if (!animation->get_item_count()) { return; + } String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); - if (!anim.is_valid()) + if (!anim.is_valid()) { return; + } Ref<Animation> new_anim = memnew(Animation); List<PropertyInfo> plist; anim->get_property_list(&plist); for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - if (E->get().usage & PROPERTY_USAGE_STORAGE) { - new_anim->set(E->get().name, anim->get(E->get().name)); } } @@ -1010,9 +966,7 @@ void AnimationPlayerEditor::_animation_duplicate() { undo_redo->commit_action(); for (int i = 0; i < animation->get_item_count(); i++) { - if (animation->get_item_text(i) == new_name) { - animation->select(i); _animation_selected(i); return; @@ -1021,7 +975,6 @@ void AnimationPlayerEditor::_animation_duplicate() { } void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) { - if (updating || !player || player->is_playing()) { return; }; @@ -1057,41 +1010,42 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) { }; void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) { - if (player == p_pl && is_visible_in_tree()) { - _update_player(); - if (blend_editor.dialog->is_visible_in_tree()) + if (blend_editor.dialog->is_visible()) { _animation_blend(); // Update. + } } } void AnimationPlayerEditor::_list_changed() { - - if (is_visible_in_tree()) + if (is_visible_in_tree()) { _update_player(); + } } void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) { - frame->set_max(p_len); } void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) { - timeline_position = p_pos; - if (!is_visible_in_tree()) + if (!is_visible_in_tree()) { return; + } - if (!player) + if (!player) { return; + } - if (player->is_playing()) + if (player->is_playing()) { return; + } - if (!player->has_animation(player->get_assigned_animation())) + if (!player->has_animation(player->get_assigned_animation())) { return; + } updating = true; frame->set_value(Math::stepify(p_pos, _get_editor_step())); @@ -1102,7 +1056,6 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) } void AnimationPlayerEditor::_animation_tool_menu(int p_option) { - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { current = animation->get_item_text(animation->get_selected()); @@ -1114,48 +1067,40 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { } switch (p_option) { - case TOOL_NEW_ANIM: { - _animation_new(); } break; case TOOL_LOAD_ANIM: { - _animation_load(); } break; case TOOL_SAVE_ANIM: { - if (anim.is_valid()) { _animation_save(anim); } } break; case TOOL_SAVE_AS_ANIM: { - if (anim.is_valid()) { _animation_save_as(anim); } } break; case TOOL_DUPLICATE_ANIM: { - _animation_duplicate(); - } break; - case TOOL_RENAME_ANIM: { + [[fallthrough]]; // Allow immediate rename after animation is duplicated + } + case TOOL_RENAME_ANIM: { _animation_rename(); } break; case TOOL_EDIT_TRANSITIONS: { - _animation_blend(); } break; case TOOL_REMOVE_ANIM: { - _animation_remove(); } break; case TOOL_COPY_ANIM: { - if (!animation->get_item_count()) { error_dialog->set_text(TTR("No animation to copy!")); - error_dialog->popup_centered_minsize(); + error_dialog->popup_centered(); return; } @@ -1164,11 +1109,10 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { EditorSettings::get_singleton()->set_resource_clipboard(anim2); } break; case TOOL_PASTE_ANIM: { - 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(); + error_dialog->popup_centered(); return; } @@ -1180,7 +1124,6 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { int idx = 1; String base = name; while (player->has_animation(name)) { - idx++; name = base + " " + itos(idx); } @@ -1195,10 +1138,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { _select_anim_by_name(name); } break; case TOOL_EDIT_RESOURCE: { - if (!animation->get_item_count()) { error_dialog->set_text(TTR("No animation to edit!")); - error_dialog->popup_centered_minsize(); + error_dialog->popup_centered(); return; } @@ -1210,30 +1152,26 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { } void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { - PopupMenu *menu = onion_skinning->get_popup(); int idx = menu->get_item_index(p_option); switch (p_option) { - case ONION_SKINNING_ENABLE: { - onion.enabled = !onion.enabled; - if (onion.enabled) + if (onion.enabled) { _start_onion_skinning(); - else + } else { _stop_onion_skinning(); + } } break; case ONION_SKINNING_PAST: { - // Ensure at least one of past/future is checked. onion.past = onion.future ? !onion.past : true; menu->set_item_checked(idx, onion.past); } break; case ONION_SKINNING_FUTURE: { - // Ensure at least one of past/future is checked. onion.future = onion.past ? !onion.future : true; menu->set_item_checked(idx, onion.future); @@ -1241,7 +1179,6 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { case ONION_SKINNING_1_STEP: // Fall-through. case ONION_SKINNING_2_STEPS: case ONION_SKINNING_3_STEPS: { - onion.steps = (p_option - ONION_SKINNING_1_STEP) + 1; int one_frame_idx = menu->get_item_index(ONION_SKINNING_1_STEP); for (int i = 0; i <= ONION_SKINNING_LAST_STEPS_OPTION - ONION_SKINNING_1_STEP; i++) { @@ -1249,17 +1186,14 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { } } break; case ONION_SKINNING_DIFFERENCES_ONLY: { - onion.differences_only = !onion.differences_only; menu->set_item_checked(idx, onion.differences_only); } break; case ONION_SKINNING_FORCE_WHITE_MODULATE: { - onion.force_white_modulate = !onion.force_white_modulate; menu->set_item_checked(idx, onion.force_white_modulate); } break; case ONION_SKINNING_INCLUDE_GIZMOS: { - onion.include_gizmos = !onion.include_gizmos; menu->set_item_checked(idx, onion.include_gizmos); } break; @@ -1267,40 +1201,37 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { } void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { - Ref<InputEventKey> k = p_ev; if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->get_alt() && !k->get_control() && !k->get_metakey()) { - - switch (k->get_scancode()) { - + switch (k->get_keycode()) { case KEY_A: { - if (!k->get_shift()) + if (!k->get_shift()) { _play_bw_from_pressed(); - else + } else { _play_bw_pressed(); + } } break; case KEY_S: { _stop_pressed(); } break; case KEY_D: { - if (!k->get_shift()) + if (!k->get_shift()) { _play_from_pressed(); - else + } else { _play_pressed(); + } } break; } } } void AnimationPlayerEditor::_editor_visibility_changed() { - if (is_visible() && animation->get_item_count() > 0) { _start_onion_skinning(); } } bool AnimationPlayerEditor::_are_onion_layers_valid() { - ERR_FAIL_COND_V(!onion.past && !onion.future, false); Point2 capture_size = get_tree()->get_root()->get_size(); @@ -1308,7 +1239,6 @@ bool AnimationPlayerEditor::_are_onion_layers_valid() { } void AnimationPlayerEditor::_allocate_onion_layers() { - _free_onion_layers(); int captures = onion.get_needed_capture_count(); @@ -1321,27 +1251,25 @@ void AnimationPlayerEditor::_allocate_onion_layers() { bool is_present = onion.differences_only && i == captures - 1; // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport. - onion.captures.write[i] = VS::get_singleton()->viewport_create(); - VS::get_singleton()->viewport_set_usage(onion.captures[i], VS::VIEWPORT_USAGE_2D); - VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); - VS::get_singleton()->viewport_set_update_mode(onion.captures[i], VS::VIEWPORT_UPDATE_ALWAYS); - VS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present); - VS::get_singleton()->viewport_set_vflip(onion.captures[i], true); - VS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas); + onion.captures.write[i] = RS::get_singleton()->viewport_create(); + + RS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); + RS::get_singleton()->viewport_set_update_mode(onion.captures[i], RS::VIEWPORT_UPDATE_ALWAYS); + RS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present); + RS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas); } // Reset the capture canvas item to the current root viewport texture (defensive). - VS::get_singleton()->canvas_item_clear(onion.capture.canvas_item); - VS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid()); + RS::get_singleton()->canvas_item_clear(onion.capture.canvas_item); + RS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid()); onion.capture_size = capture_size; } void AnimationPlayerEditor::_free_onion_layers() { - for (int i = 0; i < onion.captures.size(); i++) { if (onion.captures[i].is_valid()) { - VS::get_singleton()->free(onion.captures[i]); + RS::get_singleton()->free(onion.captures[i]); } } onion.captures.clear(); @@ -1349,11 +1277,11 @@ void AnimationPlayerEditor::_free_onion_layers() { } void AnimationPlayerEditor::_prepare_onion_layers_1() { - // This would be called per viewport and we want to act once only. int64_t frame = get_tree()->get_frame(); - if (frame == onion.last_frame) + if (frame == onion.last_frame) { return; + } if (!onion.enabled || !is_processing() || !is_visible() || !get_player()) { _stop_onion_skinning(); @@ -1366,28 +1294,34 @@ void AnimationPlayerEditor::_prepare_onion_layers_1() { onion.can_overlay = false; plugin->update_overlays(); - if (player->is_playing()) + if (player->is_playing()) { return; + } // And go to next step afterwards. call_deferred("_prepare_onion_layers_2"); } -void AnimationPlayerEditor::_prepare_onion_layers_2() { +void AnimationPlayerEditor::_prepare_onion_layers_1_deferred() { + call_deferred("_prepare_onion_layers_1"); +} +void AnimationPlayerEditor::_prepare_onion_layers_2() { Ref<Animation> anim = player->get_animation(player->get_assigned_animation()); - if (!anim.is_valid()) + if (!anim.is_valid()) { return; + } - if (!_are_onion_layers_valid()) + if (!_are_onion_layers_valid()) { _allocate_onion_layers(); + } // Hide superfluous elements that would make the overlay unnecessary cluttered. Dictionary canvas_edit_state; Dictionary spatial_edit_state; - if (SpatialEditor::get_singleton()->is_visible()) { + if (Node3DEditor::get_singleton()->is_visible()) { // 3D - spatial_edit_state = SpatialEditor::get_singleton()->get_state(); + spatial_edit_state = Node3DEditor::get_singleton()->get_state(); Dictionary new_state = spatial_edit_state.duplicate(); new_state["show_grid"] = false; new_state["show_origin"] = false; @@ -1404,7 +1338,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { } new_state["viewports"] = vp; // TODO: Save/restore only affected entries. - SpatialEditor::get_singleton()->set_state(new_state); + Node3DEditor::get_singleton()->set_state(new_state); } else { // CanvasItemEditor // 2D canvas_edit_state = CanvasItemEditor::get_singleton()->get_state(); @@ -1420,19 +1354,19 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { // Tweak the root viewport to ensure it's rendered before our target. RID root_vp = get_tree()->get_root()->get_viewport_rid(); - Rect2 root_vp_screen_rect = get_tree()->get_root()->get_attach_to_screen_rect(); - VS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2()); - VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_ALWAYS); + Rect2 root_vp_screen_rect = Rect2(Vector2(), get_tree()->get_root()->get_size()); + RS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2()); + RS::get_singleton()->viewport_set_update_mode(root_vp, RS::VIEWPORT_UPDATE_ALWAYS); RID present_rid; if (onion.differences_only) { // Capture present scene as it is. - VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID()); + RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID()); present_rid = onion.captures[onion.captures.size() - 1]; - VS::get_singleton()->viewport_set_active(present_rid, true); - VS::get_singleton()->viewport_set_parent_viewport(root_vp, present_rid); - VS::get_singleton()->draw(false); - VS::get_singleton()->viewport_set_active(present_rid, false); + RS::get_singleton()->viewport_set_active(present_rid, true); + RS::get_singleton()->viewport_set_parent_viewport(root_vp, present_rid); + RS::get_singleton()->draw(false); + RS::get_singleton()->viewport_set_active(present_rid, false); } // Backup current animation state. @@ -1441,21 +1375,21 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { // Render every past/future step with the capture shader. - VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid()); + RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid()); onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/default_clear_color")); onion.capture.material->set_shader_param("differences_only", onion.differences_only); - onion.capture.material->set_shader_param("present", onion.differences_only ? VS::get_singleton()->viewport_get_texture(present_rid) : RID()); + onion.capture.material->set_shader_param("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID()); int step_off_a = onion.past ? -onion.steps : 0; int step_off_b = onion.future ? onion.steps : 0; int cidx = 0; onion.capture.material->set_shader_param("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color"))); for (int step_off = step_off_a; step_off <= step_off_b; step_off++) { - if (step_off == 0) { // Skip present step and switch to the color of future. - if (!onion.force_white_modulate) + if (!onion.force_white_modulate) { onion.capture.material->set_shader_param("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color")); + } continue; } @@ -1465,22 +1399,22 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { onion.captures_valid.write[cidx] = valid; if (valid) { player->seek(pos, true); - get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials. + get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds. values_backup.update_skeletons(); // Needed for Skeletons (2D & 3D). - VS::get_singleton()->viewport_set_active(onion.captures[cidx], true); - VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); - VS::get_singleton()->draw(false); - VS::get_singleton()->viewport_set_active(onion.captures[cidx], false); + RS::get_singleton()->viewport_set_active(onion.captures[cidx], true); + RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); + RS::get_singleton()->draw(false); + RS::get_singleton()->viewport_set_active(onion.captures[cidx], false); } cidx++; } // Restore root viewport. - VS::get_singleton()->viewport_set_parent_viewport(root_vp, RID()); - VS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect); - VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_WHEN_VISIBLE); + RS::get_singleton()->viewport_set_parent_viewport(root_vp, RID()); + RS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect); + RS::get_singleton()->viewport_set_update_mode(root_vp, RS::VIEWPORT_UPDATE_WHEN_VISIBLE); // Restore animation state // (Seeking with update=true wouldn't do the trick because the current value of the properties @@ -1489,9 +1423,9 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { player->restore_animated_values(values_backup); // Restore state of main editors. - if (SpatialEditor::get_singleton()->is_visible()) { + if (Node3DEditor::get_singleton()->is_visible()) { // 3D - SpatialEditor::get_singleton()->set_state(spatial_edit_state); + Node3DEditor::get_singleton()->set_state(spatial_edit_state); } else { // CanvasItemEditor // 2D CanvasItemEditor::get_singleton()->set_state(canvas_edit_state); @@ -1503,18 +1437,15 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { } void AnimationPlayerEditor::_start_onion_skinning() { - // FIXME: Using "idle_frame" makes onion layers update one frame behind the current. - if (!get_tree()->is_connected("idle_frame", this, "call_deferred")) { - get_tree()->connect("idle_frame", this, "call_deferred", varray("_prepare_onion_layers_1")); + if (!get_tree()->is_connected("idle_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { + get_tree()->connect("idle_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); } } void AnimationPlayerEditor::_stop_onion_skinning() { - - if (get_tree()->is_connected("idle_frame", this, "call_deferred")) { - - get_tree()->disconnect("idle_frame", this, "call_deferred"); + if (get_tree()->is_connected("idle_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { + get_tree()->disconnect("idle_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); _free_onion_layers(); @@ -1525,56 +1456,31 @@ void AnimationPlayerEditor::_stop_onion_skinning() { } void AnimationPlayerEditor::_pin_pressed() { - EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->update_tree(); } void AnimationPlayerEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayerEditor::_node_removed); - ClassDB::bind_method(D_METHOD("_play_pressed"), &AnimationPlayerEditor::_play_pressed); - ClassDB::bind_method(D_METHOD("_play_from_pressed"), &AnimationPlayerEditor::_play_from_pressed); - ClassDB::bind_method(D_METHOD("_play_bw_pressed"), &AnimationPlayerEditor::_play_bw_pressed); - ClassDB::bind_method(D_METHOD("_play_bw_from_pressed"), &AnimationPlayerEditor::_play_bw_from_pressed); - ClassDB::bind_method(D_METHOD("_stop_pressed"), &AnimationPlayerEditor::_stop_pressed); - ClassDB::bind_method(D_METHOD("_autoplay_pressed"), &AnimationPlayerEditor::_autoplay_pressed); - ClassDB::bind_method(D_METHOD("_animation_selected"), &AnimationPlayerEditor::_animation_selected); - ClassDB::bind_method(D_METHOD("_animation_name_edited"), &AnimationPlayerEditor::_animation_name_edited); ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename); ClassDB::bind_method(D_METHOD("_animation_load"), &AnimationPlayerEditor::_animation_load); ClassDB::bind_method(D_METHOD("_animation_remove"), &AnimationPlayerEditor::_animation_remove); - ClassDB::bind_method(D_METHOD("_animation_remove_confirmed"), &AnimationPlayerEditor::_animation_remove_confirmed); ClassDB::bind_method(D_METHOD("_animation_blend"), &AnimationPlayerEditor::_animation_blend); ClassDB::bind_method(D_METHOD("_animation_edit"), &AnimationPlayerEditor::_animation_edit); ClassDB::bind_method(D_METHOD("_animation_resource_edit"), &AnimationPlayerEditor::_animation_resource_edit); - ClassDB::bind_method(D_METHOD("_dialog_action"), &AnimationPlayerEditor::_dialog_action); - ClassDB::bind_method(D_METHOD("_seek_value_changed"), &AnimationPlayerEditor::_seek_value_changed, DEFVAL(true)); ClassDB::bind_method(D_METHOD("_animation_player_changed"), &AnimationPlayerEditor::_animation_player_changed); - ClassDB::bind_method(D_METHOD("_blend_edited"), &AnimationPlayerEditor::_blend_edited); - ClassDB::bind_method(D_METHOD("_scale_changed"), &AnimationPlayerEditor::_scale_changed); ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); - ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); - ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate); - ClassDB::bind_method(D_METHOD("_blend_editor_next_changed"), &AnimationPlayerEditor::_blend_editor_next_changed); ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &AnimationPlayerEditor::_unhandled_key_input); - ClassDB::bind_method(D_METHOD("_animation_tool_menu"), &AnimationPlayerEditor::_animation_tool_menu); - ClassDB::bind_method(D_METHOD("_onion_skinning_menu"), &AnimationPlayerEditor::_onion_skinning_menu); - ClassDB::bind_method(D_METHOD("_editor_visibility_changed"), &AnimationPlayerEditor::_editor_visibility_changed); ClassDB::bind_method(D_METHOD("_prepare_onion_layers_1"), &AnimationPlayerEditor::_prepare_onion_layers_1); ClassDB::bind_method(D_METHOD("_prepare_onion_layers_2"), &AnimationPlayerEditor::_prepare_onion_layers_2); ClassDB::bind_method(D_METHOD("_start_onion_skinning"), &AnimationPlayerEditor::_start_onion_skinning); ClassDB::bind_method(D_METHOD("_stop_onion_skinning"), &AnimationPlayerEditor::_stop_onion_skinning); - - ClassDB::bind_method(D_METHOD("_pin_pressed"), &AnimationPlayerEditor::_pin_pressed); } -AnimationPlayerEditor *AnimationPlayerEditor::singleton = NULL; +AnimationPlayerEditor *AnimationPlayerEditor::singleton = nullptr; AnimationPlayer *AnimationPlayerEditor::get_player() const { - return player; } @@ -1587,29 +1493,34 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay set_focus_mode(FOCUS_ALL); - player = NULL; + player = nullptr; HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); - play_bw_from = memnew(ToolButton); + play_bw_from = memnew(Button); + play_bw_from->set_flat(true); play_bw_from->set_tooltip(TTR("Play selected animation backwards from current pos. (A)")); hb->add_child(play_bw_from); - play_bw = memnew(ToolButton); + play_bw = memnew(Button); + play_bw->set_flat(true); play_bw->set_tooltip(TTR("Play selected animation backwards from end. (Shift+A)")); hb->add_child(play_bw); - stop = memnew(ToolButton); + stop = memnew(Button); + stop->set_flat(true); stop->set_toggle_mode(true); hb->add_child(stop); stop->set_tooltip(TTR("Stop animation playback. (S)")); - play = memnew(ToolButton); + play = memnew(Button); + play->set_flat(true); play->set_tooltip(TTR("Play selected animation from start. (Shift+D)")); hb->add_child(play); - play_from = memnew(ToolButton); + play_from = memnew(Button); + play_from->set_flat(true); play_from->set_tooltip(TTR("Play selected animation from current pos. (D)")); hb->add_child(play_from); @@ -1629,13 +1540,9 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay scale->set_tooltip(TTR("Scale animation playback globally for the node.")); scale->hide(); - accept = memnew(AcceptDialog); - add_child(accept); - accept->connect("confirmed", this, "_menu_confirm_current"); - delete_dialog = memnew(ConfirmationDialog); add_child(delete_dialog); - delete_dialog->connect("confirmed", this, "_animation_remove_confirmed"); + delete_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_remove_confirmed)); tool_anim = memnew(MenuButton); tool_anim->set_flat(false); @@ -1665,7 +1572,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay animation->set_tooltip(TTR("Display list of animations in player.")); animation->set_clip_text(true); - autoplay = memnew(ToolButton); + autoplay = memnew(Button); + autoplay->set_flat(true); hb->add_child(autoplay); autoplay->set_tooltip(TTR("Autoplay on Load")); @@ -1677,10 +1585,11 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(memnew(VSeparator)); - onion_toggle = memnew(ToolButton); + onion_toggle = memnew(Button); + onion_toggle->set_flat(true); onion_toggle->set_toggle_mode(true); onion_toggle->set_tooltip(TTR("Enable Onion Skinning")); - onion_toggle->connect("pressed", this, "_onion_skinning_menu", varray(ONION_SKINNING_ENABLE)); + onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu), varray(ONION_SKINNING_ENABLE)); hb->add_child(onion_toggle); onion_skinning = memnew(MenuButton); @@ -1702,11 +1611,12 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay hb->add_child(memnew(VSeparator)); - pin = memnew(ToolButton); + pin = memnew(Button); + pin->set_flat(true); pin->set_toggle_mode(true); pin->set_tooltip(TTR("Pin AnimationPlayer")); hb->add_child(pin); - pin->connect("pressed", this, "_pin_pressed"); + pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); file = memnew(EditorFileDialog); add_child(file); @@ -1730,7 +1640,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay error_dialog->set_title(TTR("Error!")); add_child(error_dialog); - name_dialog->connect("confirmed", this, "_animation_name_edited"); + name_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_name_edited)); blend_editor.dialog = memnew(AcceptDialog); add_child(blend_editor.dialog); @@ -1746,21 +1656,21 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay blend_editor.dialog->set_title(TTR("Cross-Animation Blend Times")); updating_blends = false; - blend_editor.tree->connect("item_edited", this, "_blend_edited"); + blend_editor.tree->connect("item_edited", callable_mp(this, &AnimationPlayerEditor::_blend_edited)); - autoplay->connect("pressed", this, "_autoplay_pressed"); + autoplay->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_autoplay_pressed)); autoplay->set_toggle_mode(true); - play->connect("pressed", this, "_play_pressed"); - play_from->connect("pressed", this, "_play_from_pressed"); - play_bw->connect("pressed", this, "_play_bw_pressed"); - play_bw_from->connect("pressed", this, "_play_bw_from_pressed"); - stop->connect("pressed", this, "_stop_pressed"); + play->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_pressed)); + play_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_from_pressed)); + play_bw->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_pressed)); + play_bw_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_from_pressed)); + stop->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_stop_pressed)); - animation->connect("item_selected", this, "_animation_selected", Vector<Variant>(), true); + animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected)); - file->connect("file_selected", this, "_dialog_action"); - frame->connect("value_changed", this, "_seek_value_changed", Vector<Variant>(), true); - scale->connect("text_entered", this, "_scale_changed", Vector<Variant>(), true); + file->connect("file_selected", callable_mp(this, &AnimationPlayerEditor::_dialog_action)); + frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true)); + scale->connect("text_entered", callable_mp(this, &AnimationPlayerEditor::_scale_changed)); renaming = false; last_active = false; @@ -1770,14 +1680,14 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay add_child(track_editor); track_editor->set_v_size_flags(SIZE_EXPAND_FILL); - track_editor->connect("timeline_changed", this, "_animation_key_editor_seek"); - track_editor->connect("animation_len_changed", this, "_animation_key_editor_anim_len_changed"); + track_editor->connect("timeline_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_seek)); + track_editor->connect("animation_len_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_anim_len_changed)); _update_player(); // Onion skinning. - track_editor->connect("visibility_changed", this, "_editor_visibility_changed"); + track_editor->connect("visibility_changed", callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed)); onion.enabled = false; onion.past = true; @@ -1790,9 +1700,9 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay onion.last_frame = 0; onion.can_overlay = false; onion.capture_size = Size2(); - onion.capture.canvas = VS::get_singleton()->canvas_create(); - onion.capture.canvas_item = VS::get_singleton()->canvas_item_create(); - VS::get_singleton()->canvas_item_set_parent(onion.capture.canvas_item, onion.capture.canvas); + onion.capture.canvas = RS::get_singleton()->canvas_create(); + onion.capture.canvas_item = RS::get_singleton()->canvas_item_create(); + RS::get_singleton()->canvas_item_set_parent(onion.capture.canvas_item, onion.capture.canvas); onion.capture.material = Ref<ShaderMaterial>(memnew(ShaderMaterial)); @@ -1818,43 +1728,37 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay COLOR = vec4(capture_samp.rgb * dir_color.rgb, bkg_mask * diff_mask); \ } \ "); - VS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid()); + RS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid()); } AnimationPlayerEditor::~AnimationPlayerEditor() { - _free_onion_layers(); - VS::get_singleton()->free(onion.capture.canvas); - VS::get_singleton()->free(onion.capture.canvas_item); + RS::get_singleton()->free(onion.capture.canvas); + RS::get_singleton()->free(onion.capture.canvas_item); } void AnimationPlayerEditorPlugin::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_ENTER_TREE: { - set_force_draw_over_forwarding_enabled(); } break; } } void AnimationPlayerEditorPlugin::edit(Object *p_object) { - anim_editor->set_undo_redo(&get_undo_redo()); - if (!p_object) + if (!p_object) { return; + } anim_editor->edit(Object::cast_to<AnimationPlayer>(p_object)); } bool AnimationPlayerEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AnimationPlayer"); } void AnimationPlayerEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - editor->make_bottom_panel_item_visible(anim_editor); anim_editor->set_process(true); anim_editor->ensure_visibility(); @@ -1862,7 +1766,6 @@ void AnimationPlayerEditorPlugin::make_visible(bool p_visible) { } AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) { - editor = p_node; anim_editor = memnew(AnimationPlayerEditor(editor, this)); anim_editor->set_undo_redo(EditorNode::get_undo_redo()); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 55c2f365ce..e11db1390b 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -43,7 +43,6 @@ class AnimationTrackEditor; class AnimationPlayerEditorPlugin; class AnimationPlayerEditor : public VBoxContainer { - GDCLASS(AnimationPlayerEditor, VBoxContainer); EditorNode *editor; @@ -97,25 +96,23 @@ class AnimationPlayerEditor : public VBoxContainer { Button *autoplay; MenuButton *tool_anim; - ToolButton *onion_toggle; + Button *onion_toggle; MenuButton *onion_skinning; - ToolButton *pin; + Button *pin; SpinBox *frame; LineEdit *scale; LineEdit *name; Label *name_title; UndoRedo *undo_redo; - Ref<Texture> autoplay_icon; + Ref<Texture2D> autoplay_icon; bool last_active; float timeline_position; EditorFileDialog *file; - AcceptDialog *accept; ConfirmationDialog *delete_dialog; int current_option; struct BlendEditor { - AcceptDialog *dialog; Tree *tree; OptionButton *next; @@ -210,6 +207,7 @@ class AnimationPlayerEditor : public VBoxContainer { void _allocate_onion_layers(); void _free_onion_layers(); void _prepare_onion_layers_1(); + void _prepare_onion_layers_1_deferred(); void _prepare_onion_layers_2(); void _start_onion_skinning(); void _stop_onion_skinning(); @@ -244,7 +242,6 @@ public: }; class AnimationPlayerEditorPlugin : public EditorPlugin { - GDCLASS(AnimationPlayerEditorPlugin, EditorPlugin); AnimationPlayerEditor *anim_editor; @@ -254,16 +251,16 @@ protected: void _notification(int p_what); public: - virtual Dictionary get_state() const { return anim_editor->get_state(); } - virtual void set_state(const Dictionary &p_state) { anim_editor->set_state(p_state); } + virtual Dictionary get_state() const override { return anim_editor->get_state(); } + virtual void set_state(const Dictionary &p_state) override { anim_editor->set_state(p_state); } - virtual String get_name() const { return "Anim"; } - 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); + virtual String get_name() const override { return "Anim"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; - virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) { anim_editor->forward_canvas_force_draw_over_viewport(p_overlay); } + virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_canvas_force_draw_over_viewport(p_overlay); } AnimationPlayerEditorPlugin(EditorNode *p_node); ~AnimationPlayerEditorPlugin(); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 2a582a1249..26006d85c9 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -30,9 +30,9 @@ #include "animation_state_machine_editor.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" -#include "core/math/delaunay.h" -#include "core/os/input.h" +#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/editor_scale.h" @@ -40,20 +40,17 @@ #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) { - Ref<AnimationNodeStateMachine> ansm = p_node; return ansm.is_valid(); } void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { - state_machine = p_node; if (state_machine.is_valid()) { - selected_transition_from = StringName(); selected_transition_to = StringName(); selected_node = StringName(); @@ -63,13 +60,13 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { } void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - if (playback.is_null()) + if (playback.is_null()) { return; + } Ref<InputEventKey> k = p_event; - if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && !k->is_echo()) { if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) { _erase_selected(); accept_event(); @@ -97,17 +94,17 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv List<StringName> names; ap->get_animation_list(&names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get()); + animations_menu->add_icon_item(get_theme_icon("Animation", "EditorIcons"), E->get()); animations_to_add.push_back(E->get()); } } } for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { - String name = String(E->get()).replace_first("AnimationNode", ""); - if (name == "Animation") + if (name == "Animation") { continue; // nope + } int idx = menu->get_item_count(); menu->add_item(vformat("Add %s", name), idx); menu->set_item_metadata(idx, E->get()); @@ -121,14 +118,13 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv menu->add_separator(); menu->add_item(TTR("Load..."), MENU_LOAD_FILE); - menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); + menu->set_position(state_machine_draw->get_screen_transform().xform(mb->get_position())); menu->popup(); add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset(); } // select node or push a field inside if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - selected_transition_from = StringName(); selected_transition_to = StringName(); selected_node = StringName(); @@ -149,16 +145,16 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv if (node_rects[i].name.has_point(mb->get_position())) { //edit name - Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit"); + Ref<StyleBox> line_sb = get_theme_stylebox("normal", "LineEdit"); Rect2 edit_rect = node_rects[i].name; edit_rect.position -= line_sb->get_offset(); edit_rect.size += line_sb->get_minimum_size(); - name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); - name_edit->set_size(edit_rect.size); + name_edit_popup->set_position(state_machine_draw->get_screen_transform().xform(edit_rect.position)); + name_edit_popup->set_size(edit_rect.size); name_edit->set_text(node_rects[i].node_name); - name_edit->show_modal(); + name_edit_popup->popup(); name_edit->grab_focus(); name_edit->select_all(); @@ -191,12 +187,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv int closest = -1; float closest_d = 1e20; for (int i = 0; i < transition_lines.size(); i++) { - Vector2 s[2] = { transition_lines[i].from, transition_lines[i].to }; - Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s); + Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mb->get_position(), s); float d = cpoint.distance_to(mb->get_position()); if (d > transition_lines[i].width) { continue; @@ -222,9 +217,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //end moving node if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { - if (dragging_selected) { - Ref<AnimationNode> an = state_machine->get_node(selected_node); updating = true; undo_redo->create_action(TTR("Move Node")); @@ -245,7 +238,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //connect nodes if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected connecting = true; @@ -259,14 +251,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //end connecting nodes if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { - if (connecting_to_node != StringName()) { - if (state_machine->has_transition(connecting_from, connecting_to_node)) { EditorNode::get_singleton()->show_warning(TTR("Transition exists!")); } else { - Ref<AnimationNodeStateMachineTransition> tr; tr.instance(); tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); @@ -296,14 +285,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //pan window if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) { - h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); } //move mouse while connecting if (mm.is_valid() && connecting) { - connecting_to = mm->get_position(); connecting_to_node = StringName(); state_machine_draw->update(); @@ -318,7 +305,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //move mouse while moving a node if (mm.is_valid() && dragging_selected_attempt) { - dragging_selected = true; drag_ofs = mm->get_position() - drag_from; snap_x = StringName(); @@ -333,8 +319,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv float best_d_y = 1e20; for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { - if (E->get() == selected_node) + if (E->get() == selected_node) { continue; + } Vector2 npos = state_machine->get_node_position(E->get()); float d_x = ABS(npos.x - cpos.x); @@ -358,14 +345,12 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv //put ibeam (text cursor) over names to make it clearer that they are editable if (mm.is_valid()) { - state_machine_draw->grab_focus(); bool over_text_now = false; String new_over_node = StringName(); int new_over_node_what = -1; if (tool_select->is_pressed()) { - for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order if (node_rects[i].name.has_point(mm->get_position())) { @@ -392,7 +377,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } if (over_text != over_text_now) { - if (over_text_now) { state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM); } else { @@ -405,7 +389,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) { - file_loaded = ResourceLoader::load(p_file); if (file_loaded.is_valid()) { _add_menu_type(MENU_LOAD_FILE_CONFIRM); @@ -413,25 +396,22 @@ void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) { } void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { - String base_name; Ref<AnimationRootNode> node; if (p_index == MENU_LOAD_FILE) { - open_file->clear_filters(); List<String> filters; ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters); for (List<String>::Element *E = filters.front(); E; E = E->next()) { open_file->add_filter("*." + E->get()); } - open_file->popup_centered_ratio(); + open_file->popup_file_dialog(); return; } else if (p_index == MENU_LOAD_FILE_CONFIRM) { node = file_loaded; file_loaded.unref(); } else if (p_index == MENU_PASTE) { - node = EditorSettings::get_singleton()->get_resource_clipboard(); } else { @@ -452,7 +432,6 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } if (base_name == String()) { - base_name = node->get_class().replace_first("AnimationNode", ""); } @@ -476,7 +455,6 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { - Ref<AnimationNodeAnimation> anim; anim.instance(); @@ -503,10 +481,9 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { } void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance) { - - Color linecolor = get_color("font_color", "Label"); + Color linecolor = get_theme_color("font_color", "Label"); Color icon_color(1, 1, 1); - Color accent = get_color("accent_color", "Editor"); + Color accent = get_theme_color("accent_color", "Editor"); if (!p_enabled) { linecolor.a *= 0.2; @@ -514,26 +491,26 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co accent.a *= 0.6; } - Ref<Texture> icons[6] = { - get_icon("TransitionImmediateBig", "EditorIcons"), - get_icon("TransitionSyncBig", "EditorIcons"), - get_icon("TransitionEndBig", "EditorIcons"), - get_icon("TransitionImmediateAutoBig", "EditorIcons"), - get_icon("TransitionSyncAutoBig", "EditorIcons"), - get_icon("TransitionEndAutoBig", "EditorIcons") + Ref<Texture2D> icons[6] = { + get_theme_icon("TransitionImmediateBig", "EditorIcons"), + get_theme_icon("TransitionSyncBig", "EditorIcons"), + get_theme_icon("TransitionEndBig", "EditorIcons"), + get_theme_icon("TransitionImmediateAutoBig", "EditorIcons"), + get_theme_icon("TransitionSyncAutoBig", "EditorIcons"), + get_theme_icon("TransitionEndAutoBig", "EditorIcons") }; if (p_selected) { - state_machine_draw->draw_line(p_from, p_to, accent, 6, true); + state_machine_draw->draw_line(p_from, p_to, accent, 6); } if (p_travel) { linecolor = accent; linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v()); } - state_machine_draw->draw_line(p_from, p_to, linecolor, 2, true); + state_machine_draw->draw_line(p_from, p_to, linecolor, 2); - Ref<Texture> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; + Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; Transform2D xf; xf.elements[0] = (p_to - p_from).normalized(); @@ -546,9 +523,9 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co } void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { - - if (r_to == r_from) + if (r_to == r_from) { return; + } //this could be optimized... Vector2 n = (r_to - r_from).normalized(); @@ -558,9 +535,9 @@ void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, Ve } void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { - - if (r_to == r_from) + if (r_to == r_from) { return; + } //this could be optimized... Vector2 n = (r_to - r_from).normalized(); @@ -570,21 +547,20 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Ve } void AnimationNodeStateMachineEditor::_state_machine_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - Ref<StyleBox> style = get_stylebox("state_machine_frame", "GraphNode"); - Ref<StyleBox> style_selected = get_stylebox("state_machine_selectedframe", "GraphNode"); + Ref<StyleBox> style = get_theme_stylebox("state_machine_frame", "GraphNode"); + Ref<StyleBox> style_selected = get_theme_stylebox("state_machine_selectedframe", "GraphNode"); - Ref<Font> font = get_font("title_font", "GraphNode"); - Color font_color = get_color("title_color", "GraphNode"); - Ref<Texture> play = get_icon("Play", "EditorIcons"); - Ref<Texture> auto_play = get_icon("AutoPlay", "EditorIcons"); - Ref<Texture> edit = get_icon("Edit", "EditorIcons"); - Color accent = get_color("accent_color", "Editor"); - Color linecolor = get_color("font_color", "Label"); + Ref<Font> font = get_theme_font("title_font", "GraphNode"); + Color font_color = get_theme_color("title_color", "GraphNode"); + Ref<Texture2D> play = get_theme_icon("Play", "EditorIcons"); + Ref<Texture2D> auto_play = get_theme_icon("AutoPlay", "EditorIcons"); + Ref<Texture2D> edit = get_theme_icon("Edit", "EditorIcons"); + Color accent = get_theme_color("accent_color", "Editor"); + Color linecolor = get_theme_color("font_color", "Label"); linecolor.a *= 0.3; - Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode"); + Ref<StyleBox> playing_overlay = get_theme_stylebox("position", "GraphNode"); bool playing = false; StringName current; @@ -611,7 +587,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { //snap lines if (dragging_selected) { - Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE; if (snap_x != StringName()) { Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; @@ -625,7 +600,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { //pre pass nodes so we know the rectangles for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { - Ref<AnimationNode> anode = state_machine->get_node(E->get()); String name = E->get(); bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr()); @@ -686,12 +660,11 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false); } - Ref<Texture> tr_reference_icon = get_icon("TransitionImmediateBig", "EditorIcons"); + Ref<Texture2D> tr_reference_icon = get_theme_icon("TransitionImmediateBig", "EditorIcons"); float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8); //draw transition lines for (int i = 0; i < state_machine->get_transition_count(); i++) { - TransitionLine tl; tl.from_node = state_machine->get_transition_from(i); Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2(); @@ -733,7 +706,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } if (travel_path.size()) { - if (current == tl.from_node && travel_path[0] == tl.to_node) { travel = true; } else { @@ -759,7 +731,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { //draw actual nodes for (int i = 0; i < node_rects.size(); i++) { - String name = node_rects[i].node_name; Ref<AnimationNode> anode = state_machine->get_node(name); bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); @@ -786,7 +757,6 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } if (state_machine->get_end_node() == name) { - int endofs = nr.node.size.x - font->get_string_size(TTR("End")).x; state_machine_draw->draw_string(font, offset + Vector2(endofs, -font->get_height() - 3 * EDSCALE + font->get_ascent()), TTR("End"), font_color); } @@ -796,7 +766,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor(); nr.play.size = play->get_size(); - Ref<Texture> play_tex = onstart ? auto_play : play; + Ref<Texture2D> play_tex = onstart ? auto_play : play; if (over_node == name && over_node_what == 0) { state_machine_draw->draw_texture(play_tex, nr.play.position, accent); @@ -844,11 +814,11 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - if (!playback.is_valid() || !playback->is_playing()) + if (!playback.is_valid() || !playback->is_playing()) { return; + } int idx = -1; for (int i = 0; i < node_rects.size(); i++) { @@ -858,8 +828,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { } } - if (idx == -1) + if (idx == -1) { return; + } const NodeRect &nr = node_rects[idx]; @@ -879,21 +850,21 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { float pos = CLAMP(play_pos, 0, len); float c = pos / len; - Color fg = get_color("font_color", "Label"); + Color fg = get_theme_color("font_color", "Label"); Color bg = fg; bg.a *= 0.3; state_machine_play_pos->draw_line(from, to, bg, 2); - to = from.linear_interpolate(to, c); + to = from.lerp(to, c); state_machine_play_pos->draw_line(from, to, fg, 2); } void AnimationNodeStateMachineEditor::_update_graph() { - - if (updating) + if (updating) { return; + } updating = true; @@ -903,40 +874,30 @@ void AnimationNodeStateMachineEditor::_update_graph() { } void AnimationNodeStateMachineEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); - panel->add_style_override("panel", get_stylebox("bg", "Tree")); + error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); + panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); - tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); - tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons")); - tool_connect->set_icon(get_icon("ToolConnect", "EditorIcons")); + tool_select->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_theme_icon("ToolAddNode", "EditorIcons")); + tool_connect->set_icon(get_theme_icon("ToolConnect", "EditorIcons")); transition_mode->clear(); - transition_mode->add_icon_item(get_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate")); - transition_mode->add_icon_item(get_icon("TransitionSync", "EditorIcons"), TTR("Sync")); - transition_mode->add_icon_item(get_icon("TransitionEnd", "EditorIcons"), TTR("At End")); - - //force filter on those, so they deform better - get_icon("TransitionImmediateBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - get_icon("TransitionEndBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - get_icon("TransitionSyncBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - get_icon("TransitionImmediateAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - get_icon("TransitionEndAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - get_icon("TransitionSyncAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); - - tool_erase->set_icon(get_icon("Remove", "EditorIcons")); - tool_autoplay->set_icon(get_icon("AutoPlay", "EditorIcons")); - tool_end->set_icon(get_icon("AutoEnd", "EditorIcons")); + transition_mode->add_icon_item(get_theme_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate")); + transition_mode->add_icon_item(get_theme_icon("TransitionSync", "EditorIcons"), TTR("Sync")); + transition_mode->add_icon_item(get_theme_icon("TransitionEnd", "EditorIcons"), TTR("At End")); + + tool_erase->set_icon(get_theme_icon("Remove", "EditorIcons")); + tool_autoplay->set_icon(get_theme_icon("AutoPlay", "EditorIcons")); + tool_end->set_icon(get_theme_icon("AutoEnd", "EditorIcons")); play_mode->clear(); - play_mode->add_icon_item(get_icon("PlayTravel", "EditorIcons"), TTR("Travel")); - play_mode->add_icon_item(get_icon("Play", "EditorIcons"), TTR("Immediate")); + play_mode->add_icon_item(get_theme_icon("PlayTravel", "EditorIcons"), TTR("Travel")); + play_mode->add_icon_item(get_theme_icon("Play", "EditorIcons"), TTR("Immediate")); } if (p_what == NOTIFICATION_PROCESS) { - String error; Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); @@ -1025,7 +986,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } { - if (last_travel_path.size() != tp.size()) { same_travel_path = false; } else { @@ -1040,7 +1000,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { //update if travel state changed if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) { - state_machine_draw->update(); last_travel_path = tp; last_current_node = current_node; @@ -1051,7 +1010,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { { if (current_node != StringName() && state_machine->has_node(current_node)) { - String next = current_node; Ref<AnimationNodeStateMachine> anodesm = state_machine->get_node(next); Ref<AnimationNodeStateMachinePlayback> current_node_playback; @@ -1071,7 +1029,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } if (last_play_pos != play_pos) { - last_play_pos = play_pos; state_machine_play_pos->update(); } @@ -1084,17 +1041,14 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) { - AnimationTreeEditor::get_singleton()->enter_editor(p_name); } void AnimationNodeStateMachineEditor::_removed_from_graph() { - - EditorNode::get_singleton()->edit_item(NULL); + EditorNode::get_singleton()->edit_item(nullptr); } void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { - const String &new_name = p_text; ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1); @@ -1118,31 +1072,30 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); - name_edit->hide(); + name_edit_popup->hide(); updating = false; state_machine_draw->update(); } void AnimationNodeStateMachineEditor::_name_edited_focus_out() { - - if (updating) + if (updating) { return; + } _name_edited(name_edit->get_text()); } void AnimationNodeStateMachineEditor::_scroll_changed(double) { - - if (updating) + if (updating) { return; + } state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value())); state_machine_draw->update(); } void AnimationNodeStateMachineEditor::_erase_selected() { - if (selected_node != StringName() && state_machine->has_node(selected_node)) { updating = true; undo_redo->create_action(TTR("Node Removed")); @@ -1166,7 +1119,6 @@ void AnimationNodeStateMachineEditor::_erase_selected() { } if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) { - Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to)); updating = true; undo_redo->create_action(TTR("Transition Removed")); @@ -1184,9 +1136,7 @@ void AnimationNodeStateMachineEditor::_erase_selected() { } void AnimationNodeStateMachineEditor::_autoplay_selected() { - if (selected_node != StringName() && state_machine->has_node(selected_node)) { - StringName new_start_node; if (state_machine->get_start_node() == selected_node) { //toggle it new_start_node = StringName(); @@ -1207,9 +1157,7 @@ void AnimationNodeStateMachineEditor::_autoplay_selected() { } void AnimationNodeStateMachineEditor::_end_selected() { - if (selected_node != StringName() && state_machine->has_node(selected_node)) { - StringName new_end_node; if (state_machine->get_end_node() == selected_node) { //toggle it new_end_node = StringName(); @@ -1228,8 +1176,8 @@ void AnimationNodeStateMachineEditor::_end_selected() { state_machine_draw->update(); } } -void AnimationNodeStateMachineEditor::_update_mode() { +void AnimationNodeStateMachineEditor::_update_mode() { if (tool_select->is_pressed()) { tool_erase_hb->show(); tool_erase->set_disabled(selected_node == StringName() && selected_transition_from == StringName() && selected_transition_to == StringName()); @@ -1241,34 +1189,16 @@ void AnimationNodeStateMachineEditor::_update_mode() { } void AnimationNodeStateMachineEditor::_bind_methods() { - - ClassDB::bind_method("_state_machine_gui_input", &AnimationNodeStateMachineEditor::_state_machine_gui_input); - ClassDB::bind_method("_state_machine_draw", &AnimationNodeStateMachineEditor::_state_machine_draw); - ClassDB::bind_method("_state_machine_pos_draw", &AnimationNodeStateMachineEditor::_state_machine_pos_draw); ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph); - ClassDB::bind_method("_add_menu_type", &AnimationNodeStateMachineEditor::_add_menu_type); - ClassDB::bind_method("_add_animation_type", &AnimationNodeStateMachineEditor::_add_animation_type); - - ClassDB::bind_method("_name_edited", &AnimationNodeStateMachineEditor::_name_edited); - ClassDB::bind_method("_name_edited_focus_out", &AnimationNodeStateMachineEditor::_name_edited_focus_out); - ClassDB::bind_method("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph); ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor); - ClassDB::bind_method("_scroll_changed", &AnimationNodeStateMachineEditor::_scroll_changed); - - ClassDB::bind_method("_erase_selected", &AnimationNodeStateMachineEditor::_erase_selected); - ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected); - ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected); - ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode); - ClassDB::bind_method("_file_opened", &AnimationNodeStateMachineEditor::_file_opened); } -AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL; +AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = nullptr; AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { - singleton = this; updating = false; @@ -1278,49 +1208,55 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { Ref<ButtonGroup> bg; bg.instance(); - tool_select = memnew(ToolButton); + tool_select = memnew(Button); + tool_select->set_flat(true); top_hb->add_child(tool_select); tool_select->set_toggle_mode(true); tool_select->set_button_group(bg); tool_select->set_pressed(true); tool_select->set_tooltip(TTR("Select and move nodes.\nRMB to add new nodes.\nShift+LMB to create connections.")); - tool_select->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + tool_select->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED); - tool_create = memnew(ToolButton); + tool_create = memnew(Button); + tool_create->set_flat(true); top_hb->add_child(tool_create); tool_create->set_toggle_mode(true); tool_create->set_button_group(bg); tool_create->set_tooltip(TTR("Create new nodes.")); - tool_create->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + tool_create->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED); - tool_connect = memnew(ToolButton); + tool_connect = memnew(Button); + tool_connect->set_flat(true); top_hb->add_child(tool_connect); tool_connect->set_toggle_mode(true); tool_connect->set_button_group(bg); tool_connect->set_tooltip(TTR("Connect nodes.")); - tool_connect->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), varray(), CONNECT_DEFERRED); tool_erase_hb = memnew(HBoxContainer); top_hb->add_child(tool_erase_hb); tool_erase_hb->add_child(memnew(VSeparator)); - tool_erase = memnew(ToolButton); + tool_erase = memnew(Button); + tool_erase->set_flat(true); tool_erase->set_tooltip(TTR("Remove selected node or transition.")); tool_erase_hb->add_child(tool_erase); - tool_erase->connect("pressed", this, "_erase_selected"); + tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected)); tool_erase->set_disabled(true); tool_erase_hb->add_child(memnew(VSeparator)); - tool_autoplay = memnew(ToolButton); + tool_autoplay = memnew(Button); + tool_autoplay->set_flat(true); tool_autoplay->set_tooltip(TTR("Toggle autoplay this animation on start, restart or seek to zero.")); tool_erase_hb->add_child(tool_autoplay); - tool_autoplay->connect("pressed", this, "_autoplay_selected"); + tool_autoplay->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_autoplay_selected)); tool_autoplay->set_disabled(true); - tool_end = memnew(ToolButton); + tool_end = memnew(Button); + tool_end->set_flat(true); tool_end->set_tooltip(TTR("Set the end animation. This is useful for sub-transitions.")); tool_erase_hb->add_child(tool_end); - tool_end->connect("pressed", this, "_end_selected"); + tool_end->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_end_selected)); tool_end->set_disabled(true); top_hb->add_child(memnew(VSeparator)); @@ -1341,26 +1277,26 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { state_machine_draw = memnew(Control); panel->add_child(state_machine_draw); - state_machine_draw->connect("gui_input", this, "_state_machine_gui_input"); - state_machine_draw->connect("draw", this, "_state_machine_draw"); + state_machine_draw->connect("gui_input", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_gui_input)); + state_machine_draw->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_draw)); state_machine_draw->set_focus_mode(FOCUS_ALL); state_machine_play_pos = memnew(Control); state_machine_draw->add_child(state_machine_play_pos); state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent state_machine_play_pos->set_anchors_and_margins_preset(PRESET_WIDE); - state_machine_play_pos->connect("draw", this, "_state_machine_pos_draw"); + state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw)); v_scroll = memnew(VScrollBar); state_machine_draw->add_child(v_scroll); v_scroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); - v_scroll->connect("value_changed", this, "_scroll_changed"); + v_scroll->connect("value_changed", callable_mp(this, &AnimationNodeStateMachineEditor::_scroll_changed)); h_scroll = memnew(HScrollBar); state_machine_draw->add_child(h_scroll); h_scroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); h_scroll->set_margin(MARGIN_RIGHT, -v_scroll->get_size().x * EDSCALE); - h_scroll->connect("value_changed", this, "_scroll_changed"); + h_scroll->connect("value_changed", callable_mp(this, &AnimationNodeStateMachineEditor::_scroll_changed)); error_panel = memnew(PanelContainer); add_child(error_panel); @@ -1374,25 +1310,26 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { menu = memnew(PopupMenu); add_child(menu); - menu->connect("id_pressed", this, "_add_menu_type"); + menu->connect("id_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_menu_type)); animations_menu = memnew(PopupMenu); menu->add_child(animations_menu); animations_menu->set_name("animations"); - animations_menu->connect("index_pressed", this, "_add_animation_type"); + animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_add_animation_type)); + name_edit_popup = memnew(Popup); + add_child(name_edit_popup); name_edit = memnew(LineEdit); - state_machine_draw->add_child(name_edit); - name_edit->hide(); - name_edit->connect("text_entered", this, "_name_edited"); - name_edit->connect("focus_exited", this, "_name_edited_focus_out"); - name_edit->set_as_toplevel(true); + name_edit_popup->add_child(name_edit); + name_edit->set_anchors_and_margins_preset(PRESET_WIDE); + name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); + name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); open_file = memnew(EditorFileDialog); add_child(open_file); open_file->set_title(TTR("Open Animation Node")); - open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE); - open_file->connect("file_selected", this, "_file_opened"); + open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + open_file->connect("file_selected", callable_mp(this, &AnimationNodeStateMachineEditor::_file_opened)); undo_redo = EditorNode::get_undo_redo(); over_text = false; diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 132e66b28d..f78d90bdbf 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -42,20 +42,20 @@ #include "scene/gui/tree.h" class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { - GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin); Ref<AnimationNodeStateMachine> state_machine; - ToolButton *tool_select; - ToolButton *tool_create; - ToolButton *tool_connect; + Button *tool_select; + Button *tool_create; + Button *tool_connect; + Popup *name_edit_popup; LineEdit *name_edit; HBoxContainer *tool_erase_hb; - ToolButton *tool_erase; - ToolButton *tool_autoplay; - ToolButton *tool_end; + Button *tool_erase; + Button *tool_autoplay; + Button *tool_end; OptionButton *transition_mode; OptionButton *play_mode; @@ -182,8 +182,8 @@ protected: public: static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } - virtual bool can_edit(const Ref<AnimationNode> &p_node); - virtual void edit(const Ref<AnimationNode> &p_node); + virtual bool can_edit(const Ref<AnimationNode> &p_node) override; + virtual void edit(const Ref<AnimationNode> &p_node) override; AnimationNodeStateMachineEditor(); }; diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 8dc7e4638d..269c54ba2b 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -34,9 +34,9 @@ #include "animation_blend_space_2d_editor.h" #include "animation_blend_tree_editor_plugin.h" #include "animation_state_machine_editor.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" -#include "core/math/delaunay.h" -#include "core/os/input.h" +#include "core/math/delaunay_2d.h" #include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/editor_scale.h" @@ -44,13 +44,13 @@ #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" void AnimationTreeEditor::edit(AnimationTree *p_tree) { - - if (tree == p_tree) + if (tree == p_tree) { return; + } tree = p_tree; @@ -59,12 +59,11 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { path = tree->get_meta("_tree_edit_path"); edit_path(path); } else { - current_root = 0; + current_root = ObjectID(); } } void AnimationTreeEditor::_path_button_pressed(int p_path) { - edited_path.clear(); for (int i = 0; i <= p_path; i++) { edited_path.push_back(button_path[i]); @@ -80,12 +79,12 @@ void AnimationTreeEditor::_update_path() { group.instance(); Button *b = memnew(Button); - b->set_text("root"); + b->set_text("Root"); b->set_toggle_mode(true); b->set_button_group(group); b->set_pressed(true); b->set_focus_mode(FOCUS_NONE); - b->connect("pressed", this, "_path_button_pressed", varray(-1)); + b->connect("pressed", callable_mp(this, &AnimationTreeEditor::_path_button_pressed), varray(-1)); path_hb->add_child(b); for (int i = 0; i < button_path.size(); i++) { b = memnew(Button); @@ -95,12 +94,11 @@ void AnimationTreeEditor::_update_path() { path_hb->add_child(b); b->set_pressed(true); b->set_focus_mode(FOCUS_NONE); - b->connect("pressed", this, "_path_button_pressed", varray(i)); + b->connect("pressed", callable_mp(this, &AnimationTreeEditor::_path_button_pressed), varray(i)); } } void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { - button_path.clear(); Ref<AnimationNode> node = tree->get_tree_root(); @@ -109,7 +107,6 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { current_root = node->get_instance_id(); for (int i = 0; i < p_path.size(); i++) { - Ref<AnimationNode> child = node->get_child_by_name(p_path[i]); ERR_BREAK(child.is_null()); node = child; @@ -128,7 +125,7 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { } } } else { - current_root = 0; + current_root = ObjectID(); edited_path = button_path; } @@ -140,7 +137,6 @@ Vector<String> AnimationTreeEditor::get_edited_path() const { } void AnimationTreeEditor::enter_editor(const String &p_path) { - Vector<String> path = edited_path; path.push_back(p_path); edit_path(path); @@ -151,7 +147,7 @@ void AnimationTreeEditor::_about_to_show_root() { void AnimationTreeEditor::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - ObjectID root = 0; + ObjectID root; if (tree && tree->get_tree_root().is_valid()) { root = tree->get_tree_root()->get_instance_id(); } @@ -167,10 +163,9 @@ void AnimationTreeEditor::_notification(int p_what) { } void AnimationTreeEditor::_bind_methods() { - ClassDB::bind_method("_path_button_pressed", &AnimationTreeEditor::_path_button_pressed); } -AnimationTreeEditor *AnimationTreeEditor::singleton = NULL; +AnimationTreeEditor *AnimationTreeEditor::singleton = nullptr; void AnimationTreeEditor::add_plugin(AnimationTreeNodeEditorPlugin *p_editor) { ERR_FAIL_COND(p_editor->get_parent()); @@ -205,19 +200,20 @@ bool AnimationTreeEditor::can_edit(const Ref<AnimationNode> &p_node) const { } Vector<String> AnimationTreeEditor::get_animation_list() { - if (!singleton->is_visible()) { return Vector<String>(); } AnimationTree *tree = singleton->tree; - if (!tree || !tree->has_node(tree->get_animation_player())) + if (!tree || !tree->has_node(tree->get_animation_player())) { return Vector<String>(); + } AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); - if (!ap) + if (!ap) { return Vector<String>(); + } List<StringName> anims; ap->get_animation_list(&anims); @@ -230,7 +226,6 @@ Vector<String> AnimationTreeEditor::get_animation_list() { } AnimationTreeEditor::AnimationTreeEditor() { - AnimationNodeAnimation::get_editable_animation_list = get_animation_list; path_edit = memnew(ScrollContainer); add_child(path_edit); @@ -242,9 +237,8 @@ AnimationTreeEditor::AnimationTreeEditor() { add_child(memnew(HSeparator)); - current_root = 0; singleton = this; - editor_base = memnew(PanelContainer); + editor_base = memnew(MarginContainer); editor_base->set_v_size_flags(SIZE_EXPAND_FILL); add_child(editor_base); @@ -255,17 +249,14 @@ AnimationTreeEditor::AnimationTreeEditor() { } void AnimationTreeEditorPlugin::edit(Object *p_object) { - anim_tree_editor->edit(Object::cast_to<AnimationTree>(p_object)); } bool AnimationTreeEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AnimationTree"); } void AnimationTreeEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { //editor->hide_animation_player_editors(); //editor->animation_panel_make_visible(true); @@ -273,16 +264,15 @@ void AnimationTreeEditorPlugin::make_visible(bool p_visible) { editor->make_bottom_panel_item_visible(anim_tree_editor); anim_tree_editor->set_process(true); } else { - - if (anim_tree_editor->is_visible_in_tree()) + if (anim_tree_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } button->hide(); anim_tree_editor->set_process(false); } } AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) { - editor = p_node; anim_tree_editor = memnew(AnimationTreeEditor); anim_tree_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index 0b93b0fd8e..356a078d99 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -49,14 +49,13 @@ public: }; class AnimationTreeEditor : public VBoxContainer { - GDCLASS(AnimationTreeEditor, VBoxContainer); ScrollContainer *path_edit; HBoxContainer *path_hb; AnimationTree *tree; - PanelContainer *editor_base; + MarginContainer *editor_base; Vector<String> button_path; Vector<String> edited_path; @@ -95,7 +94,6 @@ public: }; class AnimationTreeEditorPlugin : public EditorPlugin { - GDCLASS(AnimationTreeEditorPlugin, EditorPlugin); AnimationTreeEditor *anim_tree_editor; @@ -103,11 +101,11 @@ class AnimationTreeEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "AnimationTree"; } - 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); + virtual String get_name() const override { return "AnimationTree"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; AnimationTreeEditorPlugin(EditorNode *p_node); ~AnimationTreeEditorPlugin(); diff --git a/editor/plugins/animation_tree_player_editor_plugin.cpp b/editor/plugins/animation_tree_player_editor_plugin.cpp deleted file mode 100644 index 2b365feec5..0000000000 --- a/editor/plugins/animation_tree_player_editor_plugin.cpp +++ /dev/null @@ -1,1451 +0,0 @@ -/*************************************************************************/ -/* animation_tree_player_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "animation_tree_player_editor_plugin.h" - -#include "core/io/resource_loader.h" -#include "core/os/input.h" -#include "core/os/keyboard.h" -#include "core/project_settings.h" -#include "editor/editor_scale.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/panel.h" -#include "scene/main/viewport.h" - -void AnimationTreePlayerEditor::edit(AnimationTreePlayer *p_anim_tree) { - - anim_tree = p_anim_tree; - - if (!anim_tree) { - hide(); - } else { - order.clear(); - p_anim_tree->get_node_list(&order); - /* - for(List<StringName>::Element* E=order.front();E;E=E->next()) { - - if (E->get() >= (int)last_id) - last_id=E->get()+1; - }*/ - play_button->set_pressed(p_anim_tree->is_active()); - //read the orders - } -} - -Size2 AnimationTreePlayerEditor::_get_maximum_size() { - - Size2 max; - - for (List<StringName>::Element *E = order.front(); E; E = E->next()) { - - Point2 pos = anim_tree->node_get_position(E->get()); - - if (click_type == CLICK_NODE && click_node == E->get()) { - - pos += click_motion - click_pos; - } - pos += get_node_size(E->get()); - if (pos.x > max.x) - max.x = pos.x; - if (pos.y > max.y) - max.y = pos.y; - } - - return max; -} - -const char *AnimationTreePlayerEditor::_node_type_names[] = { "Output", "Animation", "OneShot", "Mix", "Blend2", "Blend3", "Blend4", "TimeScale", "TimeSeek", "Transition" }; - -Size2 AnimationTreePlayerEditor::get_node_size(const StringName &p_node) const { - - AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node); - - Ref<StyleBox> style = get_stylebox("panel", "PopupMenu"); - Ref<Font> font = get_font("font", "PopupMenu"); - - Size2 size = style->get_minimum_size(); - - int count = 2; // title and name - int inputs = anim_tree->node_get_input_count(p_node); - count += inputs ? inputs : 1; - String name = p_node; - - float name_w = font->get_string_size(name).width; - float type_w = font->get_string_size(String(_node_type_names[type])).width; - float max_w = MAX(name_w, type_w); - - switch (type) { - case AnimationTreePlayer::NODE_TIMESEEK: - case AnimationTreePlayer::NODE_OUTPUT: { - } break; - case AnimationTreePlayer::NODE_ANIMATION: - case AnimationTreePlayer::NODE_ONESHOT: - case AnimationTreePlayer::NODE_MIX: - case AnimationTreePlayer::NODE_BLEND2: - case AnimationTreePlayer::NODE_BLEND3: - case AnimationTreePlayer::NODE_BLEND4: - case AnimationTreePlayer::NODE_TIMESCALE: - case AnimationTreePlayer::NODE_TRANSITION: { - - size.height += font->get_height(); - } break; - case AnimationTreePlayer::NODE_MAX: { - } - } - - size.x += max_w + 20; - size.y += count * (font->get_height() + get_constant("vseparation", "PopupMenu")); - - return size; -} - -void AnimationTreePlayerEditor::_edit_dialog_changede(String) { - - edit_dialog->hide(); -} - -void AnimationTreePlayerEditor::_edit_dialog_changeds(String s) { - - _edit_dialog_changed(); -} - -void AnimationTreePlayerEditor::_edit_dialog_changedf(float) { - - _edit_dialog_changed(); -} - -void AnimationTreePlayerEditor::_edit_dialog_changed() { - - if (updating_edit) - return; - - if (renaming_edit) { - - if (anim_tree->node_rename(edited_node, edit_line[0]->get_text()) == OK) { - for (List<StringName>::Element *E = order.front(); E; E = E->next()) { - - if (E->get() == edited_node) - E->get() = edit_line[0]->get_text(); - } - edited_node = edit_line[0]->get_text(); - } - update(); - return; - } - - AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node); - - switch (type) { - - case AnimationTreePlayer::NODE_TIMESCALE: - anim_tree->timescale_node_set_scale(edited_node, edit_line[0]->get_text().to_double()); - break; - case AnimationTreePlayer::NODE_ONESHOT: - anim_tree->oneshot_node_set_fadein_time(edited_node, edit_line[0]->get_text().to_double()); - anim_tree->oneshot_node_set_fadeout_time(edited_node, edit_line[1]->get_text().to_double()); - anim_tree->oneshot_node_set_autorestart_delay(edited_node, edit_line[2]->get_text().to_double()); - anim_tree->oneshot_node_set_autorestart_random_delay(edited_node, edit_line[3]->get_text().to_double()); - anim_tree->oneshot_node_set_autorestart(edited_node, edit_check->is_pressed()); - anim_tree->oneshot_node_set_mix_mode(edited_node, edit_option->get_selected()); - - break; - - case AnimationTreePlayer::NODE_MIX: - - anim_tree->mix_node_set_amount(edited_node, edit_scroll[0]->get_value()); - break; - case AnimationTreePlayer::NODE_BLEND2: - anim_tree->blend2_node_set_amount(edited_node, edit_scroll[0]->get_value()); - - break; - - case AnimationTreePlayer::NODE_BLEND3: - anim_tree->blend3_node_set_amount(edited_node, edit_scroll[0]->get_value()); - - break; - case AnimationTreePlayer::NODE_BLEND4: - - anim_tree->blend4_node_set_amount(edited_node, Point2(edit_scroll[0]->get_value(), edit_scroll[1]->get_value())); - - break; - - case AnimationTreePlayer::NODE_TRANSITION: { - anim_tree->transition_node_set_xfade_time(edited_node, edit_line[0]->get_text().to_double()); - if (anim_tree->transition_node_get_current(edited_node) != edit_option->get_selected()) - anim_tree->transition_node_set_current(edited_node, edit_option->get_selected()); - } break; - default: { - } - } -} - -void AnimationTreePlayerEditor::_edit_dialog_animation_changed() { - - Ref<Animation> anim = property_editor->get_variant().operator RefPtr(); - anim_tree->animation_node_set_animation(edited_node, anim); - update(); -} - -void AnimationTreePlayerEditor::_edit_dialog_edit_animation() { - - if (Engine::get_singleton()->is_editor_hint()) { - get_tree()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr()); - }; -}; - -void AnimationTreePlayerEditor::_edit_oneshot_start() { - - anim_tree->oneshot_node_start(edited_node); -} - -void AnimationTreePlayerEditor::_play_toggled() { - - anim_tree->set_active(play_button->is_pressed()); -} - -void AnimationTreePlayerEditor::_master_anim_menu_item(int p_item) { - - if (p_item == 0) - _edit_filters(); - else { - - String str = master_anim_popup->get_item_text(p_item); - anim_tree->animation_node_set_master_animation(edited_node, str); - } - update(); -} - -void AnimationTreePlayerEditor::_popup_edit_dialog() { - - updating_edit = true; - - for (int i = 0; i < 2; i++) - edit_scroll[i]->hide(); - - for (int i = 0; i < 4; i++) { - - edit_line[i]->hide(); - edit_label[i]->hide(); - } - - edit_option->hide(); - edit_button->hide(); - filter_button->hide(); - edit_check->hide(); - - Point2 pos = anim_tree->node_get_position(edited_node) - Point2(h_scroll->get_value(), v_scroll->get_value()); - Ref<StyleBox> style = get_stylebox("panel", "PopupMenu"); - Size2 size = get_node_size(edited_node); - Point2 popup_pos(pos.x + style->get_margin(MARGIN_LEFT), pos.y + size.y - style->get_margin(MARGIN_BOTTOM)); - popup_pos += get_global_position(); - - if (renaming_edit) { - - edit_label[0]->set_text(TTR("New name:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_line[0]->set_begin(Point2(15, 25)); - edit_line[0]->set_text(edited_node); - edit_line[0]->show(); - edit_dialog->set_size(Size2(150, 50)); - - } else { - - AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node); - - switch (type) { - - case AnimationTreePlayer::NODE_ANIMATION: - - if (anim_tree->get_master_player() != NodePath() && anim_tree->has_node(anim_tree->get_master_player()) && Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player()))) { - - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(anim_tree->get_node(anim_tree->get_master_player())); - master_anim_popup->clear(); - master_anim_popup->add_item(TTR("Edit Filters")); - master_anim_popup->add_separator(); - List<StringName> sn; - ap->get_animation_list(&sn); - sn.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = sn.front(); E; E = E->next()) { - master_anim_popup->add_item(E->get()); - } - - master_anim_popup->set_position(popup_pos); - master_anim_popup->popup(); - } else { - property_editor->edit(this, "", Variant::OBJECT, anim_tree->animation_node_get_animation(edited_node), PROPERTY_HINT_RESOURCE_TYPE, "Animation"); - property_editor->set_position(popup_pos); - property_editor->popup(); - updating_edit = false; - } - return; - case AnimationTreePlayer::NODE_TIMESCALE: - edit_label[0]->set_text(TTR("Scale:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_line[0]->set_begin(Point2(15, 25)); - edit_line[0]->set_text(rtos(anim_tree->timescale_node_get_scale(edited_node))); - edit_line[0]->show(); - edit_dialog->set_size(Size2(150, 50)); - break; - case AnimationTreePlayer::NODE_ONESHOT: - edit_label[0]->set_text(TTR("Fade In (s):")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_line[0]->set_begin(Point2(15, 25)); - edit_line[0]->set_text(rtos(anim_tree->oneshot_node_get_fadein_time(edited_node))); - edit_line[0]->show(); - edit_label[1]->set_text(TTR("Fade Out (s):")); - edit_label[1]->set_position(Point2(5, 55)); - edit_label[1]->show(); - edit_line[1]->set_begin(Point2(15, 75)); - edit_line[1]->set_text(rtos(anim_tree->oneshot_node_get_fadeout_time(edited_node))); - edit_line[1]->show(); - - edit_option->clear(); - edit_option->add_item(TTR("Blend"), 0); - edit_option->add_item(TTR("Mix"), 1); - edit_option->set_begin(Point2(15, 105)); - - edit_option->select(anim_tree->oneshot_node_get_mix_mode(edited_node)); - edit_option->show(); - - edit_check->set_text(TTR("Auto Restart:")); - edit_check->set_begin(Point2(15, 125)); - edit_check->set_pressed(anim_tree->oneshot_node_has_autorestart(edited_node)); - edit_check->show(); - - edit_label[2]->set_text(TTR("Restart (s):")); - edit_label[2]->set_position(Point2(5, 145)); - edit_label[2]->show(); - edit_line[2]->set_begin(Point2(15, 165)); - edit_line[2]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_delay(edited_node))); - edit_line[2]->show(); - edit_label[3]->set_text(TTR("Random Restart (s):")); - edit_label[3]->set_position(Point2(5, 195)); - edit_label[3]->show(); - edit_line[3]->set_begin(Point2(15, 215)); - edit_line[3]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_random_delay(edited_node))); - edit_line[3]->show(); - - filter_button->set_begin(Point2(10, 245)); - filter_button->show(); - - edit_button->set_begin(Point2(10, 268)); - edit_button->set_text(TTR("Start!")); - - edit_button->show(); - - edit_dialog->set_size(Size2(180, 293)); - - break; - - case AnimationTreePlayer::NODE_MIX: - - edit_label[0]->set_text(TTR("Amount:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_scroll[0]->set_min(0); - edit_scroll[0]->set_max(1); - edit_scroll[0]->set_step(0.01); - edit_scroll[0]->set_value(anim_tree->mix_node_get_amount(edited_node)); - edit_scroll[0]->set_begin(Point2(15, 25)); - edit_scroll[0]->show(); - edit_dialog->set_size(Size2(150, 50)); - - break; - case AnimationTreePlayer::NODE_BLEND2: - edit_label[0]->set_text(TTR("Blend:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_scroll[0]->set_min(0); - edit_scroll[0]->set_max(1); - edit_scroll[0]->set_step(0.01); - edit_scroll[0]->set_value(anim_tree->blend2_node_get_amount(edited_node)); - edit_scroll[0]->set_begin(Point2(15, 25)); - edit_scroll[0]->show(); - filter_button->set_begin(Point2(10, 47)); - filter_button->show(); - edit_dialog->set_size(Size2(150, 74)); - - break; - - case AnimationTreePlayer::NODE_BLEND3: - edit_label[0]->set_text(TTR("Blend:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_scroll[0]->set_min(-1); - edit_scroll[0]->set_max(1); - edit_scroll[0]->set_step(0.01); - edit_scroll[0]->set_value(anim_tree->blend3_node_get_amount(edited_node)); - edit_scroll[0]->set_begin(Point2(15, 25)); - edit_scroll[0]->show(); - edit_dialog->set_size(Size2(150, 50)); - - break; - case AnimationTreePlayer::NODE_BLEND4: - - edit_label[0]->set_text(TTR("Blend 0:")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_scroll[0]->set_min(0); - edit_scroll[0]->set_max(1); - edit_scroll[0]->set_step(0.01); - edit_scroll[0]->set_value(anim_tree->blend4_node_get_amount(edited_node).x); - edit_scroll[0]->set_begin(Point2(15, 25)); - edit_scroll[0]->show(); - edit_label[1]->set_text(TTR("Blend 1:")); - edit_label[1]->set_position(Point2(5, 55)); - edit_label[1]->show(); - edit_scroll[1]->set_min(0); - edit_scroll[1]->set_max(1); - edit_scroll[1]->set_step(0.01); - edit_scroll[1]->set_value(anim_tree->blend4_node_get_amount(edited_node).y); - edit_scroll[1]->set_begin(Point2(15, 75)); - edit_scroll[1]->show(); - edit_dialog->set_size(Size2(150, 100)); - - break; - - case AnimationTreePlayer::NODE_TRANSITION: { - - edit_label[0]->set_text(TTR("X-Fade Time (s):")); - edit_label[0]->set_position(Point2(5, 5)); - edit_label[0]->show(); - edit_line[0]->set_begin(Point2(15, 25)); - edit_line[0]->set_text(rtos(anim_tree->transition_node_get_xfade_time(edited_node))); - edit_line[0]->show(); - - edit_label[1]->set_text(TTR("Current:")); - edit_label[1]->set_position(Point2(5, 55)); - edit_label[1]->show(); - edit_option->set_begin(Point2(15, 75)); - - edit_option->clear(); - - for (int i = 0; i < anim_tree->transition_node_get_input_count(edited_node); i++) { - edit_option->add_item(itos(i), i); - } - - edit_option->select(anim_tree->transition_node_get_current(edited_node)); - edit_option->show(); - edit_dialog->set_size(Size2(150, 100)); - - } break; - default: { - } - } - } - - edit_dialog->set_position(popup_pos); - edit_dialog->popup(); - - updating_edit = false; -} - -void AnimationTreePlayerEditor::_draw_node(const StringName &p_node) { - - RID ci = get_canvas_item(); - AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node); - - Ref<StyleBox> style = get_stylebox("panel", "PopupMenu"); - Ref<Font> font = get_font("font", "PopupMenu"); - Color font_color = get_color("font_color", "PopupMenu"); - Color font_color_title = get_color("font_color_hover", "PopupMenu"); - font_color_title.a *= 0.8; - Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons"); - - Size2 size = get_node_size(p_node); - Point2 pos = anim_tree->node_get_position(p_node); - if (click_type == CLICK_NODE && click_node == p_node) { - - pos += click_motion - click_pos; - if (pos.x < 5) - pos.x = 5; - if (pos.y < 5) - pos.y = 5; - } - - pos -= Point2(h_scroll->get_value(), v_scroll->get_value()); - - style->draw(ci, Rect2(pos, size)); - - float w = size.width - style->get_minimum_size().width; - float h = font->get_height() + get_constant("vseparation", "PopupMenu"); - - Point2 ofs = style->get_offset() + pos; - Point2 ascofs(0, font->get_ascent()); - - Color bx = font_color_title; - bx.a *= 0.1; - draw_rect(Rect2(ofs, Size2(size.width - style->get_minimum_size().width, font->get_height())), bx); - font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, String(_node_type_names[type]), font_color_title); - - ofs.y += h; - font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, p_node, font_color); - ofs.y += h; - - int inputs = anim_tree->node_get_input_count(p_node); - - float icon_h_ofs = Math::floor((font->get_height() - slot_icon->get_height()) / 2.0) + 1; - - if (type != AnimationTreePlayer::NODE_OUTPUT) - slot_icon->draw(ci, ofs + Point2(w, icon_h_ofs)); //output - - if (inputs) { - for (int i = 0; i < inputs; i++) { - - slot_icon->draw(ci, ofs + Point2(-slot_icon->get_width(), icon_h_ofs)); - String text; - switch (type) { - - case AnimationTreePlayer::NODE_TIMESCALE: - case AnimationTreePlayer::NODE_TIMESEEK: text = "in"; break; - case AnimationTreePlayer::NODE_OUTPUT: text = "out"; break; - case AnimationTreePlayer::NODE_ANIMATION: break; - case AnimationTreePlayer::NODE_ONESHOT: text = (i == 0 ? "in" : "add"); break; - case AnimationTreePlayer::NODE_BLEND2: - case AnimationTreePlayer::NODE_MIX: text = (i == 0 ? "a" : "b"); break; - case AnimationTreePlayer::NODE_BLEND3: - switch (i) { - case 0: text = "b-"; break; - case 1: text = "a"; break; - case 2: text = "b+"; break; - } - break; - - case AnimationTreePlayer::NODE_BLEND4: - switch (i) { - case 0: text = "a0"; break; - case 1: text = "b0"; break; - case 2: text = "a1"; break; - case 3: text = "b1"; break; - } - break; - - case AnimationTreePlayer::NODE_TRANSITION: - text = itos(i); - if (anim_tree->transition_node_has_input_auto_advance(p_node, i)) - text += "->"; - - break; - default: { - } - } - font->draw(ci, ofs + ascofs + Point2(3, 0), text, font_color); - - ofs.y += h; - } - } else { - ofs.y += h; - } - - Ref<StyleBox> pg_bg = get_stylebox("bg", "ProgressBar"); - Ref<StyleBox> pg_fill = get_stylebox("fill", "ProgressBar"); - Rect2 pg_rect(ofs, Size2(w, h)); - - bool editable = true; - switch (type) { - case AnimationTreePlayer::NODE_ANIMATION: { - - Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node); - String text; - if (anim_tree->animation_node_get_master_animation(p_node) != "") - text = anim_tree->animation_node_get_master_animation(p_node); - else if (anim.is_null()) - text = "load..."; - else - text = anim->get_name(); - - font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, text, font_color_title); - - } break; - case AnimationTreePlayer::NODE_ONESHOT: - case AnimationTreePlayer::NODE_MIX: - case AnimationTreePlayer::NODE_BLEND2: - case AnimationTreePlayer::NODE_BLEND3: - case AnimationTreePlayer::NODE_BLEND4: - case AnimationTreePlayer::NODE_TIMESCALE: - case AnimationTreePlayer::NODE_TRANSITION: { - - font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit...", font_color_title); - } break; - default: editable = false; - } - - if (editable) { - - Ref<Texture> arrow = get_icon("GuiDropdown", "EditorIcons"); - Point2 arrow_ofs(w - arrow->get_width(), Math::floor((h - arrow->get_height()) / 2)); - arrow->draw(ci, ofs + arrow_ofs); - } -} - -AnimationTreePlayerEditor::ClickType AnimationTreePlayerEditor::_locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const { - - Ref<StyleBox> style = get_stylebox("panel", "PopupMenu"); - Ref<Font> font = get_font("font", "PopupMenu"); - - float h = (font->get_height() + get_constant("vseparation", "PopupMenu")); - - for (const List<StringName>::Element *E = order.back(); E; E = E->prev()) { - - const StringName &node = E->get(); - - AnimationTreePlayer::NodeType type = anim_tree->node_get_type(node); - - Point2 pos = anim_tree->node_get_position(node); - Size2 size = get_node_size(node); - - pos -= Point2(h_scroll->get_value(), v_scroll->get_value()); - - if (!Rect2(pos, size).has_point(p_click)) - continue; - - if (p_node_id) - *p_node_id = node; - - pos = p_click - pos; - - float y = pos.y - style->get_offset().height; - - if (y < 2 * h) - return CLICK_NODE; - y -= 2 * h; - - int inputs = anim_tree->node_get_input_count(node); - int count = MAX(inputs, 1); - - if (inputs == 0 || (pos.x > size.width / 2 && type != AnimationTreePlayer::NODE_OUTPUT)) { - - if (y < count * h) { - - if (p_slot_index) - *p_slot_index = 0; - return CLICK_OUTPUT_SLOT; - } - } - - for (int i = 0; i < count; i++) { - - if (y < h) { - if (p_slot_index) - *p_slot_index = i; - return CLICK_INPUT_SLOT; - } - y -= h; - } - - bool has_parameters = type != AnimationTreePlayer::NODE_OUTPUT && type != AnimationTreePlayer::NODE_TIMESEEK; - return has_parameters ? CLICK_PARAMETER : CLICK_NODE; - } - - return CLICK_NONE; -} - -Point2 AnimationTreePlayerEditor::_get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot) { - - Ref<StyleBox> style = get_stylebox("panel", "PopupMenu"); - Ref<Font> font = get_font("font", "PopupMenu"); - Ref<Texture> slot_icon = get_icon("VisualShaderPort", "EditorIcons"); - - Size2 size = get_node_size(p_node_id); - Point2 pos = anim_tree->node_get_position(p_node_id); - - if (click_type == CLICK_NODE && click_node == p_node_id) { - - pos += click_motion - click_pos; - if (pos.x < 5) - pos.x = 5; - if (pos.y < 5) - pos.y = 5; - } - - pos -= Point2(h_scroll->get_value(), v_scroll->get_value()); - - float w = size.width - style->get_minimum_size().width; - float h = font->get_height() + get_constant("vseparation", "PopupMenu"); - - pos += style->get_offset(); - - pos.y += h * 2; - - pos.y += h * p_slot; - - pos += Point2(-slot_icon->get_width() / 2.0, h / 2.0).floor(); - - if (!p_input) { - pos.x += w + slot_icon->get_width(); - } - - return pos; -} - -void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) { - - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid()) { - - if (mb->is_pressed()) { - - if (mb->get_button_index() == 1) { - click_pos = Point2(mb->get_position().x, mb->get_position().y); - click_motion = click_pos; - click_type = _locate_click(click_pos, &click_node, &click_slot); - if (click_type != CLICK_NONE) { - - order.erase(click_node); - order.push_back(click_node); - update(); - } - - switch (click_type) { - case CLICK_INPUT_SLOT: { - click_pos = _get_slot_pos(click_node, true, click_slot); - } break; - case CLICK_OUTPUT_SLOT: { - click_pos = _get_slot_pos(click_node, false, click_slot); - } break; - case CLICK_PARAMETER: { - - edited_node = click_node; - renaming_edit = false; - _popup_edit_dialog(); - //open editor - //_node_edit_property(click_node); - } break; - default: { - } - } - } - if (mb->get_button_index() == 2) { - - if (click_type != CLICK_NONE) { - click_type = CLICK_NONE; - update(); - } else { - // try to disconnect/remove - - Point2 rclick_pos = Point2(mb->get_position().x, mb->get_position().y); - rclick_type = _locate_click(rclick_pos, &rclick_node, &rclick_slot); - if (rclick_type == CLICK_INPUT_SLOT || rclick_type == CLICK_OUTPUT_SLOT) { - - node_popup->clear(); - node_popup->set_size(Size2(1, 1)); - node_popup->add_item(TTR("Disconnect"), NODE_DISCONNECT); - if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) { - node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT); - if (rclick_type == CLICK_INPUT_SLOT) { - if (anim_tree->transition_node_has_input_auto_advance(rclick_node, rclick_slot)) - node_popup->add_item(TTR("Clear Auto-Advance"), NODE_CLEAR_AUTOADVANCE); - else - node_popup->add_item(TTR("Set Auto-Advance"), NODE_SET_AUTOADVANCE); - node_popup->add_item(TTR("Delete Input"), NODE_DELETE_INPUT); - } - } - - node_popup->set_position(rclick_pos + get_global_position()); - node_popup->popup(); - } - - if (rclick_type == CLICK_NODE) { - node_popup->clear(); - node_popup->set_size(Size2(1, 1)); - node_popup->add_item(TTR("Rename"), NODE_RENAME); - node_popup->add_item(TTR("Remove"), NODE_ERASE); - if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) - node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT); - node_popup->set_position(rclick_pos + get_global_position()); - node_popup->popup(); - } - } - } - } else { - - if (mb->get_button_index() == 1 && click_type != CLICK_NONE) { - - switch (click_type) { - case CLICK_INPUT_SLOT: - case CLICK_OUTPUT_SLOT: { - - Point2 dst_click_pos = Point2(mb->get_position().x, mb->get_position().y); - StringName id; - int slot; - ClickType dst_click_type = _locate_click(dst_click_pos, &id, &slot); - - if (dst_click_type == CLICK_INPUT_SLOT && click_type == CLICK_OUTPUT_SLOT) { - - anim_tree->connect_nodes(click_node, id, slot); - } - if (click_type == CLICK_INPUT_SLOT && dst_click_type == CLICK_OUTPUT_SLOT) { - - anim_tree->connect_nodes(id, click_node, click_slot); - } - - } break; - case CLICK_NODE: { - Point2 new_pos = anim_tree->node_get_position(click_node) + (click_motion - click_pos); - if (new_pos.x < 5) - new_pos.x = 5; - if (new_pos.y < 5) - new_pos.y = 5; - anim_tree->node_set_position(click_node, new_pos); - - } break; - default: { - } - } - - click_type = CLICK_NONE; - update(); - } - } - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - - if (mm->get_button_mask() & 1 && click_type != CLICK_NONE) { - - click_motion = Point2(mm->get_position().x, mm->get_position().y); - update(); - } - if (mm->get_button_mask() & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - - h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); - v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); - update(); - } - } -} - -void AnimationTreePlayerEditor::_draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color) { - - static const int steps = 20; - - Rect2 r; - r.position = p_from; - r.expand_to(p_to); - Vector2 sign = Vector2((p_from.x < p_to.x) ? 1 : -1, (p_from.y < p_to.y) ? 1 : -1); - bool flip = sign.x * sign.y < 0; - - Vector2 prev; - for (int i = 0; i <= steps; i++) { - - float d = i / float(steps); - float c = -Math::cos(d * Math_PI) * 0.5 + 0.5; - if (flip) - c = 1.0 - c; - Vector2 p = r.position + Vector2(d * r.size.width, c * r.size.height); - - if (i > 0) { - - draw_line(prev, p, p_color, 2); - } - - prev = p; - } -} - -void AnimationTreePlayerEditor::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_ENTER_TREE: { - - play_button->set_icon(get_icon("Play", "EditorIcons")); - add_menu->set_icon(get_icon("Add", "EditorIcons")); - } break; - case NOTIFICATION_DRAW: { - - _update_scrollbars(); - //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1)); - get_stylebox("bg", "Tree")->draw(get_canvas_item(), Rect2(Point2(), get_size())); - - for (List<StringName>::Element *E = order.front(); E; E = E->next()) { - - _draw_node(E->get()); - } - - if (click_type == CLICK_INPUT_SLOT || click_type == CLICK_OUTPUT_SLOT) { - - _draw_cos_line(click_pos, click_motion, Color(0.5, 1, 0.5, 0.8)); - } - - List<AnimationTreePlayer::Connection> connections; - anim_tree->get_connection_list(&connections); - - for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) { - - const AnimationTreePlayer::Connection &c = E->get(); - Point2 source = _get_slot_pos(c.src_node, false, 0); - Point2 dest = _get_slot_pos(c.dst_node, true, c.dst_input); - Color col = Color(1, 1, 0.5, 0.8); - /* - if (click_type==CLICK_NODE && click_node==c.src_node) { - - source+=click_motion-click_pos; - } - - if (click_type==CLICK_NODE && click_node==c.dst_node) { - - dest+=click_motion-click_pos; - }*/ - - _draw_cos_line(source, dest, col); - } - - const Ref<Font> f = get_font("font", "Label"); - const Point2 status_offset = Point2(5, 25) * EDSCALE + Point2(0, f->get_ascent()); - - switch (anim_tree->get_last_error()) { - - case AnimationTreePlayer::CONNECT_OK: { - - f->draw(get_canvas_item(), status_offset, TTR("Animation tree is valid."), Color(0, 1, 0.6, 0.8)); - } break; - default: { - - f->draw(get_canvas_item(), status_offset, TTR("Animation tree is invalid."), Color(1, 0.6, 0.0, 0.8)); - } break; - } - - } break; - } -} - -void AnimationTreePlayerEditor::_update_scrollbars() { - - Size2 size = get_size(); - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); - - v_scroll->set_begin(Point2(size.width - vmin.width, 0)); - v_scroll->set_end(Point2(size.width, size.height)); - - h_scroll->set_begin(Point2(0, size.height - hmin.height)); - h_scroll->set_end(Point2(size.width - vmin.width, size.height)); - - Size2 min = _get_maximum_size(); - - if (min.height < size.height - hmin.height) { - - v_scroll->hide(); - offset.y = 0; - } else { - - v_scroll->show(); - v_scroll->set_max(min.height); - v_scroll->set_page(size.height - hmin.height); - offset.y = v_scroll->get_value(); - } - - if (min.width < size.width - vmin.width) { - - h_scroll->hide(); - offset.x = 0; - } else { - - h_scroll->show(); - h_scroll->set_max(min.width); - h_scroll->set_page(size.width - vmin.width); - offset.x = h_scroll->get_value(); - } -} - -void AnimationTreePlayerEditor::_scroll_moved(float) { - - offset.x = h_scroll->get_value(); - offset.y = v_scroll->get_value(); - update(); -} - -void AnimationTreePlayerEditor::_node_menu_item(int p_item) { - - switch (p_item) { - - case NODE_DISCONNECT: { - - if (rclick_type == CLICK_INPUT_SLOT) { - - anim_tree->disconnect_nodes(rclick_node, rclick_slot); - update(); - } - - if (rclick_type == CLICK_OUTPUT_SLOT) { - - List<AnimationTreePlayer::Connection> connections; - anim_tree->get_connection_list(&connections); - - for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) { - - const AnimationTreePlayer::Connection &c = E->get(); - if (c.dst_node == rclick_node) { - - anim_tree->disconnect_nodes(c.dst_node, c.dst_input); - } - } - update(); - } - - } break; - case NODE_RENAME: { - - renaming_edit = true; - edited_node = rclick_node; - _popup_edit_dialog(); - - } break; - case NODE_ADD_INPUT: { - - anim_tree->transition_node_set_input_count(rclick_node, anim_tree->transition_node_get_input_count(rclick_node) + 1); - update(); - } break; - case NODE_DELETE_INPUT: { - - anim_tree->transition_node_delete_input(rclick_node, rclick_slot); - update(); - } break; - case NODE_SET_AUTOADVANCE: { - - anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, true); - update(); - - } break; - case NODE_CLEAR_AUTOADVANCE: { - - anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, false); - update(); - - } break; - - case NODE_ERASE: { - - if (rclick_node == "out") - break; - order.erase(rclick_node); - anim_tree->remove_node(rclick_node); - update(); - } break; - } -} - -StringName AnimationTreePlayerEditor::_add_node(int p_item) { - - static const char *bname[] = { - "out", - "anim", - "oneshot", - "mix", - "blend2", - "blend3", - "blend4", - "scale", - "seek", - "transition" - }; - - String name; - int idx = 1; - - while (true) { - - name = bname[p_item]; - if (idx > 1) - name += " " + itos(idx); - if (anim_tree->node_exists(name)) - idx++; - else - break; - } - - anim_tree->add_node((AnimationTreePlayer::NodeType)p_item, name); - anim_tree->node_set_position(name, Point2(last_x, last_y)); - order.push_back(name); - last_x += 10; - last_y += 10; - last_x = last_x % (int)get_size().width; - last_y = last_y % (int)get_size().height; - update(); - - return name; -}; - -void AnimationTreePlayerEditor::_file_dialog_selected(String p_path) { - - switch (file_op) { - - case MENU_IMPORT_ANIMATIONS: { - Vector<String> files = file_dialog->get_selected_files(); - - for (int i = 0; i < files.size(); i++) { - - StringName node = _add_node(AnimationTreePlayer::NODE_ANIMATION); - - RES anim = ResourceLoader::load(files[i]); - anim_tree->animation_node_set_animation(node, anim); - //anim_tree->node_set_name(node, files[i].get_file()); - }; - } break; - - default: - break; - }; -}; - -void AnimationTreePlayerEditor::_add_menu_item(int p_item) { - - if (p_item == MENU_GRAPH_CLEAR) { - - //clear - } else if (p_item == MENU_IMPORT_ANIMATIONS) { - - file_op = MENU_IMPORT_ANIMATIONS; - file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); - file_dialog->popup_centered_ratio(); - - } else { - - _add_node(p_item); - } -} - -Size2 AnimationTreePlayerEditor::get_minimum_size() const { - - return Size2(10, 200); -} - -void AnimationTreePlayerEditor::_find_paths_for_filter(const StringName &p_node, Set<String> &paths) { - - ERR_FAIL_COND(!anim_tree->node_exists(p_node)); - - for (int i = 0; i < anim_tree->node_get_input_count(p_node); i++) { - - StringName port = anim_tree->node_get_input_source(p_node, i); - if (port == StringName()) - continue; - _find_paths_for_filter(port, paths); - } - - if (anim_tree->node_get_type(p_node) == AnimationTreePlayer::NODE_ANIMATION) { - - Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node); - if (anim.is_valid()) { - - for (int i = 0; i < anim->get_track_count(); i++) { - paths.insert(anim->track_get_path(i)); - } - } - } -} - -void AnimationTreePlayerEditor::_filter_edited() { - - TreeItem *ed = filter->get_edited(); - if (!ed) - return; - - if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) { - anim_tree->oneshot_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0)); - } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) { - anim_tree->blend2_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0)); - } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) { - anim_tree->animation_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0)); - } -} - -void AnimationTreePlayerEditor::_edit_filters() { - - filter_dialog->popup_centered_ratio(); - filter->clear(); - - Set<String> npb; - _find_paths_for_filter(edited_node, npb); - - TreeItem *root = filter->create_item(); - filter->set_hide_root(true); - Map<String, TreeItem *> pm; - - Node *base = anim_tree->get_node(anim_tree->get_base_path()); - - for (Set<String>::Element *E = npb.front(); E; E = E->next()) { - - TreeItem *parent = root; - String descr = E->get(); - if (base) { - NodePath np = E->get(); - - if (np.get_subname_count() == 1) { - Node *n = base->get_node(np); - Skeleton *s = Object::cast_to<Skeleton>(n); - if (s) { - - String skelbase = E->get().substr(0, E->get().find(":")); - - int bidx = s->find_bone(np.get_subname(0)); - - if (bidx != -1) { - int bparent = s->get_bone_parent(bidx); - // - if (bparent != -1) { - - String bpn = skelbase + ":" + s->get_bone_name(bparent); - if (pm.has(bpn)) { - parent = pm[bpn]; - descr = np.get_subname(0); - } - } else { - - if (pm.has(skelbase)) { - parent = pm[skelbase]; - } - } - } - } - } - } - - TreeItem *it = filter->create_item(parent); - it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - it->set_text(0, descr); - it->set_metadata(0, NodePath(E->get())); - it->set_editable(0, true); - if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) { - it->set_checked(0, anim_tree->oneshot_node_is_path_filtered(edited_node, E->get())); - } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) { - it->set_checked(0, anim_tree->blend2_node_is_path_filtered(edited_node, E->get())); - } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) { - it->set_checked(0, anim_tree->animation_node_is_path_filtered(edited_node, E->get())); - } - pm[E->get()] = it; - } -} - -void AnimationTreePlayerEditor::_bind_methods() { - - ClassDB::bind_method("_add_menu_item", &AnimationTreePlayerEditor::_add_menu_item); - ClassDB::bind_method("_node_menu_item", &AnimationTreePlayerEditor::_node_menu_item); - ClassDB::bind_method("_gui_input", &AnimationTreePlayerEditor::_gui_input); - //ClassDB::bind_method( "_node_param_changed", &AnimationTreeEditor::_node_param_changed ); - ClassDB::bind_method("_scroll_moved", &AnimationTreePlayerEditor::_scroll_moved); - ClassDB::bind_method("_edit_dialog_changeds", &AnimationTreePlayerEditor::_edit_dialog_changeds); - ClassDB::bind_method("_edit_dialog_changede", &AnimationTreePlayerEditor::_edit_dialog_changede); - ClassDB::bind_method("_edit_dialog_changedf", &AnimationTreePlayerEditor::_edit_dialog_changedf); - ClassDB::bind_method("_edit_dialog_changed", &AnimationTreePlayerEditor::_edit_dialog_changed); - ClassDB::bind_method("_edit_dialog_animation_changed", &AnimationTreePlayerEditor::_edit_dialog_animation_changed); - ClassDB::bind_method("_edit_dialog_edit_animation", &AnimationTreePlayerEditor::_edit_dialog_edit_animation); - ClassDB::bind_method("_play_toggled", &AnimationTreePlayerEditor::_play_toggled); - ClassDB::bind_method("_edit_oneshot_start", &AnimationTreePlayerEditor::_edit_oneshot_start); - ClassDB::bind_method("_file_dialog_selected", &AnimationTreePlayerEditor::_file_dialog_selected); - ClassDB::bind_method("_master_anim_menu_item", &AnimationTreePlayerEditor::_master_anim_menu_item); - ClassDB::bind_method("_edit_filters", &AnimationTreePlayerEditor::_edit_filters); - ClassDB::bind_method("_filter_edited", &AnimationTreePlayerEditor::_filter_edited); -} - -AnimationTreePlayerEditor::AnimationTreePlayerEditor() { - - set_focus_mode(FOCUS_ALL); - - PopupMenu *p; - List<PropertyInfo> defaults; - - add_menu = memnew(MenuButton); - //add_menu->set_ - add_menu->set_position(Point2(0, 0)); - add_menu->set_size(Point2(25, 15)); - add_child(add_menu); - - p = add_menu->get_popup(); - p->add_item(TTR("Animation Node"), AnimationTreePlayer::NODE_ANIMATION); - p->add_item(TTR("OneShot Node"), AnimationTreePlayer::NODE_ONESHOT); - p->add_item(TTR("Mix Node"), AnimationTreePlayer::NODE_MIX); - p->add_item(TTR("Blend2 Node"), AnimationTreePlayer::NODE_BLEND2); - p->add_item(TTR("Blend3 Node"), AnimationTreePlayer::NODE_BLEND3); - p->add_item(TTR("Blend4 Node"), AnimationTreePlayer::NODE_BLEND4); - p->add_item(TTR("TimeScale Node"), AnimationTreePlayer::NODE_TIMESCALE); - p->add_item(TTR("TimeSeek Node"), AnimationTreePlayer::NODE_TIMESEEK); - p->add_item(TTR("Transition Node"), AnimationTreePlayer::NODE_TRANSITION); - p->add_separator(); - p->add_item(TTR("Import Animations..."), MENU_IMPORT_ANIMATIONS); // wtf - p->add_separator(); - p->add_item(TTR("Clear"), MENU_GRAPH_CLEAR); - - p->connect("id_pressed", this, "_add_menu_item"); - - play_button = memnew(Button); - play_button->set_position(Point2(25, 0) * EDSCALE); - play_button->set_size(Point2(25, 15)); - add_child(play_button); - play_button->set_toggle_mode(true); - play_button->connect("pressed", this, "_play_toggled"); - - last_x = 50; - last_y = 50; - - property_editor = memnew(CustomPropertyEditor); - add_child(property_editor); - property_editor->connect("variant_changed", this, "_edit_dialog_animation_changed"); - property_editor->connect("resource_edit_request", this, "_edit_dialog_edit_animation"); - - h_scroll = memnew(HScrollBar); - v_scroll = memnew(VScrollBar); - - add_child(h_scroll); - add_child(v_scroll); - - h_scroll->connect("value_changed", this, "_scroll_moved"); - v_scroll->connect("value_changed", this, "_scroll_moved"); - - node_popup = memnew(PopupMenu); - add_child(node_popup); - node_popup->set_as_toplevel(true); - - master_anim_popup = memnew(PopupMenu); - add_child(master_anim_popup); - master_anim_popup->connect("id_pressed", this, "_master_anim_menu_item"); - - node_popup->connect("id_pressed", this, "_node_menu_item"); - - updating_edit = false; - - edit_dialog = memnew(PopupPanel); - //edit_dialog->get_ok()->hide(); - //edit_dialog->get_cancel()->hide(); - add_child(edit_dialog); - - edit_option = memnew(OptionButton); - edit_option->set_anchor(MARGIN_RIGHT, ANCHOR_END); - edit_option->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(edit_option); - edit_option->connect("item_selected", this, "_edit_dialog_changedf"); - edit_option->hide(); - - for (int i = 0; i < 2; i++) { - edit_scroll[i] = memnew(HSlider); - edit_scroll[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END); - edit_scroll[i]->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(edit_scroll[i]); - edit_scroll[i]->hide(); - edit_scroll[i]->connect("value_changed", this, "_edit_dialog_changedf"); - } - for (int i = 0; i < 4; i++) { - edit_line[i] = memnew(LineEdit); - edit_line[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END); - edit_line[i]->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(edit_line[i]); - edit_line[i]->hide(); - edit_line[i]->connect("text_changed", this, "_edit_dialog_changeds"); - edit_line[i]->connect("text_entered", this, "_edit_dialog_changede"); - edit_label[i] = memnew(Label); - edit_dialog->add_child(edit_label[i]); - edit_label[i]->hide(); - } - - edit_button = memnew(Button); - edit_button->set_anchor(MARGIN_RIGHT, ANCHOR_END); - edit_button->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(edit_button); - edit_button->hide(); - edit_button->connect("pressed", this, "_edit_oneshot_start"); - - edit_check = memnew(CheckButton); - edit_check->set_anchor(MARGIN_RIGHT, ANCHOR_END); - edit_check->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(edit_check); - edit_check->hide(); - edit_check->connect("pressed", this, "_edit_dialog_changed"); - - file_dialog = memnew(EditorFileDialog); - file_dialog->set_enable_multiple_selection(true); - file_dialog->set_current_dir(ProjectSettings::get_singleton()->get_resource_path()); - add_child(file_dialog); - file_dialog->connect("file_selected", this, "_file_dialog_selected"); - - filter_dialog = memnew(AcceptDialog); - filter_dialog->set_title(TTR("Edit Node Filters")); - add_child(filter_dialog); - - filter = memnew(Tree); - filter_dialog->add_child(filter); - //filter_dialog->set_child_rect(filter); - filter->connect("item_edited", this, "_filter_edited"); - - filter_button = memnew(Button); - filter_button->set_anchor(MARGIN_RIGHT, ANCHOR_END); - filter_button->set_margin(MARGIN_RIGHT, -10); - edit_dialog->add_child(filter_button); - filter_button->hide(); - filter_button->set_text(TTR("Filters...")); - filter_button->connect("pressed", this, "_edit_filters"); - - set_clip_contents(true); -} - -void AnimationTreePlayerEditorPlugin::edit(Object *p_object) { - - anim_tree_editor->edit(Object::cast_to<AnimationTreePlayer>(p_object)); -} - -bool AnimationTreePlayerEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("AnimationTreePlayer"); -} - -void AnimationTreePlayerEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) { - //editor->hide_animation_player_editors(); - //editor->animation_panel_make_visible(true); - button->show(); - editor->make_bottom_panel_item_visible(anim_tree_editor); - anim_tree_editor->set_physics_process(true); - } else { - - if (anim_tree_editor->is_visible_in_tree()) - editor->hide_bottom_panel(); - button->hide(); - anim_tree_editor->set_physics_process(false); - } -} - -AnimationTreePlayerEditorPlugin::AnimationTreePlayerEditorPlugin(EditorNode *p_node) { - - editor = p_node; - anim_tree_editor = memnew(AnimationTreePlayerEditor); - anim_tree_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); - - button = editor->add_bottom_panel_item(TTR("AnimationTree"), anim_tree_editor); - button->hide(); -} - -AnimationTreePlayerEditorPlugin::~AnimationTreePlayerEditorPlugin() { -} diff --git a/editor/plugins/animation_tree_player_editor_plugin.h b/editor/plugins/animation_tree_player_editor_plugin.h deleted file mode 100644 index d3fd6ae362..0000000000 --- a/editor/plugins/animation_tree_player_editor_plugin.h +++ /dev/null @@ -1,184 +0,0 @@ -/*************************************************************************/ -/* animation_tree_player_editor_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H -#define ANIMATION_TREE_PLAYER_EDITOR_PLUGIN_H - -#include "editor/editor_node.h" -#include "editor/editor_plugin.h" -#include "editor/property_editor.h" -#include "scene/animation/animation_tree_player.h" -#include "scene/gui/button.h" -#include "scene/gui/popup.h" -#include "scene/gui/tree.h" - -class AnimationTreePlayerEditor : public Control { - - GDCLASS(AnimationTreePlayerEditor, Control); - - static const char *_node_type_names[]; - - enum ClickType { - CLICK_NONE, - CLICK_NAME, - CLICK_NODE, - CLICK_INPUT_SLOT, - CLICK_OUTPUT_SLOT, - CLICK_PARAMETER - }; - - enum { - - MENU_GRAPH_CLEAR = 100, - MENU_IMPORT_ANIMATIONS = 101, - NODE_DISCONNECT, - NODE_RENAME, - NODE_ERASE, - NODE_ADD_INPUT, - NODE_DELETE_INPUT, - NODE_SET_AUTOADVANCE, - NODE_CLEAR_AUTOADVANCE - }; - - bool renaming_edit; - StringName edited_node; - bool updating_edit; - Popup *edit_dialog; - HSlider *edit_scroll[2]; - LineEdit *edit_line[4]; - OptionButton *edit_option; - Label *edit_label[4]; - Button *edit_button; - Button *filter_button; - CheckButton *edit_check; - EditorFileDialog *file_dialog; - int file_op; - - void _popup_edit_dialog(); - - void _setup_edit_dialog(const StringName &p_node); - PopupMenu *master_anim_popup; - PopupMenu *node_popup; - PopupMenu *add_popup; - HScrollBar *h_scroll; - VScrollBar *v_scroll; - MenuButton *add_menu; - - CustomPropertyEditor *property_editor; - - AnimationTreePlayer *anim_tree; - List<StringName> order; - Set<StringName> active_nodes; - - int last_x, last_y; - - Point2 offset; - ClickType click_type; - Point2 click_pos; - StringName click_node; - int click_slot; - Point2 click_motion; - ClickType rclick_type; - StringName rclick_node; - int rclick_slot; - - Button *play_button; - - Size2 _get_maximum_size(); - Size2 get_node_size(const StringName &p_node) const; - void _draw_node(const StringName &p_node); - - AcceptDialog *filter_dialog; - Tree *filter; - - void _draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color); - void _update_scrollbars(); - void _scroll_moved(float); - void _play_toggled(); - /* - void _node_param_changed(); - void _node_add_callback(); - void _node_add(VisualServer::AnimationTreeNodeType p_type); - void _node_edit_property(const StringName& p_node); -*/ - - void _master_anim_menu_item(int p_item); - void _node_menu_item(int p_item); - void _add_menu_item(int p_item); - - void _filter_edited(); - void _find_paths_for_filter(const StringName &p_node, Set<String> &paths); - void _edit_filters(); - - void _edit_oneshot_start(); - void _edit_dialog_animation_changed(); - void _edit_dialog_edit_animation(); - void _edit_dialog_changeds(String); - void _edit_dialog_changede(String); - void _edit_dialog_changedf(float); - void _edit_dialog_changed(); - void _dialog_changed() const; - ClickType _locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const; - Point2 _get_slot_pos(const StringName &p_node_id, bool p_input, int p_slot); - - StringName _add_node(int p_item); - void _file_dialog_selected(String p_path); - -protected: - void _notification(int p_what); - void _gui_input(Ref<InputEvent> p_event); - static void _bind_methods(); - -public: - virtual Size2 get_minimum_size() const; - void edit(AnimationTreePlayer *p_anim_tree); - AnimationTreePlayerEditor(); -}; - -class AnimationTreePlayerEditorPlugin : public EditorPlugin { - - GDCLASS(AnimationTreePlayerEditorPlugin, EditorPlugin); - - AnimationTreePlayerEditor *anim_tree_editor; - EditorNode *editor; - Button *button; - -public: - virtual String get_name() const { return "AnimTree"; } - 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); - - AnimationTreePlayerEditorPlugin(EditorNode *p_node); - ~AnimationTreePlayerEditorPlugin(); -}; - -#endif // ANIMATION_TREE_EDITOR_PLUGIN_H diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 4f73a5eaea..28ac85457b 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -30,7 +30,9 @@ #include "asset_library_editor_plugin.h" +#include "core/input/input.h" #include "core/io/json.h" +#include "core/os/keyboard.h" #include "core/version.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -38,7 +40,6 @@ #include "editor/project_settings_editor.h" void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, const String &p_cost) { - title->set_text(p_title); asset_id = p_asset_id; category->set_text(p_category); @@ -48,8 +49,7 @@ void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, co price->set_text(p_cost); } -void EditorAssetLibraryItem::set_image(int p_type, int p_index, const Ref<Texture> &p_image) { - +void EditorAssetLibraryItem::set_image(int p_type, int p_index, const Ref<Texture2D> &p_image) { ERR_FAIL_COND(p_type != EditorAssetLibrary::IMAGE_QUEUE_ICON); ERR_FAIL_COND(p_index != 0); @@ -57,118 +57,102 @@ void EditorAssetLibraryItem::set_image(int p_type, int p_index, const Ref<Textur } void EditorAssetLibraryItem::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - - icon->set_normal_texture(get_icon("ProjectIconLoading", "EditorIcons")); - category->add_color_override("font_color", Color(0.5, 0.5, 0.5)); - author->add_color_override("font_color", Color(0.5, 0.5, 0.5)); - price->add_color_override("font_color", Color(0.5, 0.5, 0.5)); + icon->set_normal_texture(get_theme_icon("ProjectIconLoading", "EditorIcons")); + category->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); + author->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); + price->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); } } void EditorAssetLibraryItem::_asset_clicked() { - emit_signal("asset_selected", asset_id); } void EditorAssetLibraryItem::_category_clicked() { - emit_signal("category_selected", category_id); } -void EditorAssetLibraryItem::_author_clicked() { +void EditorAssetLibraryItem::_author_clicked() { emit_signal("author_selected", author_id); } void EditorAssetLibraryItem::_bind_methods() { - ClassDB::bind_method("set_image", &EditorAssetLibraryItem::set_image); - ClassDB::bind_method("_asset_clicked", &EditorAssetLibraryItem::_asset_clicked); - ClassDB::bind_method("_category_clicked", &EditorAssetLibraryItem::_category_clicked); - ClassDB::bind_method("_author_clicked", &EditorAssetLibraryItem::_author_clicked); ADD_SIGNAL(MethodInfo("asset_selected")); ADD_SIGNAL(MethodInfo("category_selected")); ADD_SIGNAL(MethodInfo("author_selected")); } EditorAssetLibraryItem::EditorAssetLibraryItem() { - Ref<StyleBoxEmpty> border; border.instance(); border->set_default_margin(MARGIN_LEFT, 5 * EDSCALE); border->set_default_margin(MARGIN_RIGHT, 5 * EDSCALE); border->set_default_margin(MARGIN_BOTTOM, 5 * EDSCALE); border->set_default_margin(MARGIN_TOP, 5 * EDSCALE); - add_style_override("panel", border); + add_theme_style_override("panel", border); HBoxContainer *hb = memnew(HBoxContainer); // Add some spacing to visually separate the icon from the asset details. - hb->add_constant_override("separation", 15 * EDSCALE); + hb->add_theme_constant_override("separation", 15 * EDSCALE); add_child(hb); icon = memnew(TextureButton); icon->set_custom_minimum_size(Size2(64, 64) * EDSCALE); icon->set_default_cursor_shape(CURSOR_POINTING_HAND); - icon->connect("pressed", this, "_asset_clicked"); + icon->connect("pressed", callable_mp(this, &EditorAssetLibraryItem::_asset_clicked)); hb->add_child(icon); VBoxContainer *vb = memnew(VBoxContainer); hb->add_child(vb); - vb->set_h_size_flags(SIZE_EXPAND_FILL); + vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); title = memnew(LinkButton); title->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - title->connect("pressed", this, "_asset_clicked"); + title->connect("pressed", callable_mp(this, &EditorAssetLibraryItem::_asset_clicked)); vb->add_child(title); category = memnew(LinkButton); category->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - category->connect("pressed", this, "_category_clicked"); + category->connect("pressed", callable_mp(this, &EditorAssetLibraryItem::_category_clicked)); vb->add_child(category); author = memnew(LinkButton); author->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - author->connect("pressed", this, "_author_clicked"); + author->connect("pressed", callable_mp(this, &EditorAssetLibraryItem::_author_clicked)); vb->add_child(author); price = memnew(Label); vb->add_child(price); set_custom_minimum_size(Size2(250, 100) * EDSCALE); - set_h_size_flags(SIZE_EXPAND_FILL); - - set_mouse_filter(MOUSE_FILTER_PASS); + set_h_size_flags(Control::SIZE_EXPAND_FILL); } ////////////////////////////////////////////////////////////////////////////// -void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const Ref<Texture> &p_image) { - +void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const Ref<Texture2D> &p_image) { switch (p_type) { - case EditorAssetLibrary::IMAGE_QUEUE_ICON: { - item->call("set_image", p_type, p_index, p_image); icon = p_image; } break; case EditorAssetLibrary::IMAGE_QUEUE_THUMBNAIL: { - for (int i = 0; i < preview_images.size(); i++) { if (preview_images[i].id == p_index) { if (preview_images[i].is_video) { - Ref<Image> overlay = get_icon("PlayOverlay", "EditorIcons")->get_data(); + Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_data(); Ref<Image> thumbnail = p_image->get_data(); 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(); Ref<ImageTexture> tex; tex.instance(); @@ -176,7 +160,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const preview_images[i].button->set_icon(tex); // Make it clearer that clicking it will open an external link - preview_images[i].button->set_default_cursor_shape(CURSOR_POINTING_HAND); + preview_images[i].button->set_default_cursor_shape(Control::CURSOR_POINTING_HAND); } else { preview_images[i].button->set_icon(p_image); } @@ -185,7 +169,6 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const } } break; case EditorAssetLibrary::IMAGE_QUEUE_SCREENSHOT: { - for (int i = 0; i < preview_images.size(); i++) { if (preview_images[i].id == p_index) { preview_images.write[i].image = p_image; @@ -202,15 +185,13 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const void EditorAssetLibraryItemDescription::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - previews_bg->add_style_override("panel", get_stylebox("normal", "TextEdit")); + previews_bg->add_theme_style_override("panel", previews->get_theme_stylebox("normal", "TextEdit")); } break; } } void EditorAssetLibraryItemDescription::_bind_methods() { ClassDB::bind_method(D_METHOD("set_image"), &EditorAssetLibraryItemDescription::set_image); - ClassDB::bind_method(D_METHOD("_link_click"), &EditorAssetLibraryItemDescription::_link_click); - ClassDB::bind_method(D_METHOD("_preview_click"), &EditorAssetLibraryItemDescription::_preview_click); } void EditorAssetLibraryItemDescription::_link_click(const String &p_url) { @@ -225,7 +206,7 @@ void EditorAssetLibraryItemDescription::_preview_click(int p_id) { if (!preview_images[i].is_video) { if (preview_images[i].image.is_valid()) { preview->set_texture(preview_images[i].image); - minimum_size_changed(); + child_controls_changed(); } } else { _link_click(preview_images[i].video_link); @@ -237,7 +218,6 @@ void EditorAssetLibraryItemDescription::_preview_click(int p_id) { } void EditorAssetLibraryItemDescription::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, const String &p_cost, int p_version, const String &p_version_string, const String &p_description, const String &p_download_url, const String &p_browse_url, const String &p_sha256_hash) { - asset_id = p_asset_id; title = p_title; download_url = p_download_url; @@ -255,19 +235,18 @@ void EditorAssetLibraryItemDescription::configure(const String &p_title, int p_a } void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, const String &p_url) { - Preview preview; preview.id = p_id; preview.video_link = p_url; preview.is_video = p_video; preview.button = memnew(Button); preview.button->set_flat(true); - preview.button->set_icon(get_icon("ThumbnailWait", "EditorIcons")); + preview.button->set_icon(previews->get_theme_icon("ThumbnailWait", "EditorIcons")); preview.button->set_toggle_mode(true); - preview.button->connect("pressed", this, "_preview_click", varray(p_id)); + preview.button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click), varray(p_id)); preview_hb->add_child(preview.button); if (!p_video) { - preview.image = get_icon("ThumbnailWait", "EditorIcons"); + preview.image = previews->get_theme_icon("ThumbnailWait", "EditorIcons"); } preview_images.push_back(preview); if (preview_images.size() == 1 && !p_video) { @@ -276,12 +255,11 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons } EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { - HBoxContainer *hbox = memnew(HBoxContainer); add_child(hbox); VBoxContainer *desc_vbox = memnew(VBoxContainer); hbox->add_child(desc_vbox); - hbox->add_constant_override("separation", 15 * EDSCALE); + hbox->add_theme_constant_override("separation", 15 * EDSCALE); item = memnew(EditorAssetLibraryItem); @@ -290,14 +268,14 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { description = memnew(RichTextLabel); desc_vbox->add_child(description); - description->set_v_size_flags(SIZE_EXPAND_FILL); - description->connect("meta_clicked", this, "_link_click"); - description->add_constant_override("line_separation", Math::round(5 * EDSCALE)); + description->set_v_size_flags(Control::SIZE_EXPAND_FILL); + description->connect("meta_clicked", callable_mp(this, &EditorAssetLibraryItemDescription::_link_click)); + description->add_theme_constant_override("line_separation", Math::round(5 * EDSCALE)); VBoxContainer *previews_vbox = memnew(VBoxContainer); hbox->add_child(previews_vbox); - previews_vbox->add_constant_override("separation", 15 * EDSCALE); - previews_vbox->set_v_size_flags(SIZE_EXPAND_FILL); + previews_vbox->add_theme_constant_override("separation", 15 * EDSCALE); + previews_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); preview = memnew(TextureRect); previews_vbox->add_child(preview); @@ -314,20 +292,19 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { previews->set_enable_v_scroll(false); previews->set_enable_h_scroll(true); preview_hb = memnew(HBoxContainer); - preview_hb->set_v_size_flags(SIZE_EXPAND_FILL); + preview_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL); previews->add_child(preview_hb); get_ok()->set_text(TTR("Download")); get_cancel()->set_text(TTR("Close")); } -/////////////////////////////////////////////////////////////////////////////////// -void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data) { +/////////////////////////////////////////////////////////////////////////////////// +void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { String error_text; switch (p_status) { - case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: case HTTPRequest::RESULT_CONNECTION_ERROR: case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED: { @@ -381,7 +358,7 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int if (error_text != String()) { download_error->set_text(TTR("Asset Download Error:") + "\n" + error_text); - download_error->popup_centered_minsize(); + download_error->popup_centered(); return; } @@ -393,30 +370,26 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int set_process(false); } -void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asset_id, const Ref<Texture> &p_preview, const String &p_download_url, const String &p_sha256_hash) { - +void EditorAssetLibraryItemDownload::configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash) { title->set_text(p_title); icon->set_texture(p_preview); asset_id = p_asset_id; - if (!p_preview.is_valid()) - icon->set_texture(get_icon("FileBrokenBigThumb", "EditorIcons")); + if (!p_preview.is_valid()) { + icon->set_texture(get_theme_icon("FileBrokenBigThumb", "EditorIcons")); + } host = p_download_url; sha256 = p_sha256_hash; _make_request(); } void EditorAssetLibraryItemDownload::_notification(int p_what) { - switch (p_what) { - // FIXME: The editor crashes if 'NOTICATION_THEME_CHANGED' is used. case NOTIFICATION_ENTER_TREE: { - - add_style_override("panel", get_stylebox("panel", "TabContainer")); - dismiss->set_normal_texture(get_icon("Close", "EditorIcons")); + add_theme_style_override("panel", get_theme_stylebox("panel", "TabContainer")); + dismiss->set_normal_texture(get_theme_icon("Close", "EditorIcons")); } break; case NOTIFICATION_PROCESS: { - // Make the progress bar visible again when retrying the download. progress->set_modulate(Color(1, 1, 1, 1)); @@ -444,7 +417,6 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { if (cstatus != prev_status) { switch (cstatus) { - case HTTPClient::STATUS_RESOLVING: { status->set_text(TTR("Resolving...")); progress->set_max(1); @@ -468,15 +440,14 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { } break; } } -void EditorAssetLibraryItemDownload::_close() { +void EditorAssetLibraryItemDownload::_close() { // Clean up downloaded file. DirAccess::remove_file_or_error(download->get_download_file()); queue_delete(); } void EditorAssetLibraryItemDownload::_install() { - String file = download->get_download_file(); if (external_install) { @@ -500,17 +471,10 @@ void EditorAssetLibraryItemDownload::_make_request() { } void EditorAssetLibraryItemDownload::_bind_methods() { - - ClassDB::bind_method("_http_download_completed", &EditorAssetLibraryItemDownload::_http_download_completed); - ClassDB::bind_method("_install", &EditorAssetLibraryItemDownload::_install); - ClassDB::bind_method("_close", &EditorAssetLibraryItemDownload::_close); - ClassDB::bind_method("_make_request", &EditorAssetLibraryItemDownload::_make_request); - ADD_SIGNAL(MethodInfo("install_asset", PropertyInfo(Variant::STRING, "zip_path"), PropertyInfo(Variant::STRING, "name"))); } EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { - HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); icon = memnew(TextureRect); @@ -518,16 +482,16 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { VBoxContainer *vb = memnew(VBoxContainer); hb->add_child(vb); - vb->set_h_size_flags(SIZE_EXPAND_FILL); + vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); HBoxContainer *title_hb = memnew(HBoxContainer); vb->add_child(title_hb); title = memnew(Label); title_hb->add_child(title); - title->set_h_size_flags(SIZE_EXPAND_FILL); + title->set_h_size_flags(Control::SIZE_EXPAND_FILL); dismiss = memnew(TextureButton); - dismiss->connect("pressed", this, "_close"); + dismiss->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_close)); title_hb->add_child(dismiss); title->set_clip_text(true); @@ -536,7 +500,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { status = memnew(Label(TTR("Idle"))); vb->add_child(status); - status->add_color_override("font_color", Color(0.5, 0.5, 0.5)); + status->add_theme_color_override("font_color", Color(0.5, 0.5, 0.5)); progress = memnew(ProgressBar); vb->add_child(progress); @@ -547,11 +511,11 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { install = memnew(Button); install->set_text(TTR("Install...")); install->set_disabled(true); - install->connect("pressed", this, "_install"); + install->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_install)); retry = memnew(Button); retry->set_text(TTR("Retry")); - retry->connect("pressed", this, "_make_request"); + retry->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDownload::_make_request)); hb2->add_child(retry); hb2->add_child(install); @@ -559,7 +523,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { download = memnew(HTTPRequest); add_child(download); - download->connect("request_completed", this, "_http_download_completed"); + download->connect("request_completed", callable_mp(this, &EditorAssetLibraryItemDownload::_http_download_completed)); download->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); download_error = memnew(AcceptDialog); @@ -568,7 +532,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { asset_installer = memnew(EditorAssetInstaller); add_child(asset_installer); - asset_installer->connect("confirmed", this, "_close"); + asset_installer->connect("confirmed", callable_mp(this, &EditorAssetLibraryItemDownload::_close)); prev_status = -1; @@ -577,25 +541,20 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { //////////////////////////////////////////////////////////////////////////////// void EditorAssetLibrary::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - - error_tr->set_texture(get_icon("Error", "EditorIcons")); - filter->set_right_icon(get_icon("Search", "EditorIcons")); + error_tr->set_texture(get_theme_icon("Error", "EditorIcons")); + filter->set_right_icon(get_theme_icon("Search", "EditorIcons")); filter->set_clear_button_enabled(true); error_label->raise(); } break; case NOTIFICATION_VISIBILITY_CHANGED: { - if (is_visible() && initial_loading) { _repository_changed(0); // Update when shown for the first time. } } break; case NOTIFICATION_PROCESS: { - HTTPClient::Status s = request->get_http_client_status(); const bool loading = s != HTTPClient::STATUS_DISCONNECTED; @@ -612,27 +571,36 @@ void EditorAssetLibrary::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - - library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree")); - downloads_scroll->add_style_override("bg", get_stylebox("bg", "Tree")); - error_tr->set_texture(get_icon("Error", "EditorIcons")); - filter->set_right_icon(get_icon("Search", "EditorIcons")); + library_scroll_bg->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + downloads_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree")); + error_tr->set_texture(get_theme_icon("Error", "EditorIcons")); + filter->set_right_icon(get_theme_icon("Search", "EditorIcons")); filter->set_clear_button_enabled(true); } break; } } -void EditorAssetLibrary::_install_asset() { +void EditorAssetLibrary::_unhandled_input(const Ref<InputEvent> &p_event) { + const Ref<InputEventKey> key = p_event; + + if (key.is_valid() && key->is_pressed()) { + if (key->get_keycode_with_modifiers() == (KEY_MASK_CMD | KEY_F) && is_visible_in_tree()) { + filter->grab_focus(); + filter->select_all(); + accept_event(); + } + } +} +void EditorAssetLibrary::_install_asset() { ERR_FAIL_COND(!description); for (int i = 0; i < downloads_hb->get_child_count(); i++) { - EditorAssetLibraryItemDownload *d = Object::cast_to<EditorAssetLibraryItemDownload>(downloads_hb->get_child(i)); if (d && d->get_asset_id() == description->get_asset_id()) { - - if (EditorNode::get_singleton() != NULL) + if (EditorNode::get_singleton() != nullptr) { EditorNode::get_singleton()->show_warning(TTR("Download for this asset is already in progress!")); + } return; } } @@ -643,7 +611,7 @@ void EditorAssetLibrary::_install_asset() { if (templates_only) { download->set_external_install(true); - download->connect("install_asset", this, "_install_external_asset"); + download->connect("install_asset", callable_mp(this, &EditorAssetLibrary::_install_external_asset)); } } @@ -672,16 +640,14 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = { }; void EditorAssetLibrary::_select_author(int p_id) { - // Open author window. } void EditorAssetLibrary::_select_category(int p_id) { - for (int i = 0; i < categories->get_item_count(); i++) { - - if (i == 0) + if (i == 0) { continue; + } int id = categories->get_item_metadata(i); if (id == p_id) { categories->select(i); @@ -690,17 +656,17 @@ void EditorAssetLibrary::_select_category(int p_id) { } } } -void EditorAssetLibrary::_select_asset(int p_id) { +void EditorAssetLibrary::_select_asset(int p_id) { _api_request("asset/" + itos(p_id), REQUESTING_ASSET); } -void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByteArray &p_data, int p_queue_id) { +void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedByteArray &p_data, int p_queue_id) { Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target); if (obj) { bool image_set = false; - PoolByteArray image_data = p_data; + PackedByteArray image_data = p_data; if (use_cache) { String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); @@ -708,12 +674,12 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); if (file) { - PoolByteArray cached_data; + PackedByteArray cached_data; int len = file->get_32(); cached_data.resize(len); - PoolByteArray::Write w = cached_data.write(); - file->get_buffer(w.ptr(), len); + uint8_t *w = cached_data.ptrw(); + file->get_buffer(w, len); image_data = cached_data; file->close(); @@ -722,17 +688,17 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt } int len = image_data.size(); - PoolByteArray::Read r = image_data.read(); + const uint8_t *r = image_data.ptr(); Ref<Image> image = Ref<Image>(memnew(Image)); uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; uint8_t jpg_signature[3] = { 255, 216, 255 }; - if (r.ptr()) { + if (r) { if ((memcmp(&r[0], &png_signature[0], 8) == 0) && Image::_png_mem_loader_func) { - image->copy_internals_from(Image::_png_mem_loader_func(r.ptr(), len)); + image->copy_internals_from(Image::_png_mem_loader_func(r, len)); } else if ((memcmp(&r[0], &jpg_signature[0], 3) == 0) && Image::_jpg_mem_loader_func) { - image->copy_internals_from(Image::_jpg_mem_loader_func(r.ptr(), len)); + image->copy_internals_from(Image::_jpg_mem_loader_func(r, len)); } } @@ -770,17 +736,15 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt } if (!image_set && final) { - obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("FileBrokenBigThumb", "EditorIcons")); + obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_theme_icon("FileBrokenBigThumb", "EditorIcons")); } } } -void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data, int p_queue_id) { - +void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data, int p_queue_id) { ERR_FAIL_COND(!image_queue.has(p_queue_id)); if (p_status == HTTPRequest::RESULT_SUCCESS && p_code < HTTPClient::RESPONSE_BAD_REQUEST) { - if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag @@ -796,11 +760,11 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons } int len = p_data.size(); - PoolByteArray::Read r = p_data.read(); + const uint8_t *r = p_data.ptr(); file = FileAccess::open(cache_filename_base + ".data", FileAccess::WRITE); if (file) { file->store_32(len); - file->store_buffer(r.ptr(), len); + file->store_buffer(r, len); file->close(); memdelete(file); } @@ -812,10 +776,10 @@ 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_PRINT("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("FileBrokenBigThumb", "EditorIcons")); + obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_theme_icon("FileBrokenBigThumb", "EditorIcons")); } } @@ -826,14 +790,12 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons } void EditorAssetLibrary::_update_image_queue() { - const int max_images = 6; int current_images = 0; List<int> to_delete; for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) { if (!E->get().active && current_images < max_images) { - String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text()); Vector<String> headers; @@ -866,7 +828,6 @@ void EditorAssetLibrary::_update_image_queue() { } void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, ImageType p_type, int p_image_index) { - ImageQueue iq; iq.image_url = p_image_url; iq.image_index = p_image_index; @@ -878,13 +839,13 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag iq.queue_id = ++last_queue_id; iq.active = false; - iq.request->connect("request_completed", this, "_image_request_completed", varray(iq.queue_id)); + iq.request->connect("request_completed", callable_mp(this, &EditorAssetLibrary::_image_request_completed), varray(iq.queue_id)); image_queue[iq.queue_id] = iq; add_child(iq.request); - _image_update(true, false, PoolByteArray(), iq.queue_id); + _image_update(true, false, PackedByteArray(), iq.queue_id); _update_image_queue(); } @@ -907,7 +868,6 @@ void EditorAssetLibrary::_rerun_search(int p_ignore) { } void EditorAssetLibrary::_search(int p_page) { - String args; if (templates_only) { @@ -931,7 +891,6 @@ void EditorAssetLibrary::_search(int p_page) { } if (categories->get_selected() > 0) { - args += "&category=" + itos(categories->get_item_metadata(categories->get_selected())); } @@ -952,32 +911,33 @@ void EditorAssetLibrary::_search(int p_page) { } void EditorAssetLibrary::_search_text_entered(const String &p_text) { - _search(); } HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int p_page_len, int p_total_items, int p_current_items) { - HBoxContainer *hbc = memnew(HBoxContainer); - if (p_page_count < 2) + if (p_page_count < 2) { return hbc; + } //do the mario int from = p_page - 5; - if (from < 0) + if (from < 0) { from = 0; + } int to = from + 10; - if (to > p_page_count) + if (to > p_page_count) { to = p_page_count; + } hbc->add_spacer(); - hbc->add_constant_override("separation", 5 * EDSCALE); + hbc->add_theme_constant_override("separation", 5 * EDSCALE); Button *first = memnew(Button); first->set_text(TTR("First")); if (p_page != 0) { - first->connect("pressed", this, "_search", varray(0)); + first->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(0)); } else { first->set_disabled(true); first->set_focus_mode(Control::FOCUS_NONE); @@ -987,7 +947,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int Button *prev = memnew(Button); prev->set_text(TTR("Previous")); if (p_page > 0) { - prev->connect("pressed", this, "_search", varray(p_page - 1)); + prev->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page - 1)); } else { prev->set_disabled(true); prev->set_focus_mode(Control::FOCUS_NONE); @@ -996,9 +956,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int hbc->add_child(memnew(VSeparator)); for (int i = from; i < to; i++) { - if (i == p_page) { - Button *current = memnew(Button); current->set_text(itos(i + 1)); current->set_disabled(true); @@ -1006,10 +964,9 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int hbc->add_child(current); } else { - Button *current = memnew(Button); current->set_text(itos(i + 1)); - current->connect("pressed", this, "_search", varray(i)); + current->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(i)); hbc->add_child(current); } @@ -1018,7 +975,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int Button *next = memnew(Button); next->set_text(TTR("Next")); if (p_page < p_page_count - 1) { - next->connect("pressed", this, "_search", varray(p_page + 1)); + next->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page + 1)); } else { next->set_disabled(true); next->set_focus_mode(Control::FOCUS_NONE); @@ -1029,7 +986,7 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int Button *last = memnew(Button); last->set_text(TTR("Last")); if (p_page != p_page_count - 1) { - last->connect("pressed", this, "_search", varray(p_page_count - 1)); + last->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), varray(p_page_count - 1)); } else { last->set_disabled(true); last->set_focus_mode(Control::FOCUS_NONE); @@ -1042,7 +999,6 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int } void EditorAssetLibrary::_api_request(const String &p_request, RequestType p_request_type, const String &p_arguments) { - if (requesting != REQUESTING_NONE) { request->cancel_request(); } @@ -1053,20 +1009,18 @@ void EditorAssetLibrary::_api_request(const String &p_request, RequestType p_req request->request(host + "/" + p_request + p_arguments); } -void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data) { - +void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { String str; { int datalen = p_data.size(); - PoolByteArray::Read r = p_data.read(); - str.parse_utf8((const char *)r.ptr(), datalen); + const uint8_t *r = p_data.ptr(); + str.parse_utf8((const char *)r, datalen); } bool error_abort = true; switch (p_status) { - case HTTPRequest::RESULT_CANT_RESOLVE: { error_label->set_text(TTR("Can't resolve hostname:") + " " + host); } break; @@ -1093,7 +1047,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const if (p_code != 200) { error_label->set_text(TTR("Request failed, return code:") + " " + itos(p_code)); } else { - error_abort = false; } } break; @@ -1118,7 +1071,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const switch (requested) { case REQUESTING_CONFIG: { - categories->clear(); categories->add_item(TTR("All")); categories->set_item_metadata(0, 0); @@ -1126,8 +1078,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const Array clist = d["categories"]; for (int i = 0; i < clist.size(); i++) { Dictionary cat = clist[i]; - if (!cat.has("name") || !cat.has("id")) + if (!cat.has("name") || !cat.has("id")) { continue; + } String name = cat["name"]; int id = cat["id"]; categories->add_item(name); @@ -1139,7 +1092,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const _search(); } break; case REQUESTING_SEARCH: { - initial_loading = false; // The loading text only needs to be displayed before the first page is loaded. @@ -1187,8 +1139,8 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const asset_items = memnew(GridContainer); asset_items->set_columns(2); - asset_items->add_constant_override("hseparation", 10 * EDSCALE); - asset_items->add_constant_override("vseparation", 10 * EDSCALE); + asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE); + asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE); library_vb->add_child(asset_items); @@ -1196,12 +1148,20 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const library_vb->add_child(asset_bottom_page); if (result.empty()) { - library_error->set_text(vformat(TTR("No results for \"%s\"."), filter->get_text())); + if (filter->get_text() != String()) { + library_error->set_text( + vformat(TTR("No results for \"%s\"."), filter->get_text())); + } else { + // No results, even though the user didn't search for anything specific. + // This is typically because the version number changed recently + // and no assets compatible with the new version have been published yet. + library_error->set_text( + vformat(TTR("No results compatible with %s %s."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH))); + } library_error->show(); } for (int i = 0; i < result.size(); i++) { - Dictionary r = result[i]; ERR_CONTINUE(!r.has("title")); @@ -1215,9 +1175,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const EditorAssetLibraryItem *item = memnew(EditorAssetLibraryItem); asset_items->add_child(item); item->configure(r["title"], r["asset_id"], category_map[r["category_id"]], r["category_id"], r["author"], r["author_id"], r["cost"]); - item->connect("asset_selected", this, "_select_asset"); - item->connect("author_selected", this, "_select_author"); - item->connect("category_selected", this, "_select_category"); + item->connect("asset_selected", callable_mp(this, &EditorAssetLibrary::_select_asset)); + item->connect("author_selected", callable_mp(this, &EditorAssetLibrary::_select_author)); + item->connect("category_selected", callable_mp(this, &EditorAssetLibrary::_select_category)); if (r.has("icon_url") && r["icon_url"] != "") { _request_image(item->get_instance_id(), r["icon_url"], IMAGE_QUEUE_ICON, 0); @@ -1247,8 +1207,8 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const description = memnew(EditorAssetLibraryItemDescription); add_child(description); - description->popup_centered_minsize(); - description->connect("confirmed", this, "_install_asset"); + description->popup_centered(); + description->connect("confirmed", callable_mp(this, &EditorAssetLibrary::_install_asset)); description->configure(r["title"], r["asset_id"], category_map[r["category_id"]], r["category_id"], r["author"], r["author_id"], r["cost"], r["version"], r["version_string"], r["description"], r["download_url"], r["browse_url"], r["download_hash"]); @@ -1260,7 +1220,6 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const Array previews = d["previews"]; for (int i = 0; i < previews.size(); i++) { - Dictionary p = previews[i]; ERR_CONTINUE(!p.has("type")); @@ -1284,15 +1243,15 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const } } } break; - default: break; + default: + break; } } void EditorAssetLibrary::_asset_file_selected(const String &p_file) { - if (asset_installer) { memdelete(asset_installer); - asset_installer = NULL; + asset_installer = nullptr; } asset_installer = memnew(EditorAssetInstaller); @@ -1301,18 +1260,15 @@ void EditorAssetLibrary::_asset_file_selected(const String &p_file) { } void EditorAssetLibrary::_asset_open() { - - asset_open->popup_centered_ratio(); + asset_open->popup_file_dialog(); } void EditorAssetLibrary::_manage_plugins() { - ProjectSettingsEditor::get_singleton()->popup_project_settings(); ProjectSettingsEditor::get_singleton()->set_plugins_page(); } void EditorAssetLibrary::_install_external_asset(String p_zip_path, String p_title) { - emit_signal("install_asset", p_zip_path, p_title); } @@ -1321,28 +1277,12 @@ void EditorAssetLibrary::disable_community_support() { } void EditorAssetLibrary::_bind_methods() { - - ClassDB::bind_method("_http_request_completed", &EditorAssetLibrary::_http_request_completed); - ClassDB::bind_method("_select_asset", &EditorAssetLibrary::_select_asset); - ClassDB::bind_method("_select_author", &EditorAssetLibrary::_select_author); - ClassDB::bind_method("_select_category", &EditorAssetLibrary::_select_category); - ClassDB::bind_method("_image_request_completed", &EditorAssetLibrary::_image_request_completed); - ClassDB::bind_method("_search", &EditorAssetLibrary::_search, DEFVAL(0)); - ClassDB::bind_method("_search_text_entered", &EditorAssetLibrary::_search_text_entered); - ClassDB::bind_method("_install_asset", &EditorAssetLibrary::_install_asset); - ClassDB::bind_method("_manage_plugins", &EditorAssetLibrary::_manage_plugins); - ClassDB::bind_method("_asset_open", &EditorAssetLibrary::_asset_open); - ClassDB::bind_method("_asset_file_selected", &EditorAssetLibrary::_asset_file_selected); - ClassDB::bind_method("_repository_changed", &EditorAssetLibrary::_repository_changed); - ClassDB::bind_method("_support_toggled", &EditorAssetLibrary::_support_toggled); - ClassDB::bind_method("_rerun_search", &EditorAssetLibrary::_rerun_search); - ClassDB::bind_method("_install_external_asset", &EditorAssetLibrary::_install_external_asset); + ClassDB::bind_method("_unhandled_input", &EditorAssetLibrary::_unhandled_input); ADD_SIGNAL(MethodInfo("install_asset", PropertyInfo(Variant::STRING, "zip_path"), PropertyInfo(Variant::STRING, "name"))); } EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { - requesting = REQUESTING_NONE; templates_only = p_templates_only; initial_loading = true; @@ -1354,28 +1294,29 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { HBoxContainer *search_hb = memnew(HBoxContainer); library_main->add_child(search_hb); - library_main->add_constant_override("separation", 10 * EDSCALE); + library_main->add_theme_constant_override("separation", 10 * EDSCALE); filter = memnew(LineEdit); search_hb->add_child(filter); - filter->set_h_size_flags(SIZE_EXPAND_FILL); - filter->connect("text_entered", this, "_search_text_entered"); + filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); + filter->connect("text_entered", callable_mp(this, &EditorAssetLibrary::_search_text_entered)); search = memnew(Button(TTR("Search"))); - search->connect("pressed", this, "_search"); + search->connect("pressed", callable_mp(this, &EditorAssetLibrary::_search), make_binds(0)); search_hb->add_child(search); - if (!p_templates_only) + if (!p_templates_only) { search_hb->add_child(memnew(VSeparator)); + } Button *open_asset = memnew(Button); open_asset->set_text(TTR("Import...")); search_hb->add_child(open_asset); - open_asset->connect("pressed", this, "_asset_open"); + open_asset->connect("pressed", callable_mp(this, &EditorAssetLibrary::_asset_open)); Button *plugins = memnew(Button); plugins->set_text(TTR("Plugins...")); search_hb->add_child(plugins); - plugins->connect("pressed", this, "_manage_plugins"); + plugins->connect("pressed", callable_mp(this, &EditorAssetLibrary::_manage_plugins)); if (p_templates_only) { open_asset->hide(); @@ -1393,8 +1334,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { search_hb2->add_child(sort); - sort->set_h_size_flags(SIZE_EXPAND_FILL); - sort->connect("item_selected", this, "_rerun_search"); + sort->set_h_size_flags(Control::SIZE_EXPAND_FILL); + sort->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_rerun_search)); search_hb2->add_child(memnew(VSeparator)); @@ -1402,8 +1343,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { categories = memnew(OptionButton); categories->add_item(TTR("All")); search_hb2->add_child(categories); - categories->set_h_size_flags(SIZE_EXPAND_FILL); - categories->connect("item_selected", this, "_rerun_search"); + categories->set_h_size_flags(Control::SIZE_EXPAND_FILL); + categories->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_rerun_search)); search_hb2->add_child(memnew(VSeparator)); @@ -1415,10 +1356,10 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { repository->add_item("localhost"); repository->set_item_metadata(1, "http://127.0.0.1/asset-library/api"); - repository->connect("item_selected", this, "_repository_changed"); + repository->connect("item_selected", callable_mp(this, &EditorAssetLibrary::_repository_changed)); search_hb2->add_child(repository); - repository->set_h_size_flags(SIZE_EXPAND_FILL); + repository->set_h_size_flags(Control::SIZE_EXPAND_FILL); search_hb2->add_child(memnew(VSeparator)); @@ -1430,13 +1371,13 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING); support->get_popup()->set_item_checked(SUPPORT_OFFICIAL, true); support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, true); - support->get_popup()->connect("id_pressed", this, "_support_toggled"); + support->get_popup()->connect("id_pressed", callable_mp(this, &EditorAssetLibrary::_support_toggled)); ///////// library_scroll_bg = memnew(PanelContainer); library_main->add_child(library_scroll_bg); - library_scroll_bg->set_v_size_flags(SIZE_EXPAND_FILL); + library_scroll_bg->set_v_size_flags(Control::SIZE_EXPAND_FILL); library_scroll = memnew(ScrollContainer); library_scroll->set_enable_v_scroll(true); @@ -1453,12 +1394,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { PanelContainer *library_vb_border = memnew(PanelContainer); library_scroll->add_child(library_vb_border); - library_vb_border->add_style_override("panel", border2); - library_vb_border->set_h_size_flags(SIZE_EXPAND_FILL); - library_vb_border->set_mouse_filter(MOUSE_FILTER_PASS); + library_vb_border->add_theme_style_override("panel", border2); + library_vb_border->set_h_size_flags(Control::SIZE_EXPAND_FILL); library_vb = memnew(VBoxContainer); - library_vb->set_h_size_flags(SIZE_EXPAND_FILL); + library_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); library_vb_border->add_child(library_vb); @@ -1476,8 +1416,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { asset_items = memnew(GridContainer); asset_items->set_columns(2); - asset_items->add_constant_override("hseparation", 10 * EDSCALE); - asset_items->add_constant_override("vseparation", 10 * EDSCALE); + asset_items->add_theme_constant_override("hseparation", 10 * EDSCALE); + asset_items->add_theme_constant_override("vseparation", 10 * EDSCALE); library_vb->add_child(asset_items); @@ -1487,24 +1427,25 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { request = memnew(HTTPRequest); add_child(request); request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); - request->connect("request_completed", this, "_http_request_completed"); + request->connect("request_completed", callable_mp(this, &EditorAssetLibrary::_http_request_completed)); last_queue_id = 0; - library_vb->add_constant_override("separation", 20 * EDSCALE); + library_vb->add_theme_constant_override("separation", 20 * EDSCALE); error_hb = memnew(HBoxContainer); library_main->add_child(error_hb); error_label = memnew(Label); - error_label->add_color_override("color", get_color("error_color", "Editor")); + error_label->add_theme_color_override("color", get_theme_color("error_color", "Editor")); error_hb->add_child(error_label); error_tr = memnew(TextureRect); error_tr->set_v_size_flags(Control::SIZE_SHRINK_CENTER); error_hb->add_child(error_tr); - description = NULL; + description = nullptr; set_process(true); + set_process_unhandled_input(true); downloads_scroll = memnew(ScrollContainer); downloads_scroll->set_enable_h_scroll(true); @@ -1517,28 +1458,24 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { asset_open->set_access(EditorFileDialog::ACCESS_FILESYSTEM); asset_open->add_filter("*.zip ; " + TTR("Assets ZIP File")); - asset_open->set_mode(EditorFileDialog::MODE_OPEN_FILE); + asset_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); add_child(asset_open); - asset_open->connect("file_selected", this, "_asset_file_selected"); + asset_open->connect("file_selected", callable_mp(this, &EditorAssetLibrary::_asset_file_selected)); - asset_installer = NULL; + asset_installer = nullptr; } /////// void AssetLibraryEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - addon_library->show(); } else { - addon_library->hide(); } } AssetLibraryEditorPlugin::AssetLibraryEditorPlugin(EditorNode *p_node) { - editor = p_node; addon_library = memnew(EditorAssetLibrary); addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index aa3c735810..3fca8a1084 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -50,7 +50,6 @@ #include "scene/main/http_request.h" class EditorAssetLibraryItem : public PanelContainer { - GDCLASS(EditorAssetLibraryItem, PanelContainer); TextureButton *icon; @@ -68,7 +67,7 @@ class EditorAssetLibraryItem : public PanelContainer { void _category_clicked(); void _author_clicked(); - void set_image(int p_type, int p_index, const Ref<Texture> &p_image); + void set_image(int p_type, int p_index, const Ref<Texture2D> &p_image); protected: void _notification(int p_what); @@ -81,7 +80,6 @@ public: }; class EditorAssetLibraryItemDescription : public ConfirmationDialog { - GDCLASS(EditorAssetLibraryItemDescription, ConfirmationDialog); EditorAssetLibraryItem *item; @@ -95,19 +93,19 @@ class EditorAssetLibraryItemDescription : public ConfirmationDialog { bool is_video; String video_link; Button *button; - Ref<Texture> image; + Ref<Texture2D> image; }; Vector<Preview> preview_images; TextureRect *preview; - void set_image(int p_type, int p_index, const Ref<Texture> &p_image); + void set_image(int p_type, int p_index, const Ref<Texture2D> &p_image); int asset_id; String download_url; String title; String sha256; - Ref<Texture> icon; + Ref<Texture2D> icon; void _link_click(const String &p_url); void _preview_click(int p_id); @@ -121,7 +119,7 @@ public: void add_preview(int p_id, bool p_video, const String &p_url); String get_title() { return title; } - Ref<Texture> get_preview_icon() { return icon; } + Ref<Texture2D> get_preview_icon() { return icon; } String get_download_url() { return download_url; } int get_asset_id() { return asset_id; } String get_sha256() { return sha256; } @@ -129,7 +127,6 @@ public: }; class EditorAssetLibraryItemDownload : public PanelContainer { - GDCLASS(EditorAssetLibraryItemDownload, PanelContainer); TextureRect *icon; @@ -156,7 +153,7 @@ class EditorAssetLibraryItemDownload : public PanelContainer { void _close(); void _install(); void _make_request(); - void _http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); + void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); protected: void _notification(int p_what); @@ -165,7 +162,7 @@ protected: public: void set_external_install(bool p_enable) { external_install = p_enable; } int get_asset_id() { return asset_id; } - void configure(const String &p_title, int p_asset_id, const Ref<Texture> &p_preview, const String &p_download_url, const String &p_sha256_hash); + void configure(const String &p_title, int p_asset_id, const Ref<Texture2D> &p_preview, const String &p_download_url, const String &p_sha256_hash); EditorAssetLibraryItemDownload(); }; @@ -237,7 +234,6 @@ class EditorAssetLibrary : public PanelContainer { }; struct ImageQueue { - bool active; int queue_id; ImageType image_type; @@ -250,8 +246,8 @@ class EditorAssetLibrary : public PanelContainer { int last_queue_id; Map<int, ImageQueue> image_queue; - void _image_update(bool use_cache, bool final, const PoolByteArray &p_data, int p_queue_id); - void _image_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data, int p_queue_id); + void _image_update(bool use_cache, bool final, const PackedByteArray &p_data, int p_queue_id); + void _image_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data, int p_queue_id); void _request_image(ObjectID p_for, String p_image_url, ImageType p_type, int p_image_index); void _update_image_queue(); @@ -286,8 +282,8 @@ class EditorAssetLibrary : public PanelContainer { void _rerun_search(int p_ignore); void _search_text_entered(const String &p_text = ""); void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = ""); - void _http_request_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); - void _http_download_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); + void _http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); + void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); void _repository_changed(int p_repository_id); void _support_toggled(int p_support); @@ -300,6 +296,7 @@ class EditorAssetLibrary : public PanelContainer { protected: static void _bind_methods(); void _notification(int p_what); + void _unhandled_input(const Ref<InputEvent> &p_event); public: void disable_community_support(); @@ -308,18 +305,17 @@ public: }; class AssetLibraryEditorPlugin : public EditorPlugin { - GDCLASS(AssetLibraryEditorPlugin, EditorPlugin); EditorAssetLibrary *addon_library; EditorNode *editor; public: - virtual String get_name() const { return "AssetLib"; } - bool has_main_screen() const { return true; } - virtual void edit(Object *p_object) {} - virtual bool handles(Object *p_object) const { return false; } - virtual void make_visible(bool p_visible); + virtual String get_name() const override { return "AssetLib"; } + bool has_main_screen() const override { return true; } + virtual void edit(Object *p_object) override {} + virtual bool handles(Object *p_object) const override { return false; } + virtual void make_visible(bool p_visible) override; //virtual bool get_remove_list(List<Node*> *p_list) { return canvas_item_editor->get_remove_list(p_list); } //virtual Dictionary get_state() const; //virtual void set_state(const Dictionary& p_state); diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp index 60cb2ff54d..b0f65af245 100644 --- a/editor/plugins/audio_stream_editor_plugin.cpp +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -37,16 +37,15 @@ #include "editor/editor_settings.h" void AudioStreamEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", this, "_preview_changed"); + AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AudioStreamEditor::_preview_changed)); } if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) { - _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); - _stop_button->set_icon(get_icon("Stop", "EditorIcons")); - _preview->set_frame_color(get_color("dark_color_2", "Editor")); - set_frame_color(get_color("dark_color_1", "Editor")); + _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons")); + _stop_button->set_icon(get_theme_icon("Stop", "EditorIcons")); + _preview->set_frame_color(get_theme_color("dark_color_2", "Editor")); + set_frame_color(get_theme_color("dark_color_1", "Editor")); _indicator->update(); _preview->update(); @@ -75,7 +74,6 @@ void AudioStreamEditor::_draw_preview() { lines.resize(size.width * 2); for (int i = 0; i < size.width; i++) { - float ofs = i * preview_len / size.width; float ofs_n = (i + 1) * preview_len / size.width; float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5; @@ -87,50 +85,46 @@ void AudioStreamEditor::_draw_preview() { } Vector<Color> color; - color.push_back(get_color("contrast_color_2", "Editor")); + color.push_back(get_theme_color("contrast_color_2", "Editor")); - VS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color); + RS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color); } void AudioStreamEditor::_preview_changed(ObjectID p_which) { - if (stream.is_valid() && stream->get_instance_id() == p_which) { _preview->update(); } } void AudioStreamEditor::_changed_callback(Object *p_changed, const char *p_prop) { - - if (!is_visible()) + if (!is_visible()) { return; + } update(); } void AudioStreamEditor::_play() { - if (_player->is_playing()) { _player->stop(); - _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons")); set_process(false); } else { _player->play(_current); - _play_button->set_icon(get_icon("Pause", "EditorIcons")); + _play_button->set_icon(get_theme_icon("Pause", "EditorIcons")); set_process(true); } } void AudioStreamEditor::_stop() { - _player->stop(); - _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons")); _current = 0; _indicator->update(); set_process(false); } void AudioStreamEditor::_on_finished() { - - _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + _play_button->set_icon(get_theme_icon("MainPlay", "EditorIcons")); if (_current == _player->get_stream()->get_length()) { _current = 0; _indicator->update(); @@ -138,7 +132,6 @@ void AudioStreamEditor::_on_finished() { } void AudioStreamEditor::_draw_indicator() { - if (!stream.is_valid()) { return; } @@ -146,7 +139,7 @@ void AudioStreamEditor::_draw_indicator() { Rect2 rect = _preview->get_rect(); float len = stream->get_length(); float ofs_x = _current / len * rect.size.width; - _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_color("accent_color", "Editor"), 1); + _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_theme_color("accent_color", "Editor"), 1); _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); } @@ -178,9 +171,9 @@ void AudioStreamEditor::_seek_to(real_t p_x) { } void AudioStreamEditor::edit(Ref<AudioStream> p_stream) { - - if (!stream.is_null()) + if (!stream.is_null()) { stream->remove_change_receptor(this); + } stream = p_stream; _player->set_stream(stream); @@ -197,24 +190,15 @@ void AudioStreamEditor::edit(Ref<AudioStream> p_stream) { } void AudioStreamEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_preview_changed"), &AudioStreamEditor::_preview_changed); - ClassDB::bind_method(D_METHOD("_play"), &AudioStreamEditor::_play); - ClassDB::bind_method(D_METHOD("_stop"), &AudioStreamEditor::_stop); - ClassDB::bind_method(D_METHOD("_on_finished"), &AudioStreamEditor::_on_finished); - ClassDB::bind_method(D_METHOD("_draw_preview"), &AudioStreamEditor::_draw_preview); - ClassDB::bind_method(D_METHOD("_draw_indicator"), &AudioStreamEditor::_draw_indicator); - ClassDB::bind_method(D_METHOD("_on_input_indicator"), &AudioStreamEditor::_on_input_indicator); } AudioStreamEditor::AudioStreamEditor() { - set_custom_minimum_size(Size2(1, 100) * EDSCALE); _current = 0; _dragging = false; _player = memnew(AudioStreamPlayer); - _player->connect("finished", this, "_on_finished"); + _player->connect("finished", callable_mp(this, &AudioStreamEditor::_on_finished)); add_child(_player); VBoxContainer *vbox = memnew(VBoxContainer); @@ -223,62 +207,61 @@ AudioStreamEditor::AudioStreamEditor() { _preview = memnew(ColorRect); _preview->set_v_size_flags(SIZE_EXPAND_FILL); - _preview->connect("draw", this, "_draw_preview"); + _preview->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_preview)); vbox->add_child(_preview); _indicator = memnew(Control); _indicator->set_anchors_and_margins_preset(PRESET_WIDE); - _indicator->connect("draw", this, "_draw_indicator"); - _indicator->connect("gui_input", this, "_on_input_indicator"); + _indicator->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_indicator)); + _indicator->connect("gui_input", callable_mp(this, &AudioStreamEditor::_on_input_indicator)); _preview->add_child(_indicator); HBoxContainer *hbox = memnew(HBoxContainer); - hbox->add_constant_override("separation", 0); + hbox->add_theme_constant_override("separation", 0); vbox->add_child(hbox); - _play_button = memnew(ToolButton); + _play_button = memnew(Button); + _play_button->set_flat(true); hbox->add_child(_play_button); _play_button->set_focus_mode(Control::FOCUS_NONE); - _play_button->connect("pressed", this, "_play"); + _play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play)); - _stop_button = memnew(ToolButton); + _stop_button = memnew(Button); + _stop_button->set_flat(true); hbox->add_child(_stop_button); _stop_button->set_focus_mode(Control::FOCUS_NONE); - _stop_button->connect("pressed", this, "_stop"); + _stop_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_stop)); _current_label = memnew(Label); _current_label->set_align(Label::ALIGN_RIGHT); _current_label->set_h_size_flags(SIZE_EXPAND_FILL); - _current_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + _current_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts")); _current_label->set_modulate(Color(1, 1, 1, 0.5)); hbox->add_child(_current_label); _duration_label = memnew(Label); - _duration_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + _duration_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts")); hbox->add_child(_duration_label); } void AudioStreamEditorPlugin::edit(Object *p_object) { - AudioStream *s = Object::cast_to<AudioStream>(p_object); - if (!s) + if (!s) { return; + } audio_editor->edit(Ref<AudioStream>(s)); } bool AudioStreamEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AudioStream"); } void AudioStreamEditorPlugin::make_visible(bool p_visible) { - audio_editor->set_visible(p_visible); } AudioStreamEditorPlugin::AudioStreamEditorPlugin(EditorNode *p_node) { - editor = p_node; audio_editor = memnew(AudioStreamEditor); add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, audio_editor); diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h index 2191b541f6..5936b91fa1 100644 --- a/editor/plugins/audio_stream_editor_plugin.h +++ b/editor/plugins/audio_stream_editor_plugin.h @@ -38,7 +38,6 @@ #include "scene/resources/texture.h" class AudioStreamEditor : public ColorRect { - GDCLASS(AudioStreamEditor, ColorRect); Ref<AudioStream> stream; @@ -48,8 +47,8 @@ class AudioStreamEditor : public ColorRect { Label *_current_label; Label *_duration_label; - ToolButton *_play_button; - ToolButton *_stop_button; + Button *_play_button; + Button *_stop_button; float _current; bool _dragging; @@ -64,7 +63,7 @@ protected: void _draw_indicator(); void _on_input_indicator(Ref<InputEvent> p_event); void _seek_to(real_t p_x); - void _changed_callback(Object *p_changed, const char *p_prop); + void _changed_callback(Object *p_changed, const char *p_prop) override; static void _bind_methods(); public: @@ -73,18 +72,17 @@ public: }; class AudioStreamEditorPlugin : public EditorPlugin { - GDCLASS(AudioStreamEditorPlugin, EditorPlugin); AudioStreamEditor *audio_editor; EditorNode *editor; public: - virtual String get_name() const { return "Audio"; } - 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); + virtual String get_name() const override { return "Audio"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; AudioStreamEditorPlugin(EditorNode *p_node); ~AudioStreamEditorPlugin(); diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp index 7db936ccb8..e5d4e4a761 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.cpp +++ b/editor/plugins/baked_lightmap_editor_plugin.cpp @@ -30,20 +30,33 @@ #include "baked_lightmap_editor_plugin.h" -void BakedLightmapEditorPlugin::_bake() { - +void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) { if (lightmap) { BakedLightmap::BakeError err; if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) { - err = lightmap->bake(lightmap); + err = lightmap->bake(lightmap, p_file, bake_func_step); } else { - err = lightmap->bake(lightmap->get_parent()); + err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step); } + bake_func_end(); + switch (err) { - case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: - EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene (for images to be saved in the same dir), or pick a save path from the BakedLightmap properties.")); - break; + case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: { + String scene_path = lightmap->get_filename(); + if (scene_path == String()) { + scene_path = lightmap->get_owner()->get_filename(); + } + if (scene_path == String()) { + EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene and try again.")); + break; + } + scene_path = scene_path.get_basename() + ".lmbake"; + + file_dialog->set_current_path(scene_path); + file_dialog->popup_file_dialog(); + + } break; case BakedLightmap::BAKE_ERROR_NO_MESHES: EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on.")); break; @@ -56,70 +69,69 @@ void BakedLightmapEditorPlugin::_bake() { } } -void BakedLightmapEditorPlugin::edit(Object *p_object) { +void BakedLightmapEditorPlugin::_bake() { + _bake_select_file(""); +} +void BakedLightmapEditorPlugin::edit(Object *p_object) { BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object); - if (!s) + if (!s) { return; + } lightmap = s; } bool BakedLightmapEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("BakedLightmap"); } void BakedLightmapEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { bake->show(); } else { - bake->hide(); } } -EditorProgress *BakedLightmapEditorPlugin::tmp_progress = NULL; - -void BakedLightmapEditorPlugin::bake_func_begin(int p_steps) { - - ERR_FAIL_COND(tmp_progress != NULL); - - tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), p_steps, true)); -} - -bool BakedLightmapEditorPlugin::bake_func_step(int p_step, const String &p_description) { +EditorProgress *BakedLightmapEditorPlugin::tmp_progress = nullptr; - ERR_FAIL_COND_V(tmp_progress == NULL, false); - return tmp_progress->step(p_description, p_step, false); +bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) { + if (!tmp_progress) { + tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false)); + ERR_FAIL_COND_V(tmp_progress == nullptr, false); + } + return tmp_progress->step(p_description, p_progress * 1000, p_refresh); } void BakedLightmapEditorPlugin::bake_func_end() { - ERR_FAIL_COND(tmp_progress == NULL); - memdelete(tmp_progress); - tmp_progress = NULL; + if (tmp_progress != nullptr) { + memdelete(tmp_progress); + tmp_progress = nullptr; + } } void BakedLightmapEditorPlugin::_bind_methods() { - ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake); } BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) { - editor = p_node; - bake = memnew(ToolButton); - bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons")); + bake = memnew(Button); + bake->set_flat(true); + bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons")); bake->set_text(TTR("Bake Lightmaps")); bake->hide(); - bake->connect("pressed", this, "_bake"); + bake->connect("pressed", Callable(this, "_bake")); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake); - lightmap = NULL; - - BakedLightmap::bake_begin_function = bake_func_begin; - BakedLightmap::bake_step_function = bake_func_step; - BakedLightmap::bake_end_function = bake_func_end; + lightmap = nullptr; + + file_dialog = memnew(EditorFileDialog); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + file_dialog->add_filter("*.lmbake ; LightMap Bake"); + file_dialog->set_title(TTR("Select lightmap bake file:")); + file_dialog->connect("file_selected", callable_mp(this, &BakedLightmapEditorPlugin::_bake_select_file)); + bake->add_child(file_dialog); } BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() { diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/baked_lightmap_editor_plugin.h index 8b94257a62..b4c7c07562 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.h +++ b/editor/plugins/baked_lightmap_editor_plugin.h @@ -37,33 +37,33 @@ #include "scene/resources/material.h" class BakedLightmapEditorPlugin : public EditorPlugin { - GDCLASS(BakedLightmapEditorPlugin, EditorPlugin); BakedLightmap *lightmap; - ToolButton *bake; + Button *bake; EditorNode *editor; + EditorFileDialog *file_dialog; static EditorProgress *tmp_progress; - static void bake_func_begin(int p_steps); - static bool bake_func_step(int p_step, const String &p_description); + static bool bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh); static void bake_func_end(); + void _bake_select_file(const String &p_file); void _bake(); protected: static void _bind_methods(); public: - virtual String get_name() const { return "BakedLightmap"; } - 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); + virtual String get_name() const override { return "BakedLightmap"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; BakedLightmapEditorPlugin(EditorNode *p_node); ~BakedLightmapEditorPlugin(); }; -#endif // BAKED_LIGHTMAP_EDITOR_PLUGIN_H +#endif diff --git a/editor/plugins/camera_editor_plugin.cpp b/editor/plugins/camera_3d_editor_plugin.cpp index 6f5bc69bd1..48f9f208a5 100644 --- a/editor/plugins/camera_editor_plugin.cpp +++ b/editor/plugins/camera_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_editor_plugin.cpp */ +/* camera_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,48 +28,42 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "camera_editor_plugin.h" +#include "camera_3d_editor_plugin.h" -#include "spatial_editor_plugin.h" - -void CameraEditor::_node_removed(Node *p_node) { +#include "node_3d_editor_plugin.h" +void Camera3DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; - SpatialEditor::get_singleton()->set_custom_camera(NULL); + node = nullptr; + Node3DEditor::get_singleton()->set_custom_camera(nullptr); hide(); } } -void CameraEditor::_pressed() { - - Node *sn = (node && preview->is_pressed()) ? node : NULL; - SpatialEditor::get_singleton()->set_custom_camera(sn); +void Camera3DEditor::_pressed() { + Node *sn = (node && preview->is_pressed()) ? node : nullptr; + Node3DEditor::get_singleton()->set_custom_camera(sn); } -void CameraEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_pressed"), &CameraEditor::_pressed); +void Camera3DEditor::_bind_methods() { } -void CameraEditor::edit(Node *p_camera) { - +void Camera3DEditor::edit(Node *p_camera) { node = p_camera; if (!node) { preview->set_pressed(false); - SpatialEditor::get_singleton()->set_custom_camera(NULL); + Node3DEditor::get_singleton()->set_custom_camera(nullptr); } else { - - if (preview->is_pressed()) - SpatialEditor::get_singleton()->set_custom_camera(p_camera); - else - SpatialEditor::get_singleton()->set_custom_camera(NULL); + if (preview->is_pressed()) { + Node3DEditor::get_singleton()->set_custom_camera(p_camera); + } else { + Node3DEditor::get_singleton()->set_custom_camera(nullptr); + } } } -CameraEditor::CameraEditor() { - +Camera3DEditor::Camera3DEditor() { preview = memnew(Button); add_child(preview); @@ -81,31 +75,27 @@ CameraEditor::CameraEditor() { preview->set_margin(MARGIN_RIGHT, 0); preview->set_margin(MARGIN_TOP, 0); preview->set_margin(MARGIN_BOTTOM, 10); - preview->connect("pressed", this, "_pressed"); + preview->connect("pressed", callable_mp(this, &Camera3DEditor::_pressed)); } -void CameraEditorPlugin::edit(Object *p_object) { - - SpatialEditor::get_singleton()->set_can_preview(Object::cast_to<Camera>(p_object)); +void Camera3DEditorPlugin::edit(Object *p_object) { + Node3DEditor::get_singleton()->set_can_preview(Object::cast_to<Camera3D>(p_object)); //camera_editor->edit(Object::cast_to<Node>(p_object)); } -bool CameraEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Camera"); +bool Camera3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Camera3D"); } -void CameraEditorPlugin::make_visible(bool p_visible) { - +void Camera3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - //SpatialEditor::get_singleton()->set_can_preview(Object::cast_to<Camera>(p_object)); + //Node3DEditor::get_singleton()->set_can_preview(Object::cast_to<Camera3D>(p_object)); } else { - SpatialEditor::get_singleton()->set_can_preview(NULL); + Node3DEditor::get_singleton()->set_can_preview(nullptr); } } -CameraEditorPlugin::CameraEditorPlugin(EditorNode *p_node) { - +Camera3DEditorPlugin::Camera3DEditorPlugin(EditorNode *p_node) { editor = p_node; /* camera_editor = memnew( CameraEditor ); editor->get_viewport()->add_child(camera_editor); @@ -122,5 +112,5 @@ CameraEditorPlugin::CameraEditorPlugin(EditorNode *p_node) { */ } -CameraEditorPlugin::~CameraEditorPlugin() { +Camera3DEditorPlugin::~Camera3DEditorPlugin() { } diff --git a/editor/plugins/camera_editor_plugin.h b/editor/plugins/camera_3d_editor_plugin.h index 9758a1ffbd..023f1866df 100644 --- a/editor/plugins/camera_editor_plugin.h +++ b/editor/plugins/camera_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_editor_plugin.h */ +/* camera_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,11 +33,10 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/camera.h" +#include "scene/3d/camera_3d.h" -class CameraEditor : public Control { - - GDCLASS(CameraEditor, Control); +class Camera3DEditor : public Control { + GDCLASS(Camera3DEditor, Control); Panel *panel; Button *preview; @@ -51,25 +50,24 @@ protected: public: void edit(Node *p_camera); - CameraEditor(); + Camera3DEditor(); }; -class CameraEditorPlugin : public EditorPlugin { - - GDCLASS(CameraEditorPlugin, EditorPlugin); +class Camera3DEditorPlugin : public EditorPlugin { + GDCLASS(Camera3DEditorPlugin, EditorPlugin); //CameraEditor *camera_editor; EditorNode *editor; public: - virtual String get_name() const { return "Camera"; } - 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); + virtual String get_name() const override { return "Camera3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; - CameraEditorPlugin(EditorNode *p_node); - ~CameraEditorPlugin(); + Camera3DEditorPlugin(EditorNode *p_node); + ~Camera3DEditorPlugin(); }; #endif // CAMERA_EDITOR_PLUGIN_H diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1d8f3a2bbd..9427f82f9e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -30,37 +30,40 @@ #include "canvas_item_editor_plugin.h" -#include "core/os/input.h" +#include "core/input/input.h" +#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" #include "core/print_string.h" #include "core/project_settings.h" +#include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" -#include "editor/script_editor_debugger.h" +#include "scene/2d/gpu_particles_2d.h" #include "scene/2d/light_2d.h" -#include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/2d/skeleton_2d.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" #include "scene/2d/touch_screen_button.h" #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" -#include "scene/gui/viewport_container.h" +#include "scene/gui/subviewport_container.h" #include "scene/main/canvas_layer.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/packed_scene.h" -#define MIN_ZOOM 0.01 -#define MAX_ZOOM 100 +// Min and Max are power of two in order to play nicely with successive increment. +// That way, we can naturally reach a 100% zoom from boundaries. +#define MIN_ZOOM 1. / 128 +#define MAX_ZOOM 128 #define RULER_WIDTH (15 * EDSCALE) #define SCALE_HANDLE_DISTANCE 25 +#define MOVE_HANDLE_DISTANCE 25 class SnapDialog : public ConfirmationDialog { - GDCLASS(SnapDialog, ConfirmationDialog); friend class CanvasItemEditor; @@ -86,7 +89,6 @@ public: GridContainer *child_container; set_title(TTR("Configure Snap")); - get_ok()->set_text(TTR("Close")); container = memnew(VBoxContainer); add_child(container); @@ -98,7 +100,7 @@ public: label = memnew(Label); label->set_text(TTR("Grid Offset:")); child_container->add_child(label); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); grid_offset_x = memnew(SpinBox); grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE); @@ -106,7 +108,7 @@ public: grid_offset_x->set_allow_lesser(true); grid_offset_x->set_allow_greater(true); grid_offset_x->set_suffix("px"); - grid_offset_x->set_h_size_flags(SIZE_EXPAND_FILL); + grid_offset_x->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(grid_offset_x); grid_offset_y = memnew(SpinBox); @@ -115,20 +117,20 @@ public: grid_offset_y->set_allow_lesser(true); grid_offset_y->set_allow_greater(true); grid_offset_y->set_suffix("px"); - grid_offset_y->set_h_size_flags(SIZE_EXPAND_FILL); + grid_offset_y->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(grid_offset_y); label = memnew(Label); label->set_text(TTR("Grid Step:")); child_container->add_child(label); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); grid_step_x = memnew(SpinBox); grid_step_x->set_min(0.01); grid_step_x->set_max(SPIN_BOX_GRID_RANGE); grid_step_x->set_allow_greater(true); grid_step_x->set_suffix("px"); - grid_step_x->set_h_size_flags(SIZE_EXPAND_FILL); + grid_step_x->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(grid_step_x); grid_step_y = memnew(SpinBox); @@ -136,7 +138,7 @@ public: grid_step_y->set_max(SPIN_BOX_GRID_RANGE); grid_step_y->set_allow_greater(true); grid_step_y->set_suffix("px"); - grid_step_y->set_h_size_flags(SIZE_EXPAND_FILL); + grid_step_y->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(grid_step_y); child_container = memnew(GridContainer); @@ -145,7 +147,7 @@ public: label = memnew(Label); label->set_text(TTR("Primary Line Every:")); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(label); primary_grid_steps = memnew(SpinBox); @@ -154,7 +156,7 @@ public: primary_grid_steps->set_max(100); primary_grid_steps->set_allow_greater(true); primary_grid_steps->set_suffix(TTR("steps")); - primary_grid_steps->set_h_size_flags(SIZE_EXPAND_FILL); + primary_grid_steps->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(primary_grid_steps); container->add_child(memnew(HSeparator)); @@ -168,25 +170,25 @@ public: label = memnew(Label); label->set_text(TTR("Rotation Offset:")); child_container->add_child(label); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); rotation_offset = memnew(SpinBox); rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE); rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE); rotation_offset->set_suffix("deg"); - rotation_offset->set_h_size_flags(SIZE_EXPAND_FILL); + rotation_offset->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(rotation_offset); label = memnew(Label); label->set_text(TTR("Rotation Step:")); child_container->add_child(label); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); rotation_step = memnew(SpinBox); rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE); rotation_step->set_max(SPIN_BOX_ROTATION_RANGE); rotation_step->set_suffix("deg"); - rotation_step->set_h_size_flags(SIZE_EXPAND_FILL); + rotation_step->set_h_size_flags(Control::SIZE_EXPAND_FILL); child_container->add_child(rotation_step); container->add_child(memnew(HSeparator)); @@ -197,13 +199,13 @@ public: label = memnew(Label); label->set_text(TTR("Scale Step:")); child_container->add_child(label); - label->set_h_size_flags(SIZE_EXPAND_FILL); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); scale_step = memnew(SpinBox); scale_step->set_min(SPIN_BOX_SCALE_MIN); scale_step->set_max(SPIN_BOX_SCALE_MAX); scale_step->set_allow_greater(true); - scale_step->set_h_size_flags(SIZE_EXPAND_FILL); + scale_step->set_h_size_flags(Control::SIZE_EXPAND_FILL); scale_step->set_step(0.01f); child_container->add_child(scale_step); } @@ -251,7 +253,6 @@ void CanvasItemEditor::_snap_if_closer_float( float &r_current_snap, SnapTarget &r_current_snap_target, float p_target_value, SnapTarget p_snap_target, float p_radius) { - float radius = p_radius / zoom; float dist = Math::abs(p_value - p_target_value); if ((p_radius < 0 || dist < radius) && (r_current_snap_target == SNAP_TARGET_NONE || dist < Math::abs(r_current_snap - p_value))) { @@ -266,7 +267,6 @@ void CanvasItemEditor::_snap_if_closer_point( Point2 p_target_value, SnapTarget p_snap_target, real_t rotation, float p_radius) { - Transform2D rot_trans = Transform2D(rotation, Point2()); p_value = rot_trans.inverse().xform(p_value); p_target_value = rot_trans.inverse().xform(p_target_value); @@ -329,7 +329,6 @@ void CanvasItemEditor::_snap_other_nodes( } Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsigned int p_forced_modes, const CanvasItem *p_self_canvas_item, List<CanvasItem *> p_other_nodes_exceptions) { - snap_target[0] = SNAP_TARGET_NONE; snap_target[1] = SNAP_TARGET_NONE; @@ -461,17 +460,25 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig } float CanvasItemEditor::snap_angle(float p_target, float p_start) const { - return (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) ? Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset : p_target; + if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) { + if (snap_relative) { + return Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step); + } else { + return Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset; + } + } else { + return p_target; + } } void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { - Ref<InputEventKey> k = p_ev; - if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) + if (!is_visible_in_tree()) { return; + } - if (k->get_scancode() == KEY_CONTROL || k->get_scancode() == KEY_ALT || k->get_scancode() == KEY_SHIFT) { + if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT) { viewport->update(); } @@ -483,28 +490,29 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { } else if ((grid_snap_active || show_grid) && divide_grid_step_shortcut.is_valid() && divide_grid_step_shortcut->is_shortcut(p_ev)) { // Divide the grid size Point2 new_grid_step = grid_step * Math::pow(2.0, grid_step_multiplier - 1); - if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0) + if (new_grid_step.x >= 1.0 && new_grid_step.y >= 1.0) { grid_step_multiplier--; + } viewport->update(); } } } Object *CanvasItemEditor::_get_editor_data(Object *p_what) { - CanvasItem *ci = Object::cast_to<CanvasItem>(p_what); - if (!ci) - return NULL; + if (!ci) { + return nullptr; + } return memnew(CanvasItemEditorSelectedItem); } void CanvasItemEditor::_keying_changed() { - - if (AnimationPlayerEditor::singleton->get_track_editor()->is_visible_in_tree()) + if (AnimationPlayerEditor::singleton->get_track_editor()->is_visible_in_tree()) { animation_hb->show(); - else + } else { animation_hb->hide(); + } } Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_list) { @@ -530,10 +538,12 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li } void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, bool include_locked_nodes) { - if (!p_node) + if (!p_node) { return; - if (Object::cast_to<Viewport>(p_node)) + } + if (Object::cast_to<Viewport>(p_node)) { return; + } const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); @@ -569,10 +579,12 @@ Rect2 CanvasItemEditor::_get_encompassing_rect(const Node *p_node) { } void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { - if (!p_node) + if (!p_node) { return; - if (Object::cast_to<Viewport>(p_node)) + } + if (Object::cast_to<Viewport>(p_node)) { return; + } const real_t grab_distance = EDITOR_GET("editors/poly_editor/point_grab_radius"); CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); @@ -605,8 +617,7 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no } } -void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) { - +void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked) { Node *scene = editor->get_edited_scene(); _find_canvas_items_at_pos(p_pos, scene, r_items); @@ -620,14 +631,16 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel node = node->get_parent(); }; - // Replace the node by the group if grouped CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node); - while (node && node != scene->get_parent()) { - CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node); - if (canvas_item_tmp && node->has_meta("_edit_group_")) { - canvas_item = canvas_item_tmp; + if (!p_allow_locked) { + // Replace the node by the group if grouped + while (node && node != scene->get_parent()) { + CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node); + if (canvas_item_tmp && node->has_meta("_edit_group_")) { + canvas_item = canvas_item_tmp; + } + node = node->get_parent(); } - node = node->get_parent(); } // Check if the canvas item is already in the list (for groups or scenes) @@ -640,7 +653,7 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel } //Remove the item if invalid - if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || _is_node_locked(canvas_item)) { + if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || (!p_allow_locked && _is_node_locked(canvas_item))) { r_items.remove(i); i--; } else { @@ -656,11 +669,12 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); Vector<Vector2> bone_shape; - if (!_get_bone_shape(&bone_shape, NULL, E)) + if (!_get_bone_shape(&bone_shape, nullptr, E)) { continue; + } // Check if the point is inside the Polygon2D - if (Geometry::is_point_in_polygon(screen_pos, bone_shape)) { + if (Geometry2D::is_point_in_polygon(screen_pos, bone_shape)) { // Check if the item is already in the list bool duplicate = false; for (int i = 0; i < r_items.size(); i++) { @@ -669,8 +683,9 @@ void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResu break; } } - if (duplicate) + if (duplicate) { continue; + } // Else, add it _SelectResult res; @@ -689,21 +704,25 @@ bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> * Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from)); Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to)); - if (!from_node) + if (!from_node) { return false; - if (!from_node->is_inside_tree()) + } + if (!from_node->is_inside_tree()) { return false; //may have been removed + } - if (!to_node && bone->get().length == 0) + if (!to_node && bone->get().length == 0) { return false; + } Vector2 from = transform.xform(from_node->get_global_position()); Vector2 to; - if (to_node) + if (to_node) { to = transform.xform(to_node->get_global_position()); - else + } else { to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0))); + } Vector2 rel = to - from; Vector2 relt = rel.tangent().normalized() * bone_width; @@ -731,10 +750,12 @@ bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> * } void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { - if (!p_node) + if (!p_node) { return; - if (Object::cast_to<Viewport>(p_node)) + } + if (Object::cast_to<Viewport>(p_node)) { return; + } CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); Node *scene = editor->get_edited_scene(); @@ -767,7 +788,6 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, 0))) && p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, rect.size.y))) && p_rect.has_point(xform.xform(rect.position + Vector2(0, rect.size.y)))) { - r_items->push_back(canvas_item); } } else { @@ -850,10 +870,12 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 } void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) { - if (p_bones_length) + if (p_bones_length) { *p_bones_length = List<float>(); - if (p_bones_state) + } + if (p_bones_state) { *p_bones_state = List<Dictionary>(); + } const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item); if (bone && bone->has_meta("_edit_bone_")) { @@ -879,10 +901,12 @@ void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_ite for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) { bone_xform = bone_xform * bone->get_transform().affine_inverse(); const Node2D *parent_bone = bone_E->get(); - if (p_bones_length) + if (p_bones_length) { p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position())); - if (p_bones_state) + } + if (p_bones_state) { p_bones_state->push_back(parent_bone->_edit_get_state()); + } bone = parent_bone; } } @@ -954,18 +978,18 @@ void CanvasItemEditor::_snap_changed() { } void CanvasItemEditor::_selection_result_pressed(int p_result) { - - if (selection_results.size() <= p_result) + if (selection_results.size() <= p_result) { return; + } CanvasItem *item = selection_results[p_result].item; - if (item) + if (item) { _select_click_on_item(item, Point2(), selection_menu_additive_selection); + } } void CanvasItemEditor::_selection_menu_hide() { - selection_results.clear(); selection_menu->clear(); selection_menu->set_size(Vector2(0, 0)); @@ -1016,7 +1040,6 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve // Start dragging a guide if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) { - // Press button if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) { // Drag a new double guide @@ -1184,7 +1207,26 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bool p_already_accepted) { Ref<InputEventMouseButton> b = p_event; if (b.is_valid() && !p_already_accepted) { - bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control(); + const bool pan_on_scroll = bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan")) && !b->get_control(); + + if (pan_on_scroll) { + // Perform horizontal scrolling first so we can check for Shift being held. + if (b->is_pressed() && + (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_UP))) { + // Pan left + view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); + update_viewport(); + return true; + } + + if (b->is_pressed() && + (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_DOWN))) { + // Pan right + view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); + update_viewport(); + return true; + } + } if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) { // Scroll or pan down @@ -1192,7 +1234,11 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); } else { - _zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position()); + float new_zoom = _get_next_zoom_value(-1); + if (b->get_factor() != 1.f) { + new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f); + } + _zoom_on_position(new_zoom, b->get_position()); } return true; } @@ -1203,29 +1249,15 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); update_viewport(); } else { - _zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position()); + float new_zoom = _get_next_zoom_value(1); + if (b->get_factor() != 1.f) { + new_zoom = zoom * ((new_zoom / zoom - 1.f) * b->get_factor() + 1.f); + } + _zoom_on_position(new_zoom, b->get_position()); } return true; } - if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_LEFT) { - // Pan left - if (pan_on_scroll) { - view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); - update_viewport(); - return true; - } - } - - if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_RIGHT) { - // Pan right - if (pan_on_scroll) { - view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor(); - update_viewport(); - return true; - } - } - if (!panning) { if (b->is_pressed() && (b->get_button_index() == BUTTON_MIDDLE || @@ -1263,8 +1295,9 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo } } - if (is_pan_key) + if (is_pan_key) { pan_pressed = k->is_pressed(); + } } Ref<InputEventMouseMotion> m = p_event; @@ -1293,6 +1326,18 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid() && !p_already_accepted) { + // If control key pressed, then zoom instead of pan + if (pan_gesture->get_control()) { + const float factor = pan_gesture->get_delta().y; + float new_zoom = _get_next_zoom_value(-1); + + if (factor != 1.f) { + new_zoom = zoom * ((new_zoom / zoom - 1.f) * factor + 1.f); + } + _zoom_on_position(new_zoom, pan_gesture->get_position()); + return true; + } + // Pan gesture const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta(); view_offset.x += delta.x; @@ -1312,7 +1357,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { // Drag the pivot (in pivot mode / with V key) if (drag_type == DRAG_NONE) { if ((b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) || - (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_scancode() == KEY_V)) { + (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V)) { List<CanvasItem *> selection = _get_edited_canvas_items(); // Filters the selection with nodes that allow setting the pivot @@ -1332,7 +1377,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { if (drag_selection.size() == 1) { new_pos = snap_point(drag_from, SNAP_NODE_SIDES | SNAP_NODE_CENTER | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, drag_selection[0]); } else { - new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, NULL, drag_selection); + new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, nullptr, drag_selection); } for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); @@ -1351,10 +1396,11 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { drag_to = transform.affine_inverse().xform(m->get_position()); _restore_canvas_item_state(drag_selection); Vector2 new_pos; - if (drag_selection.size() == 1) + if (drag_selection.size() == 1) { new_pos = snap_point(drag_to, SNAP_NODE_SIDES | SNAP_NODE_CENTER | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, drag_selection[0]); - else + } else { new_pos = snap_point(drag_to, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL); + } for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); canvas_item->_edit_set_pivot(canvas_item->get_global_transform_with_canvas().affine_inverse().xform(new_pos)); @@ -1364,7 +1410,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { // Confirm the pivot move if ((b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) || - (k.is_valid() && !k->is_pressed() && k->get_scancode() == KEY_V)) { + (k.is_valid() && !k->is_pressed() && k->get_keycode() == KEY_V)) { _commit_canvas_item_state(drag_selection, TTR("Move pivot")); drag_type = DRAG_NONE; return true; @@ -1386,7 +1432,6 @@ void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) { if (se) { int nb_bones = se->pre_drag_bones_undo_state.size(); if (nb_bones > 0) { - // Build the node list Point2 leaf_pos = target_position; @@ -1426,13 +1471,13 @@ void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) { Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized(); int len = E->get(); if (E == se->pre_drag_bones_length.front()) { - joints_pos[1] = joints_pos[1].linear_interpolate(joints_pos[0] + len * direction, solver_k); + joints_pos[1] = joints_pos[1].lerp(joints_pos[0] + len * direction, solver_k); } else if (E == se->pre_drag_bones_length.back()) { - joints_pos[node_id] = joints_pos[node_id].linear_interpolate(joints_pos[node_id + 1] - len * direction, solver_k); + joints_pos[node_id] = joints_pos[node_id].lerp(joints_pos[node_id + 1] - len * direction, solver_k); } else { Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0; - joints_pos[node_id] = joints_pos[node_id].linear_interpolate(center - (direction * len) / 2.0, solver_k); - joints_pos[node_id + 1] = joints_pos[node_id + 1].linear_interpolate(center + (direction * len) / 2.0, solver_k); + joints_pos[node_id] = joints_pos[node_id].lerp(center - (direction * len) / 2.0, solver_k); + joints_pos[node_id + 1] = joints_pos[node_id + 1].lerp(center + (direction * len) / 2.0, solver_k); } node_id++; } @@ -1464,8 +1509,9 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { // Remove not movable nodes for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { - if (!_is_node_movable(E->get(), true)) + if (!_is_node_movable(E->get(), true)) { selection.erase(E); + } } drag_selection = selection; @@ -1613,20 +1659,36 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) { switch (drag_type) { case DRAG_ANCHOR_TOP_LEFT: - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + if (!use_single_axis || !use_y) { + control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); + } + if (!use_single_axis || use_y) { + control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + } break; case DRAG_ANCHOR_TOP_RIGHT: - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + if (!use_single_axis || !use_y) { + control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); + } + if (!use_single_axis || use_y) { + control->set_anchor(MARGIN_TOP, new_anchor.y, false, false); + } break; case DRAG_ANCHOR_BOTTOM_RIGHT: - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + if (!use_single_axis || !use_y) { + control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false); + } + if (!use_single_axis || use_y) { + control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + } break; case DRAG_ANCHOR_BOTTOM_LEFT: - if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); - if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + if (!use_single_axis || !use_y) { + control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false); + } + if (!use_single_axis || use_y) { + control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false); + } break; case DRAG_ANCHOR_ALL: if (!use_single_axis || !use_y) { @@ -1704,13 +1766,15 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized(); ofs *= (select_handle->get_size().width / 2); ofs += endpoints[i]; - if (ofs.distance_to(b->get_position()) < radius) + if (ofs.distance_to(b->get_position()) < radius) { resize_drag = dragger[i * 2]; + } ofs = (endpoints[i] + endpoints[next]) / 2; ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2); - if (ofs.distance_to(b->get_position()) < radius) + if (ofs.distance_to(b->get_position()) < radius) { resize_drag = dragger[i * 2 + 1]; + } } if (resize_drag != DRAG_NONE) { @@ -1847,7 +1911,6 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { } bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> b = p_event; Ref<InputEventMouseMotion> m = p_event; @@ -1859,21 +1922,22 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { CanvasItem *canvas_item = selection[0]; if (_is_node_movable(canvas_item)) { - Transform2D xform = transform * canvas_item->get_global_transform_with_canvas(); Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; drag_type = DRAG_SCALE_BOTH; - Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); - Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { - drag_type = DRAG_SCALE_X; - } - Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { - drag_type = DRAG_SCALE_Y; + if (show_transformation_gizmos) { + Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); + Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_SCALE_X; + } + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_SCALE_Y; + } } drag_from = transform.affine_inverse().xform(b->get_position()); @@ -1906,6 +1970,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Point2 offset = drag_to_local - drag_from_local; Size2 scale = canvas_item->call("get_scale"); + Size2 original_scale = scale; float ratio = scale.y / scale.x; if (drag_type == DRAG_SCALE_BOTH) { Size2 scale_factor = drag_to_local / drag_from_local; @@ -1918,13 +1983,14 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE; Size2 parent_scale = parent_xform.get_scale(); scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y); + if (drag_type == DRAG_SCALE_X) { scale.x += scale_factor.x; if (uniform) { scale.y = scale.x * ratio; } } else if (drag_type == DRAG_SCALE_Y) { - scale.y += scale_factor.y; + scale.y -= scale_factor.y; if (uniform) { scale.x = scale.y / ratio; } @@ -1932,8 +1998,13 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { } if (snap_scale && !is_ctrl) { - scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step; - scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step; + if (snap_relative) { + scale.x = original_scale.x * (roundf((scale.x / original_scale.x) / snap_scale_step) * snap_scale_step); + scale.y = original_scale.y * (roundf((scale.y / original_scale.y) / snap_scale_step) * snap_scale_step); + } else { + scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step; + scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step; + } } canvas_item->call("set_scale", scale); @@ -1974,17 +2045,34 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) { List<CanvasItem *> selection = _get_edited_canvas_items(); - // Remove not movable nodes + drag_selection.clear(); for (int i = 0; i < selection.size(); i++) { - if (!_is_node_movable(selection[i], true)) { - selection.erase(selection[i]); + if (_is_node_movable(selection[i], true)) { + drag_selection.push_back(selection[i]); } } if (selection.size() > 0) { drag_type = DRAG_MOVE; + + CanvasItem *canvas_item = selection[0]; + Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse(); + Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized(); + Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + + if (show_transformation_gizmos) { + Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE); + Rect2 x_handle_rect = Rect2(move_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_MOVE_X; + } + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, move_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_MOVE_Y; + } + } + drag_from = transform.affine_inverse().xform(b->get_position()); - drag_selection = selection; _save_canvas_item_state(drag_selection); } return true; @@ -1992,15 +2080,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } } - if (drag_type == DRAG_MOVE) { + if (drag_type == DRAG_MOVE || drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) { // Move the nodes if (m.is_valid()) { - // Save the ik chain for reapplying before IK solve - Vector<List<Dictionary> > all_bones_ik_states; + Vector<List<Dictionary>> all_bones_ik_states; for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { List<Dictionary> bones_ik_states; - _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states); + _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states); all_bones_ik_states.push_back(bones_ik_states); } @@ -2014,7 +2101,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } else { previous_pos = _get_encompassing_rect_from_list(drag_selection).position; } - Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, NULL, drag_selection); + + Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection); + + if (drag_type == DRAG_MOVE_X) { + new_pos.y = previous_pos.y; + } else if (drag_type == DRAG_MOVE_Y) { + new_pos.x = previous_pos.x; + } + bool single_axis = m->get_shift(); if (single_axis) { if (ABS(new_pos.x - previous_pos.x) > ABS(new_pos.y - previous_pos.y)) { @@ -2077,8 +2172,8 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } // Move the canvas items with the arrow keys - if (k.is_valid() && k->is_pressed() && tool == TOOL_SELECT && - (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)) { + if (k.is_valid() && k->is_pressed() && (tool == TOOL_SELECT || tool == TOOL_MOVE) && + (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) { if (!k->is_echo()) { // Start moving the canvas items with the keyboard drag_selection = _get_edited_canvas_items(); @@ -2089,12 +2184,11 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } if (drag_selection.size() > 0) { - // Save the ik chain for reapplying before IK solve - Vector<List<Dictionary> > all_bones_ik_states; + Vector<List<Dictionary>> all_bones_ik_states; for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { List<Dictionary> bones_ik_states; - _save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states); + _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states); all_bones_ik_states.push_back(bones_ik_states); } @@ -2104,20 +2198,23 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { bool move_local_base_rotated = k->get_control() || k->get_metakey(); Vector2 dir; - if (k->get_scancode() == KEY_UP) + if (k->get_keycode() == KEY_UP) { dir += Vector2(0, -1); - else if (k->get_scancode() == KEY_DOWN) + } else if (k->get_keycode() == KEY_DOWN) { dir += Vector2(0, 1); - else if (k->get_scancode() == KEY_LEFT) + } else if (k->get_keycode() == KEY_LEFT) { dir += Vector2(-1, 0); - else if (k->get_scancode() == KEY_RIGHT) + } else if (k->get_keycode() == KEY_RIGHT) { dir += Vector2(1, 0); - if (k->get_shift()) + } + if (k->get_shift()) { dir *= grid_step * Math::pow(2.0, grid_step_multiplier); + } drag_to += dir; - if (k->get_shift()) + if (k->get_shift()) { drag_to = drag_to.snapped(grid_step * Math::pow(2.0, grid_step_multiplier)); + } Point2 previous_pos; if (drag_selection.size() == 1) { @@ -2165,8 +2262,8 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { return true; } - if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && tool == TOOL_SELECT && - (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)) { + if (k.is_valid() && !k->is_pressed() && drag_type == DRAG_KEY_MOVE && (tool == TOOL_SELECT || tool == TOOL_MOVE) && + (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)) { // Confirm canvas items move by arrow keys if ((!Input::get_singleton()->is_key_pressed(KEY_UP)) && (!Input::get_singleton()->is_key_pressed(KEY_DOWN)) && @@ -2179,7 +2276,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { return true; } - return (k.is_valid() && (k->get_scancode() == KEY_UP || k->get_scancode() == KEY_DOWN || k->get_scancode() == KEY_LEFT || k->get_scancode() == KEY_RIGHT)); // Accept the key event in any case + return (k.is_valid() && (k->get_keycode() == KEY_UP || k->get_keycode() == KEY_DOWN || k->get_keycode() == KEY_LEFT || k->get_keycode() == KEY_RIGHT)); // Accept the key event in any case } bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { @@ -2194,7 +2291,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Popup the selection menu list Point2 click = transform.affine_inverse().xform(b->get_position()); - _get_canvas_items_at_pos(click, selection_results); + _get_canvas_items_at_pos(click, selection_results, b->get_alt() && tool != TOOL_LIST_SELECT); if (selection_results.size() == 1) { CanvasItem *item = selection_results[0].item; @@ -2213,17 +2310,39 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { for (int i = 0; i < selection_results.size(); i++) { CanvasItem *item = selection_results[i].item; - Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(item, "Node"); + Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(item, "Node"); String node_path = "/" + root_name + "/" + root_path.rel_path_to(item->get_path()); - selection_menu->add_item(item->get_name()); + int locked = 0; + if (_is_node_locked(item)) { + locked = 1; + } else { + Node *scene = editor->get_edited_scene(); + Node *node = item; + + while (node && node != scene->get_parent()) { + CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node); + if (canvas_item_tmp && node->has_meta("_edit_group_")) { + locked = 2; + } + node = node->get_parent(); + } + } + + String suffix = String(); + if (locked == 1) { + suffix = " (" + TTR("Locked") + ")"; + } else if (locked == 2) { + suffix = " (" + TTR("Grouped") + ")"; + } + selection_menu->add_item((String)item->get_name() + suffix); selection_menu->set_item_icon(i, icon); selection_menu->set_item_metadata(i, node_path); selection_menu->set_item_tooltip(i, String(item->get_name()) + "\nType: " + item->get_class() + "\nPath: " + node_path); } selection_menu_additive_selection = b->get_shift(); - selection_menu->set_global_position(b->get_global_position()); + selection_menu->set_position(get_screen_transform().xform(b->get_position())); selection_menu->popup(); return true; } @@ -2234,11 +2353,12 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { Point2 click = transform.affine_inverse().xform(b->get_position()); Node *scene = editor->get_edited_scene(); - if (!scene) + if (!scene) { return true; + } // Find the item to select - CanvasItem *canvas_item = NULL; + CanvasItem *canvas_item = nullptr; // Retrieve the bones Vector<_SelectResult> selection = Vector<_SelectResult>(); @@ -2274,16 +2394,15 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Drag the node(s) if requested List<CanvasItem *> selection2 = _get_edited_canvas_items(); - // Remove not movable nodes + drag_selection.clear(); for (int i = 0; i < selection2.size(); i++) { - if (!_is_node_movable(selection2[i], true)) { - selection2.erase(selection2[i]); + if (_is_node_movable(selection2[i], true)) { + drag_selection.push_back(selection2[i]); } } if (selection2.size() > 0) { drag_type = DRAG_MOVE; - drag_selection = selection2; drag_from = click; _save_canvas_item_state(drag_selection); } @@ -2303,10 +2422,12 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { Point2 bsfrom = drag_from; Point2 bsto = box_selecting_to; - if (bsfrom.x > bsto.x) + if (bsfrom.x > bsto.x) { SWAP(bsfrom.x, bsto.x); - if (bsfrom.y > bsto.y) + } + if (bsfrom.y > bsto.y) { SWAP(bsfrom.y, bsto.y); + } _find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems); for (List<CanvasItem *>::Element *E = selitems.front(); E; E = E->next()) { @@ -2334,7 +2455,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } } - if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) { + if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_ESCAPE && drag_type == DRAG_NONE && tool == TOOL_SELECT) { // Unselect everything editor_selection->clear(); viewport->update(); @@ -2343,16 +2464,17 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) { - - if (tool != TOOL_RULER) + if (tool != TOOL_RULER) { return false; + } Ref<InputEventMouseButton> b = p_event; Ref<InputEventMouseMotion> m = p_event; Point2 previous_origin = ruler_tool_origin; - if (!ruler_tool_active) + if (!ruler_tool_active) { ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset); + } if (b.is_valid() && b->get_button_index() == BUTTON_LEFT) { if (b->is_pressed()) { @@ -2366,7 +2488,6 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) { } if (m.is_valid() && (ruler_tool_active || (grid_snap_active && previous_origin != ruler_tool_origin))) { - viewport->update(); return true; } @@ -2375,7 +2496,6 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) { } bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { Point2 click = transform.affine_inverse().xform(m->get_position()); @@ -2390,8 +2510,9 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) { for (int i = 0; i < hovering_results_items.size(); i++) { CanvasItem *canvas_item = hovering_results_items[i].item; - if (canvas_item->_edit_use_rect()) + if (canvas_item->_edit_use_rect()) { continue; + } _HoverResult hover_result; hover_result.position = canvas_item->get_global_transform_with_canvas().get_origin(); @@ -2460,14 +2581,29 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { accepted = (_gui_input_zoom_or_pan(p_event, accepted) || accepted); - if (accepted) + if (accepted) { accept_event(); + } // Handles the mouse hovering _gui_input_hover(p_event); // Change the cursor + _update_cursor(); + + // Grab focus + if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { + viewport->call_deferred("grab_focus"); + } +} + +void CanvasItemEditor::_update_cursor() { CursorShape c = CURSOR_ARROW; + bool should_switch = false; + if (drag_selection.size() != 0) { + float angle = drag_selection[0]->_edit_get_rotation(); + should_switch = abs(Math::cos(angle)) < Math_SQRT12; + } switch (drag_type) { case DRAG_NONE: switch (tool) { @@ -2490,21 +2626,37 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { case DRAG_LEFT: case DRAG_RIGHT: case DRAG_V_GUIDE: - c = CURSOR_HSIZE; + if (should_switch) { + c = CURSOR_VSIZE; + } else { + c = CURSOR_HSIZE; + } break; case DRAG_TOP: case DRAG_BOTTOM: case DRAG_H_GUIDE: - c = CURSOR_VSIZE; + if (should_switch) { + c = CURSOR_HSIZE; + } else { + c = CURSOR_VSIZE; + } break; case DRAG_TOP_LEFT: case DRAG_BOTTOM_RIGHT: case DRAG_DOUBLE_GUIDE: - c = CURSOR_FDIAGSIZE; + if (should_switch) { + c = CURSOR_BDIAGSIZE; + } else { + c = CURSOR_FDIAGSIZE; + } break; case DRAG_TOP_RIGHT: case DRAG_BOTTOM_LEFT: - c = CURSOR_BDIAGSIZE; + if (should_switch) { + c = CURSOR_FDIAGSIZE; + } else { + c = CURSOR_BDIAGSIZE; + } break; case DRAG_MOVE: c = CURSOR_MOVE; @@ -2513,23 +2665,19 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { break; } - if (is_hovering_h_guide) + if (is_hovering_h_guide) { c = CURSOR_VSIZE; - else if (is_hovering_v_guide) + } else if (is_hovering_v_guide) { c = CURSOR_HSIZE; + } viewport->set_default_cursor_shape(c); - - // Grab focus - if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { - viewport->call_deferred("grab_focus"); - } } void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Margin p_side) { - Color color = get_color("font_color", "Editor"); + Color color = get_theme_color("font_color", "Editor"); color.a = 0.8; - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); Size2 text_size = font->get_string_size(p_string); switch (p_side) { case MARGIN_LEFT: @@ -2565,12 +2713,11 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi void CanvasItemEditor::_draw_focus() { // Draw the focus around the base viewport if (viewport->has_focus()) { - get_stylebox("Focus", "EditorStyles")->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size())); + get_theme_stylebox("Focus", "EditorStyles")->draw(viewport->get_canvas_item(), Rect2(Point2(), viewport->get_size())); } } void CanvasItemEditor::_draw_guides() { - Color guide_color = EditorSettings::get_singleton()->get("editors/2d/guides_color"); Transform2D xform = viewport_scrollable->get_transform() * transform; @@ -2578,8 +2725,9 @@ void CanvasItemEditor::_draw_guides() { if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); for (int i = 0; i < vguides.size(); i++) { - if (drag_type == DRAG_V_GUIDE && i == dragged_guide_index) + if (drag_type == DRAG_V_GUIDE && i == dragged_guide_index) { continue; + } float x = xform.xform(Point2(vguides[i], 0)).x; viewport->draw_line(Point2(x, 0), Point2(x, viewport->get_size().y), guide_color, Math::round(EDSCALE)); } @@ -2588,26 +2736,27 @@ void CanvasItemEditor::_draw_guides() { if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); for (int i = 0; i < hguides.size(); i++) { - if (drag_type == DRAG_H_GUIDE && i == dragged_guide_index) + if (drag_type == DRAG_H_GUIDE && i == dragged_guide_index) { continue; + } float y = xform.xform(Point2(0, hguides[i])).y; viewport->draw_line(Point2(0, y), Point2(viewport->get_size().x, y), guide_color, Math::round(EDSCALE)); } } // Dragged guide - Color text_color = get_color("font_color", "Editor"); + Color text_color = get_theme_color("font_color", "Editor"); text_color.a = 0.5; if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_V_GUIDE) { String str = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).x)); - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); Size2 text_size = font->get_string_size(str); viewport->draw_string(font, Point2(dragged_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, text_color); viewport->draw_line(Point2(dragged_guide_pos.x, 0), Point2(dragged_guide_pos.x, viewport->get_size().y), guide_color, Math::round(EDSCALE)); } if (drag_type == DRAG_DOUBLE_GUIDE || drag_type == DRAG_H_GUIDE) { String str = vformat("%d px", Math::round(xform.affine_inverse().xform(dragged_guide_pos).y)); - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); Size2 text_size = font->get_string_size(str); viewport->draw_string(font, Point2(RULER_WIDTH + 10, dragged_guide_pos.y + text_size.y / 2 + 10), str, text_color); viewport->draw_line(Point2(0, dragged_guide_pos.y), Point2(viewport->get_size().x, dragged_guide_pos.y), guide_color, Math::round(EDSCALE)); @@ -2629,11 +2778,11 @@ void CanvasItemEditor::_draw_smart_snapping() { } void CanvasItemEditor::_draw_rulers() { - Color bg_color = get_color("dark_color_2", "Editor"); - Color graduation_color = get_color("font_color", "Editor").linear_interpolate(bg_color, 0.5); - Color font_color = get_color("font_color", "Editor"); + Color bg_color = get_theme_color("dark_color_2", "Editor"); + Color graduation_color = get_theme_color("font_color", "Editor").lerp(bg_color, 0.5); + Color font_color = get_theme_color("font_color", "Editor"); font_color.a = 0.8; - Ref<Font> font = get_font("rulers", "EditorFonts"); + Ref<Font> font = get_theme_font("rulers", "EditorFonts"); // The rule transform Transform2D ruler_transform = Transform2D(); @@ -2717,7 +2866,6 @@ void CanvasItemEditor::_draw_rulers() { } void CanvasItemEditor::_draw_grid() { - if (show_grid || grid_snap_active) { // Draw the grid Vector2 real_grid_offset; @@ -2790,12 +2938,12 @@ void CanvasItemEditor::_draw_grid() { } void CanvasItemEditor::_draw_ruler_tool() { - - if (tool != TOOL_RULER) + if (tool != TOOL_RULER) { return; + } if (ruler_tool_active) { - Color ruler_primary_color = get_color("accent_color", "Editor"); + Color ruler_primary_color = get_theme_color("accent_color", "Editor"); Color ruler_secondary_color = ruler_primary_color; ruler_secondary_color.a = 0.5; @@ -2806,14 +2954,14 @@ void CanvasItemEditor::_draw_ruler_tool() { bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x)); - viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3), true); + viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3)); if (draw_secondary_lines) { viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE)); viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE)); } - Ref<Font> font = get_font("bold", "EditorFonts"); - Color font_color = get_color("font_color", "Editor"); + Ref<Font> font = get_theme_font("bold", "EditorFonts"); + Color font_color = get_theme_color("font_color", "Editor"); Color font_secondary_color = font_color; font_secondary_color.a = 0.5; float text_height = font->get_height(); @@ -2891,7 +3039,6 @@ void CanvasItemEditor::_draw_ruler_tool() { } if (grid_snap_active) { - text_pos = (begin + end) / 2 + Vector2(-text_width / 2, text_height / 2); text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5); text_pos.y = CLAMP(text_pos.y, text_height * 2.5, viewport->get_rect().size.y - text_height / 2); @@ -2911,10 +3058,9 @@ void CanvasItemEditor::_draw_ruler_tool() { } } } else { - if (grid_snap_active) { - Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons"); - viewport->draw_texture(get_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); + Ref<Texture2D> position_icon = get_theme_icon("EditorPosition", "EditorIcons"); + viewport->draw_texture(get_theme_icon("EditorPosition", "EditorIcons"), (ruler_tool_origin - view_offset) * zoom - position_icon->get_size() / 2); } } } @@ -2923,7 +3069,6 @@ void CanvasItemEditor::_draw_control_anchors(Control *control) { Transform2D xform = transform * control->get_global_transform_with_canvas(); RID ci = viewport->get_canvas_item(); if (tool == TOOL_SELECT && !Object::cast_to<Container>(control->get_parent())) { - // Compute the anchors float anchors_values[4]; anchors_values[0] = control->get_anchor(MARGIN_LEFT); @@ -3004,8 +3149,8 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { Vector2 line_ends[4]; for (int i = 0; i < 4; i++) { float anchor_val = (i >= 2) ? ANCHOR_END - anchors_values[i] : anchors_values[i]; - line_starts[i] = Vector2::linear_interpolate(corners_pos[i], corners_pos[(i + 1) % 4], anchor_val); - line_ends[i] = Vector2::linear_interpolate(corners_pos[(i + 3) % 4], corners_pos[(i + 2) % 4], anchor_val); + line_starts[i] = corners_pos[i].lerp(corners_pos[(i + 1) % 4], anchor_val); + line_ends[i] = corners_pos[(i + 3) % 4].lerp(corners_pos[(i + 2) % 4], anchor_val); anchor_snapped = anchors_values[i] == 0.0 || anchors_values[i] == 0.5 || anchors_values[i] == 1.0; viewport->draw_line(line_starts[i], line_ends[i], anchor_snapped ? color_snapped : color_base, (i == dragged_anchor || (i + 3) % 4 == dragged_anchor) ? 2 : 1); } @@ -3047,7 +3192,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; + [[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); @@ -3062,7 +3207,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; + [[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); @@ -3077,7 +3222,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; + [[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)); @@ -3092,7 +3237,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; + [[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)); @@ -3126,19 +3271,21 @@ void CanvasItemEditor::_draw_control_helpers(Control *control) { } void CanvasItemEditor::_draw_selection() { - Ref<Texture> pivot_icon = get_icon("EditorPivot", "EditorIcons"); - Ref<Texture> position_icon = get_icon("EditorPosition", "EditorIcons"); - Ref<Texture> previous_position_icon = get_icon("EditorPositionPrevious", "EditorIcons"); + Ref<Texture2D> pivot_icon = get_theme_icon("EditorPivot", "EditorIcons"); + Ref<Texture2D> position_icon = get_theme_icon("EditorPosition", "EditorIcons"); + Ref<Texture2D> previous_position_icon = get_theme_icon("EditorPositionPrevious", "EditorIcons"); RID ci = viewport->get_canvas_item(); - List<CanvasItem *> selection = _get_edited_canvas_items(false, false); + List<CanvasItem *> selection = _get_edited_canvas_items(true, false); bool single = selection.size() == 1; for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); + bool item_locked = canvas_item->has_meta("_edit_lock_"); + // Draw the previous position if we are dragging the node if (show_helpers && (drag_type == DRAG_MOVE || drag_type == DRAG_ROTATE || @@ -3157,7 +3304,7 @@ void CanvasItemEditor::_draw_selection() { }; for (int i = 0; i < 4; i++) { - viewport->draw_line(pre_drag_endpoints[i], pre_drag_endpoints[(i + 1) % 4], pre_drag_color, Math::round(2 * EDSCALE), true); + viewport->draw_line(pre_drag_endpoints[i], pre_drag_endpoints[(i + 1) % 4], pre_drag_color, Math::round(2 * EDSCALE)); } } else { viewport->draw_texture(previous_position_icon, (pre_drag_xform.xform(Point2()) - (previous_position_icon->get_size() / 2)).floor()); @@ -3178,11 +3325,14 @@ void CanvasItemEditor::_draw_selection() { Color c = Color(1, 0.6, 0.4, 0.7); + if (item_locked) { + c = Color(0.7, 0.7, 0.7, 0.7); + } + for (int i = 0; i < 4; i++) { - viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, Math::round(2 * EDSCALE), true); + viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, Math::round(2 * EDSCALE)); } } else { - Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; viewport->draw_set_transform_matrix(simple_xform); @@ -3190,10 +3340,9 @@ void CanvasItemEditor::_draw_selection() { viewport->draw_set_transform_matrix(viewport->get_transform()); } - if (single && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks + if (single && !item_locked && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks // Draw the pivot if (canvas_item->_edit_use_pivot()) { - // Draw the node's pivot Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; @@ -3235,10 +3384,39 @@ void CanvasItemEditor::_draw_selection() { } } - // Draw the rescale handles + // Draw the move handles bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); - if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { + if (tool == TOOL_MOVE && show_transformation_gizmos) { + if (_is_node_movable(canvas_item)) { + Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); + Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + + Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE); + viewport->draw_set_transform_matrix(simple_xform); + + Vector<Point2> points; + points.push_back(Vector2(move_factor.x * EDSCALE, 5 * EDSCALE)); + points.push_back(Vector2(move_factor.x * EDSCALE, -5 * EDSCALE)); + points.push_back(Vector2((move_factor.x + 10) * EDSCALE, 0)); + + viewport->draw_colored_polygon(points, get_theme_color("axis_x_color", "Editor")); + viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_theme_color("axis_x_color", "Editor"), Math::round(EDSCALE)); + + points.clear(); + points.push_back(Vector2(5 * EDSCALE, move_factor.y * EDSCALE)); + points.push_back(Vector2(-5 * EDSCALE, move_factor.y * EDSCALE)); + points.push_back(Vector2(0, (move_factor.y + 10) * EDSCALE)); + + viewport->draw_colored_polygon(points, get_theme_color("axis_y_color", "Editor")); + viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_theme_color("axis_y_color", "Editor"), Math::round(EDSCALE)); + + viewport->draw_set_transform_matrix(viewport->get_transform()); + } + } + + // Draw the rescale handles + if (show_transformation_gizmos && ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y)) { if (_is_node_movable(canvas_item)) { Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; @@ -3253,20 +3431,20 @@ void CanvasItemEditor::_draw_selection() { scale_factor.y += offset.x; } } else if (drag_type == DRAG_SCALE_Y) { - scale_factor.y -= offset.y; + scale_factor.y += offset.y; if (uniform) { - scale_factor.x -= offset.y; + scale_factor.x += offset.y; } } viewport->draw_set_transform_matrix(simple_xform); Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - viewport->draw_rect(x_handle_rect, get_color("axis_x_color", "Editor")); - viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE), true); + viewport->draw_rect(x_handle_rect, get_theme_color("axis_x_color", "Editor")); + viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_theme_color("axis_x_color", "Editor"), Math::round(EDSCALE)); - Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - viewport->draw_rect(y_handle_rect, get_color("axis_y_color", "Editor")); - viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE), true); + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + viewport->draw_rect(y_handle_rect, get_theme_color("axis_y_color", "Editor")); + viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_theme_color("axis_y_color", "Editor"), Math::round(EDSCALE)); viewport->draw_set_transform_matrix(viewport->get_transform()); } @@ -3281,11 +3459,11 @@ void CanvasItemEditor::_draw_selection() { viewport->draw_rect( Rect2(bsfrom, bsto - bsfrom), - get_color("box_selection_fill_color", "Editor")); + get_theme_color("box_selection_fill_color", "Editor")); viewport->draw_rect( Rect2(bsfrom, bsto - bsfrom), - get_color("box_selection_stroke_color", "Editor"), + get_theme_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE)); } @@ -3295,9 +3473,8 @@ void CanvasItemEditor::_draw_selection() { 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); + get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.6), + Math::round(2 * EDSCALE)); } } @@ -3338,20 +3515,17 @@ void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_c } } if (points.size() >= 2) { - VisualServer::get_singleton()->canvas_item_add_line(ci, points[0], points[1], p_color); + RenderingServer::get_singleton()->canvas_item_add_line(ci, points[0], points[1], p_color); } } void CanvasItemEditor::_draw_axis() { - if (show_origin) { - - _draw_straight_line(Point2(), Point2(1, 0), get_color("axis_x_color", "Editor") * Color(1, 1, 1, 0.75)); - _draw_straight_line(Point2(), Point2(0, 1), get_color("axis_y_color", "Editor") * Color(1, 1, 1, 0.75)); + _draw_straight_line(Point2(), Point2(1, 0), get_theme_color("axis_x_color", "Editor") * Color(1, 1, 1, 0.75)); + _draw_straight_line(Point2(), Point2(0, 1), get_theme_color("axis_y_color", "Editor") * Color(1, 1, 1, 0.75)); } if (show_viewport) { - RID ci = viewport->get_canvas_item(); Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color"); @@ -3366,7 +3540,7 @@ void CanvasItemEditor::_draw_axis() { }; for (int i = 0; i < 4; i++) { - VisualServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color); + RenderingServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color); } } } @@ -3382,15 +3556,16 @@ void CanvasItemEditor::_draw_bones() { Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Vector<Vector2> bone_shape; Vector<Vector2> bone_shape_outline; - if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) + if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) { continue; + } Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); - if (!from_node->is_visible_in_tree()) + if (!from_node->is_visible_in_tree()) { continue; + } Vector<Color> colors; if (from_node->has_meta("_edit_ik_")) { @@ -3423,8 +3598,8 @@ void CanvasItemEditor::_draw_bones() { outline_colors.push_back(bone_outline_color); } - VisualServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors); - VisualServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID()); + RenderingServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID()); } } } @@ -3433,11 +3608,13 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans ERR_FAIL_COND(!p_node); Node *scene = editor->get_edited_scene(); - if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) + if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) { return; + } CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - if (canvas_item && !canvas_item->is_visible()) + if (canvas_item && !canvas_item->is_visible()) { return; + } Transform2D parent_xform = p_parent_xform; Transform2D canvas_xform = p_canvas_xform; @@ -3458,7 +3635,7 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans Transform2D xform = transform * canvas_xform * parent_xform; // Draw the node's position - Ref<Texture> position_icon = get_icon("EditorPositionUnselected", "EditorIcons"); + Ref<Texture2D> position_icon = get_theme_icon("EditorPositionUnselected", "EditorIcons"); Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; viewport->draw_set_transform_matrix(simple_xform); @@ -3471,11 +3648,10 @@ void CanvasItemEditor::_draw_hover() { List<Rect2> previous_rects; for (int i = 0; i < hovering_results.size(); i++) { - - Ref<Texture> node_icon = hovering_results[i].icon; + Ref<Texture2D> node_icon = hovering_results[i].icon; String node_name = hovering_results[i].name; - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); Size2 node_name_size = font->get_string_size(node_name); Size2 item_size = Size2(node_icon->get_size().x + 4 + node_name_size.x, MAX(node_icon->get_size().y, node_name_size.y - 3)); @@ -3501,11 +3677,13 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p ERR_FAIL_COND(!p_node); Node *scene = editor->get_edited_scene(); - if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) + if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) { return; + } CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - if (canvas_item && !canvas_item->is_visible()) + if (canvas_item && !canvas_item->is_visible()) { return; + } Transform2D parent_xform = p_parent_xform; Transform2D canvas_xform = p_canvas_xform; @@ -3526,13 +3704,13 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p if (canvas_item) { float offset = 0; - Ref<Texture> lock = get_icon("LockViewport", "EditorIcons"); + Ref<Texture2D> lock = get_theme_icon("LockViewport", "EditorIcons"); if (p_node->has_meta("_edit_lock_") && show_edit_locks) { lock->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0)); offset += lock->get_size().x; } - Ref<Texture> group = get_icon("GroupViewport", "EditorIcons"); + Ref<Texture2D> group = get_theme_icon("GroupViewport", "EditorIcons"); if (canvas_item->has_meta("_edit_group_") && show_edit_locks) { group->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0)); //offset += group->get_size().x; @@ -3578,7 +3756,7 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) { // Add a last bone if the Bone2D has no Bone2D child BoneKey bk; bk.from = canvas_item->get_instance_id(); - bk.to = 0; + bk.to = ObjectID(); if (!bone_list.has(bk)) { BoneList b; b.length = 0; @@ -3607,7 +3785,6 @@ bool CanvasItemEditor::_build_bones_list(Node *p_node) { } void CanvasItemEditor::_draw_viewport() { - // Update the transform transform = Transform2D(); transform.scale_basis(Size2(zoom, zoom)); @@ -3655,7 +3832,7 @@ void CanvasItemEditor::_draw_viewport() { } RID ci = viewport->get_canvas_item(); - VisualServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D()); + RenderingServer::get_singleton()->canvas_item_add_set_transform(ci, Transform2D()); EditorPluginList *over_plugin_list = editor->get_editor_plugins_over(); if (!over_plugin_list->empty()) { @@ -3667,10 +3844,12 @@ void CanvasItemEditor::_draw_viewport() { } _draw_bones(); - if (show_rulers) + if (show_rulers) { _draw_rulers(); - if (show_guides) + } + if (show_guides) { _draw_guides(); + } _draw_smart_snapping(); _draw_focus(); _draw_hover(); @@ -3686,7 +3865,6 @@ void CanvasItemEditor::set_current_tool(Tool p_tool) { } void CanvasItemEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PHYSICS_PROCESS) { EditorNode::get_singleton()->get_scene_root()->set_snap_controls_to_pixels(GLOBAL_GET("gui/common/snap_controls_to_pixels")); @@ -3772,10 +3950,8 @@ void CanvasItemEditor::_notification(int p_what) { // Update the viewport if bones changes for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Object *b = ObjectDB::get_instance(E->key().from); if (!b) { - viewport->update(); break; } @@ -3788,14 +3964,12 @@ void CanvasItemEditor::_notification(int p_what) { Transform2D global_xform = b2->get_global_transform(); if (global_xform != E->get().xform) { - E->get().xform = global_xform; viewport->update(); } Bone2D *bone = Object::cast_to<Bone2D>(b); if (bone && bone->get_default_length() != E->get().length) { - E->get().length = bone->get_default_length(); viewport->update(); } @@ -3803,115 +3977,113 @@ void CanvasItemEditor::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE) { - - select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons")); + select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons")); for (int i = 0; i < 4; i++) { select_sb->set_margin_size(Margin(i), 4); select_sb->set_default_margin(Margin(i), 4); } - AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", this, "_keying_changed"); + AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed)); _keying_changed(); - get_tree()->connect("node_added", this, "_tree_changed", varray()); - get_tree()->connect("node_removed", this, "_tree_changed", varray()); + get_tree()->connect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed), varray()); + get_tree()->connect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed), varray()); } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - - select_sb->set_texture(get_icon("EditorRect2D", "EditorIcons")); + select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons")); } if (p_what == NOTIFICATION_EXIT_TREE) { - get_tree()->disconnect("node_added", this, "_tree_changed"); - get_tree()->disconnect("node_removed", this, "_tree_changed"); + get_tree()->disconnect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed)); + get_tree()->disconnect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed)); } if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - select_button->set_icon(get_icon("ToolSelect", "EditorIcons")); - list_select_button->set_icon(get_icon("ListSelect", "EditorIcons")); - move_button->set_icon(get_icon("ToolMove", "EditorIcons")); - scale_button->set_icon(get_icon("ToolScale", "EditorIcons")); - rotate_button->set_icon(get_icon("ToolRotate", "EditorIcons")); - smart_snap_button->set_icon(get_icon("Snap", "EditorIcons")); - grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons")); - snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons")); - skeleton_menu->set_icon(get_icon("Bone", "EditorIcons")); - override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons")); - pan_button->set_icon(get_icon("ToolPan", "EditorIcons")); - ruler_button->set_icon(get_icon("Ruler", "EditorIcons")); - pivot_button->set_icon(get_icon("EditPivot", "EditorIcons")); - select_handle = get_icon("EditorHandle", "EditorIcons"); - anchor_handle = get_icon("EditorControlAnchor", "EditorIcons"); - lock_button->set_icon(get_icon("Lock", "EditorIcons")); - unlock_button->set_icon(get_icon("Unlock", "EditorIcons")); - group_button->set_icon(get_icon("Group", "EditorIcons")); - ungroup_button->set_icon(get_icon("Ungroup", "EditorIcons")); - key_loc_button->set_icon(get_icon("KeyPosition", "EditorIcons")); - key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons")); - key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons")); - key_insert_button->set_icon(get_icon("Key", "EditorIcons")); - key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons")); - animation_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons")); - - zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons")); - zoom_plus->set_icon(get_icon("ZoomMore", "EditorIcons")); - - presets_menu->set_icon(get_icon("ControlLayout", "EditorIcons")); + select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + list_select_button->set_icon(get_theme_icon("ListSelect", "EditorIcons")); + move_button->set_icon(get_theme_icon("ToolMove", "EditorIcons")); + scale_button->set_icon(get_theme_icon("ToolScale", "EditorIcons")); + rotate_button->set_icon(get_theme_icon("ToolRotate", "EditorIcons")); + smart_snap_button->set_icon(get_theme_icon("Snap", "EditorIcons")); + grid_snap_button->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); + snap_config_menu->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons")); + skeleton_menu->set_icon(get_theme_icon("Bone", "EditorIcons")); + override_camera_button->set_icon(get_theme_icon("Camera2D", "EditorIcons")); + pan_button->set_icon(get_theme_icon("ToolPan", "EditorIcons")); + ruler_button->set_icon(get_theme_icon("Ruler", "EditorIcons")); + pivot_button->set_icon(get_theme_icon("EditPivot", "EditorIcons")); + select_handle = get_theme_icon("EditorHandle", "EditorIcons"); + anchor_handle = get_theme_icon("EditorControlAnchor", "EditorIcons"); + lock_button->set_icon(get_theme_icon("Lock", "EditorIcons")); + unlock_button->set_icon(get_theme_icon("Unlock", "EditorIcons")); + group_button->set_icon(get_theme_icon("Group", "EditorIcons")); + ungroup_button->set_icon(get_theme_icon("Ungroup", "EditorIcons")); + key_loc_button->set_icon(get_theme_icon("KeyPosition", "EditorIcons")); + key_rot_button->set_icon(get_theme_icon("KeyRotation", "EditorIcons")); + key_scale_button->set_icon(get_theme_icon("KeyScale", "EditorIcons")); + key_insert_button->set_icon(get_theme_icon("Key", "EditorIcons")); + key_auto_insert_button->set_icon(get_theme_icon("AutoKey", "EditorIcons")); + animation_menu->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons")); + + zoom_minus->set_icon(get_theme_icon("ZoomLess", "EditorIcons")); + zoom_plus->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); + + presets_menu->set_icon(get_theme_icon("ControlLayout", "EditorIcons")); PopupMenu *p = presets_menu->get_popup(); p->clear(); - p->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT); - p->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT); - p->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT); - p->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_AND_MARGINS_PRESET_TOP_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_AND_MARGINS_PRESET_TOP_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_LEFT); p->add_separator(); - p->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT); - p->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP); - p->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT); - p->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM); - p->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER); + p->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_AND_MARGINS_PRESET_CENTER_LEFT); + p->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_AND_MARGINS_PRESET_CENTER_TOP); + p->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_AND_MARGINS_PRESET_CENTER_RIGHT); + p->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_AND_MARGINS_PRESET_CENTER_BOTTOM); + p->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_AND_MARGINS_PRESET_CENTER); p->add_separator(); - p->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE); - p->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE); - p->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE); - p->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE); - p->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE); - p->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_AND_MARGINS_PRESET_LEFT_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_AND_MARGINS_PRESET_TOP_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_AND_MARGINS_PRESET_RIGHT_WIDE); + p->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_AND_MARGINS_PRESET_BOTTOM_WIDE); + p->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_AND_MARGINS_PRESET_VCENTER_WIDE); + p->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_AND_MARGINS_PRESET_HCENTER_WIDE); p->add_separator(); - p->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE); - p->add_icon_item(get_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO); + p->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_AND_MARGINS_PRESET_WIDE); + p->add_icon_item(get_theme_icon("Anchor", "EditorIcons"), TTR("Keep Ratio"), ANCHORS_AND_MARGINS_PRESET_KEEP_RATIO); p->add_separator(); p->add_submenu_item(TTR("Anchors only"), "Anchors"); - p->set_item_icon(21, get_icon("Anchor", "EditorIcons")); + p->set_item_icon(21, get_theme_icon("Anchor", "EditorIcons")); anchors_popup->clear(); - anchors_popup->add_icon_item(get_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT); - anchors_popup->add_icon_item(get_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT); - anchors_popup->add_icon_item(get_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT); - anchors_popup->add_icon_item(get_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopLeft", "EditorIcons"), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopRight", "EditorIcons"), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomRight", "EditorIcons"), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomLeft", "EditorIcons"), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT); anchors_popup->add_separator(); - anchors_popup->add_icon_item(get_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT); - anchors_popup->add_icon_item(get_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP); - anchors_popup->add_icon_item(get_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT); - anchors_popup->add_icon_item(get_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM); - anchors_popup->add_icon_item(get_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_PRESET_CENTER); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignLeftCenter", "EditorIcons"), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopCenter", "EditorIcons"), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignRightCenter", "EditorIcons"), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomCenter", "EditorIcons"), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignCenter", "EditorIcons"), TTR("Center"), ANCHORS_PRESET_CENTER); anchors_popup->add_separator(); - anchors_popup->add_icon_item(get_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE); - anchors_popup->add_icon_item(get_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE); - anchors_popup->add_icon_item(get_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE); - anchors_popup->add_icon_item(get_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE); - anchors_popup->add_icon_item(get_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE); - anchors_popup->add_icon_item(get_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignLeftWide", "EditorIcons"), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignTopWide", "EditorIcons"), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignRightWide", "EditorIcons"), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignBottomWide", "EditorIcons"), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlVcenterWide", "EditorIcons"), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlHcenterWide", "EditorIcons"), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE); anchors_popup->add_separator(); - anchors_popup->add_icon_item(get_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_PRESET_WIDE); + anchors_popup->add_icon_item(get_theme_icon("ControlAlignWide", "EditorIcons"), TTR("Full Rect"), ANCHORS_PRESET_WIDE); - anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons")); + anchor_mode_button->set_icon(get_theme_icon("Anchor", "EditorIcons")); } if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { if (!is_visible() && override_camera_button->is_pressed()) { - ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton(); - debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE); override_camera_button->set_pressed(false); } } @@ -3924,10 +4096,12 @@ void CanvasItemEditor::_selection_changed() { List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Control *control = Object::cast_to<Control>(E->get()); - if (!control) + if (!control) { continue; - if (Object::cast_to<Container>(control->get_parent())) + } + if (Object::cast_to<Container>(control->get_parent())) { continue; + } nbValidControls++; if (control->has_meta("_edit_use_anchors_") && control->get_meta("_edit_use_anchors_")) { @@ -3944,7 +4118,6 @@ void CanvasItemEditor::_selection_changed() { } void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { - Array selection = editor_selection->get_selected_nodes(); if (selection.size() != 1 || (Node *)selection[0] != p_canvas_item) { drag_type = DRAG_NONE; @@ -3956,16 +4129,15 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { } void CanvasItemEditor::_queue_update_bone_list() { - - if (bone_list_dirty) + if (bone_list_dirty) { return; + } call_deferred("_update_bone_list"); bone_list_dirty = true; } void CanvasItemEditor::_update_bone_list() { - bone_last_frame++; if (editor->get_edited_scene()) { @@ -3997,7 +4169,6 @@ void CanvasItemEditor::_tree_changed(Node *) { } void CanvasItemEditor::_update_scrollbars() { - updating_scroll = true; // Move the zoom buttons. @@ -4100,7 +4271,7 @@ void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const floa Timer *timer; if (!popup_temporarily_timers.has(p_control)) { timer = memnew(Timer); - timer->connect("timeout", this, "_popup_warning_depop", varray(p_control)); + timer->connect("timeout", callable_mp(this, &CanvasItemEditor::_popup_warning_depop), varray(p_control)); timer->set_one_shot(true); add_child(timer); @@ -4115,9 +4286,9 @@ void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const floa } void CanvasItemEditor::_update_scroll(float) { - - if (updating_scroll) + if (updating_scroll) { return; + } view_offset.x = h_scroll->get_value(); view_offset.y = v_scroll->get_value(); @@ -4130,7 +4301,6 @@ void CanvasItemEditor::_set_anchors_and_margins_preset(Control::LayoutPreset p_p undo_redo->create_action(TTR("Change Anchors and Margins")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Control *control = Object::cast_to<Control>(E->get()); if (control) { undo_redo->add_do_method(control, "set_anchors_preset", p_preset); @@ -4172,7 +4342,6 @@ void CanvasItemEditor::_set_anchors_and_margins_to_keep_ratio() { undo_redo->create_action(TTR("Change Anchors and Margins")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Control *control = Object::cast_to<Control>(E->get()); if (control) { Point2 top_left_anchor = _position_to_anchor(control, Point2()); @@ -4200,7 +4369,6 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) { undo_redo->create_action(TTR("Change Anchors")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Control *control = Object::cast_to<Control>(E->get()); if (control) { undo_redo->add_do_method(control, "set_anchors_preset", p_preset); @@ -4211,16 +4379,56 @@ void CanvasItemEditor::_set_anchors_preset(Control::LayoutPreset p_preset) { undo_redo->commit_action(); } +float CanvasItemEditor::_get_next_zoom_value(int p_increment_count) const { + // Base increment factor defined as the twelveth root of two. + // This allow a smooth geometric evolution of the zoom, with the advantage of + // visiting all integer power of two scale factors. + // note: this is analogous to the 'semitones' interval in the music world + // In order to avoid numerical imprecisions, we compute and edit a zoom index + // with the following relation: zoom = 2 ^ (index / 12) + + if (zoom < CMP_EPSILON || p_increment_count == 0) { + return 1.f; + } + + // Remove Editor scale from the index computation + float zoom_noscale = zoom / MAX(1, EDSCALE); + + // zoom = 2**(index/12) => log2(zoom) = index/12 + float closest_zoom_index = Math::round(Math::log(zoom_noscale) * 12.f / Math::log(2.f)); + + float new_zoom_index = closest_zoom_index + p_increment_count; + float new_zoom = Math::pow(2.f, new_zoom_index / 12.f); + + // Restore Editor scale transformation + new_zoom *= MAX(1, EDSCALE); + + return new_zoom; +} + void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) { - if (p_zoom < MIN_ZOOM || p_zoom > MAX_ZOOM) + p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM); + + if (p_zoom == zoom) { return; + } float prev_zoom = zoom; zoom = p_zoom; - Point2 ofs = p_position; - ofs = ofs / prev_zoom - ofs / zoom; - view_offset.x = Math::round(view_offset.x + ofs.x); - view_offset.y = Math::round(view_offset.y + ofs.y); + + view_offset += p_position / prev_zoom - p_position / zoom; + + // We want to align in-scene pixels to screen pixels, this prevents blurry rendering + // in small details (texts, lines). + // This correction adds a jitter movement when zooming, so we correct only when the + // zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway) + float closest_zoom_factor = Math::round(zoom); + if (Math::is_zero_approx(zoom - closest_zoom_factor)) { + // make sure scene pixel at view_offset is aligned on a screen pixel + Vector2 view_offset_int = view_offset.floor(); + Vector2 view_offset_frac = view_offset - view_offset_int; + view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor; + } _update_zoom_label(); update_viewport(); @@ -4243,7 +4451,7 @@ void CanvasItemEditor::_update_zoom_label() { } void CanvasItemEditor::_button_zoom_minus() { - _zoom_on_position(zoom / Math_SQRT2, viewport_scrollable->get_size() / 2.0); + _zoom_on_position(_get_next_zoom_value(-6), viewport_scrollable->get_size() / 2.0); } void CanvasItemEditor::_button_zoom_reset() { @@ -4251,7 +4459,7 @@ void CanvasItemEditor::_button_zoom_reset() { } void CanvasItemEditor::_button_zoom_plus() { - _zoom_on_position(zoom * Math_SQRT2, viewport_scrollable->get_size() / 2.0); + _zoom_on_position(_get_next_zoom_value(6), viewport_scrollable->get_size() / 2.0); } void CanvasItemEditor::_button_toggle_smart_snap(bool p_status) { @@ -4263,49 +4471,58 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) { grid_snap_active = p_status; viewport->update(); } + void CanvasItemEditor::_button_override_camera(bool p_pressed) { - ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton(); if (p_pressed) { - debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D); + debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_2D); } else { - debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE); } } void CanvasItemEditor::_button_tool_select(int p_index) { - - ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button }; + Button *tb[TOOL_MAX] = { select_button, list_select_button, move_button, scale_button, rotate_button, pivot_button, pan_button, ruler_button }; for (int i = 0; i < TOOL_MAX; i++) { tb[i]->set_pressed(i == p_index); } tool = (Tool)p_index; + viewport->update(); + _update_cursor(); + + // Request immediate refresh of cursor when using hot-keys to switch between tools + DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)viewport->get_default_cursor_shape(); + DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape); } void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) { - Map<Node *, Object *> &selection = editor_selection->get_selection(); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) + if (!canvas_item || !canvas_item->is_visible_in_tree()) { continue; + } - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } if (Object::cast_to<Node2D>(canvas_item)) { Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - if (key_pos && p_location) + if (key_pos && p_location) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing); - if (key_rot && p_rotation) + } + if (key_rot && p_rotation) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing); - if (key_scale && p_scale) + } + if (key_scale && p_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing); + } if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { //look for an IK chain @@ -4315,42 +4532,45 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool has_chain = false; while (n) { - ik_chain.push_back(n); if (n->has_meta("_edit_ik_")) { has_chain = true; break; } - if (!n->get_parent_item()) + if (!n->get_parent_item()) { break; + } n = Object::cast_to<Node2D>(n->get_parent_item()); } if (has_chain && ik_chain.size()) { - for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { - - if (key_pos) + if (key_pos) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing); - if (key_rot) + } + if (key_rot) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing); - if (key_scale) + } + if (key_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing); + } } } } } else if (Object::cast_to<Control>(canvas_item)) { - Control *ctrl = Object::cast_to<Control>(canvas_item); - if (key_pos) + if (key_pos) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); - if (key_rot) + } + if (key_rot) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing); - if (key_scale) + } + if (key_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); + } } } } @@ -4359,8 +4579,9 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) { List<CanvasItem *> selection = _get_edited_canvas_items(false, false); for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { Control *control = Object::cast_to<Control>(E->get()); - if (!control || Object::cast_to<Container>(control->get_parent())) + if (!control || Object::cast_to<Container>(control->get_parent())) { continue; + } control->set_meta("_edit_use_anchors_", p_status); } @@ -4381,10 +4602,8 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { } void CanvasItemEditor::_popup_callback(int p_op) { - last_option = MenuOption(p_op); switch (p_op) { - case SHOW_GRID: { show_grid = !show_grid; int idx = view_menu->get_popup()->get_item_index(SHOW_GRID); @@ -4409,6 +4628,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { view_menu->get_popup()->set_item_checked(idx, show_edit_locks); viewport->update(); } break; + case SHOW_TRANSFORMATION_GIZMOS: { + show_transformation_gizmos = !show_transformation_gizmos; + int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + viewport->update(); + } break; case SNAP_USE_NODE_PARENT: { snap_node_parent = !snap_node_parent; int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_PARENT); @@ -4495,10 +4720,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_inside_tree()) + if (!canvas_item || !canvas_item->is_inside_tree()) { continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true); undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_"); @@ -4515,10 +4742,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_inside_tree()) + if (!canvas_item || !canvas_item->is_inside_tree()) { continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_"); undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true); @@ -4535,10 +4764,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_inside_tree()) + if (!canvas_item || !canvas_item->is_inside_tree()) { continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true); undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_"); @@ -4555,10 +4786,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { List<Node *> selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_inside_tree()) + if (!canvas_item || !canvas_item->is_inside_tree()) { continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_"); undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true); @@ -4672,41 +4905,36 @@ void CanvasItemEditor::_popup_callback(int p_op) { case ANIM_INSERT_KEY: case ANIM_INSERT_KEY_EXISTING: { - bool existing = p_op == ANIM_INSERT_KEY_EXISTING; _insert_animation_keys(true, true, true, existing); } break; case ANIM_INSERT_POS: { - key_pos = key_loc_button->is_pressed(); } break; case ANIM_INSERT_ROT: { - key_rot = key_rot_button->is_pressed(); } break; case ANIM_INSERT_SCALE: { - key_scale = key_scale_button->is_pressed(); } break; case ANIM_COPY_POSE: { - pose_clipboard.clear(); Map<Node *, Object *> &selection = editor_selection->get_selection(); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) + if (!canvas_item || !canvas_item->is_visible_in_tree()) { continue; + } - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } if (Object::cast_to<Node2D>(canvas_item)) { - Node2D *n2d = Object::cast_to<Node2D>(canvas_item); PoseClipboard pc; pc.pos = n2d->get_position(); @@ -4719,16 +4947,16 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case ANIM_PASTE_POSE: { - - if (!pose_clipboard.size()) + if (!pose_clipboard.size()) { break; + } undo_redo->create_action(TTR("Paste Pose")); for (List<PoseClipboard>::Element *E = pose_clipboard.front(); E; E = E->next()) { - Node2D *n2d = Object::cast_to<Node2D>(ObjectDB::get_instance(E->get().id)); - if (!n2d) + if (!n2d) { continue; + } undo_redo->add_do_method(n2d, "set_position", E->get().pos); undo_redo->add_do_method(n2d, "set_rotation", E->get().rot); undo_redo->add_do_method(n2d, "set_scale", E->get().scale); @@ -4740,33 +4968,36 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case ANIM_CLEAR_POSE: { - Map<Node *, Object *> &selection = editor_selection->get_selection(); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) + if (!canvas_item || !canvas_item->is_visible_in_tree()) { continue; + } - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } if (Object::cast_to<Node2D>(canvas_item)) { Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - if (key_pos) + if (key_pos) { n2d->set_position(Vector2()); - if (key_rot) + } + if (key_rot) { n2d->set_rotation(0); - if (key_scale) + } + if (key_scale) { n2d->set_scale(Vector2(1, 1)); + } } else if (Object::cast_to<Control>(canvas_item)) { - Control *ctrl = Object::cast_to<Control>(canvas_item); - if (key_pos) + if (key_pos) { ctrl->set_position(Point2()); + } /* if (key_scale) AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size()); @@ -4776,7 +5007,6 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case CLEAR_GUIDES: { - Node *const root = EditorNode::get_singleton()->get_edited_scene(); if (root && (root->has_meta("_edit_horizontal_guides_") || root->has_meta("_edit_vertical_guides_"))) { @@ -4800,34 +5030,34 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case VIEW_CENTER_TO_SELECTION: case VIEW_FRAME_TO_SELECTION: { - _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); + RS::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(); undo_redo->create_action(TTR("Create Custom Bone(s) from Node(s)")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - Node2D *n2d = Object::cast_to<Node2D>(E->key()); - if (!n2d) + if (!n2d) { continue; - if (!n2d->is_visible_in_tree()) + } + if (!n2d->is_visible_in_tree()) { continue; - if (!n2d->get_parent_item()) + } + if (!n2d->get_parent_item()) { continue; - if (n2d->has_meta("_edit_bone_") && n2d->get_meta("_edit_bone_")) + } + if (n2d->has_meta("_edit_bone_") && n2d->get_meta("_edit_bone_")) { continue; + } undo_redo->add_do_method(n2d, "set_meta", "_edit_bone_", true); undo_redo->add_undo_method(n2d, "remove_meta", "_edit_bone_"); @@ -4840,19 +5070,20 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case SKELETON_CLEAR_BONES: { - Map<Node *, Object *> &selection = editor_selection->get_selection(); undo_redo->create_action(TTR("Clear Bones")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - Node2D *n2d = Object::cast_to<Node2D>(E->key()); - if (!n2d) + if (!n2d) { continue; - if (!n2d->is_visible_in_tree()) + } + if (!n2d->is_visible_in_tree()) { continue; - if (!n2d->has_meta("_edit_bone_")) + } + if (!n2d->has_meta("_edit_bone_")) { continue; + } undo_redo->add_do_method(n2d, "remove_meta", "_edit_bone_"); undo_redo->add_undo_method(n2d, "set_meta", "_edit_bone_", n2d->get_meta("_edit_bone_")); @@ -4865,19 +5096,20 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case SKELETON_SET_IK_CHAIN: { - List<Node *> selection = editor_selection->get_selected_node_list(); undo_redo->create_action(TTR("Make IK Chain")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) + if (!canvas_item || !canvas_item->is_visible_in_tree()) { continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; - if (canvas_item->has_meta("_edit_ik_") && canvas_item->get_meta("_edit_ik_")) + } + if (canvas_item->has_meta("_edit_ik_") && canvas_item->get_meta("_edit_ik_")) { continue; + } undo_redo->add_do_method(canvas_item, "set_meta", "_edit_ik_", true); undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_ik_"); @@ -4888,19 +5120,20 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case SKELETON_CLEAR_IK_CHAIN: { - Map<Node *, Object *> &selection = editor_selection->get_selection(); undo_redo->create_action(TTR("Clear IK Chain")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *n2d = Object::cast_to<CanvasItem>(E->key()); - if (!n2d) + if (!n2d) { continue; - if (!n2d->is_visible_in_tree()) + } + if (!n2d->is_visible_in_tree()) { continue; - if (!n2d->has_meta("_edit_ik_")) + } + if (!n2d->has_meta("_edit_ik_")) { continue; + } undo_redo->add_do_method(n2d, "remove_meta", "_edit_ik_"); undo_redo->add_undo_method(n2d, "set_meta", "_edit_ik_", n2d->get_meta("_edit_ik_")); @@ -4921,9 +5154,12 @@ void CanvasItemEditor::_focus_selection(int p_op) { Map<Node *, Object *> &selection = editor_selection->get_selection(); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item) continue; - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (!canvas_item) { continue; + } + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { + continue; + } // counting invisible items, for now //if (!canvas_item->is_visible_in_tree()) continue; @@ -4949,10 +5185,11 @@ void CanvasItemEditor::_focus_selection(int p_op) { rect = rect.merge(canvas_item_rect); } }; - if (count == 0) return; + if (count == 0) { + return; + } if (p_op == VIEW_CENTER_TO_SELECTION) { - center = rect.position + rect.size / 2; Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center); view_offset.x -= Math::round(offset.x / zoom); @@ -4967,38 +5204,18 @@ void CanvasItemEditor::_focus_selection(int p_op) { zoom = scale_x < scale_y ? scale_x : scale_y; zoom *= 0.90; viewport->update(); + _update_zoom_label(); call_deferred("_popup_callback", VIEW_CENTER_TO_SELECTION); } } } void CanvasItemEditor::_bind_methods() { - - ClassDB::bind_method("_button_zoom_minus", &CanvasItemEditor::_button_zoom_minus); - ClassDB::bind_method("_button_zoom_reset", &CanvasItemEditor::_button_zoom_reset); - ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus); - ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap); - ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap); - ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera); ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button); - ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode); - ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll); - ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars); - ClassDB::bind_method("_popup_callback", &CanvasItemEditor::_popup_callback); ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data); - ClassDB::bind_method("_button_tool_select", &CanvasItemEditor::_button_tool_select); - ClassDB::bind_method("_keying_changed", &CanvasItemEditor::_keying_changed); ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input); - ClassDB::bind_method("_draw_viewport", &CanvasItemEditor::_draw_viewport); - ClassDB::bind_method("_gui_input_viewport", &CanvasItemEditor::_gui_input_viewport); - ClassDB::bind_method("_snap_changed", &CanvasItemEditor::_snap_changed); ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); - ClassDB::bind_method("_tree_changed", &CanvasItemEditor::_tree_changed); - ClassDB::bind_method("_selection_changed", &CanvasItemEditor::_selection_changed); - ClassDB::bind_method("_popup_warning_depop", &CanvasItemEditor::_popup_warning_depop); - ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed); - ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); @@ -5007,7 +5224,6 @@ void CanvasItemEditor::_bind_methods() { } Dictionary CanvasItemEditor::get_state() const { - Dictionary state; // Take the editor scale into account. state["zoom"] = zoom / MAX(1, EDSCALE); @@ -5034,6 +5250,7 @@ Dictionary CanvasItemEditor::get_state() const { state["show_helpers"] = show_helpers; state["show_zoom_control"] = zoom_hb->is_visible(); state["show_edit_locks"] = show_edit_locks; + state["show_transformation_gizmos"] = show_transformation_gizmos; state["snap_rotation"] = snap_rotation; state["snap_scale"] = snap_scale; state["snap_relative"] = snap_relative; @@ -5043,7 +5260,6 @@ Dictionary CanvasItemEditor::get_state() const { } void CanvasItemEditor::set_state(const Dictionary &p_state) { - bool update_scrollbars = false; Dictionary state = p_state; if (state.has("zoom")) { @@ -5172,6 +5388,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, show_edit_locks); } + if (state.has("show_transformation_gizmos")) { + show_transformation_gizmos = state["show_transformation_gizmos"]; + int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + } + if (state.has("show_zoom_control")) { // This one is not user-controllable, but instrumentable zoom_hb->set_visible(state["show_zoom_control"]); @@ -5222,7 +5444,6 @@ void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) { } void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) { - info_overlay->remove_child(p_control); info_overlay->set_margin(MARGIN_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } @@ -5234,17 +5455,14 @@ void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) { } void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) { - hb->remove_child(p_control); } HSplitContainer *CanvasItemEditor::get_palette_split() { - return palette_split; } VSplitContainer *CanvasItemEditor::get_bottom_split() { - return bottom_split; } @@ -5253,7 +5471,6 @@ void CanvasItemEditor::focus_selection() { } CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { - key_pos = true; key_rot = true; key_scale = false; @@ -5264,6 +5481,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { show_helpers = false; show_rulers = true; show_guides = true; + show_transformation_gizmos = true; show_edit_locks = true; zoom = 1.0 / MAX(1, EDSCALE); view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH); @@ -5316,11 +5534,11 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { editor = p_editor; editor_selection = p_editor->get_editor_selection(); editor_selection->add_editor_plugin(this); - editor_selection->connect("selection_changed", this, "update"); - editor_selection->connect("selection_changed", this, "_selection_changed"); + editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed)); - editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true)); - editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false)); + editor->call_deferred("connect", "play_pressed", Callable(this, "_update_override_camera_button"), make_binds(true)); + editor->call_deferred("connect", "stop_pressed", Callable(this, "_update_override_camera_button"), make_binds(false)); hb = memnew(HBoxContainer); add_child(hb); @@ -5328,21 +5546,21 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { bottom_split = memnew(VSplitContainer); add_child(bottom_split); - bottom_split->set_v_size_flags(SIZE_EXPAND_FILL); + bottom_split->set_v_size_flags(Control::SIZE_EXPAND_FILL); palette_split = memnew(HSplitContainer); bottom_split->add_child(palette_split); - palette_split->set_v_size_flags(SIZE_EXPAND_FILL); + palette_split->set_v_size_flags(Control::SIZE_EXPAND_FILL); viewport_scrollable = memnew(Control); palette_split->add_child(viewport_scrollable); viewport_scrollable->set_mouse_filter(MOUSE_FILTER_PASS); viewport_scrollable->set_clip_contents(true); - viewport_scrollable->set_v_size_flags(SIZE_EXPAND_FILL); - viewport_scrollable->set_h_size_flags(SIZE_EXPAND_FILL); - viewport_scrollable->connect("draw", this, "_update_scrollbars"); + viewport_scrollable->set_v_size_flags(Control::SIZE_EXPAND_FILL); + viewport_scrollable->set_h_size_flags(Control::SIZE_EXPAND_FILL); + viewport_scrollable->connect("draw", callable_mp(this, &CanvasItemEditor::_update_scrollbars)); - ViewportContainer *scene_tree = memnew(ViewportContainer); + SubViewportContainer *scene_tree = memnew(SubViewportContainer); viewport_scrollable->add_child(scene_tree); scene_tree->set_stretch(true); scene_tree->set_anchors_and_margins_preset(Control::PRESET_WIDE); @@ -5353,7 +5571,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { zoom_hb = memnew(HBoxContainer); // Bring the zoom percentage closer to the zoom buttons - zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE)); + zoom_hb->add_theme_constant_override("separation", Math::round(-8 * EDSCALE)); controls_vb->add_child(zoom_hb); viewport = memnew(CanvasItemEditorViewport(p_editor, this)); @@ -5362,15 +5580,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { viewport->set_anchors_and_margins_preset(Control::PRESET_WIDE); viewport->set_clip_contents(true); viewport->set_focus_mode(FOCUS_ALL); - viewport->connect("draw", this, "_draw_viewport"); - viewport->connect("gui_input", this, "_gui_input_viewport"); + viewport->connect("draw", callable_mp(this, &CanvasItemEditor::_draw_viewport)); + viewport->connect("gui_input", callable_mp(this, &CanvasItemEditor::_gui_input_viewport)); info_overlay = memnew(VBoxContainer); info_overlay->set_anchors_and_margins_preset(Control::PRESET_BOTTOM_LEFT); info_overlay->set_margin(MARGIN_LEFT, 10); info_overlay->set_margin(MARGIN_BOTTOM, -15); info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN); - info_overlay->add_constant_override("separation", 10); + info_overlay->add_theme_constant_override("separation", 10); viewport_scrollable->add_child(info_overlay); Theme *info_overlay_theme = memnew(Theme); @@ -5385,116 +5603,130 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { warning_child_of_container = memnew(Label); warning_child_of_container->hide(); warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent.")); - warning_child_of_container->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor")); - warning_child_of_container->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts")); + warning_child_of_container->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor")); + warning_child_of_container->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); add_control_to_info_overlay(warning_child_of_container); h_scroll = memnew(HScrollBar); viewport->add_child(h_scroll); - h_scroll->connect("value_changed", this, "_update_scroll"); + h_scroll->connect("value_changed", callable_mp(this, &CanvasItemEditor::_update_scroll)); h_scroll->hide(); v_scroll = memnew(VScrollBar); viewport->add_child(v_scroll); - v_scroll->connect("value_changed", this, "_update_scroll"); + v_scroll->connect("value_changed", callable_mp(this, &CanvasItemEditor::_update_scroll)); v_scroll->hide(); viewport->add_child(controls_vb); - zoom_minus = memnew(ToolButton); + zoom_minus = memnew(Button); + zoom_minus->set_flat(true); zoom_hb->add_child(zoom_minus); - zoom_minus->connect("pressed", this, "_button_zoom_minus"); + zoom_minus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_minus)); zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KEY_MASK_CMD | KEY_MINUS)); zoom_minus->set_focus_mode(FOCUS_NONE); - zoom_reset = memnew(ToolButton); + zoom_reset = memnew(Button); + zoom_reset->set_flat(true); zoom_hb->add_child(zoom_reset); - zoom_reset->connect("pressed", this, "_button_zoom_reset"); + zoom_reset->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_reset)); zoom_reset->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_reset", TTR("Zoom Reset"), KEY_MASK_CMD | KEY_0)); zoom_reset->set_focus_mode(FOCUS_NONE); zoom_reset->set_text_align(Button::TextAlign::ALIGN_CENTER); // Prevent the button's size from changing when the text size changes zoom_reset->set_custom_minimum_size(Size2(75 * EDSCALE, 0)); - zoom_plus = memnew(ToolButton); + zoom_plus = memnew(Button); + zoom_plus->set_flat(true); zoom_hb->add_child(zoom_plus); - zoom_plus->connect("pressed", this, "_button_zoom_plus"); + zoom_plus->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_zoom_plus)); zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KEY_MASK_CMD | KEY_EQUAL)); // Usually direct access key for PLUS zoom_plus->set_focus_mode(FOCUS_NONE); updating_scroll = false; - select_button = memnew(ToolButton); + select_button = memnew(Button); + select_button->set_flat(true); hb->add_child(select_button); select_button->set_toggle_mode(true); - select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECT)); + select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SELECT)); select_button->set_pressed(true); select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q)); select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate") + "\n" + TTR("Alt+Drag: Move") + "\n" + TTR("Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).") + "\n" + TTR("Alt+RMB: Depth list selection")); hb->add_child(memnew(VSeparator)); - move_button = memnew(ToolButton); + move_button = memnew(Button); + move_button->set_flat(true); hb->add_child(move_button); move_button->set_toggle_mode(true); - move_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_MOVE)); + move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_MOVE)); move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W)); move_button->set_tooltip(TTR("Move Mode")); - rotate_button = memnew(ToolButton); + rotate_button = memnew(Button); + rotate_button->set_flat(true); hb->add_child(rotate_button); rotate_button->set_toggle_mode(true); - rotate_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_ROTATE)); + rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_ROTATE)); rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E)); rotate_button->set_tooltip(TTR("Rotate Mode")); - scale_button = memnew(ToolButton); + scale_button = memnew(Button); + scale_button->set_flat(true); hb->add_child(scale_button); scale_button->set_toggle_mode(true); - scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE)); + scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_SCALE)); scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S)); scale_button->set_tooltip(TTR("Scale Mode")); hb->add_child(memnew(VSeparator)); - list_select_button = memnew(ToolButton); + list_select_button = memnew(Button); + list_select_button->set_flat(true); hb->add_child(list_select_button); list_select_button->set_toggle_mode(true); - list_select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_LIST_SELECT)); + list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_LIST_SELECT)); list_select_button->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode).")); - pivot_button = memnew(ToolButton); + pivot_button = memnew(Button); + pivot_button->set_flat(true); hb->add_child(pivot_button); pivot_button->set_toggle_mode(true); - pivot_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_EDIT_PIVOT)); + pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_EDIT_PIVOT)); pivot_button->set_tooltip(TTR("Click to change object's rotation pivot.")); - pan_button = memnew(ToolButton); + pan_button = memnew(Button); + pan_button->set_flat(true); hb->add_child(pan_button); pan_button->set_toggle_mode(true); - pan_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PAN)); + pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_PAN)); + pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G)); pan_button->set_tooltip(TTR("Pan Mode")); - ruler_button = memnew(ToolButton); + ruler_button = memnew(Button); + ruler_button->set_flat(true); hb->add_child(ruler_button); ruler_button->set_toggle_mode(true); - ruler_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_RULER)); + ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select), make_binds(TOOL_RULER)); ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), KEY_R)); ruler_button->set_tooltip(TTR("Ruler Mode")); hb->add_child(memnew(VSeparator)); - smart_snap_button = memnew(ToolButton); + smart_snap_button = memnew(Button); + smart_snap_button->set_flat(true); hb->add_child(smart_snap_button); smart_snap_button->set_toggle_mode(true); - smart_snap_button->connect("toggled", this, "_button_toggle_smart_snap"); + smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap)); smart_snap_button->set_tooltip(TTR("Toggle smart snapping.")); smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KEY_MASK_SHIFT | KEY_S)); - grid_snap_button = memnew(ToolButton); + grid_snap_button = memnew(Button); + grid_snap_button->set_flat(true); hb->add_child(grid_snap_button); grid_snap_button->set_toggle_mode(true); - grid_snap_button->connect("toggled", this, "_button_toggle_grid_snap"); + grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap)); grid_snap_button->set_tooltip(TTR("Toggle grid snapping.")); grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KEY_MASK_SHIFT | KEY_G)); @@ -5505,7 +5737,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_config_menu->set_switch_on_hover(true); PopupMenu *p = snap_config_menu->get_popup(); - p->connect("id_pressed", this, "_popup_callback"); + p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_scale_snap", TTR("Use Scale Snap")), SNAP_USE_SCALE); @@ -5519,7 +5751,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { smartsnap_config_popup = memnew(PopupMenu); p->add_child(smartsnap_config_popup); smartsnap_config_popup->set_name("SmartSnapping"); - smartsnap_config_popup->connect("id_pressed", this, "_popup_callback"); + smartsnap_config_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); smartsnap_config_popup->set_hide_on_checkable_item_selection(false); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_parent", TTR("Snap to Parent")), SNAP_USE_NODE_PARENT); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to Node Anchor")), SNAP_USE_NODE_ANCHORS); @@ -5530,25 +5762,29 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { hb->add_child(memnew(VSeparator)); - lock_button = memnew(ToolButton); + lock_button = memnew(Button); + lock_button->set_flat(true); hb->add_child(lock_button); - lock_button->connect("pressed", this, "_popup_callback", varray(LOCK_SELECTED)); + lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(LOCK_SELECTED)); lock_button->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); - unlock_button = memnew(ToolButton); + unlock_button = memnew(Button); + unlock_button->set_flat(true); hb->add_child(unlock_button); - unlock_button->connect("pressed", this, "_popup_callback", varray(UNLOCK_SELECTED)); + unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNLOCK_SELECTED)); unlock_button->set_tooltip(TTR("Unlock the selected object (can be moved).")); - group_button = memnew(ToolButton); + group_button = memnew(Button); + group_button->set_flat(true); hb->add_child(group_button); - group_button->connect("pressed", this, "_popup_callback", varray(GROUP_SELECTED)); + group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(GROUP_SELECTED)); group_button->set_tooltip(TTR("Makes sure the object's children are not selectable.")); - ungroup_button = memnew(ToolButton); + ungroup_button = memnew(Button); + ungroup_button->set_flat(true); hb->add_child(ungroup_button); - ungroup_button->connect("pressed", this, "_popup_callback", varray(UNGROUP_SELECTED)); + ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNGROUP_SELECTED)); ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected.")); hb->add_child(memnew(VSeparator)); @@ -5567,13 +5803,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Custom Bone(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES); - p->connect("id_pressed", this, "_popup_callback"); + p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); hb->add_child(memnew(VSeparator)); - override_camera_button = memnew(ToolButton); + override_camera_button = memnew(Button); + override_camera_button->set_flat(true); hb->add_child(override_camera_button); - override_camera_button->connect("toggled", this, "_button_override_camera"); + override_camera_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_override_camera)); override_camera_button->set_toggle_mode(true); override_camera_button->set_disabled(true); _update_override_camera_button(false); @@ -5583,7 +5820,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { view_menu = memnew(MenuButton); view_menu->set_text(TTR("View")); hb->add_child(view_menu); - view_menu->get_popup()->connect("id_pressed", this, "_popup_callback"); + view_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); view_menu->set_switch_on_hover(true); p = view_menu->get_popup(); @@ -5595,6 +5832,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_edit_locks", TTR("Show Group And Lock Icons")), SHOW_EDIT_LOCKS); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_transformation_gizmos", TTR("Show Transformation Gizmos")), SHOW_TRANSFORMATION_GIZMOS); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); @@ -5610,18 +5848,19 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { presets_menu->set_switch_on_hover(true); p = presets_menu->get_popup(); - p->connect("id_pressed", this, "_popup_callback"); + p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); anchors_popup = memnew(PopupMenu); p->add_child(anchors_popup); anchors_popup->set_name("Anchors"); - anchors_popup->connect("id_pressed", this, "_popup_callback"); + anchors_popup->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); - anchor_mode_button = memnew(ToolButton); + anchor_mode_button = memnew(Button); + anchor_mode_button->set_flat(true); hb->add_child(anchor_mode_button); anchor_mode_button->set_toggle_mode(true); anchor_mode_button->hide(); - anchor_mode_button->connect("toggled", this, "_button_toggle_anchor_mode"); + anchor_mode_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_anchor_mode)); animation_hb = memnew(HBoxContainer); hb->add_child(animation_hb); @@ -5633,7 +5872,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_loc_button->set_flat(true); key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); - key_loc_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_POS)); + key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_POS)); key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); @@ -5641,20 +5880,20 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_rot_button->set_flat(true); key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); - key_rot_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_ROT)); + key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_ROT)); key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); key_scale_button->set_toggle_mode(true); key_scale_button->set_flat(true); key_scale_button->set_focus_mode(FOCUS_NONE); - key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE)); + key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_SCALE)); key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); - key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); + key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY)); key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT)); animation_hb->add_child(key_insert_button); @@ -5670,7 +5909,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { animation_menu = memnew(MenuButton); animation_menu->set_tooltip(TTR("Animation Key and Pose Options")); animation_hb->add_child(animation_menu); - animation_menu->get_popup()->connect("id_pressed", this, "_popup_callback"); + animation_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); animation_menu->set_switch_on_hover(true); p = animation_menu->get_popup(); @@ -5683,16 +5922,16 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_shortcut(ED_SHORTCUT("canvas_item_editor/anim_clear_pose", TTR("Clear Pose"), KEY_MASK_SHIFT | KEY_K), ANIM_CLEAR_POSE); snap_dialog = memnew(SnapDialog); - snap_dialog->connect("confirmed", this, "_snap_changed"); + snap_dialog->connect("confirmed", callable_mp(this, &CanvasItemEditor::_snap_changed)); add_child(snap_dialog); select_sb = Ref<StyleBoxTexture>(memnew(StyleBoxTexture)); selection_menu = memnew(PopupMenu); add_child(selection_menu); - selection_menu->set_custom_minimum_size(Vector2(100, 0)); - selection_menu->connect("id_pressed", this, "_selection_result_pressed"); - selection_menu->connect("popup_hide", this, "_selection_menu_hide"); + selection_menu->set_min_size(Vector2(100, 0)); + selection_menu->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_selection_result_pressed)); + selection_menu->connect("popup_hide", callable_mp(this, &CanvasItemEditor::_selection_menu_hide)); multiply_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/multiply_grid_step", TTR("Multiply grid step by 2"), KEY_KP_MULTIPLY); divide_grid_step_shortcut = ED_SHORTCUT("canvas_item_editor/divide_grid_step", TTR("Divide grid step by 2"), KEY_KP_DIVIDE); @@ -5707,45 +5946,39 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { call_deferred("set_state", get_state()); } -CanvasItemEditor *CanvasItemEditor::singleton = NULL; +CanvasItemEditor *CanvasItemEditor::singleton = nullptr; void CanvasItemEditorPlugin::edit(Object *p_object) { - canvas_item_editor->set_undo_redo(&get_undo_redo()); canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object)); } bool CanvasItemEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("CanvasItem"); } void CanvasItemEditorPlugin::make_visible(bool p_visible) { - if (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); + RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false); } else { - canvas_item_editor->hide(); canvas_item_editor->set_physics_process(false); - VisualServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true); + RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true); } } Dictionary CanvasItemEditorPlugin::get_state() const { - return canvas_item_editor->get_state(); } -void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) { +void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) { canvas_item_editor->set_state(p_state); } CanvasItemEditorPlugin::CanvasItemEditorPlugin(EditorNode *p_node) { - editor = p_node; canvas_item_editor = memnew(CanvasItemEditor(editor)); canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -5771,8 +6004,9 @@ void CanvasItemEditorViewport::_on_select_type(Object *selected) { } void CanvasItemEditorViewport::_on_change_type_confirmed() { - if (!button_group->get_pressed_button()) + if (!button_group->get_pressed_button()) { return; + } CheckBox *check = Object::cast_to<CheckBox>(button_group->get_pressed_button()); default_type = check->get_text(); @@ -5781,7 +6015,6 @@ void CanvasItemEditorViewport::_on_change_type_confirmed() { } void CanvasItemEditorViewport::_on_change_type_closed() { - _remove_preview(); } @@ -5791,11 +6024,11 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons String path = files[i]; RES res = ResourceLoader::load(path); ERR_FAIL_COND(res.is_null()); - Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res)); + Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - if (texture != NULL || scene != NULL) { - if (texture != NULL) { - Sprite *sprite = memnew(Sprite); + if (texture != nullptr || scene != nullptr) { + if (texture != nullptr) { + Sprite2D *sprite = memnew(Sprite2D); sprite->set_texture(texture); sprite->set_modulate(Color(1, 1, 1, 0.7f)); preview_node->add_child(sprite); @@ -5813,8 +6046,9 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons } } - if (add_preview) + if (add_preview) { editor->get_scene_root()->add_child(preview_node); + } } void CanvasItemEditorViewport::_remove_preview() { @@ -5848,7 +6082,7 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) { child->set_name(path.get_file().get_basename()); - Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path))); + Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(ResourceCache::get(path))); Size2 texture_size = texture->get_size(); if (parent) { @@ -5860,14 +6094,14 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child); editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr); } if (parent) { String new_name = parent->validate_child_name(child); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); } // handle with different property for texture @@ -5892,7 +6126,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & if (default_type == "NinePatchRect") { editor_data->get_undo_redo().add_do_property(child, "rect/size", texture_size); } else if (default_type == "Polygon2D") { - PoolVector<Vector2> list; + Vector<Vector2> list; list.push_back(Vector2(0, 0)); list.push_back(Vector2(texture_size.width, 0)); list.push_back(Vector2(texture_size.width, texture_size.height)); @@ -5935,15 +6169,20 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); String new_name = parent->validate_child_name(instanced_scene); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); + editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent); if (parent_ci) { Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point); target_pos = canvas_item_editor->snap_point(target_pos); target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos); + // Preserve instance position of the original scene. + CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instanced_scene); + if (instance_ci) { + target_pos += instance_ci->_edit_get_position(); + } editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos); } @@ -5956,7 +6195,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { // Without root dropping multiple files is not allowed if (!target_node && selected_files.size() > 1) { accept->set_text(TTR("Cannot instantiate multiple nodes without root.")); - accept->popup_centered_minsize(); + accept->popup_centered(); return; } @@ -5971,7 +6210,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { continue; } Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - if (scene != NULL && scene.is_valid()) { + if (scene != nullptr && scene.is_valid()) { if (!target_node) { // Without root node act the same as "Load Inherited Scene" Error err = EditorNode::get_singleton()->load_scene(path, false, true); @@ -5985,23 +6224,24 @@ void CanvasItemEditorViewport::_perform_drop_data() { } } } else { - Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res)); - if (texture != NULL && texture.is_valid()) { + Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); + if (texture != nullptr && texture.is_valid()) { Node *child; - if (default_type == "Light2D") + if (default_type == "Light2D") { child = memnew(Light2D); - else if (default_type == "Particles2D") - child = memnew(Particles2D); - else if (default_type == "Polygon2D") + } else if (default_type == "GPUParticles2D") { + child = memnew(GPUParticles2D); + } else if (default_type == "Polygon2D") { child = memnew(Polygon2D); - else if (default_type == "TouchScreenButton") + } else if (default_type == "TouchScreenButton") { child = memnew(TouchScreenButton); - else if (default_type == "TextureRect") + } else if (default_type == "TextureRect") { child = memnew(TextureRect); - else if (default_type == "NinePatchRect") + } else if (default_type == "NinePatchRect") { child = memnew(NinePatchRect); - else - child = memnew(Sprite); // default + } else { + child = memnew(Sprite2D); // default + } _create_nodes(target_node, child, path, drop_pos); } @@ -6016,8 +6256,8 @@ void CanvasItemEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); - accept->popup_centered_minsize(); + accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data())); + accept->popup_centered(); } } @@ -6040,15 +6280,15 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian continue; } memdelete(instanced_scene); - } else if (type == "Texture" || + } else if (type == "Texture2D" || type == "ImageTexture" || type == "ViewportTexture" || type == "CurveTexture" || type == "GradientTexture" || - type == "StreamTexture" || + type == "StreamTexture2D" || type == "AtlasTexture" || type == "LargeTexture") { - Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(*res)); + Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); if (!texture.is_valid()) { continue; } @@ -6083,11 +6323,10 @@ void CanvasItemEditorViewport::_show_resource_type_selector() { check->set_pressed(check->get_text() == default_type); } selector->set_title(vformat(TTR("Add %s"), default_type)); - selector->popup_centered_minsize(); + selector->popup_centered(); } bool CanvasItemEditorViewport::_only_packed_scenes_selected() const { - for (int i = 0; i < selected_files.size(); ++i) { if (ResourceLoader::load(selected_files[i])->get_class() != "PackedScene") { return false; @@ -6106,8 +6345,9 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p if (d.has("type") && String(d["type"]) == "files") { selected_files = d["files"]; } - if (selected_files.size() == 0) + if (selected_files.size() == 0) { return; + } List<Node *> list = editor->get_editor_selection()->get_selected_node_list(); if (list.size() == 0) { @@ -6116,7 +6356,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p list.push_back(root_node); } else { drop_pos = p_point; - target_node = NULL; + target_node = nullptr; } } @@ -6139,37 +6379,34 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p void CanvasItemEditorViewport::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - connect("mouse_exited", this, "_on_mouse_exit"); - label->add_color_override("font_color", get_color("warning_color", "Editor")); + connect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit)); + label->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor")); } break; case NOTIFICATION_EXIT_TREE: { - disconnect("mouse_exited", this, "_on_mouse_exit"); + disconnect("mouse_exited", callable_mp(this, &CanvasItemEditorViewport::_on_mouse_exit)); } break; - default: break; + default: + break; } } void CanvasItemEditorViewport::_bind_methods() { - ClassDB::bind_method(D_METHOD("_on_select_type"), &CanvasItemEditorViewport::_on_select_type); - ClassDB::bind_method(D_METHOD("_on_change_type_confirmed"), &CanvasItemEditorViewport::_on_change_type_confirmed); - ClassDB::bind_method(D_METHOD("_on_change_type_closed"), &CanvasItemEditorViewport::_on_change_type_closed); - ClassDB::bind_method(D_METHOD("_on_mouse_exit"), &CanvasItemEditorViewport::_on_mouse_exit); } CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor) { - default_type = "Sprite"; + default_type = "Sprite2D"; // Node2D - types.push_back("Sprite"); + types.push_back("Sprite2D"); types.push_back("Light2D"); - types.push_back("Particles2D"); + types.push_back("GPUParticles2D"); types.push_back("Polygon2D"); types.push_back("TouchScreenButton"); // Control types.push_back("TextureRect"); types.push_back("NinePatchRect"); - target_node = NULL; + target_node = nullptr; editor = p_node; editor_data = editor->get_scene_tree_dock()->get_editor_data(); canvas_item_editor = p_canvas_item_editor; @@ -6181,14 +6418,14 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte selector = memnew(AcceptDialog); editor->get_gui_base()->add_child(selector); selector->set_title(TTR("Change Default Type")); - selector->connect("confirmed", this, "_on_change_type_confirmed"); - selector->connect("popup_hide", this, "_on_change_type_closed"); + selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed)); + selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed)); VBoxContainer *vbc = memnew(VBoxContainer); selector->add_child(vbc); - vbc->set_h_size_flags(SIZE_EXPAND_FILL); - vbc->set_v_size_flags(SIZE_EXPAND_FILL); - vbc->set_custom_minimum_size(Size2(200, 260) * EDSCALE); + vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + vbc->set_v_size_flags(Control::SIZE_EXPAND_FILL); + vbc->set_custom_minimum_size(Size2(240, 260) * EDSCALE); btn_group = memnew(VBoxContainer); vbc->add_child(btn_group); @@ -6199,26 +6436,26 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte CheckBox *check = memnew(CheckBox); btn_group->add_child(check); check->set_text(types[i]); - check->connect("button_down", this, "_on_select_type", varray(check)); + check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_type), varray(check)); check->set_button_group(button_group); } label = memnew(Label); - label->add_color_override("font_color_shadow", Color(0, 0, 0, 1)); - label->add_constant_override("shadow_as_outline", 1 * EDSCALE); + label->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 1)); + label->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE); label->hide(); canvas_item_editor->get_controls_container()->add_child(label); label_desc = memnew(Label); label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type")); - label_desc->add_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1)); - label_desc->add_color_override("font_color_shadow", Color(0.2f, 0.2f, 0.2f, 1)); - label_desc->add_constant_override("shadow_as_outline", 1 * EDSCALE); - label_desc->add_constant_override("line_spacing", 0); + label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1)); + label_desc->add_theme_color_override("font_color_shadow", Color(0.2f, 0.2f, 0.2f, 1)); + label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE); + label_desc->add_theme_constant_override("line_spacing", 0); label_desc->hide(); canvas_item_editor->get_controls_container()->add_child(label_desc); - VS::get_singleton()->canvas_set_disable_scale(true); + RS::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 3291d6b9bf..859e80befe 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -33,25 +33,24 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/2d/canvas_item.h" #include "scene/gui/box_container.h" #include "scene/gui/check_box.h" #include "scene/gui/label.h" #include "scene/gui/panel_container.h" #include "scene/gui/spin_box.h" +#include "scene/main/canvas_item.h" class CanvasItemEditorViewport; class CanvasItemEditorSelectedItem : public Object { - GDCLASS(CanvasItemEditorSelectedItem, Object); public: Transform2D prev_xform; - float prev_rot; + float prev_rot = 0; Rect2 prev_rect; Vector2 prev_pivot; - float prev_anchors[4]; + float prev_anchors[4] = { 0.0f }; Transform2D pre_drag_xform; Rect2 pre_drag_rect; @@ -61,14 +60,10 @@ public: Dictionary undo_state; - CanvasItemEditorSelectedItem() : - prev_anchors() { - prev_rot = 0; - } + CanvasItemEditorSelectedItem() {} }; class CanvasItemEditor : public VBoxContainer { - GDCLASS(CanvasItemEditor, VBoxContainer); public: @@ -119,6 +114,7 @@ private: SHOW_ORIGIN, SHOW_VIEWPORT, SHOW_EDIT_LOCKS, + SHOW_TRANSFORMATION_GIZMOS, LOCK_SELECTED, UNLOCK_SELECTED, GROUP_SELECTED, @@ -189,7 +185,6 @@ private: SKELETON_SHOW_BONES, SKELETON_SET_IK_CHAIN, SKELETON_CLEAR_IK_CHAIN - }; enum DragType { @@ -209,6 +204,8 @@ private: DRAG_ANCHOR_BOTTOM_LEFT, DRAG_ANCHOR_ALL, DRAG_MOVE, + DRAG_MOVE_X, + DRAG_MOVE_Y, DRAG_SCALE_X, DRAG_SCALE_Y, DRAG_SCALE_BOTH, @@ -231,9 +228,9 @@ private: VScrollBar *v_scroll; HBoxContainer *hb; - ToolButton *zoom_minus; - ToolButton *zoom_reset; - ToolButton *zoom_plus; + Button *zoom_minus; + Button *zoom_reset; + Button *zoom_plus; Map<Control *, Timer *> popup_temporarily_timers; @@ -248,6 +245,8 @@ private: bool show_viewport; bool show_helpers; bool show_edit_locks; + bool show_transformation_gizmos; + float zoom; Point2 view_offset; Point2 previous_update_view_offset; @@ -289,7 +288,6 @@ private: MenuOption last_option; struct _SelectResult { - CanvasItem *item; float z_index; bool has_z; @@ -300,22 +298,18 @@ private: Vector<_SelectResult> selection_results; struct _HoverResult { - Point2 position; - Ref<Texture> icon; + Ref<Texture2D> icon; String name; }; Vector<_HoverResult> hovering_results; struct BoneList { - Transform2D xform; - float length; - uint64_t last_pass; + float length = 0.f; + uint64_t last_pass = 0; - BoneList() : - length(0.f), - last_pass(0) {} + BoneList() {} }; uint64_t bone_last_frame; @@ -324,10 +318,11 @@ private: ObjectID from; ObjectID to; _FORCE_INLINE_ bool operator<(const BoneKey &p_key) const { - if (from == p_key.from) + if (from == p_key.from) { return to < p_key.to; - else + } else { return from < p_key.from; + } } }; @@ -341,31 +336,31 @@ private: }; List<PoseClipboard> pose_clipboard; - ToolButton *select_button; + Button *select_button; - ToolButton *move_button; - ToolButton *scale_button; - ToolButton *rotate_button; + Button *move_button; + Button *scale_button; + Button *rotate_button; - ToolButton *list_select_button; - ToolButton *pivot_button; - ToolButton *pan_button; + Button *list_select_button; + Button *pivot_button; + Button *pan_button; - ToolButton *ruler_button; + Button *ruler_button; - ToolButton *smart_snap_button; - ToolButton *grid_snap_button; + Button *smart_snap_button; + Button *grid_snap_button; MenuButton *snap_config_menu; PopupMenu *smartsnap_config_popup; - ToolButton *lock_button; - ToolButton *unlock_button; + Button *lock_button; + Button *unlock_button; - ToolButton *group_button; - ToolButton *ungroup_button; + Button *group_button; + Button *ungroup_button; MenuButton *skeleton_menu; - ToolButton *override_camera_button; + Button *override_camera_button; MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; @@ -374,7 +369,7 @@ private: PopupMenu *anchors_and_margins_popup; PopupMenu *anchors_popup; - ToolButton *anchor_mode_button; + Button *anchor_mode_button; Button *key_loc_button; Button *key_rot_button; @@ -402,19 +397,19 @@ private: Point2 box_selecting_to; Ref<StyleBoxTexture> select_sb; - Ref<Texture> select_handle; - Ref<Texture> anchor_handle; + Ref<Texture2D> select_handle; + Ref<Texture2D> anchor_handle; - Ref<ShortCut> drag_pivot_shortcut; - Ref<ShortCut> set_pivot_shortcut; - Ref<ShortCut> multiply_grid_step_shortcut; - Ref<ShortCut> divide_grid_step_shortcut; - Ref<ShortCut> pan_view_shortcut; + Ref<Shortcut> drag_pivot_shortcut; + Ref<Shortcut> set_pivot_shortcut; + Ref<Shortcut> multiply_grid_step_shortcut; + Ref<Shortcut> divide_grid_step_shortcut; + Ref<Shortcut> pan_view_shortcut; bool _is_node_locked(const Node *p_node); bool _is_node_movable(const Node *p_node, bool p_popup_warning = false); void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); - void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items); + void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false); void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items); void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); @@ -497,6 +492,7 @@ private: bool _gui_input_hover(const Ref<InputEvent> &p_event); void _gui_input_viewport(const Ref<InputEvent> &p_event); + void _update_cursor(); void _selection_changed(); @@ -533,6 +529,7 @@ private: VBoxContainer *controls_vb; HBoxContainer *zoom_hb; + float _get_next_zoom_value(int p_increment_count) const; void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); void _update_zoom_label(); void _button_zoom_minus(); @@ -609,7 +606,7 @@ public: SNAP_DEFAULT = SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL, }; - Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = NULL, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>()); + Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, unsigned int p_forced_modes = 0, const CanvasItem *p_self_canvas_item = nullptr, List<CanvasItem *> p_other_nodes_exceptions = List<CanvasItem *>()); float snap_angle(float p_target, float p_start = 0) const; Transform2D get_canvas_transform() const { return transform; } @@ -647,20 +644,19 @@ public: }; class CanvasItemEditorPlugin : public EditorPlugin { - GDCLASS(CanvasItemEditorPlugin, EditorPlugin); CanvasItemEditor *canvas_item_editor; EditorNode *editor; public: - virtual String get_name() const { return "2D"; } - bool has_main_screen() const { return true; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); - virtual Dictionary get_state() const; - virtual void set_state(const Dictionary &p_state); + virtual String get_name() const override { return "2D"; } + bool has_main_screen() const override { return true; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + virtual Dictionary get_state() const override; + virtual void set_state(const Dictionary &p_state) override; CanvasItemEditor *get_canvas_item_editor() { return canvas_item_editor; } @@ -683,7 +679,7 @@ class CanvasItemEditorViewport : public Control { CanvasItemEditor *canvas_item_editor; Node2D *preview_node; AcceptDialog *accept; - WindowDialog *selector; + AcceptDialog *selector; Label *selector_label; Label *label; Label *label_desc; @@ -711,8 +707,8 @@ protected: void _notification(int p_what); public: - virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const; - virtual void drop_data(const Point2 &p_point, const Variant &p_data); + virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; + virtual void drop_data(const Point2 &p_point, const Variant &p_data) override; CanvasItemEditorViewport(EditorNode *p_node, CanvasItemEditor *p_canvas_item_editor); ~CanvasItemEditorViewport(); diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp index 3d32c0b698..08d6fc966d 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -31,18 +31,16 @@ #include "collision_polygon_2d_editor_plugin.h" Node2D *CollisionPolygon2DEditor::_get_node() const { - return node; } void CollisionPolygon2DEditor::_set_node(Node *p_polygon) { - node = Object::cast_to<CollisionPolygon2D>(p_polygon); } CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { - node = NULL; + node = nullptr; } CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.h b/editor/plugins/collision_polygon_2d_editor_plugin.h index a4fa7c7b3b..482f00a7f7 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.h +++ b/editor/plugins/collision_polygon_2d_editor_plugin.h @@ -35,21 +35,19 @@ #include "scene/2d/collision_polygon_2d.h" class CollisionPolygon2DEditor : public AbstractPolygon2DEditor { - GDCLASS(CollisionPolygon2DEditor, AbstractPolygon2DEditor); CollisionPolygon2D *node; protected: - virtual Node2D *_get_node() const; - virtual void _set_node(Node *p_polygon); + virtual Node2D *_get_node() const override; + virtual void _set_node(Node *p_polygon) override; public: CollisionPolygon2DEditor(EditorNode *p_editor); }; class CollisionPolygon2DEditorPlugin : public AbstractPolygon2DEditorPlugin { - GDCLASS(CollisionPolygon2DEditorPlugin, AbstractPolygon2DEditorPlugin); public: diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp index 8620437ac6..6eb17685f6 100644 --- a/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_polygon_editor_plugin.cpp */ +/* collision_polygon_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,26 +28,24 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_polygon_editor_plugin.h" +#include "collision_polygon_3d_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "core/input/input.h" +#include "core/math/geometry_2d.h" #include "core/os/file_access.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "editor/editor_settings.h" -#include "scene/3d/camera.h" -#include "spatial_editor_plugin.h" - -void Polygon3DEditor::_notification(int p_what) { +#include "node_3d_editor_plugin.h" +#include "scene/3d/camera_3d.h" +void CollisionPolygon3DEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - - button_create->set_icon(get_icon("Edit", "EditorIcons")); - button_edit->set_icon(get_icon("MovePoint", "EditorIcons")); + button_create->set_icon(get_theme_icon("Edit", "EditorIcons")); + button_edit->set_icon(get_theme_icon("MovePoint", "EditorIcons")); button_edit->set_pressed(true); - get_tree()->connect("node_removed", this, "_node_removed"); + get_tree()->connect("node_removed", callable_mp(this, &CollisionPolygon3DEditor::_node_removed)); } break; case NOTIFICATION_PROCESS: { @@ -63,29 +61,26 @@ void Polygon3DEditor::_notification(int p_what) { } break; } } -void Polygon3DEditor::_node_removed(Node *p_node) { +void CollisionPolygon3DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; - if (imgeom->get_parent() == p_node) + node = nullptr; + if (imgeom->get_parent() == p_node) { p_node->remove_child(imgeom); + } hide(); set_process(false); } } -void Polygon3DEditor::_menu_option(int p_option) { - +void CollisionPolygon3DEditor::_menu_option(int p_option) { switch (p_option) { - case MODE_CREATE: { - mode = MODE_CREATE; button_create->set_pressed(true); button_edit->set_pressed(false); } break; case MODE_EDIT: { - mode = MODE_EDIT; button_create->set_pressed(false); button_edit->set_pressed(true); @@ -93,8 +88,7 @@ void Polygon3DEditor::_menu_option(int p_option) { } } -void Polygon3DEditor::_wip_close() { - +void CollisionPolygon3DEditor::_wip_close() { undo_redo->create_action(TTR("Create Polygon3D")); undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon")); undo_redo->add_do_method(node, "set_polygon", wip); @@ -109,10 +103,10 @@ void Polygon3DEditor::_wip_close() { undo_redo->commit_action(); } -bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { - - if (!node) +bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { + if (!node) { return false; + } Transform gt = node->get_global_transform(); Transform gi = gt.affine_inverse(); @@ -123,15 +117,15 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - Vector2 gpoint = mb->get_position(); Vector3 ray_from = p_camera->project_ray_origin(gpoint); Vector3 ray_dir = p_camera->project_ray_normal(gpoint); Vector3 spoint; - if (!p.intersects_ray(ray_from, ray_dir, &spoint)) + if (!p.intersects_ray(ray_from, ray_dir, &spoint)) { return false; + } spoint = gi.xform(spoint); @@ -147,13 +141,9 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); switch (mode) { - case MODE_CREATE: { - if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - if (!wip_active) { - wip.clear(); wip.push_back(cpoint); wip_active = true; @@ -163,14 +153,12 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu edited_point = 1; return true; } else { - if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, wip[0].y, depth))).distance_to(gpoint) < grab_threshold) { //wip closed _wip_close(); return true; } else { - wip.push_back(cpoint); edited_point = wip.size(); snap_ignore = false; @@ -185,14 +173,10 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } break; case MODE_EDIT: { - if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { - if (mb->get_control()) { - if (poly.size() < 3) { - undo_redo->create_action(TTR("Edit Poly")); undo_redo->add_undo_method(node, "set_polygon", poly); poly.push_back(cpoint); @@ -208,15 +192,15 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu Vector2 closest_pos; real_t closest_dist = 1e10; for (int i = 0; i < poly.size(); i++) { - Vector2 points[2] = { p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))), p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth))) }; - Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint, points); - if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) + Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, points); + if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) { continue; //not valid to reuse point + } real_t d = cp.distance_to(gpoint); if (d < closest_dist && d < grab_threshold) { @@ -227,7 +211,6 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } if (closest_idx >= 0) { - pre_move_edit = poly; poly.insert(closest_idx + 1, cpoint); edited_point = closest_idx + 1; @@ -239,14 +222,12 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu return true; } } else { - //look for points to move int closest_idx = -1; Vector2 closest_pos; real_t closest_dist = 1e10; for (int i = 0; i < poly.size(); i++) { - Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))); real_t d = cp.distance_to(gpoint); @@ -258,7 +239,6 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } if (closest_idx >= 0) { - pre_move_edit = poly; edited_point = closest_idx; edited_point_pos = poly[closest_idx]; @@ -268,11 +248,9 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } } } else { - snap_ignore = false; if (edited_point != -1) { - //apply ERR_FAIL_INDEX_V(edited_point, poly.size(), false); @@ -290,12 +268,10 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } } if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) { - int closest_idx = -1; Vector2 closest_pos; real_t closest_dist = 1e10; for (int i = 0; i < poly.size(); i++) { - Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))); real_t d = cp.distance_to(gpoint); @@ -307,7 +283,6 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu } if (closest_idx >= 0) { - undo_redo->create_action(TTR("Edit Poly (Remove Point)")); undo_redo->add_undo_method(node, "set_polygon", poly); poly.remove(closest_idx); @@ -327,7 +302,6 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu if (mm.is_valid()) { if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) { - Vector2 gpoint = mm->get_position(); Vector3 ray_from = p_camera->project_ray_origin(gpoint); @@ -335,8 +309,9 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu Vector3 spoint; - if (!p.intersects_ray(ray_from, ray_dir, &spoint)) + if (!p.intersects_ray(ray_from, ray_dir, &spoint)) { return false; + } spoint = gi.xform(spoint); @@ -346,10 +321,10 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu snap_ignore = false; } - if (!snap_ignore && SpatialEditor::get_singleton()->is_snap_enabled()) { + if (!snap_ignore && Node3DEditor::get_singleton()->is_snap_enabled()) { cpoint = cpoint.snapped(Vector2( - SpatialEditor::get_singleton()->get_translate_snap(), - SpatialEditor::get_singleton()->get_translate_snap())); + Node3DEditor::get_singleton()->get_translate_snap(), + Node3DEditor::get_singleton()->get_translate_snap())); } edited_point_pos = cpoint; @@ -360,47 +335,49 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu return false; } -float Polygon3DEditor::_get_depth() { - - if (bool(node->call("_has_editable_3d_polygon_no_depth"))) +float CollisionPolygon3DEditor::_get_depth() { + if (bool(node->call("_has_editable_3d_polygon_no_depth"))) { return 0; + } return float(node->call("get_depth")); } -void Polygon3DEditor::_polygon_draw() { - - if (!node) +void CollisionPolygon3DEditor::_polygon_draw() { + if (!node) { return; + } Vector<Vector2> poly; - if (wip_active) + if (wip_active) { poly = wip; - else + } else { poly = node->call("get_polygon"); + } float depth = _get_depth() * 0.5; imgeom->clear(); imgeom->set_material_override(line_material); - imgeom->begin(Mesh::PRIMITIVE_LINES, Ref<Texture>()); + imgeom->begin(Mesh::PRIMITIVE_LINES, Ref<Texture2D>()); Rect2 rect; for (int i = 0; i < poly.size(); i++) { - Vector2 p, p2; p = i == edited_point ? edited_point_pos : poly[i]; - if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point)) + if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point)) { p2 = edited_point_pos; - else + } else { p2 = poly[(i + 1) % poly.size()]; + } - if (i == 0) + if (i == 0) { rect.position = p; - else + } else { rect.expand_to(p); + } Vector3 point = Vector3(p.x, p.y, depth); Vector3 next_point = Vector3(p2.x, p2.y, depth); @@ -463,22 +440,19 @@ void Polygon3DEditor::_polygon_draw() { imgeom->end(); - while (m->get_surface_count()) { - m->surface_remove(0); - } + m->clear_surfaces(); - if (poly.size() == 0) + if (poly.size() == 0) { return; + } Array a; a.resize(Mesh::ARRAY_MAX); - PoolVector<Vector3> va; + Vector<Vector3> va; { - va.resize(poly.size()); - PoolVector<Vector3>::Write w = va.write(); + Vector3 *w = va.ptrw(); for (int i = 0; i < poly.size(); i++) { - Vector2 p, p2; p = i == edited_point ? edited_point_pos : poly[i]; @@ -491,11 +465,9 @@ void Polygon3DEditor::_polygon_draw() { m->surface_set_material(0, handle_material); } -void Polygon3DEditor::edit(Node *p_collision_polygon) { - +void CollisionPolygon3DEditor::edit(Node *p_collision_polygon) { if (p_collision_polygon) { - - node = Object::cast_to<Spatial>(p_collision_polygon); + node = Object::cast_to<Node3D>(p_collision_polygon); //Enable the pencil tool if the polygon is empty if (Vector<Vector2>(node->call("get_polygon")).size() == 0) { _menu_option(MODE_CREATE); @@ -509,63 +481,61 @@ void Polygon3DEditor::edit(Node *p_collision_polygon) { prev_depth = -1; } else { - node = NULL; + node = nullptr; - if (imgeom->get_parent()) + if (imgeom->get_parent()) { imgeom->get_parent()->remove_child(imgeom); + } set_process(false); } } -void Polygon3DEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_menu_option"), &Polygon3DEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_polygon_draw"), &Polygon3DEditor::_polygon_draw); - ClassDB::bind_method(D_METHOD("_node_removed"), &Polygon3DEditor::_node_removed); +void CollisionPolygon3DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_polygon_draw"), &CollisionPolygon3DEditor::_polygon_draw); } -Polygon3DEditor::Polygon3DEditor(EditorNode *p_editor) { - - node = NULL; +CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) { + node = nullptr; editor = p_editor; undo_redo = EditorNode::get_undo_redo(); add_child(memnew(VSeparator)); - button_create = memnew(ToolButton); + button_create = memnew(Button); + button_create->set_flat(true); add_child(button_create); - button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE)); + button_create->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_CREATE)); button_create->set_toggle_mode(true); - button_edit = memnew(ToolButton); + button_edit = memnew(Button); + button_edit->set_flat(true); add_child(button_edit); - button_edit->connect("pressed", this, "_menu_option", varray(MODE_EDIT)); + button_edit->connect("pressed", callable_mp(this, &CollisionPolygon3DEditor::_menu_option), varray(MODE_EDIT)); button_edit->set_toggle_mode(true); mode = MODE_EDIT; wip_active = false; - imgeom = memnew(ImmediateGeometry); + imgeom = memnew(ImmediateGeometry3D); imgeom->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001))); - line_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - line_material->set_line_width(3.0); - line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - line_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); + line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); line_material->set_albedo(Color(1, 1, 1)); - handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); - handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - Ref<Texture> handle = editor->get_gui_base()->get_icon("Editor3DHandle", "EditorIcons"); + handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); + handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true); + handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + Ref<Texture2D> handle = editor->get_gui_base()->get_theme_icon("Editor3DHandle", "EditorIcons"); handle_material->set_point_size(handle->get_width()); - handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle); + handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle); - pointsm = memnew(MeshInstance); + pointsm = memnew(MeshInstance3D); imgeom->add_child(pointsm); m.instance(); pointsm->set_mesh(m); @@ -574,37 +544,31 @@ Polygon3DEditor::Polygon3DEditor(EditorNode *p_editor) { snap_ignore = false; } -Polygon3DEditor::~Polygon3DEditor() { - +CollisionPolygon3DEditor::~CollisionPolygon3DEditor() { memdelete(imgeom); } void Polygon3DEditorPlugin::edit(Object *p_object) { - collision_polygon_editor->edit(Object::cast_to<Node>(p_object)); } bool Polygon3DEditorPlugin::handles(Object *p_object) const { - - return Object::cast_to<Spatial>(p_object) && bool(p_object->call("_is_editable_3d_polygon")); + return Object::cast_to<Node3D>(p_object) && bool(p_object->call("_is_editable_3d_polygon")); } void Polygon3DEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { collision_polygon_editor->show(); } else { - collision_polygon_editor->hide(); - collision_polygon_editor->edit(NULL); + collision_polygon_editor->edit(nullptr); } } Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) { - editor = p_node; - collision_polygon_editor = memnew(Polygon3DEditor(p_node)); - SpatialEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); + collision_polygon_editor = memnew(CollisionPolygon3DEditor(p_node)); + Node3DEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor); collision_polygon_editor->hide(); } diff --git a/editor/plugins/collision_polygon_editor_plugin.h b/editor/plugins/collision_polygon_3d_editor_plugin.h index 1871c6ee7e..98f499031a 100644 --- a/editor/plugins/collision_polygon_editor_plugin.h +++ b/editor/plugins/collision_polygon_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_polygon_editor_plugin.h */ +/* collision_polygon_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,16 +33,14 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/collision_polygon.h" -#include "scene/3d/immediate_geometry.h" -#include "scene/3d/mesh_instance.h" -#include "scene/gui/tool_button.h" +#include "scene/3d/collision_polygon_3d.h" +#include "scene/3d/immediate_geometry_3d.h" +#include "scene/3d/mesh_instance_3d.h" class CanvasItemEditor; -class Polygon3DEditor : public HBoxContainer { - - GDCLASS(Polygon3DEditor, HBoxContainer); +class CollisionPolygon3DEditor : public HBoxContainer { + GDCLASS(CollisionPolygon3DEditor, HBoxContainer); UndoRedo *undo_redo; enum Mode { @@ -54,17 +52,17 @@ class Polygon3DEditor : public HBoxContainer { Mode mode; - ToolButton *button_create; - ToolButton *button_edit; + Button *button_create; + Button *button_edit; - Ref<SpatialMaterial> line_material; - Ref<SpatialMaterial> handle_material; + Ref<StandardMaterial3D> line_material; + Ref<StandardMaterial3D> handle_material; EditorNode *editor; Panel *panel; - Spatial *node; - ImmediateGeometry *imgeom; - MeshInstance *pointsm; + Node3D *node; + ImmediateGeometry3D *imgeom; + MeshInstance3D *pointsm; Ref<ArrayMesh> m; MenuButton *options; @@ -90,27 +88,26 @@ protected: static void _bind_methods(); public: - virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); + virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event); void edit(Node *p_collision_polygon); - Polygon3DEditor(EditorNode *p_editor); - ~Polygon3DEditor(); + CollisionPolygon3DEditor(EditorNode *p_editor); + ~CollisionPolygon3DEditor(); }; class Polygon3DEditorPlugin : public EditorPlugin { - GDCLASS(Polygon3DEditorPlugin, EditorPlugin); - Polygon3DEditor *collision_polygon_editor; + CollisionPolygon3DEditor *collision_polygon_editor; EditorNode *editor; public: - virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); } + virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); } - virtual String get_name() const { return "Polygon3DEditor"; } - 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); + virtual String get_name() const override { return "Polygon3DEditor"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; Polygon3DEditorPlugin(EditorNode *p_node); ~Polygon3DEditorPlugin(); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index be9e5b0e3a..105ac24950 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -36,11 +36,17 @@ #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/ray_shape_2d.h" #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/segment_shape_2d.h" -Variant CollisionShape2DEditor::get_handle_value(int idx) const { +void CollisionShape2DEditor::_node_removed(Node *p_node) { + if (p_node == node) { + node = nullptr; + } +} +Variant CollisionShape2DEditor::get_handle_value(int idx) const { switch (shape_type) { case CAPSULE_SHAPE: { Ref<CapsuleShape2D> capsule = node->get_shape(); @@ -63,18 +69,16 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const { } break; case CONCAVE_POLYGON_SHAPE: { - } break; case CONVEX_POLYGON_SHAPE: { - } break; case LINE_SHAPE: { Ref<LineShape2D> line = node->get_shape(); if (idx == 0) { - return line->get_d(); + return line->get_distance(); } else { return line->get_normal(); } @@ -115,7 +119,6 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const { } void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { - switch (shape_type) { case CAPSULE_SHAPE: { if (idx < 2) { @@ -143,11 +146,9 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { } break; case CONCAVE_POLYGON_SHAPE: { - } break; case CONVEX_POLYGON_SHAPE: { - } break; case LINE_SHAPE: { @@ -155,7 +156,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { Ref<LineShape2D> line = node->get_shape(); if (idx == 0) { - line->set_d(p_point.length()); + line->set_distance(p_point.length()); } else { line->set_normal(p_point.normalized()); } @@ -210,7 +211,6 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) { } void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { - undo_redo->create_action(TTR("Set Handle")); switch (shape_type) { @@ -242,20 +242,20 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { } break; case CONCAVE_POLYGON_SHAPE: { - + // Cannot be edited directly, use CollisionPolygon2D instead. } break; case CONVEX_POLYGON_SHAPE: { - + // Cannot be edited directly, use CollisionPolygon2D instead. } break; case LINE_SHAPE: { Ref<LineShape2D> line = node->get_shape(); if (idx == 0) { - undo_redo->add_do_method(line.ptr(), "set_d", line->get_d()); + undo_redo->add_do_method(line.ptr(), "set_distance", line->get_distance()); undo_redo->add_do_method(canvas_item_editor, "update_viewport"); - undo_redo->add_undo_method(line.ptr(), "set_d", p_org); + undo_redo->add_undo_method(line.ptr(), "set_distance", p_org); undo_redo->add_undo_method(canvas_item_editor, "update_viewport"); } else { undo_redo->add_do_method(line.ptr(), "set_normal", line->get_normal()); @@ -307,7 +307,6 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) { } bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { - if (!node) { return false; } @@ -324,7 +323,6 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); if (mb.is_valid()) { - Vector2 gpoint = mb->get_position(); if (mb->get_button_index() == BUTTON_LEFT) { @@ -366,7 +364,6 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (edit_handle == -1 || !pressed) { return false; } @@ -383,7 +380,6 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e } void CollisionShape2DEditor::_get_current_shape_type() { - if (!node) { return; } @@ -418,7 +414,6 @@ void CollisionShape2DEditor::_get_current_shape_type() { } void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (!node) { return; } @@ -435,7 +430,7 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - Ref<Texture> h = get_icon("EditorHandle", "EditorIcons"); + Ref<Texture2D> h = get_theme_icon("EditorHandle", "EditorIcons"); Vector2 size = h->get_size() * 0.5; handles.clear(); @@ -448,8 +443,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla float radius = shape->get_radius(); float height = shape->get_height() / 2; - handles.write[0] = Point2(radius, -height); - handles.write[1] = Point2(0, -(height + radius)); + handles.write[0] = Point2(radius, height); + handles.write[1] = Point2(0, height + radius); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -467,19 +462,17 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla } break; case CONCAVE_POLYGON_SHAPE: { - } break; case CONVEX_POLYGON_SHAPE: { - } break; case LINE_SHAPE: { Ref<LineShape2D> shape = node->get_shape(); handles.resize(2); - handles.write[0] = shape->get_normal() * shape->get_d(); - handles.write[1] = shape->get_normal() * (shape->get_d() + 30.0); + handles.write[0] = shape->get_normal() * shape->get_distance(); + handles.write[1] = shape->get_normal() * (shape->get_distance() + 30.0); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -502,8 +495,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla handles.resize(3); Vector2 ext = shape->get_extents(); handles.write[0] = Point2(ext.x, 0); - handles.write[1] = Point2(0, -ext.y); - handles.write[2] = Point2(ext.x, -ext.y); + handles.write[1] = Point2(0, ext.y); + handles.write[2] = Point2(ext.x, ext.y); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -525,8 +518,19 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla } } -void CollisionShape2DEditor::edit(Node *p_node) { +void CollisionShape2DEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + get_tree()->connect("node_removed", callable_mp(this, &CollisionShape2DEditor::_node_removed)); + } break; + + case NOTIFICATION_EXIT_TREE: { + get_tree()->disconnect("node_removed", callable_mp(this, &CollisionShape2DEditor::_node_removed)); + } break; + } +} +void CollisionShape2DEditor::edit(Node *p_node) { if (!canvas_item_editor) { canvas_item_editor = CanvasItemEditor::get_singleton(); } @@ -540,21 +544,19 @@ void CollisionShape2DEditor::edit(Node *p_node) { edit_handle = -1; shape_type = -1; - node = NULL; + node = nullptr; } canvas_item_editor->update_viewport(); } void CollisionShape2DEditor::_bind_methods() { - ClassDB::bind_method("_get_current_shape_type", &CollisionShape2DEditor::_get_current_shape_type); } CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) { - - node = NULL; - canvas_item_editor = NULL; + node = nullptr; + canvas_item_editor = nullptr; editor = p_editor; undo_redo = p_editor->get_undo_redo(); @@ -564,24 +566,20 @@ CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) { } void CollisionShape2DEditorPlugin::edit(Object *p_obj) { - collision_shape_2d_editor->edit(Object::cast_to<Node>(p_obj)); } bool CollisionShape2DEditorPlugin::handles(Object *p_obj) const { - return p_obj->is_class("CollisionShape2D"); } void CollisionShape2DEditorPlugin::make_visible(bool visible) { - if (!visible) { - edit(NULL); + edit(nullptr); } } CollisionShape2DEditorPlugin::CollisionShape2DEditorPlugin(EditorNode *p_editor) { - editor = p_editor; collision_shape_2d_editor = memnew(CollisionShape2DEditor(p_editor)); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index 025420a886..083ceb4b38 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -71,6 +71,8 @@ class CollisionShape2DEditor : public Control { void _get_current_shape_type(); protected: + void _notification(int p_what); + void _node_removed(Node *p_node); static void _bind_methods(); public: @@ -88,14 +90,14 @@ class CollisionShape2DEditorPlugin : public EditorPlugin { EditorNode *editor; public: - virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { collision_shape_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } - - virtual String get_name() const { return "CollisionShape2D"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_obj); - virtual bool handles(Object *p_obj) const; - virtual void make_visible(bool visible); + virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { collision_shape_2d_editor->forward_canvas_draw_over_viewport(p_overlay); } + + virtual String get_name() const override { return "CollisionShape2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_obj) override; + virtual bool handles(Object *p_obj) const override; + virtual void make_visible(bool visible) override; CollisionShape2DEditorPlugin(EditorNode *p_editor); ~CollisionShape2DEditorPlugin(); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 655048c271..32f7d02af2 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -37,53 +37,42 @@ #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(); + emission_mask->popup_centered(); } void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) { - switch (p_idx) { case MENU_LOAD_EMISSION_MASK: { - - file->popup_centered_ratio(); + file->popup_file_dialog(); } break; case MENU_CLEAR_EMISSION_MASK: { - - emission_mask->popup_centered_minsize(); + emission_mask->popup_centered(); } break; case MENU_RESTART: { - particles->restart(); } } } void CPUParticles2DEditorPlugin::_generate_emission_mask() { - Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); @@ -118,18 +107,15 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { int vpc = 0; { - PoolVector<uint8_t> data = img->get_data(); - PoolVector<uint8_t>::Read r = data.read(); + Vector<uint8_t> data = img->get_data(); + const uint8_t *r = data.ptr(); 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]; @@ -139,19 +125,18 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { 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) + if (on_border) { break; + } } if (on_border) { @@ -161,9 +146,9 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { 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) + 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(); @@ -198,9 +183,9 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); if (capture_colors) { - PoolColorArray pca; + PackedColorArray pca; pca.resize(vpc); - PoolColorArray::Write pcaw = pca.write(); + Color *pcaw = pca.ptrw(); for (int i = 0; i < vpc; i += 1) { Color color; color.r = valid_colors[i * 4 + 0] / 255.0f; @@ -214,9 +199,9 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { if (valid_normals.size()) { particles->set_emission_shape(CPUParticles2D::EMISSION_SHAPE_DIRECTED_POINTS); - PoolVector2Array norms; + PackedVector2Array norms; norms.resize(valid_normals.size()); - PoolVector2Array::Write normsw = norms.write(); + Vector2 *normsw = norms.ptrw(); for (int i = 0; i < valid_normals.size(); i += 1) { normsw[i] = valid_normals[i]; } @@ -226,9 +211,9 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { } { - PoolVector2Array points; + PackedVector2Array points; points.resize(valid_positions.size()); - PoolVector2Array::Write pointsw = points.write(); + Vector2 *pointsw = points.ptrw(); for (int i = 0; i < valid_positions.size(); i += 1) { pointsw[i] = valid_positions[i]; } @@ -237,25 +222,18 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { } 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"); + menu->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles2DEditorPlugin::_menu_callback)); + menu->set_icon(epoints->get_theme_icon("CPUParticles2D", "EditorIcons")); + file->connect("file_selected", callable_mp(this, &CPUParticles2DEditorPlugin::_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; + particles = nullptr; editor = p_node; undo_redo = editor->get_undo_redo(); @@ -266,11 +244,9 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { 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_separator(); menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); - // menu->get_popup()->add_item(TTR("Clear Emission Mask"), MENU_CLEAR_EMISSION_MASK); - menu->set_text(TTR("Particles")); + menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK); + menu->set_text(TTR("CPUParticles2D")); menu->set_switch_on_hover(true); toolbar->add_child(menu); @@ -280,7 +256,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { 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); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); toolbar->add_child(file); epoints = memnew(SpinBox); @@ -305,7 +281,7 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(emission_mask); - emission_mask->connect("confirmed", this, "_generate_emission_mask"); + emission_mask->connect("confirmed", callable_mp(this, &CPUParticles2DEditorPlugin::_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 index 21b06b6489..58984d6d16 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -39,7 +39,6 @@ #include "scene/gui/file_dialog.h" class CPUParticles2DEditorPlugin : public EditorPlugin { - GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin); enum { @@ -80,11 +79,11 @@ protected: 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); + virtual String get_name() const override { return "CPUParticles2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; CPUParticles2DEditorPlugin(EditorNode *p_node); ~CPUParticles2DEditorPlugin(); diff --git a/editor/plugins/cpu_particles_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index 2074ba6b99..d44e487ae4 100644 --- a/editor/plugins/cpu_particles_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* cpu_particles_editor_plugin.cpp */ +/* cpu_particles_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,127 +28,104 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "cpu_particles_editor_plugin.h" +#include "cpu_particles_3d_editor_plugin.h" -#include "editor/plugins/spatial_editor_plugin.h" - -void CPUParticlesEditor::_node_removed(Node *p_node) { +#include "editor/plugins/node_3d_editor_plugin.h" +void CPUParticles3DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; + node = nullptr; hide(); } } -void CPUParticlesEditor::_notification(int p_notification) { - +void CPUParticles3DEditor::_notification(int p_notification) { if (p_notification == NOTIFICATION_ENTER_TREE) { - options->set_icon(options->get_popup()->get_icon("CPUParticles", "EditorIcons")); + options->set_icon(get_theme_icon("CPUParticles3D", "EditorIcons")); } } -void CPUParticlesEditor::_menu_option(int p_option) { - +void CPUParticles3DEditor::_menu_option(int p_option) { switch (p_option) { - - case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { - - emission_file_dialog->popup_centered_ratio(); - - } break; - case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: { - - emission_tree_dialog->popup_centered_ratio(); + emission_tree_dialog->popup_scenetree_dialog(); } break; case MENU_OPTION_RESTART: { - node->restart(); } break; } } -void CPUParticlesEditor::edit(CPUParticles *p_particles) { - +void CPUParticles3DEditor::edit(CPUParticles3D *p_particles) { base_node = p_particles; node = p_particles; } -void CPUParticlesEditor::_generate_emission_points() { - +void CPUParticles3DEditor::_generate_emission_points() { /// hacer codigo aca - PoolVector<Vector3> points; - PoolVector<Vector3> normals; + Vector<Vector3> points; + Vector<Vector3> normals; if (!_generate(points, normals)) { return; } if (normals.size() == 0) { - node->set_emission_shape(CPUParticles::EMISSION_SHAPE_POINTS); + node->set_emission_shape(CPUParticles3D::EMISSION_SHAPE_POINTS); node->set_emission_points(points); } else { - node->set_emission_shape(CPUParticles::EMISSION_SHAPE_DIRECTED_POINTS); + node->set_emission_shape(CPUParticles3D::EMISSION_SHAPE_DIRECTED_POINTS); node->set_emission_points(points); node->set_emission_normals(normals); } } -void CPUParticlesEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &CPUParticlesEditor::_menu_option); +void CPUParticles3DEditor::_bind_methods() { } -CPUParticlesEditor::CPUParticlesEditor() { - +CPUParticles3DEditor::CPUParticles3DEditor() { particles_editor_hb = memnew(HBoxContainer); - SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); + Node3DEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); options = memnew(MenuButton); options->set_switch_on_hover(true); particles_editor_hb->add_child(options); particles_editor_hb->hide(); - options->set_text(TTR("CPUParticles")); - options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH); - options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); - options->get_popup()->add_separator(); + options->set_text(TTR("CPUParticles3D")); options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); + options->get_popup()->connect("id_pressed", callable_mp(this, &CPUParticles3DEditor::_menu_option)); } -void CPUParticlesEditorPlugin::edit(Object *p_object) { - - particles_editor->edit(Object::cast_to<CPUParticles>(p_object)); +void CPUParticles3DEditorPlugin::edit(Object *p_object) { + particles_editor->edit(Object::cast_to<CPUParticles3D>(p_object)); } -bool CPUParticlesEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("CPUParticles"); +bool CPUParticles3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("CPUParticles3D"); } -void CPUParticlesEditorPlugin::make_visible(bool p_visible) { - +void CPUParticles3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { particles_editor->show(); particles_editor->particles_editor_hb->show(); } else { particles_editor->particles_editor_hb->hide(); particles_editor->hide(); - particles_editor->edit(NULL); + particles_editor->edit(nullptr); } } -CPUParticlesEditorPlugin::CPUParticlesEditorPlugin(EditorNode *p_node) { - +CPUParticles3DEditorPlugin::CPUParticles3DEditorPlugin(EditorNode *p_node) { editor = p_node; - particles_editor = memnew(CPUParticlesEditor); + particles_editor = memnew(CPUParticles3DEditor); editor->get_viewport()->add_child(particles_editor); particles_editor->hide(); } -CPUParticlesEditorPlugin::~CPUParticlesEditorPlugin() { +CPUParticles3DEditorPlugin::~CPUParticles3DEditorPlugin() { } diff --git a/editor/plugins/cpu_particles_editor_plugin.h b/editor/plugins/cpu_particles_3d_editor_plugin.h index deaced9ad9..90300daf71 100644 --- a/editor/plugins/cpu_particles_editor_plugin.h +++ b/editor/plugins/cpu_particles_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* cpu_particles_editor_plugin.h */ +/* cpu_particles_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,29 +31,27 @@ #ifndef CPU_PARTICLES_EDITOR_PLUGIN_H #define CPU_PARTICLES_EDITOR_PLUGIN_H -#include "editor/plugins/particles_editor_plugin.h" -#include "scene/3d/cpu_particles.h" +#include "editor/plugins/gpu_particles_3d_editor_plugin.h" +#include "scene/3d/cpu_particles_3d.h" -class CPUParticlesEditor : public ParticlesEditorBase { - - GDCLASS(CPUParticlesEditor, ParticlesEditorBase); +class CPUParticles3DEditor : public GPUParticles3DEditorBase { + GDCLASS(CPUParticles3DEditor, GPUParticles3DEditorBase); enum Menu { MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE, - MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH, MENU_OPTION_CLEAR_EMISSION_VOLUME, MENU_OPTION_RESTART }; - CPUParticles *node; + CPUParticles3D *node; void _menu_option(int); - friend class CPUParticlesEditorPlugin; + friend class CPUParticles3DEditorPlugin; - virtual void _generate_emission_points(); + virtual void _generate_emission_points() override; protected: void _notification(int p_notification); @@ -61,26 +59,25 @@ protected: static void _bind_methods(); public: - void edit(CPUParticles *p_particles); - CPUParticlesEditor(); + void edit(CPUParticles3D *p_particles); + CPUParticles3DEditor(); }; -class CPUParticlesEditorPlugin : public EditorPlugin { - - GDCLASS(CPUParticlesEditorPlugin, EditorPlugin); +class CPUParticles3DEditorPlugin : public EditorPlugin { + GDCLASS(CPUParticles3DEditorPlugin, EditorPlugin); - CPUParticlesEditor *particles_editor; + CPUParticles3DEditor *particles_editor; EditorNode *editor; public: - virtual String get_name() const { return "CPUParticles"; } - 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); - - CPUParticlesEditorPlugin(EditorNode *p_node); - ~CPUParticlesEditorPlugin(); + virtual String get_name() const override { return "CPUParticles3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + CPUParticles3DEditorPlugin(EditorNode *p_node); + ~CPUParticles3DEditorPlugin(); }; #endif // CPU_PARTICLES_EDITOR_PLUGIN_H diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index a4fc9b37ad..539ab03f5b 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -32,7 +32,7 @@ #include "canvas_item_editor_plugin.h" #include "core/core_string_names.h" -#include "core/os/input.h" +#include "core/input/input.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" @@ -49,7 +49,7 @@ CurveEditor::CurveEditor() { set_clip_contents(true); _context_menu = memnew(PopupMenu); - _context_menu->connect("id_pressed", this, "_on_context_menu_item_selected"); + _context_menu->connect("id_pressed", callable_mp(this, &CurveEditor::on_context_menu_item_selected)); add_child(_context_menu); _presets_menu = memnew(PopupMenu); @@ -60,25 +60,25 @@ CurveEditor::CurveEditor() { _presets_menu->add_item(TTR("Ease In"), PRESET_EASE_IN); _presets_menu->add_item(TTR("Ease Out"), PRESET_EASE_OUT); _presets_menu->add_item(TTR("Smoothstep"), PRESET_SMOOTHSTEP); - _presets_menu->connect("id_pressed", this, "_on_preset_item_selected"); + _presets_menu->connect("id_pressed", callable_mp(this, &CurveEditor::on_preset_item_selected)); _context_menu->add_child(_presets_menu); } void CurveEditor::set_curve(Ref<Curve> curve) { - - if (curve == _curve_ref) + if (curve == _curve_ref) { return; + } if (_curve_ref.is_valid()) { - _curve_ref->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); - _curve_ref->disconnect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); + _curve_ref->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveEditor::_curve_changed)); + _curve_ref->disconnect(Curve::SIGNAL_RANGE_CHANGED, callable_mp(this, &CurveEditor::_curve_changed)); } _curve_ref = curve; if (_curve_ref.is_valid()) { - _curve_ref->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); - _curve_ref->connect(Curve::SIGNAL_RANGE_CHANGED, this, "_curve_changed"); + _curve_ref->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CurveEditor::_curve_changed)); + _curve_ref->connect(Curve::SIGNAL_RANGE_CHANGED, callable_mp(this, &CurveEditor::_curve_changed)); } _selected_point = -1; @@ -96,24 +96,23 @@ Size2 CurveEditor::get_minimum_size() const { } void CurveEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) + if (p_what == NOTIFICATION_DRAW) { _draw(); + } } void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb_ref = p_event; if (mb_ref.is_valid()) { - const InputEventMouseButton &mb = **mb_ref; if (mb.is_pressed() && !_dragging) { - Vector2 mpos = mb.get_position(); _selected_tangent = get_tangent_at(mpos); - if (_selected_tangent == TANGENT_NONE) + if (_selected_tangent == TANGENT_NONE) { set_selected_point(get_point_at(mpos)); + } switch (mb.get_button_index()) { case BUTTON_RIGHT: @@ -134,7 +133,6 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) { _dragging = false; if (_has_undo_data) { - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); @@ -151,13 +149,11 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm_ref = p_event; if (mm_ref.is_valid()) { - const InputEventMouseMotion &mm = **mm_ref; Vector2 mpos = mm.get_position(); if (_dragging && _curve_ref.is_valid()) { - if (_selected_point != -1) { Curve &curve = **_curve_ref; @@ -189,10 +185,11 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { set_selected_point(i); // This is to prevent the user from losing a point out of view. - if (point_pos.y < curve.get_min_value()) + if (point_pos.y < curve.get_min_value()) { point_pos.y = curve.get_min_value(); - else if (point_pos.y > curve.get_max_value()) + } else if (point_pos.y > curve.get_max_value()) { point_pos.y = curve.get_max_value(); + } curve.set_point_value(_selected_point, point_pos.y); @@ -205,10 +202,11 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { Vector2 dir = (control_pos - point_pos).normalized(); real_t tangent; - if (!Math::is_zero_approx(dir.x)) + if (!Math::is_zero_approx(dir.x)) { tangent = dir.y / dir.x; - else + } else { tangent = 9999 * (dir.y >= 0 ? 1 : -1); + } bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT); @@ -216,14 +214,16 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { curve.set_point_left_tangent(_selected_point, tangent); // Note: if a tangent is set to linear, it shouldn't be linked to the other - if (link && _selected_point != (curve.get_point_count() - 1) && curve.get_point_right_mode(_selected_point) != Curve::TANGENT_LINEAR) + if (link && _selected_point != (curve.get_point_count() - 1) && curve.get_point_right_mode(_selected_point) != Curve::TANGENT_LINEAR) { curve.set_point_right_tangent(_selected_point, tangent); + } } else { curve.set_point_right_tangent(_selected_point, tangent); - if (link && _selected_point != 0 && curve.get_point_left_mode(_selected_point) != Curve::TANGENT_LINEAR) + if (link && _selected_point != 0 && curve.get_point_left_mode(_selected_point) != Curve::TANGENT_LINEAR) { curve.set_point_left_tangent(_selected_point, tangent); + } } } } @@ -238,8 +238,9 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { const InputEventKey &key = **key_ref; if (key.is_pressed() && _selected_point != -1) { - if (key.get_scancode() == KEY_DELETE) + if (key.get_keycode() == KEY_DELETE) { remove_point(_selected_point); + } } } } @@ -358,8 +359,9 @@ void CurveEditor::open_context_menu(Vector2 pos) { _context_menu->set_item_checked(_context_menu->get_item_index(CONTEXT_LINEAR), is_linear); } else { - if (_selected_point > 0 || _selected_point + 1 < _curve_ref->get_point_count()) + if (_selected_point > 0 || _selected_point + 1 < _curve_ref->get_point_count()) { _context_menu->add_separator(); + } if (_selected_point > 0) { _context_menu->add_check_item(TTR("Left Linear"), CONTEXT_LEFT_LINEAR); @@ -384,8 +386,9 @@ void CurveEditor::open_context_menu(Vector2 pos) { } int CurveEditor::get_point_at(Vector2 pos) const { - if (_curve_ref.is_null()) + if (_curve_ref.is_null()) { return -1; + } const Curve &curve = **_curve_ref; const float r = _hover_radius * _hover_radius; @@ -401,8 +404,9 @@ int CurveEditor::get_point_at(Vector2 pos) const { } CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { - if (_curve_ref.is_null() || _selected_point < 0) + if (_curve_ref.is_null() || _selected_point < 0) { return TANGENT_NONE; + } if (_selected_point != 0) { Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_LEFT); @@ -428,10 +432,11 @@ void CurveEditor::add_point(Vector2 pos) { ur.create_action(TTR("Remove Curve Point")); Vector2 point_pos = get_world_pos(pos); - if (point_pos.y < 0.0) + if (point_pos.y < 0.0) { point_pos.y = 0.0; - else if (point_pos.y > 1.0) + } else if (point_pos.y > 1.0) { point_pos.y = 1.0; + } // Small trick to get the point index to feed the undo method int i = _curve_ref->add_point(point_pos); @@ -454,11 +459,13 @@ void CurveEditor::remove_point(int index) { ur.add_do_method(*_curve_ref, "remove_point", index); ur.add_undo_method(*_curve_ref, "add_point", p.pos, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); - if (index == _selected_point) + if (index == _selected_point) { set_selected_point(-1); + } - if (index == _hover_point) + if (index == _hover_point) { set_hover_point_index(-1); + } ur.commit_action(); } @@ -469,11 +476,11 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); ur.create_action(TTR("Toggle Curve Linear Tangent")); - if (tangent == TANGENT_NONE) + if (tangent == TANGENT_NONE) { tangent = _selected_tangent; + } if (tangent == TANGENT_LEFT) { - bool is_linear = _curve_ref->get_point_left_mode(_selected_point) == Curve::TANGENT_LINEAR; Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point); @@ -483,7 +490,6 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); } else { - bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point); @@ -511,7 +517,7 @@ void CurveEditor::set_hover_point_index(int index) { } void CurveEditor::update_view_transform() { - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); const real_t margin = font->get_height() + 2 * EDSCALE; float min_y = 0; @@ -538,12 +544,12 @@ void CurveEditor::update_view_transform() { } Vector2 CurveEditor::get_tangent_view_pos(int i, TangentIndex tangent) const { - Vector2 dir; - if (tangent == TANGENT_LEFT) + if (tangent == TANGENT_LEFT) { dir = -Vector2(1, _curve_ref->get_point_left_tangent(i)); - else + } else { dir = Vector2(1, _curve_ref->get_point_right_tangent(i)); + } Vector2 point_pos = get_view_pos(_curve_ref->get_point_position(i)); Vector2 control_pos = get_view_pos(_curve_ref->get_point_position(i) + dir); @@ -562,7 +568,6 @@ Vector2 CurveEditor::get_world_pos(Vector2 view_pos) const { // Uses non-baked points, but takes advantage of ordered iteration to be faster template <typename T> static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { - if (curve.get_point_count() <= 1) { // Not enough points to make a curve, so it's just a straight line float y = curve.interpolate(0); @@ -600,7 +605,6 @@ static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { } struct CanvasItemPlotCurve { - CanvasItem &ci; Color color1; Color color2; @@ -612,13 +616,14 @@ struct CanvasItemPlotCurve { void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) { // FIXME: Using a line width greater than 1 breaks curve rendering - ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1, true); + ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1); } }; void CurveEditor::_draw() { - if (_curve_ref.is_null()) + if (_curve_ref.is_null()) { return; + } Curve &curve = **_curve_ref; update_view_transform(); @@ -626,7 +631,7 @@ void CurveEditor::_draw() { // Background Vector2 view_size = get_rect().size; - draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), view_size)); + draw_style_box(get_theme_stylebox("bg", "Tree"), Rect2(Point2(), view_size)); // Grid @@ -635,8 +640,8 @@ void CurveEditor::_draw() { Vector2 min_edge = get_world_pos(Vector2(0, view_size.y)); Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0)); - const Color grid_color0 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.15); - const Color grid_color1 = get_color("mono_color", "Editor") * Color(1, 1, 1, 0.07); + const Color grid_color0 = get_theme_color("mono_color", "Editor") * Color(1, 1, 1, 0.15); + const Color grid_color1 = get_theme_color("mono_color", "Editor") * Color(1, 1, 1, 0.07); draw_line(Vector2(min_edge.x, curve.get_min_value()), Vector2(max_edge.x, curve.get_min_value()), grid_color0); draw_line(Vector2(max_edge.x, curve.get_max_value()), Vector2(min_edge.x, curve.get_max_value()), grid_color0); draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0); @@ -656,9 +661,9 @@ void CurveEditor::_draw() { draw_set_transform_matrix(Transform2D()); - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); float font_height = font->get_height(); - Color text_color = get_color("font_color", "Editor"); + Color text_color = get_theme_color("font_color", "Editor"); { // X axis @@ -685,21 +690,20 @@ void CurveEditor::_draw() { // Draw tangents for current point if (_selected_point >= 0) { - - const Color tangent_color = get_color("accent_color", "Editor"); + const Color tangent_color = get_theme_color("accent_color", "Editor"); int i = _selected_point; Vector2 pos = curve.get_point_position(i); if (i != 0) { Vector2 control_pos = get_tangent_view_pos(i, TANGENT_LEFT); - draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); + draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE)); draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), tangent_color); } if (i != curve.get_point_count() - 1) { Vector2 control_pos = get_tangent_view_pos(i, TANGENT_RIGHT); - draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); + draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE)); draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), tangent_color); } } @@ -708,8 +712,8 @@ void CurveEditor::_draw() { draw_set_transform_matrix(_world_to_view); - const Color line_color = get_color("font_color", "Editor"); - const Color edge_line_color = get_color("highlight_color", "Editor"); + const Color line_color = get_theme_color("font_color", "Editor"); + const Color edge_line_color = get_theme_color("highlight_color", "Editor"); CanvasItemPlotCurve plot_func(*this, line_color, edge_line_color); plot_curve_accurate(curve, 4.f / view_size.x, plot_func); @@ -718,8 +722,8 @@ void CurveEditor::_draw() { draw_set_transform_matrix(Transform2D()); - const Color point_color = get_color("font_color", "Editor"); - const Color selected_point_color = get_color("accent_color", "Editor"); + const Color point_color = get_theme_color("font_color", "Editor"); + const Color selected_point_color = get_theme_color("accent_color", "Editor"); for (int i = 0; i < curve.get_point_count(); ++i) { Vector2 pos = curve.get_point_position(i); @@ -749,20 +753,15 @@ void CurveEditor::_draw() { void CurveEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &CurveEditor::on_gui_input); - ClassDB::bind_method(D_METHOD("_on_preset_item_selected"), &CurveEditor::on_preset_item_selected); - ClassDB::bind_method(D_METHOD("_curve_changed"), &CurveEditor::_curve_changed); - ClassDB::bind_method(D_METHOD("_on_context_menu_item_selected"), &CurveEditor::on_context_menu_item_selected); } //--------------- bool EditorInspectorPluginCurve::can_handle(Object *p_object) { - - return Object::cast_to<Curve>(p_object) != NULL; + return Object::cast_to<Curve>(p_object) != nullptr; } void EditorInspectorPluginCurve::parse_begin(Object *p_object) { - Curve *curve = Object::cast_to<Curve>(p_object); ERR_FAIL_COND(!curve); Ref<Curve> c(curve); @@ -787,10 +786,9 @@ bool CurvePreviewGenerator::handles(const String &p_type) const { return p_type == "Curve"; } -Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const Size2 &p_size) const { - +Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const Size2 &p_size) const { Ref<Curve> curve_ref = p_from; - ERR_FAIL_COND_V_MSG(curve_ref.is_null(), Ref<Texture>(), "It's not a reference to a valid Resource object."); + ERR_FAIL_COND_V_MSG(curve_ref.is_null(), Ref<Texture2D>(), "It's not a reference to a valid Resource object."); Curve &curve = **curve_ref; // FIXME: Should be ported to use p_size as done in b2633a97 @@ -800,9 +798,7 @@ Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const img_ref.instance(); Image &im = **img_ref; - im.create(thumbnail_size, thumbnail_size / 2, 0, Image::FORMAT_RGBA8); - - im.lock(); + im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8); Color bg_color(0.1, 0.1, 0.1, 1.0); for (int i = 0; i < thumbnail_size; i++) { @@ -816,7 +812,6 @@ Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const int prev_y = 0; for (int x = 0; x < im.get_width(); ++x) { - float t = static_cast<float>(x) / im.get_width(); float v = (curve.interpolate_baked(t) - curve.get_min_value()) / range_y; int y = CLAMP(im.get_height() - v * im.get_height(), 0, im.get_height()); @@ -844,10 +839,8 @@ Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, const prev_y = y; } - im.unlock(); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img_ref, 0); + ptex->create_from_image(img_ref); return ptex; } diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 06e2692373..2872f65730 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -43,7 +43,7 @@ class CurveEditor : public Control { public: CurveEditor(); - Size2 get_minimum_size() const; + Size2 get_minimum_size() const override; void set_curve(Ref<Curve> curve); @@ -123,8 +123,8 @@ class EditorInspectorPluginCurve : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginCurve, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; }; class CurveEditorPlugin : public EditorPlugin { @@ -133,15 +133,15 @@ class CurveEditorPlugin : public EditorPlugin { public: CurveEditorPlugin(EditorNode *p_node); - virtual String get_name() const { return "Curve"; } + virtual String get_name() const override { return "Curve"; } }; class CurvePreviewGenerator : public EditorResourcePreviewGenerator { GDCLASS(CurvePreviewGenerator, EditorResourcePreviewGenerator); public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const Ref<Resource> &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size) const override; }; #endif // CURVE_EDITOR_PLUGIN_H diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp new file mode 100644 index 0000000000..0747e42045 --- /dev/null +++ b/editor/plugins/debugger_editor_plugin.cpp @@ -0,0 +1,214 @@ +/*************************************************************************/ +/* debugger_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "debugger_editor_plugin.h" + +#include "core/os/keyboard.h" +#include "editor/debugger/editor_debugger_node.h" +#include "editor/debugger/editor_debugger_server.h" +#include "editor/editor_node.h" +#include "editor/fileserver/editor_file_server.h" +#include "scene/gui/menu_button.h" + +DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_debug_menu) { + EditorDebuggerServer::initialize(); + + ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11); + ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10); + ED_SHORTCUT("debugger/break", TTR("Break")); + ED_SHORTCUT("debugger/continue", TTR("Continue"), KEY_F12); + ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")); + ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor")); + + // File Server for deploy with remote filesystem. + file_server = memnew(EditorFileServer); + + EditorDebuggerNode *debugger = memnew(EditorDebuggerNode); + Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"), debugger); + debugger->set_tool_button(db); + + // Main editor debug menu. + debug_menu = p_debug_menu; + PopupMenu *p = debug_menu->get_popup(); + p->set_hide_on_checkable_item_selection(false); + p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, using one-click deploy will make the executable attempt to connect to this computer's IP so the running project can be debugged.\nThis option is intended to be used for remote debugging (typically with a mobile device).\nYou don't need to enable it to use the GDScript debugger locally.")); + p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, using one-click deploy for Android will only export an executable without the project data.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploying will use the USB cable for faster performance. This option speeds up testing for projects with large assets.")); + p->add_separator(); + p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, collision shapes and raycast nodes (for 2D and 3D) will be visible in the running project.")); + p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project.")); + p->add_separator(); + p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled.")); + p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS); + p->set_item_tooltip( + p->get_item_count() - 1, + TTR("When this option is enabled, any script that is saved will be reloaded in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled.")); + + // Multi-instance, start/stop + instances_menu = memnew(PopupMenu); + instances_menu->set_name("run_instances"); + instances_menu->set_hide_on_checkable_item_selection(false); + + p->add_child(instances_menu); + p->add_separator(); + p->add_submenu_item(TTR("Run Multiple Instances"), "run_instances"); + + instances_menu->add_radio_check_item(TTR("Run 1 Instance")); + instances_menu->set_item_metadata(0, 1); + instances_menu->add_radio_check_item(TTR("Run 2 Instances")); + instances_menu->set_item_metadata(1, 2); + instances_menu->add_radio_check_item(TTR("Run 3 Instances")); + instances_menu->set_item_metadata(2, 3); + instances_menu->add_radio_check_item(TTR("Run 4 Instances")); + instances_menu->set_item_metadata(3, 4); + instances_menu->set_item_checked(0, true); + instances_menu->connect("index_pressed", callable_mp(this, &DebuggerEditorPlugin::_select_run_count)); + p->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option)); +} + +DebuggerEditorPlugin::~DebuggerEditorPlugin() { + EditorDebuggerServer::deinitialize(); + memdelete(file_server); +} + +void DebuggerEditorPlugin::_select_run_count(int p_index) { + int len = instances_menu->get_item_count(); + for (int idx = 0; idx < len; idx++) { + instances_menu->set_item_checked(idx, idx == p_index); + } + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_instances", instances_menu->get_item_metadata(p_index)); +} + +void DebuggerEditorPlugin::_menu_option(int p_option) { + switch (p_option) { + case RUN_FILE_SERVER: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER)); + + if (ischecked) { + file_server->stop(); + } else { + file_server->start(); + } + + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER), !ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_file_server", !ischecked); + + } break; + case RUN_LIVE_DEBUG: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG)); + + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG), !ischecked); + EditorDebuggerNode::get_singleton()->set_live_debugging(!ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_live_debug", !ischecked); + + } break; + case RUN_DEPLOY_REMOTE_DEBUG: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG)); + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG), !ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_deploy_remote_debug", !ischecked); + + } break; + case RUN_DEBUG_COLLISONS: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS)); + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS), !ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_collisons", !ischecked); + + } break; + case RUN_DEBUG_NAVIGATION: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION)); + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_navigation", !ischecked); + + } break; + case RUN_RELOAD_SCRIPTS: { + bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS)); + debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked); + + ScriptEditor::get_singleton()->set_live_auto_reload_running_scripts(!ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_reload_scripts", !ischecked); + + } break; + } +} + +void DebuggerEditorPlugin::_notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + _update_debug_options(); + } +} + +void DebuggerEditorPlugin::_update_debug_options() { + bool check_deploy_remote = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_deploy_remote_debug", false); + bool check_file_server = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_file_server", false); + bool check_debug_collisions = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisons", false); + bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false); + bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true); + bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true); + int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1); + + if (check_deploy_remote) { + _menu_option(RUN_DEPLOY_REMOTE_DEBUG); + } + if (check_file_server) { + _menu_option(RUN_FILE_SERVER); + } + if (check_debug_collisions) { + _menu_option(RUN_DEBUG_COLLISONS); + } + if (check_debug_navigation) { + _menu_option(RUN_DEBUG_NAVIGATION); + } + if (check_live_debug) { + _menu_option(RUN_LIVE_DEBUG); + } + if (check_reload_scripts) { + _menu_option(RUN_RELOAD_SCRIPTS); + } + + int len = instances_menu->get_item_count(); + for (int idx = 0; idx < len; idx++) { + bool checked = (int)instances_menu->get_item_metadata(idx) == instances; + instances_menu->set_item_checked(idx, checked); + } +} diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h new file mode 100644 index 0000000000..c5ae4cd8a9 --- /dev/null +++ b/editor/plugins/debugger_editor_plugin.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* debugger_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 DEBUGGER_EDITOR_PLUGIN_H +#define DEBUGGER_EDITOR_PLUGIN_H + +#include "editor/editor_plugin.h" + +class EditorNode; +class EditorFileServer; +class MenuButton; +class PopupMenu; + +class DebuggerEditorPlugin : public EditorPlugin { + GDCLASS(DebuggerEditorPlugin, EditorPlugin); + +private: + MenuButton *debug_menu; + EditorFileServer *file_server; + PopupMenu *instances_menu; + + enum MenuOptions { + RUN_FILE_SERVER, + RUN_LIVE_DEBUG, + RUN_DEBUG_COLLISONS, + RUN_DEBUG_NAVIGATION, + RUN_DEPLOY_REMOTE_DEBUG, + RUN_RELOAD_SCRIPTS, + }; + + void _update_debug_options(); + void _notification(int p_what); + void _select_run_count(int p_index); + void _menu_option(int p_option); + +public: + virtual String get_name() const override { return "Debugger"; } + bool has_main_screen() const override { return false; } + + DebuggerEditorPlugin(EditorNode *p_node, MenuButton *p_menu); + ~DebuggerEditorPlugin(); +}; + +#endif // DEBUGGER_EDITOR_PLUGIN_H diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp new file mode 100644 index 0000000000..b775e871e2 --- /dev/null +++ b/editor/plugins/editor_debugger_plugin.cpp @@ -0,0 +1,124 @@ +/*************************************************************************/ +/* editor_debugger_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "editor_debugger_plugin.h" + +#include "editor/debugger/script_editor_debugger.h" + +void EditorDebuggerPlugin::_breaked(bool p_really_did, bool p_can_debug) { + if (p_really_did) { + emit_signal("breaked", p_can_debug); + } else { + emit_signal("continued"); + } +} + +void EditorDebuggerPlugin::_started() { + emit_signal("started"); +} + +void EditorDebuggerPlugin::_stopped() { + emit_signal("stopped"); +} + +void EditorDebuggerPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &EditorDebuggerPlugin::send_message); + ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &EditorDebuggerPlugin::register_message_capture); + ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &EditorDebuggerPlugin::unregister_message_capture); + ClassDB::bind_method(D_METHOD("has_capture", "name"), &EditorDebuggerPlugin::has_capture); + ClassDB::bind_method(D_METHOD("is_breaked"), &EditorDebuggerPlugin::is_breaked); + ClassDB::bind_method(D_METHOD("is_debuggable"), &EditorDebuggerPlugin::is_debuggable); + ClassDB::bind_method(D_METHOD("is_session_active"), &EditorDebuggerPlugin::is_session_active); + + ADD_SIGNAL(MethodInfo("started")); + ADD_SIGNAL(MethodInfo("stopped")); + ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "can_debug"))); + ADD_SIGNAL(MethodInfo("continued")); +} + +void EditorDebuggerPlugin::attach_debugger(ScriptEditorDebugger *p_debugger) { + debugger = p_debugger; + if (debugger) { + debugger->connect("started", callable_mp(this, &EditorDebuggerPlugin::_started)); + debugger->connect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped)); + debugger->connect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked)); + } +} + +void EditorDebuggerPlugin::detach_debugger(bool p_call_debugger) { + if (debugger) { + debugger->disconnect("started", callable_mp(this, &EditorDebuggerPlugin::_started)); + debugger->disconnect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped)); + debugger->disconnect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked)); + if (p_call_debugger && get_script_instance()) { + debugger->remove_debugger_plugin(get_script_instance()->get_script()); + } + debugger = nullptr; + } +} + +void EditorDebuggerPlugin::send_message(const String &p_message, const Array &p_args) { + ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger"); + debugger->send_message(p_message, p_args); +} + +void EditorDebuggerPlugin::register_message_capture(const StringName &p_name, const Callable &p_callable) { + ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger"); + debugger->register_message_capture(p_name, p_callable); +} + +void EditorDebuggerPlugin::unregister_message_capture(const StringName &p_name) { + ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger"); + debugger->unregister_message_capture(p_name); +} + +bool EditorDebuggerPlugin::has_capture(const StringName &p_name) { + ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger"); + return debugger->has_capture(p_name); +} + +bool EditorDebuggerPlugin::is_breaked() { + ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger"); + return debugger->is_breaked(); +} + +bool EditorDebuggerPlugin::is_debuggable() { + ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger"); + return debugger->is_debuggable(); +} + +bool EditorDebuggerPlugin::is_session_active() { + ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger"); + return debugger->is_session_active(); +} + +EditorDebuggerPlugin::~EditorDebuggerPlugin() { + detach_debugger(true); +} diff --git a/editor/plugins/editor_debugger_plugin.h b/editor/plugins/editor_debugger_plugin.h new file mode 100644 index 0000000000..10fd1151de --- /dev/null +++ b/editor/plugins/editor_debugger_plugin.h @@ -0,0 +1,64 @@ +/*************************************************************************/ +/* editor_debugger_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 EDITOR_DEBUGGER_PLUGIN_H +#define EDITOR_DEBUGGER_PLUGIN_H + +#include "scene/gui/control.h" + +class ScriptEditorDebugger; + +class EditorDebuggerPlugin : public Control { + GDCLASS(EditorDebuggerPlugin, Control); + +private: + ScriptEditorDebugger *debugger = nullptr; + + void _breaked(bool p_really_did, bool p_can_debug); + void _started(); + void _stopped(); + +protected: + static void _bind_methods(); + +public: + void attach_debugger(ScriptEditorDebugger *p_debugger); + void detach_debugger(bool p_call_debugger); + void send_message(const String &p_message, const Array &p_args); + void register_message_capture(const StringName &p_name, const Callable &p_callable); + void unregister_message_capture(const StringName &p_name); + bool has_capture(const StringName &p_name); + bool is_breaked(); + bool is_debuggable(); + bool is_session_active(); + ~EditorDebuggerPlugin(); +}; + +#endif // EDITOR_DEBUGGER_PLUGIN_H diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 9b0d5d3daf..3cf4dc5ac8 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -43,11 +43,9 @@ #include "servers/audio/audio_stream.h" void post_process_preview(Ref<Image> p_image) { - - if (p_image->get_format() != Image::FORMAT_RGBA8) + if (p_image->get_format() != Image::FORMAT_RGBA8) { p_image->convert(Image::FORMAT_RGBA8); - - p_image->lock(); + } const int w = p_image->get_width(); const int h = p_image->get_height(); @@ -70,40 +68,36 @@ void post_process_preview(Ref<Image> p_image) { } } } - - p_image->unlock(); } bool EditorTexturePreviewPlugin::handles(const String &p_type) const { - - return ClassDB::is_parent_class(p_type, "Texture"); + return ClassDB::is_parent_class(p_type, "Texture2D"); } bool EditorTexturePreviewPlugin::generate_small_preview_automatically() const { return true; } -Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Image> img; Ref<AtlasTexture> atex = p_from; Ref<LargeTexture> ltex = p_from; if (atex.is_valid()) { - Ref<Texture> tex = atex->get_atlas(); + Ref<Texture2D> tex = atex->get_atlas(); if (!tex.is_valid()) { - return Ref<Texture>(); + return Ref<Texture2D>(); } Ref<Image> atlas = tex->get_data(); if (!atlas.is_valid()) { - return Ref<Texture>(); + return Ref<Texture2D>(); } img = atlas->get_rect(atex->get_region()); } else if (ltex.is_valid()) { img = ltex->to_image(); } else { - Ref<Texture> tex = p_from; + Ref<Texture2D> tex = p_from; if (tex.is_valid()) { img = tex->get_data(); if (img.is_valid()) { @@ -112,14 +106,16 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 } } - if (img.is_null() || img->empty()) - return Ref<Texture>(); + if (img.is_null() || img->empty()) { + return Ref<Texture2D>(); + } img->clear_mipmaps(); if (img->is_compressed()) { - if (img->decompress() != OK) - return Ref<Texture>(); + if (img->decompress() != OK) { + return Ref<Texture2D>(); + } } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) { img->convert(Image::FORMAT_RGBA8); } @@ -131,13 +127,14 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from, const Size2 if (new_size.y > p_size.y) { new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } - img->resize(new_size.x, new_size.y, Image::INTERPOLATE_CUBIC); + Vector2i new_size_i(MAX(1, (int)new_size.x), MAX(1, (int)new_size.y)); + img->resize(new_size_i.x, new_size_i.y, Image::INTERPOLATE_CUBIC); post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } @@ -147,23 +144,23 @@ EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() { //////////////////////////////////////////////////////////////////////////// bool EditorImagePreviewPlugin::handles(const String &p_type) const { - return p_type == "Image"; } -Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Image> img = p_from; - if (img.is_null() || img->empty()) + if (img.is_null() || img->empty()) { return Ref<Image>(); + } img = img->duplicate(); img->clear_mipmaps(); if (img->is_compressed()) { - if (img->decompress() != OK) + if (img->decompress() != OK) { return Ref<Image>(); + } } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) { img->convert(Image::FORMAT_RGBA8); } @@ -182,7 +179,7 @@ Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 & Ref<ImageTexture> ptex; ptex.instance(); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } @@ -192,34 +189,33 @@ EditorImagePreviewPlugin::EditorImagePreviewPlugin() { bool EditorImagePreviewPlugin::generate_small_preview_automatically() const { return true; } + //////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////// bool EditorBitmapPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "BitMap"); } -Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<BitMap> bm = p_from; if (bm->get_size() == Size2()) { - return Ref<Texture>(); + return Ref<Texture2D>(); } - PoolVector<uint8_t> data; + Vector<uint8_t> data; data.resize(bm->get_size().width * bm->get_size().height); { - PoolVector<uint8_t>::Write w = data.write(); + uint8_t *w = data.ptrw(); for (int i = 0; i < bm->get_size().width; i++) { for (int j = 0; j < bm->get_size().height; j++) { if (bm->get_bit(Point2i(i, j))) { - w[j * bm->get_size().width + i] = 255; + w[j * (int)bm->get_size().width + i] = 255; } else { - w[j * bm->get_size().width + i] = 0; + w[j * (int)bm->get_size().width + i] = 0; } } } @@ -227,11 +223,12 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 Ref<Image> img; img.instance(); - img->create(bm->get_size().width, bm->get_size().height, 0, Image::FORMAT_L8, data); + img->create(bm->get_size().width, bm->get_size().height, false, Image::FORMAT_L8, data); if (img->is_compressed()) { - if (img->decompress() != OK) - return Ref<Texture>(); + if (img->decompress() != OK) { + return Ref<Texture2D>(); + } } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) { img->convert(Image::FORMAT_RGBA8); } @@ -249,7 +246,7 @@ Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size2 Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } @@ -263,16 +260,14 @@ EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() { /////////////////////////////////////////////////////////////////////////// bool EditorPackedScenePreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "PackedScene"); } -Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { +Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { return generate_from_path(p_from->get_path(), p_size); } -Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { - +Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); @@ -281,22 +276,22 @@ Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_ String path = cache_base + ".png"; - if (!FileAccess::exists(path)) - return Ref<Texture>(); + if (!FileAccess::exists(path)) { + return Ref<Texture2D>(); + } Ref<Image> img; img.instance(); Error err = img->load(path); if (err == OK) { - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); post_process_preview(img); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } else { - return Ref<Texture>(); + return Ref<Texture2D>(); } } @@ -306,17 +301,14 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() { ////////////////////////////////////////////////////////////////// void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; } void EditorMaterialPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorMaterialPreviewPlugin::_preview_done); } bool EditorMaterialPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Material"); //any material } @@ -324,26 +316,24 @@ bool EditorMaterialPreviewPlugin::generate_small_preview_automatically() const { return true; } -Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Material> material = p_from; - ERR_FAIL_COND_V(material.is_null(), Ref<Texture>()); + ERR_FAIL_COND_V(material.is_null(), Ref<Texture2D>()); if (material->get_shader_mode() == Shader::MODE_SPATIAL) { + RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); - - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant()); + RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); } - Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); + Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); + RS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); @@ -352,54 +342,52 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size img->resize(thumbnail_size, thumbnail_size, Image::INTERPOLATE_CUBIC); post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } - return Ref<Texture>(); + return Ref<Texture2D>(); } EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { + scenario = RS::get_singleton()->scenario_create(); - scenario = VS::get_singleton()->scenario_create(); - - viewport = VS::get_singleton()->viewport_create(); - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED); - VS::get_singleton()->viewport_set_scenario(viewport, scenario); - VS::get_singleton()->viewport_set_size(viewport, 128, 128); - VS::get_singleton()->viewport_set_transparent_background(viewport, true); - VS::get_singleton()->viewport_set_active(viewport, true); - VS::get_singleton()->viewport_set_vflip(viewport, true); - viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); + viewport = RS::get_singleton()->viewport_create(); + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED); + RS::get_singleton()->viewport_set_scenario(viewport, scenario); + RS::get_singleton()->viewport_set_size(viewport, 128, 128); + RS::get_singleton()->viewport_set_transparent_background(viewport, true); + RS::get_singleton()->viewport_set_active(viewport, true); + viewport_texture = RS::get_singleton()->viewport_get_texture(viewport); - camera = VS::get_singleton()->camera_create(); - VS::get_singleton()->viewport_attach_camera(viewport, camera); - VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); - VS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10); + camera = RS::get_singleton()->camera_create(); + RS::get_singleton()->viewport_attach_camera(viewport, camera); + RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); + RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10); - light = VS::get_singleton()->directional_light_create(); - light_instance = VS::get_singleton()->instance_create2(light, scenario); - VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + light = RS::get_singleton()->directional_light_create(); + light_instance = RS::get_singleton()->instance_create2(light, scenario); + RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); - light2 = VS::get_singleton()->directional_light_create(); - VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); - //VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); + light2 = RS::get_singleton()->directional_light_create(); + RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); + //RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); - light_instance2 = VS::get_singleton()->instance_create2(light2, scenario); + light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); - VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); - sphere = VS::get_singleton()->mesh_create(); - sphere_instance = VS::get_singleton()->instance_create2(sphere, scenario); + sphere = RS::get_singleton()->mesh_create(); + sphere_instance = RS::get_singleton()->instance_create2(sphere, scenario); int lats = 32; int lons = 32; float radius = 1.0; - PoolVector<Vector3> vertices; - PoolVector<Vector3> normals; - PoolVector<Vector2> uvs; - PoolVector<float> tangents; + Vector<Vector3> vertices; + Vector<Vector3> normals; + Vector<Vector2> uvs; + Vector<float> tangents; Basis tt = Basis(Vector3(0, 1, 0), Math_PI * 0.5); for (int i = 1; i <= lats; i++) { @@ -412,7 +400,6 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { double zr1 = Math::cos(lat1); for (int j = lons; j >= 1; j--) { - double lng0 = 2 * Math_PI * (double)(j - 1) / lons; double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); @@ -457,48 +444,46 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { } Array arr; - arr.resize(VS::ARRAY_MAX); - arr[VS::ARRAY_VERTEX] = vertices; - arr[VS::ARRAY_NORMAL] = normals; - arr[VS::ARRAY_TANGENT] = tangents; - arr[VS::ARRAY_TEX_UV] = uvs; - VS::get_singleton()->mesh_add_surface_from_arrays(sphere, VS::PRIMITIVE_TRIANGLES, arr); + arr.resize(RS::ARRAY_MAX); + arr[RS::ARRAY_VERTEX] = vertices; + arr[RS::ARRAY_NORMAL] = normals; + arr[RS::ARRAY_TANGENT] = tangents; + arr[RS::ARRAY_TEX_UV] = uvs; + RS::get_singleton()->mesh_add_surface_from_arrays(sphere, RS::PRIMITIVE_TRIANGLES, arr); } EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() { - - VS::get_singleton()->free(sphere); - VS::get_singleton()->free(sphere_instance); - VS::get_singleton()->free(viewport); - VS::get_singleton()->free(light); - VS::get_singleton()->free(light_instance); - VS::get_singleton()->free(light2); - VS::get_singleton()->free(light_instance2); - VS::get_singleton()->free(camera); - VS::get_singleton()->free(scenario); + RS::get_singleton()->free(sphere); + RS::get_singleton()->free(sphere_instance); + RS::get_singleton()->free(viewport); + RS::get_singleton()->free(light); + RS::get_singleton()->free(light_instance); + RS::get_singleton()->free(light2); + RS::get_singleton()->free(light_instance2); + RS::get_singleton()->free(camera); + RS::get_singleton()->free(scenario); } /////////////////////////////////////////////////////////////////////////// -static bool _is_text_char(CharType c) { - +static bool _is_text_char(char32_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } bool EditorScriptPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Script"); } -Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Script> scr = p_from; - if (scr.is_null()) - return Ref<Texture>(); + if (scr.is_null()) { + return Ref<Texture2D>(); + } String code = scr->get_source_code().strip_edges(); - if (code == "") - return Ref<Texture>(); + if (code == "") { + return Ref<Texture2D>(); + } List<String> kwors; scr->get_language()->get_reserved_words(&kwors); @@ -506,7 +491,6 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 Set<String> keywords; for (List<String>::Element *E = kwors.front(); E; E = E->next()) { - keywords.insert(E->get()); } @@ -515,17 +499,16 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 Ref<Image> img; img.instance(); int thumbnail_size = MAX(p_size.x, p_size.y); - img->create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8); + img->create(thumbnail_size, thumbnail_size, false, Image::FORMAT_RGBA8); Color bg_color = EditorSettings::get_singleton()->get("text_editor/highlighting/background_color"); Color keyword_color = EditorSettings::get_singleton()->get("text_editor/highlighting/keyword_color"); Color text_color = EditorSettings::get_singleton()->get("text_editor/highlighting/text_color"); Color symbol_color = EditorSettings::get_singleton()->get("text_editor/highlighting/symbol_color"); - img->lock(); - - if (bg_color.a == 0) + if (bg_color.a == 0) { bg_color = Color(0, 0, 0, 0); + } bg_color.a = MAX(bg_color.a, 0.2); // some background for (int i = 0; i < thumbnail_size; i++) { @@ -542,8 +525,7 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 bool prev_is_text = false; bool in_keyword = false; for (int i = 0; i < code.length(); i++) { - - CharType c = code[i]; + char32_t c = code[i]; if (c > 32) { if (col < thumbnail_size) { Color color = text_color; @@ -559,15 +541,17 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 pos++; } String word = code.substr(i, pos - i); - if (keywords.has(word)) + if (keywords.has(word)) { in_keyword = true; + } } else if (!_is_text_char(c)) { in_keyword = false; } - if (in_keyword) + if (in_keyword) { color = keyword_color; + } Color ul = color; ul.a *= 0.5; @@ -577,15 +561,15 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 prev_is_text = _is_text_char(c); } } else { - prev_is_text = false; in_keyword = false; if (c == '\n') { col = x0; line++; - if (line >= available_height / 2) + if (line >= available_height / 2) { break; + } } else if (c == '\t') { col += 3; } @@ -593,41 +577,38 @@ Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size2 col++; } - img->unlock(); - post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() { } + /////////////////////////////////////////////////////////////////// bool EditorAudioStreamPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "AudioStream"); } -Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<AudioStream> stream = p_from; - ERR_FAIL_COND_V(stream.is_null(), Ref<Texture>()); + ERR_FAIL_COND_V(stream.is_null(), Ref<Texture2D>()); - PoolVector<uint8_t> img; + Vector<uint8_t> img; int w = p_size.x; int h = p_size.y; img.resize(w * h * 3); - PoolVector<uint8_t>::Write imgdata = img.write(); - uint8_t *imgw = imgdata.ptr(); + uint8_t *imgdata = img.ptrw(); + uint8_t *imgw = imgdata; Ref<AudioStreamPlayback> playback = stream->instance_playback(); - ERR_FAIL_COND_V(playback.is_null(), Ref<Texture>()); + ERR_FAIL_COND_V(playback.is_null(), Ref<Texture2D>()); float len_s = stream->get_length(); if (len_s == 0) { @@ -643,7 +624,6 @@ Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const S playback->stop(); for (int i = 0; i < w; i++) { - float max = -1000; float min = 1000; int from = uint64_t(i) * frame_length / w; @@ -655,7 +635,6 @@ Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const S } for (int j = from; j < to; j++) { - max = MAX(max, frames[j].l); max = MAX(max, frames[j].r); @@ -680,14 +659,13 @@ Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const S } } - imgdata.release(); //post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); Ref<Image> image; image.instance(); image->create(w, h, false, Image::FORMAT_RGB8, img); - ptex->create_from_image(image, 0); + ptex->create_from_image(image); return ptex; } @@ -697,25 +675,22 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() { /////////////////////////////////////////////////////////////////////////// void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; } void EditorMeshPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorMeshPreviewPlugin::_preview_done); } -bool EditorMeshPreviewPlugin::handles(const String &p_type) const { +bool EditorMeshPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh } -Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { Ref<Mesh> mesh = p_from; - ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture>()); + ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture2D>()); - VS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid()); + RS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid()); AABB aabb = mesh->get_aabb(); Vector3 ofs = aabb.position + aabb.size * 0.5; @@ -725,28 +700,29 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis; AABB rot_aabb = xform.xform(aabb); float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; - if (m == 0) - return Ref<Texture>(); + if (m == 0) { + return Ref<Texture2D>(); + } m = 1.0 / m; m *= 0.5; xform.basis.scale(Vector3(m, m, m)); xform.origin = -xform.basis.xform(ofs); //-ofs*m; xform.origin.z -= rot_aabb.size.z * 2; - VS::get_singleton()->instance_set_transform(mesh_instance, xform); + RS::get_singleton()->instance_set_transform(mesh_instance, xform); - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant()); + RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); } - Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); + Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); - VS::get_singleton()->instance_set_base(mesh_instance, RID()); + RS::get_singleton()->instance_set_base(mesh_instance, RID()); img->convert(Image::FORMAT_RGBA8); @@ -762,77 +738,70 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { + scenario = RS::get_singleton()->scenario_create(); - scenario = VS::get_singleton()->scenario_create(); - - viewport = VS::get_singleton()->viewport_create(); - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED); - VS::get_singleton()->viewport_set_vflip(viewport, true); - VS::get_singleton()->viewport_set_scenario(viewport, scenario); - VS::get_singleton()->viewport_set_size(viewport, 128, 128); - VS::get_singleton()->viewport_set_transparent_background(viewport, true); - VS::get_singleton()->viewport_set_active(viewport, true); - viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); + viewport = RS::get_singleton()->viewport_create(); + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED); + RS::get_singleton()->viewport_set_scenario(viewport, scenario); + RS::get_singleton()->viewport_set_size(viewport, 128, 128); + RS::get_singleton()->viewport_set_transparent_background(viewport, true); + RS::get_singleton()->viewport_set_active(viewport, true); + viewport_texture = RS::get_singleton()->viewport_get_texture(viewport); - camera = VS::get_singleton()->camera_create(); - VS::get_singleton()->viewport_attach_camera(viewport, camera); - VS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); - //VS::get_singleton()->camera_set_perspective(camera,45,0.1,10); - VS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0); + camera = RS::get_singleton()->camera_create(); + RS::get_singleton()->viewport_attach_camera(viewport, camera); + RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); + //RS::get_singleton()->camera_set_perspective(camera,45,0.1,10); + RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0); - light = VS::get_singleton()->directional_light_create(); - light_instance = VS::get_singleton()->instance_create2(light, scenario); - VS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + light = RS::get_singleton()->directional_light_create(); + light_instance = RS::get_singleton()->instance_create2(light, scenario); + RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); - light2 = VS::get_singleton()->directional_light_create(); - VS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); - //VS::get_singleton()->light_set_color(light2, VS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0)); - light_instance2 = VS::get_singleton()->instance_create2(light2, scenario); + light2 = RS::get_singleton()->directional_light_create(); + RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); + //RS::get_singleton()->light_set_color(light2, RS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0)); + light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); - VS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); - //sphere = VS::get_singleton()->mesh_create(); - mesh_instance = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_scenario(mesh_instance, scenario); + //sphere = RS::get_singleton()->mesh_create(); + mesh_instance = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_scenario(mesh_instance, scenario); } EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() { - - //VS::get_singleton()->free(sphere); - VS::get_singleton()->free(mesh_instance); - VS::get_singleton()->free(viewport); - VS::get_singleton()->free(light); - VS::get_singleton()->free(light_instance); - VS::get_singleton()->free(light2); - VS::get_singleton()->free(light_instance2); - VS::get_singleton()->free(camera); - VS::get_singleton()->free(scenario); + //RS::get_singleton()->free(sphere); + RS::get_singleton()->free(mesh_instance); + RS::get_singleton()->free(viewport); + RS::get_singleton()->free(light); + RS::get_singleton()->free(light_instance); + RS::get_singleton()->free(light2); + RS::get_singleton()->free(light_instance2); + RS::get_singleton()->free(camera); + RS::get_singleton()->free(scenario); } /////////////////////////////////////////////////////////////////////////// void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; } void EditorFontPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorFontPreviewPlugin::_preview_done); } bool EditorFontPreviewPlugin::handles(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "DynamicFontData") || ClassDB::is_parent_class(p_type, "DynamicFont"); } -Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { - +Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { RES res = ResourceLoader::load(p_path); Ref<DynamicFont> sampled_font; if (res->is_class("DynamicFont")) { @@ -859,16 +828,16 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c font->draw(canvas_item, pos, sampled_text); 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()); + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + RS::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); + RS::get_singleton()->canvas_item_clear(canvas_item); - Ref<Image> img = VS::get_singleton()->texture_get_data(viewport_texture); + Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); img->convert(Image::FORMAT_RGBA8); @@ -885,39 +854,35 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path, c post_process_preview(img); Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); + ptex->create_from_image(img); return ptex; } -Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { - +Ref<Texture2D> EditorFontPreviewPlugin::generate(const RES &p_from, const Size2 &p_size) const { String path = p_from->get_path(); if (!FileAccess::exists(path)) { - return Ref<Texture>(); + return Ref<Texture2D>(); } return generate_from_path(path, p_size); } EditorFontPreviewPlugin::EditorFontPreviewPlugin() { + viewport = RS::get_singleton()->viewport_create(); + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_DISABLED); + RS::get_singleton()->viewport_set_size(viewport, 128, 128); + RS::get_singleton()->viewport_set_active(viewport, true); + viewport_texture = RS::get_singleton()->viewport_get_texture(viewport); - viewport = VS::get_singleton()->viewport_create(); - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_DISABLED); - VS::get_singleton()->viewport_set_vflip(viewport, true); - VS::get_singleton()->viewport_set_size(viewport, 128, 128); - VS::get_singleton()->viewport_set_active(viewport, true); - viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); + canvas = RS::get_singleton()->canvas_create(); + canvas_item = RS::get_singleton()->canvas_item_create(); - canvas = VS::get_singleton()->canvas_create(); - canvas_item = VS::get_singleton()->canvas_item_create(); - - VS::get_singleton()->viewport_attach_canvas(viewport, canvas); - VS::get_singleton()->canvas_item_set_parent(canvas_item, canvas); + RS::get_singleton()->viewport_attach_canvas(viewport, canvas); + RS::get_singleton()->canvas_item_set_parent(canvas_item, canvas); } EditorFontPreviewPlugin::~EditorFontPreviewPlugin() { - - VS::get_singleton()->free(canvas_item); - VS::get_singleton()->free(canvas); - VS::get_singleton()->free(viewport); + RS::get_singleton()->free(canvas_item); + RS::get_singleton()->free(canvas); + RS::get_singleton()->free(viewport); } diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index e6e4aff8de..9885efc2b5 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -39,9 +39,9 @@ class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator); public: - virtual bool handles(const String &p_type) const; - virtual bool generate_small_preview_automatically() const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual bool generate_small_preview_automatically() const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; EditorTexturePreviewPlugin(); }; @@ -50,9 +50,9 @@ class EditorImagePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorImagePreviewPlugin, EditorResourcePreviewGenerator); public: - virtual bool handles(const String &p_type) const; - virtual bool generate_small_preview_automatically() const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual bool generate_small_preview_automatically() const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; EditorImagePreviewPlugin(); }; @@ -61,25 +61,23 @@ class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorBitmapPreviewPlugin, EditorResourcePreviewGenerator); public: - virtual bool handles(const String &p_type) const; - virtual bool generate_small_preview_automatically() const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual bool generate_small_preview_automatically() const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; EditorBitmapPreviewPlugin(); }; class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator { - public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; - virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 &p_size) const; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const; + virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const; EditorPackedScenePreviewPlugin(); }; class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { - GDCLASS(EditorMaterialPreviewPlugin, EditorResourcePreviewGenerator); RID scenario; @@ -100,9 +98,9 @@ protected: static void _bind_methods(); public: - virtual bool handles(const String &p_type) const; - virtual bool generate_small_preview_automatically() const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual bool generate_small_preview_automatically() const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; EditorMaterialPreviewPlugin(); ~EditorMaterialPreviewPlugin(); @@ -111,7 +109,7 @@ public: class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator { public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const; EditorScriptPreviewPlugin(); }; @@ -119,13 +117,12 @@ public: class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator { public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const; EditorAudioStreamPreviewPlugin(); }; class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { - GDCLASS(EditorMeshPreviewPlugin, EditorResourcePreviewGenerator); RID scenario; @@ -145,15 +142,14 @@ protected: static void _bind_methods(); public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; EditorMeshPreviewPlugin(); ~EditorMeshPreviewPlugin(); }; class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator { - GDCLASS(EditorFontPreviewPlugin, EditorResourcePreviewGenerator); RID viewport; @@ -168,9 +164,9 @@ protected: static void _bind_methods(); public: - virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from, const Size2 &p_size) const; - virtual Ref<Texture> generate_from_path(const String &p_path, const Size2 &p_size) const; + virtual bool handles(const String &p_type) const override; + virtual Ref<Texture2D> generate(const RES &p_from, const Size2 &p_size) const override; + virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size) const override; EditorFontPreviewPlugin(); ~EditorFontPreviewPlugin(); diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp index 8914e0ed01..2f5dd36ef1 100644 --- a/editor/plugins/gi_probe_editor_plugin.cpp +++ b/editor/plugins/gi_probe_editor_plugin.cpp @@ -31,72 +31,138 @@ #include "gi_probe_editor_plugin.h" void GIProbeEditorPlugin::_bake() { - if (gi_probe) { + if (gi_probe->get_probe_data().is_null()) { + String path = get_tree()->get_edited_scene_root()->get_filename(); + if (path == String()) { + path = "res://" + gi_probe->get_name() + "_data.res"; + } else { + String ext = path.get_extension(); + path = path.get_basename() + "." + gi_probe->get_name() + "_data.res"; + } + probe_file->set_current_path(path); + probe_file->popup_file_dialog(); + return; + } gi_probe->bake(); } } void GIProbeEditorPlugin::edit(Object *p_object) { - GIProbe *s = Object::cast_to<GIProbe>(p_object); - if (!s) + if (!s) { return; + } gi_probe = s; } bool GIProbeEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("GIProbe"); } -void GIProbeEditorPlugin::make_visible(bool p_visible) { +void GIProbeEditorPlugin::_notification(int p_what) { + if (p_what == NOTIFICATION_PROCESS) { + if (!gi_probe) { + return; + } + + const Vector3i size = gi_probe->get_estimated_cell_size(); + String text = vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z); + int data_size = 4; + if (GLOBAL_GET("rendering/quality/gi_probes/anisotropic")) { + data_size += 4; + } + const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0); + text += " - " + vformat(TTR("VRAM Size: %s MB"), String::num(size_mb, 2)); + + if (bake_info->get_text() == text) { + return; + } + + // Color the label depending on the estimated performance level. + Color color; + if (size_mb <= 16.0 + CMP_EPSILON) { + // Fast. + color = bake_info->get_theme_color("success_color", "Editor"); + } else if (size_mb <= 64.0 + CMP_EPSILON) { + // Medium. + color = bake_info->get_theme_color("warning_color", "Editor"); + } else { + // Slow. + color = bake_info->get_theme_color("error_color", "Editor"); + } + bake_info->add_theme_color_override("font_color", color); + + bake_info->set_text(text); + } +} +void GIProbeEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - bake->show(); + bake_hb->show(); + set_process(true); } else { - - bake->hide(); + bake_hb->hide(); + set_process(false); } } -EditorProgress *GIProbeEditorPlugin::tmp_progress = NULL; +EditorProgress *GIProbeEditorPlugin::tmp_progress = nullptr; void GIProbeEditorPlugin::bake_func_begin(int p_steps) { - - ERR_FAIL_COND(tmp_progress != NULL); + ERR_FAIL_COND(tmp_progress != nullptr); tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps)); } void GIProbeEditorPlugin::bake_func_step(int p_step, const String &p_description) { - - ERR_FAIL_COND(tmp_progress == NULL); + ERR_FAIL_COND(tmp_progress == nullptr); tmp_progress->step(p_description, p_step, false); } void GIProbeEditorPlugin::bake_func_end() { - ERR_FAIL_COND(tmp_progress == NULL); + ERR_FAIL_COND(tmp_progress == nullptr); memdelete(tmp_progress); - tmp_progress = NULL; + tmp_progress = nullptr; } -void GIProbeEditorPlugin::_bind_methods() { +void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String &p_path) { + probe_file->hide(); + if (gi_probe) { + gi_probe->bake(); + ERR_FAIL_COND(gi_probe->get_probe_data().is_null()); + ResourceSaver::save(p_path, gi_probe->get_probe_data(), ResourceSaver::FLAG_CHANGE_PATH); + } +} - ClassDB::bind_method("_bake", &GIProbeEditorPlugin::_bake); +void GIProbeEditorPlugin::_bind_methods() { } GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { - editor = p_node; - bake = memnew(ToolButton); - bake->set_icon(editor->get_gui_base()->get_icon("Bake", "EditorIcons")); + bake_hb = memnew(HBoxContainer); + bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + bake_hb->hide(); + bake = memnew(Button); + bake->set_flat(true); + bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons")); bake->set_text(TTR("Bake GI Probe")); - bake->hide(); - bake->connect("pressed", this, "_bake"); - add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake); - gi_probe = NULL; + bake->connect("pressed", callable_mp(this, &GIProbeEditorPlugin::_bake)); + bake_hb->add_child(bake); + bake_info = memnew(Label); + bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL); + bake_info->set_clip_text(true); + bake_hb->add_child(bake_info); + + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb); + gi_probe = nullptr; + probe_file = memnew(EditorFileDialog); + probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + probe_file->add_filter("*.res"); + probe_file->connect("file_selected", callable_mp(this, &GIProbeEditorPlugin::_giprobe_save_path_and_bake)); + get_editor_interface()->get_base_control()->add_child(probe_file); + probe_file->set_title(TTR("Select path for GIProbe Data File")); GIProbe::bake_begin_function = bake_func_begin; GIProbe::bake_step_function = bake_func_step; diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h index 5db682835d..85d2b6f449 100644 --- a/editor/plugins/gi_probe_editor_plugin.h +++ b/editor/plugins/gi_probe_editor_plugin.h @@ -37,30 +37,35 @@ #include "scene/resources/material.h" class GIProbeEditorPlugin : public EditorPlugin { - GDCLASS(GIProbeEditorPlugin, EditorPlugin); GIProbe *gi_probe; - ToolButton *bake; + HBoxContainer *bake_hb; + Label *bake_info; + Button *bake; EditorNode *editor; + EditorFileDialog *probe_file; + static EditorProgress *tmp_progress; static void bake_func_begin(int p_steps); static void bake_func_step(int p_step, const String &p_description); static void bake_func_end(); void _bake(); + void _giprobe_save_path_and_bake(const String &p_path); protected: static void _bind_methods(); + void _notification(int p_what); public: - virtual String get_name() const { return "GIProbe"; } - 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); + virtual String get_name() const override { return "GIProbe"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; GIProbeEditorPlugin(EditorNode *p_node); ~GIProbeEditorPlugin(); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index b036368bc8..d27df1d063 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_2d_editor_plugin.cpp */ +/* gpu_particles_2d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "particles_2d_editor_plugin.h" +#include "gpu_particles_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" #include "core/io/image_loader.h" @@ -36,55 +36,46 @@ #include "scene/gui/separator.h" #include "scene/resources/particles_material.h" -void Particles2DEditorPlugin::edit(Object *p_object) { - - particles = Object::cast_to<Particles2D>(p_object); +void GPUParticles2DEditorPlugin::edit(Object *p_object) { + particles = Object::cast_to<GPUParticles2D>(p_object); } -bool Particles2DEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Particles2D"); +bool GPUParticles2DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("GPUParticles2D"); } -void Particles2DEditorPlugin::make_visible(bool p_visible) { - +void GPUParticles2DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - toolbar->show(); } else { - toolbar->hide(); } } -void Particles2DEditorPlugin::_file_selected(const String &p_file) { - +void GPUParticles2DEditorPlugin::_file_selected(const String &p_file) { source_emission_file = p_file; - emission_mask->popup_centered_minsize(); + emission_mask->popup_centered(); } -void Particles2DEditorPlugin::_menu_callback(int p_idx) { - +void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) { switch (p_idx) { case MENU_GENERATE_VISIBILITY_RECT: { float gen_time = particles->get_lifetime(); - if (gen_time < 1.0) + if (gen_time < 1.0) { generate_seconds->set_value(1.0); - else + } else { generate_seconds->set_value(trunc(gen_time) + 1.0); - generate_visibility_rect->popup_centered_minsize(); + } + generate_visibility_rect->popup_centered(); } break; case MENU_LOAD_EMISSION_MASK: { - - file->popup_centered_ratio(); + file->popup_file_dialog(); } break; case MENU_CLEAR_EMISSION_MASK: { - - emission_mask->popup_centered_minsize(); + emission_mask->popup_centered(); } break; case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: { - CPUParticles2D *cpu_particles = memnew(CPUParticles2D); cpu_particles->convert_from_particles(particles); cpu_particles->set_name(particles->get_name()); @@ -94,7 +85,7 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { cpu_particles->set_z_index(particles->get_z_index()); UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Convert to CPUParticles")); + ur->create_action(TTR("Convert to CPUParticles2D")); ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", particles, cpu_particles, true, false); ur->add_do_reference(cpu_particles); ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, particles, false, false); @@ -103,14 +94,12 @@ void Particles2DEditorPlugin::_menu_callback(int p_idx) { } break; case MENU_RESTART: { - particles->restart(); } } } -void Particles2DEditorPlugin::_generate_visibility_rect() { - +void GPUParticles2DEditorPlugin::_generate_visibility_rect() { float time = generate_seconds->get_value(); float running = 0.0; @@ -125,16 +114,16 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { Rect2 rect; while (running < time) { - uint64_t ticks = OS::get_singleton()->get_ticks_usec(); ep.step("Generating...", int(running), true); OS::get_singleton()->delay_usec(1000); Rect2 capture = particles->capture_rect(); - if (rect == Rect2()) + if (rect == Rect2()) { rect = capture; - else + } else { rect = rect.merge(capture); + } running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } @@ -149,8 +138,7 @@ void Particles2DEditorPlugin::_generate_visibility_rect() { undo_redo->commit_action(); } -void Particles2DEditorPlugin::_generate_emission_mask() { - +void GPUParticles2DEditorPlugin::_generate_emission_mask() { Ref<ParticlesMaterial> pm = particles->get_process_material(); if (!pm.is_valid()) { EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material")); @@ -191,18 +179,15 @@ void Particles2DEditorPlugin::_generate_emission_mask() { int vpc = 0; { - PoolVector<uint8_t> data = img->get_data(); - PoolVector<uint8_t>::Read r = data.read(); + Vector<uint8_t> data = img->get_data(); + const uint8_t *r = data.ptr(); 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]; @@ -212,19 +197,18 @@ void Particles2DEditorPlugin::_generate_emission_mask() { 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) + if (on_border) { break; + } } if (on_border) { @@ -234,9 +218,9 @@ void Particles2DEditorPlugin::_generate_emission_mask() { 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) + 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(); @@ -270,7 +254,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); - PoolVector<uint8_t> texdata; + Vector<uint8_t> texdata; int w = 2048; int h = (vpc / 2048) + 1; @@ -278,10 +262,9 @@ void Particles2DEditorPlugin::_generate_emission_mask() { texdata.resize(w * h * 2 * sizeof(float)); { - PoolVector<uint8_t>::Write tw = texdata.write(); - float *twf = (float *)tw.ptr(); + uint8_t *tw = texdata.ptrw(); + float *twf = (float *)tw; for (int i = 0; i < vpc; i++) { - twf[i * 2 + 0] = valid_positions[i].x; twf[i * 2 + 1] = valid_positions[i].y; } @@ -292,20 +275,18 @@ void Particles2DEditorPlugin::_generate_emission_mask() { Ref<ImageTexture> imgt; imgt.instance(); - imgt->create_from_image(img, 0); + imgt->create_from_image(img); pm->set_emission_point_texture(imgt); pm->set_emission_point_count(vpc); if (capture_colors) { - - PoolVector<uint8_t> colordata; + Vector<uint8_t> colordata; colordata.resize(w * h * 4); //use RG texture { - PoolVector<uint8_t>::Write tw = colordata.write(); + uint8_t *tw = colordata.ptrw(); for (int i = 0; i < vpc * 4; i++) { - tw[i] = valid_colors[i]; } } @@ -314,19 +295,19 @@ void Particles2DEditorPlugin::_generate_emission_mask() { img->create(w, h, false, Image::FORMAT_RGBA8, colordata); imgt.instance(); - imgt->create_from_image(img, 0); + imgt->create_from_image(img); pm->set_emission_color_texture(imgt); } if (valid_normals.size()) { pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); - PoolVector<uint8_t> normdata; + Vector<uint8_t> normdata; normdata.resize(w * h * 2 * sizeof(float)); //use RG texture { - PoolVector<uint8_t>::Write tw = normdata.write(); - float *twf = (float *)tw.ptr(); + uint8_t *tw = normdata.ptrw(); + float *twf = (float *)tw; for (int i = 0; i < vpc; i++) { twf[i * 2 + 0] = valid_normals[i].x; twf[i * 2 + 1] = valid_normals[i].y; @@ -337,7 +318,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { img->create(w, h, false, Image::FORMAT_RGF, normdata); imgt.instance(); - imgt->create_from_image(img, 0); + imgt->create_from_image(img); pm->set_emission_normal_texture(imgt); } else { @@ -345,27 +326,19 @@ void Particles2DEditorPlugin::_generate_emission_mask() { } } -void Particles2DEditorPlugin::_notification(int p_what) { - +void GPUParticles2DEditorPlugin::_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"); + menu->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles2DEditorPlugin::_menu_callback)); + menu->set_icon(menu->get_theme_icon("GPUParticles2D", "EditorIcons")); + file->connect("file_selected", callable_mp(this, &GPUParticles2DEditorPlugin::_file_selected)); } } -void Particles2DEditorPlugin::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_menu_callback"), &Particles2DEditorPlugin::_menu_callback); - ClassDB::bind_method(D_METHOD("_file_selected"), &Particles2DEditorPlugin::_file_selected); - ClassDB::bind_method(D_METHOD("_generate_visibility_rect"), &Particles2DEditorPlugin::_generate_visibility_rect); - ClassDB::bind_method(D_METHOD("_generate_emission_mask"), &Particles2DEditorPlugin::_generate_emission_mask); +void GPUParticles2DEditorPlugin::_bind_methods() { } -Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { - - particles = NULL; +GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin(EditorNode *p_node) { + particles = nullptr; editor = p_node; undo_redo = editor->get_undo_redo(); @@ -376,15 +349,12 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(memnew(VSeparator)); menu = memnew(MenuButton); + menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT); - menu->get_popup()->add_separator(); 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->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART); - menu->set_text(TTR("Particles")); + menu->get_popup()->add_item(TTR("Convert to CPUParticles2D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); + menu->set_text(TTR("GPUParticles2D")); menu->set_switch_on_hover(true); toolbar->add_child(menu); @@ -394,7 +364,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { 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); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); toolbar->add_child(file); epoints = memnew(SpinBox); @@ -416,7 +386,7 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(generate_visibility_rect); - generate_visibility_rect->connect("confirmed", this, "_generate_visibility_rect"); + generate_visibility_rect->connect("confirmed", callable_mp(this, &GPUParticles2DEditorPlugin::_generate_visibility_rect)); emission_mask = memnew(ConfirmationDialog); emission_mask->set_title(TTR("Load Emission Mask")); @@ -433,8 +403,8 @@ Particles2DEditorPlugin::Particles2DEditorPlugin(EditorNode *p_node) { toolbar->add_child(emission_mask); - emission_mask->connect("confirmed", this, "_generate_emission_mask"); + emission_mask->connect("confirmed", callable_mp(this, &GPUParticles2DEditorPlugin::_generate_emission_mask)); } -Particles2DEditorPlugin::~Particles2DEditorPlugin() { +GPUParticles2DEditorPlugin::~GPUParticles2DEditorPlugin() { } diff --git a/editor/plugins/particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h index 29652a1826..86e89bd0b0 100644 --- a/editor/plugins/particles_2d_editor_plugin.h +++ b/editor/plugins/gpu_particles_2d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_2d_editor_plugin.h */ +/* gpu_particles_2d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,13 +34,12 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "scene/2d/collision_polygon_2d.h" -#include "scene/2d/particles_2d.h" +#include "scene/2d/gpu_particles_2d.h" #include "scene/gui/box_container.h" #include "scene/gui/file_dialog.h" -class Particles2DEditorPlugin : public EditorPlugin { - - GDCLASS(Particles2DEditorPlugin, EditorPlugin); +class GPUParticles2DEditorPlugin : public EditorPlugin { + GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin); enum { @@ -57,7 +56,7 @@ class Particles2DEditorPlugin : public EditorPlugin { EMISSION_MODE_BORDER_DIRECTED }; - Particles2D *particles; + GPUParticles2D *particles; EditorFileDialog *file; EditorNode *editor; @@ -87,14 +86,14 @@ protected: static void _bind_methods(); public: - virtual String get_name() const { return "Particles2D"; } - 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); - - Particles2DEditorPlugin(EditorNode *p_node); - ~Particles2DEditorPlugin(); + virtual String get_name() const override { return "GPUParticles2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + GPUParticles2DEditorPlugin(EditorNode *p_node); + ~GPUParticles2DEditorPlugin(); }; #endif // PARTICLES_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index f869dabf9a..c98ba25db5 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_editor_plugin.cpp */ +/* gpu_particles_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,33 +28,30 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "particles_editor_plugin.h" +#include "gpu_particles_3d_editor_plugin.h" #include "core/io/resource_loader.h" -#include "editor/plugins/spatial_editor_plugin.h" -#include "scene/3d/cpu_particles.h" +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/cpu_particles_3d.h" #include "scene/resources/particles_material.h" -bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals) { - +bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) { bool use_normals = emission_fill->get_selected() == 1; if (emission_fill->get_selected() < 2) { - float area_accum = 0; Map<float, int> triangle_area_map; for (int i = 0; i < geometry.size(); i++) { - float area = geometry[i].get_area(); - if (area < CMP_EPSILON) + if (area < CMP_EPSILON) { continue; + } triangle_area_map[area_accum] = i; area_accum += area; } if (!triangle_area_map.size() || area_accum == 0) { - EditorNode::get_singleton()->show_warning(TTR("The geometry's faces don't contain any area.")); return false; } @@ -62,7 +59,6 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect int emissor_count = emission_amount->get_value(); for (int i = 0; i < emissor_count; i++) { - float areapos = Math::random(0.0f, area_accum); Map<float, int>::Element *E = triangle_area_map.find_closest(areapos); @@ -84,38 +80,33 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect } } } else { - int gcount = geometry.size(); if (gcount == 0) { - EditorNode::get_singleton()->show_warning(TTR("The geometry doesn't contain any faces.")); return false; } - PoolVector<Face3>::Read r = geometry.read(); + const Face3 *r = geometry.ptr(); AABB aabb; for (int i = 0; i < gcount; i++) { - for (int j = 0; j < 3; j++) { - - if (i == 0 && j == 0) + if (i == 0 && j == 0) { aabb.position = r[i].vertex[j]; - else + } else { aabb.expand_to(r[i].vertex[j]); + } } } int emissor_count = emission_amount->get_value(); for (int i = 0; i < emissor_count; i++) { - int attempts = 5; for (int j = 0; j < attempts; j++) { - Vector3 dir; dir[Math::rand() % 3] = 1.0; Vector3 ofs = (Vector3(1, 1, 1) - dir) * Vector3(Math::randf(), Math::randf(), Math::randf()) * aabb.size + aabb.position; @@ -129,24 +120,25 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect float max = -1e7, min = 1e7; for (int k = 0; k < gcount; k++) { - const Face3 &f3 = r[k]; Vector3 res; if (f3.intersects_segment(ofs, ofsv, &res)) { - res -= ofs; float d = dir.dot(res); - if (d < min) + if (d < min) { min = d; - if (d > max) + } + if (d > max) { max = d; + } } } - if (max < min) + if (max < min) { continue; //lost attempt + } float val = min + (max - min) * Math::randf(); @@ -161,29 +153,26 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect return true; } -void ParticlesEditorBase::_node_selected(const NodePath &p_path) { - +void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) { Node *sel = get_node(p_path); - if (!sel) + if (!sel) { return; + } - if (!sel->is_class("Spatial")) { - - EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't inherit from Spatial."), sel->get_name())); + if (!sel->is_class("Node3D")) { + EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't inherit from Node3D."), sel->get_name())); return; } - VisualInstance *vi = Object::cast_to<VisualInstance>(sel); + VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sel); if (!vi) { - EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain geometry."), sel->get_name())); return; } - geometry = vi->get_faces(VisualInstance::FACES_SOLID); + geometry = vi->get_faces(VisualInstance3D::FACES_SOLID); if (geometry.size() == 0) { - EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain face geometry."), sel->get_name())); return; } @@ -191,7 +180,7 @@ void ParticlesEditorBase::_node_selected(const NodePath &p_path) { Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform(); int gc = geometry.size(); - PoolVector<Face3>::Write w = geometry.write(); + Face3 *w = geometry.ptrw(); for (int i = 0; i < gc; i++) { for (int j = 0; j < 3; j++) { @@ -199,19 +188,13 @@ void ParticlesEditorBase::_node_selected(const NodePath &p_path) { } } - w.release(); - emission_dialog->popup_centered(Size2(300, 130)); } -void ParticlesEditorBase::_bind_methods() { - - ClassDB::bind_method("_node_selected", &ParticlesEditorBase::_node_selected); - ClassDB::bind_method("_generate_emission_points", &ParticlesEditorBase::_generate_emission_points); +void GPUParticles3DEditorBase::_bind_methods() { } -ParticlesEditorBase::ParticlesEditorBase() { - +GPUParticles3DEditorBase::GPUParticles3DEditorBase() { emission_dialog = memnew(ConfirmationDialog); emission_dialog->set_title(TTR("Create Emitter")); add_child(emission_dialog); @@ -231,67 +214,39 @@ ParticlesEditorBase::ParticlesEditorBase() { emd_vb->add_margin_child(TTR("Emission Source: "), emission_fill); emission_dialog->get_ok()->set_text(TTR("Create")); - emission_dialog->connect("confirmed", this, "_generate_emission_points"); + emission_dialog->connect("confirmed", callable_mp(this, &GPUParticles3DEditorBase::_generate_emission_points)); - emission_file_dialog = memnew(EditorFileDialog); - add_child(emission_file_dialog); - emission_file_dialog->connect("file_selected", this, "_resource_seleted"); emission_tree_dialog = memnew(SceneTreeDialog); add_child(emission_tree_dialog); - emission_tree_dialog->connect("selected", this, "_node_selected"); - - List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("Mesh", &extensions); - - emission_file_dialog->clear_filters(); - for (int i = 0; i < extensions.size(); i++) { - - emission_file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); - } - - emission_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + emission_tree_dialog->connect("selected", callable_mp(this, &GPUParticles3DEditorBase::_node_selected)); } -void ParticlesEditor::_node_removed(Node *p_node) { - +void GPUParticles3DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; + node = nullptr; hide(); } } -void ParticlesEditor::_notification(int p_notification) { - +void GPUParticles3DEditor::_notification(int p_notification) { if (p_notification == NOTIFICATION_ENTER_TREE) { - options->set_icon(options->get_popup()->get_icon("Particles", "EditorIcons")); - get_tree()->connect("node_removed", this, "_node_removed"); + options->set_icon(options->get_popup()->get_theme_icon("GPUParticles3D", "EditorIcons")); + get_tree()->connect("node_removed", callable_mp(this, &GPUParticles3DEditor::_node_removed)); } } -void ParticlesEditor::_menu_option(int p_option) { - +void GPUParticles3DEditor::_menu_option(int p_option) { switch (p_option) { - case MENU_OPTION_GENERATE_AABB: { float gen_time = node->get_lifetime(); - if (gen_time < 1.0) + if (gen_time < 1.0) { generate_seconds->set_value(1.0); - else + } else { generate_seconds->set_value(trunc(gen_time) + 1.0); - generate_aabb->popup_centered_minsize(); - } break; - case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { - - Ref<ParticlesMaterial> material = node->get_process_material(); - if (material.is_null()) { - EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required.")); - return; } - emission_file_dialog->popup_centered_ratio(); - + generate_aabb->popup_centered(); } break; - case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: { Ref<ParticlesMaterial> material = node->get_process_material(); if (material.is_null()) { @@ -299,12 +254,11 @@ void ParticlesEditor::_menu_option(int p_option) { return; } - emission_tree_dialog->popup_centered_ratio(); + emission_tree_dialog->popup_scenetree_dialog(); } break; case MENU_OPTION_CONVERT_TO_CPU_PARTICLES: { - - CPUParticles *cpu_particles = memnew(CPUParticles); + CPUParticles3D *cpu_particles = memnew(CPUParticles3D); cpu_particles->convert_from_particles(node); cpu_particles->set_name(node->get_name()); cpu_particles->set_transform(node->get_transform()); @@ -312,7 +266,7 @@ void ParticlesEditor::_menu_option(int p_option) { cpu_particles->set_pause_mode(node->get_pause_mode()); UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Convert to CPUParticles")); + ur->create_action(TTR("Convert to CPUParticles3D")); ur->add_do_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", node, cpu_particles, true, false); ur->add_do_reference(cpu_particles); ur->add_undo_method(EditorNode::get_singleton()->get_scene_tree_dock(), "replace_node", cpu_particles, node, false, false); @@ -321,15 +275,13 @@ void ParticlesEditor::_menu_option(int p_option) { } break; case MENU_OPTION_RESTART: { - node->restart(); } break; } } -void ParticlesEditor::_generate_aabb() { - +void GPUParticles3DEditor::_generate_aabb() { float time = generate_seconds->get_value(); float running = 0.0; @@ -345,16 +297,16 @@ void ParticlesEditor::_generate_aabb() { AABB rect; while (running < time) { - uint64_t ticks = OS::get_singleton()->get_ticks_usec(); ep.step("Generating...", int(running), true); OS::get_singleton()->delay_usec(1000); AABB capture = node->capture_aabb(); - if (rect == AABB()) + if (rect == AABB()) { rect = capture; - else + } else { rect.merge_with(capture); + } running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } @@ -370,17 +322,15 @@ void ParticlesEditor::_generate_aabb() { ur->commit_action(); } -void ParticlesEditor::edit(Particles *p_particles) { - +void GPUParticles3DEditor::edit(GPUParticles3D *p_particles) { base_node = p_particles; node = p_particles; } -void ParticlesEditor::_generate_emission_points() { - +void GPUParticles3DEditor::_generate_emission_points() { /// hacer codigo aca - PoolVector<Vector3> points; - PoolVector<Vector3> normals; + Vector<Vector3> points; + Vector<Vector3> normals; if (!_generate(points, normals)) { return; @@ -391,14 +341,14 @@ void ParticlesEditor::_generate_emission_points() { int w = 2048; int h = (point_count / 2048) + 1; - PoolVector<uint8_t> point_img; + Vector<uint8_t> point_img; point_img.resize(w * h * 3 * sizeof(float)); { - PoolVector<uint8_t>::Write iw = point_img.write(); - zeromem(iw.ptr(), w * h * 3 * sizeof(float)); - PoolVector<Vector3>::Read r = points.read(); - float *wf = (float *)iw.ptr(); + uint8_t *iw = point_img.ptrw(); + zeromem(iw, w * h * 3 * sizeof(float)); + const Vector3 *r = points.ptr(); + float *wf = (float *)iw; for (int i = 0; i < point_count; i++) { wf[i * 3 + 0] = r[i].x; wf[i * 3 + 1] = r[i].y; @@ -410,25 +360,23 @@ void ParticlesEditor::_generate_emission_points() { Ref<ImageTexture> tex; tex.instance(); - tex->create_from_image(image, Texture::FLAG_FILTER); Ref<ParticlesMaterial> material = node->get_process_material(); ERR_FAIL_COND(material.is_null()); if (normals.size() > 0) { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); - PoolVector<uint8_t> point_img2; + Vector<uint8_t> point_img2; point_img2.resize(w * h * 3 * sizeof(float)); { - PoolVector<uint8_t>::Write iw = point_img2.write(); - zeromem(iw.ptr(), w * h * 3 * sizeof(float)); - PoolVector<Vector3>::Read r = normals.read(); - float *wf = (float *)iw.ptr(); + uint8_t *iw = point_img2.ptrw(); + zeromem(iw, w * h * 3 * sizeof(float)); + const Vector3 *r = normals.ptr(); + float *wf = (float *)iw; for (int i = 0; i < point_count; i++) { wf[i * 3 + 0] = r[i].x; wf[i * 3 + 1] = r[i].y; @@ -440,45 +388,34 @@ void ParticlesEditor::_generate_emission_points() { Ref<ImageTexture> tex2; tex2.instance(); - tex2->create_from_image(image2, Texture::FLAG_FILTER); material->set_emission_normal_texture(tex2); } else { - material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS); material->set_emission_point_count(point_count); material->set_emission_point_texture(tex); } } -void ParticlesEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &ParticlesEditor::_menu_option); - ClassDB::bind_method("_generate_aabb", &ParticlesEditor::_generate_aabb); - ClassDB::bind_method("_node_removed", &ParticlesEditor::_node_removed); +void GPUParticles3DEditor::_bind_methods() { } -ParticlesEditor::ParticlesEditor() { - - node = NULL; +GPUParticles3DEditor::GPUParticles3DEditor() { + node = nullptr; particles_editor_hb = memnew(HBoxContainer); - SpatialEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); + Node3DEditor::get_singleton()->add_control_to_menu_panel(particles_editor_hb); options = memnew(MenuButton); options->set_switch_on_hover(true); particles_editor_hb->add_child(options); particles_editor_hb->hide(); - options->set_text(TTR("Particles")); + options->set_text(TTR("GPUParticles3D")); + options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); options->get_popup()->add_item(TTR("Generate AABB"), MENU_OPTION_GENERATE_AABB); - options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Create Emission Points From Mesh"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH); options->get_popup()->add_item(TTR("Create Emission Points From Node"), MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE); - options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Convert to CPUParticles"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - options->get_popup()->add_separator(); - options->get_popup()->add_item(TTR("Restart"), MENU_OPTION_RESTART); + options->get_popup()->add_item(TTR("Convert to CPUParticles3D"), MENU_OPTION_CONVERT_TO_CPU_PARTICLES); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->connect("id_pressed", callable_mp(this, &GPUParticles3DEditor::_menu_option)); generate_aabb = memnew(ConfirmationDialog); generate_aabb->set_title(TTR("Generate Visibility AABB")); @@ -492,39 +429,35 @@ ParticlesEditor::ParticlesEditor() { add_child(generate_aabb); - generate_aabb->connect("confirmed", this, "_generate_aabb"); + generate_aabb->connect("confirmed", callable_mp(this, &GPUParticles3DEditor::_generate_aabb)); } -void ParticlesEditorPlugin::edit(Object *p_object) { - - particles_editor->edit(Object::cast_to<Particles>(p_object)); +void GPUParticles3DEditorPlugin::edit(Object *p_object) { + particles_editor->edit(Object::cast_to<GPUParticles3D>(p_object)); } -bool ParticlesEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Particles"); +bool GPUParticles3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("GPUParticles3D"); } -void ParticlesEditorPlugin::make_visible(bool p_visible) { - +void GPUParticles3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { particles_editor->show(); particles_editor->particles_editor_hb->show(); } else { particles_editor->particles_editor_hb->hide(); particles_editor->hide(); - particles_editor->edit(NULL); + particles_editor->edit(nullptr); } } -ParticlesEditorPlugin::ParticlesEditorPlugin(EditorNode *p_node) { - +GPUParticles3DEditorPlugin::GPUParticles3DEditorPlugin(EditorNode *p_node) { editor = p_node; - particles_editor = memnew(ParticlesEditor); + particles_editor = memnew(GPUParticles3DEditor); editor->get_viewport()->add_child(particles_editor); particles_editor->hide(); } -ParticlesEditorPlugin::~ParticlesEditorPlugin() { +GPUParticles3DEditorPlugin::~GPUParticles3DEditorPlugin() { } diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/gpu_particles_3d_editor_plugin.h index 4b20d00670..1665b3676a 100644 --- a/editor/plugins/particles_editor_plugin.h +++ b/editor/plugins/gpu_particles_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* particles_editor_plugin.h */ +/* gpu_particles_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,51 +33,47 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/particles.h" +#include "scene/3d/gpu_particles_3d.h" #include "scene/gui/spin_box.h" -class ParticlesEditorBase : public Control { - - GDCLASS(ParticlesEditorBase, Control); +class GPUParticles3DEditorBase : public Control { + GDCLASS(GPUParticles3DEditorBase, Control); protected: - Spatial *base_node; + Node3D *base_node; Panel *panel; MenuButton *options; HBoxContainer *particles_editor_hb; - EditorFileDialog *emission_file_dialog; SceneTreeDialog *emission_tree_dialog; ConfirmationDialog *emission_dialog; SpinBox *emission_amount; OptionButton *emission_fill; - PoolVector<Face3> geometry; + Vector<Face3> geometry; - bool _generate(PoolVector<Vector3> &points, PoolVector<Vector3> &normals); + bool _generate(Vector<Vector3> &points, Vector<Vector3> &normals); virtual void _generate_emission_points() = 0; void _node_selected(const NodePath &p_path); static void _bind_methods(); public: - ParticlesEditorBase(); + GPUParticles3DEditorBase(); }; -class ParticlesEditor : public ParticlesEditorBase { - - GDCLASS(ParticlesEditor, ParticlesEditorBase); +class GPUParticles3DEditor : public GPUParticles3DEditorBase { + GDCLASS(GPUParticles3DEditor, GPUParticles3DEditorBase); ConfirmationDialog *generate_aabb; SpinBox *generate_seconds; - Particles *node; + GPUParticles3D *node; enum Menu { MENU_OPTION_GENERATE_AABB, MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE, - MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH, MENU_OPTION_CLEAR_EMISSION_VOLUME, MENU_OPTION_CONVERT_TO_CPU_PARTICLES, MENU_OPTION_RESTART, @@ -88,9 +84,9 @@ class ParticlesEditor : public ParticlesEditorBase { void _menu_option(int); - friend class ParticlesEditorPlugin; + friend class GPUParticles3DEditorPlugin; - virtual void _generate_emission_points(); + virtual void _generate_emission_points() override; protected: void _notification(int p_notification); @@ -98,26 +94,25 @@ protected: static void _bind_methods(); public: - void edit(Particles *p_particles); - ParticlesEditor(); + void edit(GPUParticles3D *p_particles); + GPUParticles3DEditor(); }; -class ParticlesEditorPlugin : public EditorPlugin { - - GDCLASS(ParticlesEditorPlugin, EditorPlugin); +class GPUParticles3DEditorPlugin : public EditorPlugin { + GDCLASS(GPUParticles3DEditorPlugin, EditorPlugin); - ParticlesEditor *particles_editor; + GPUParticles3DEditor *particles_editor; EditorNode *editor; public: - virtual String get_name() const { return "Particles"; } - 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); - - ParticlesEditorPlugin(EditorNode *p_node); - ~ParticlesEditorPlugin(); + virtual String get_name() const override { return "GPUParticles3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + GPUParticles3DEditorPlugin(EditorNode *p_node); + ~GPUParticles3DEditorPlugin(); }; #endif // PARTICLES_EDITOR_PLUGIN_H diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 0a3a994eb7..13b5c8cef5 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -32,15 +32,16 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_scale.h" -#include "spatial_editor_plugin.h" +#include "node_3d_editor_plugin.h" Size2 GradientEditor::get_minimum_size() const { return Size2(0, 60) * EDSCALE; } -void GradientEditor::_gradient_changed() { - if (editing) +void GradientEditor::_gradient_changed() { + if (editing) { return; + } editing = true; Vector<Gradient::Point> points = gradient->get_points(); @@ -49,7 +50,6 @@ void GradientEditor::_gradient_changed() { } void GradientEditor::_ramp_changed() { - editing = true; UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Gradient Edited")); @@ -62,15 +62,12 @@ void GradientEditor::_ramp_changed() { } void GradientEditor::_bind_methods() { - - ClassDB::bind_method("_gradient_changed", &GradientEditor::_gradient_changed); - ClassDB::bind_method("_ramp_changed", &GradientEditor::_ramp_changed); } void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { gradient = p_gradient; - connect("ramp_changed", this, "_ramp_changed"); - gradient->connect("changed", this, "_gradient_changed"); + connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed)); + gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed)); set_points(gradient->get_points()); } @@ -81,12 +78,10 @@ GradientEditor::GradientEditor() { /////////////////////// bool EditorInspectorPluginGradient::can_handle(Object *p_object) { - - return Object::cast_to<Gradient>(p_object) != NULL; + return Object::cast_to<Gradient>(p_object) != nullptr; } void EditorInspectorPluginGradient::parse_begin(Object *p_object) { - Gradient *gradient = Object::cast_to<Gradient>(p_object); Ref<Gradient> g(gradient); @@ -96,7 +91,6 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) { } GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { - Ref<EditorInspectorPluginGradient> plugin; plugin.instance(); add_inspector_plugin(plugin); diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 9ebd9610e5..59cf787020 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -48,7 +48,7 @@ protected: static void _bind_methods(); public: - virtual Size2 get_minimum_size() const; + virtual Size2 get_minimum_size() const override; void set_gradient(const Ref<Gradient> &p_gradient); GradientEditor(); }; @@ -57,16 +57,15 @@ class EditorInspectorPluginGradient : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; }; class GradientEditorPlugin : public EditorPlugin { - GDCLASS(GradientEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "ColorRamp"; } + virtual String get_name() const override { return "ColorRamp"; } GradientEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp index 9f836ed0d3..b4dcbdfe20 100644 --- a/editor/plugins/item_list_editor_plugin.cpp +++ b/editor/plugins/item_list_editor_plugin.cpp @@ -34,16 +34,15 @@ #include "editor/editor_scale.h" bool ItemListPlugin::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name; int idx = name.get_slice("/", 0).to_int(); String what = name.get_slice("/", 1); - if (what == "text") + if (what == "text") { set_item_text(idx, p_value); - else if (what == "icon") + } else if (what == "icon") { set_item_icon(idx, p_value); - else if (what == "checkable") { + } else if (what == "checkable") { // This keeps compatibility to/from versions where this property was a boolean, before radio buttons switch ((int)p_value) { case 0: @@ -54,58 +53,58 @@ bool ItemListPlugin::_set(const StringName &p_name, const Variant &p_value) { set_item_radio_checkable(idx, true); break; } - } else if (what == "checked") + } else if (what == "checked") { set_item_checked(idx, p_value); - else if (what == "id") + } else if (what == "id") { set_item_id(idx, p_value); - else if (what == "enabled") + } else if (what == "enabled") { set_item_enabled(idx, p_value); - else if (what == "separator") + } else if (what == "separator") { set_item_separator(idx, p_value); - else + } else { return false; + } return true; } bool ItemListPlugin::_get(const StringName &p_name, Variant &r_ret) const { - String name = p_name; int idx = name.get_slice("/", 0).to_int(); String what = name.get_slice("/", 1); - if (what == "text") + if (what == "text") { r_ret = get_item_text(idx); - else if (what == "icon") + } else if (what == "icon") { r_ret = get_item_icon(idx); - else if (what == "checkable") { + } else if (what == "checkable") { // This keeps compatibility to/from versions where this property was a boolean, before radio buttons if (!is_item_checkable(idx)) { r_ret = 0; } else { r_ret = is_item_radio_checkable(idx) ? 2 : 1; } - } else if (what == "checked") + } else if (what == "checked") { r_ret = is_item_checked(idx); - else if (what == "id") + } else if (what == "id") { r_ret = get_item_id(idx); - else if (what == "enabled") + } else if (what == "enabled") { r_ret = is_item_enabled(idx); - else if (what == "separator") + } else if (what == "separator") { r_ret = is_item_separator(idx); - else + } else { return false; + } return true; } -void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const { +void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < get_item_count(); i++) { - String base = itos(i) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, base + "text")); - p_list->push_back(PropertyInfo(Variant::OBJECT, base + "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); + p_list->push_back(PropertyInfo(Variant::OBJECT, base + "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D")); int flags = get_flags(); @@ -114,14 +113,17 @@ void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, base + "checked")); } - if (flags & FLAG_ID) + if (flags & FLAG_ID) { p_list->push_back(PropertyInfo(Variant::INT, base + "id", PROPERTY_HINT_RANGE, "-1,4096")); + } - if (flags & FLAG_ENABLE) + if (flags & FLAG_ENABLE) { p_list->push_back(PropertyInfo(Variant::BOOL, base + "enabled")); + } - if (flags & FLAG_SEPARATOR) + if (flags & FLAG_SEPARATOR) { p_list->push_back(PropertyInfo(Variant::BOOL, base + "separator")); + } } } @@ -130,121 +132,101 @@ void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const { /////////////////////////////////////////////////////////////// void ItemListOptionButtonPlugin::set_object(Object *p_object) { - ob = Object::cast_to<OptionButton>(p_object); } bool ItemListOptionButtonPlugin::handles(Object *p_object) const { - return p_object->is_class("OptionButton"); } int ItemListOptionButtonPlugin::get_flags() const { - return FLAG_ICON | FLAG_ID | FLAG_ENABLE; } void ItemListOptionButtonPlugin::add_item() { - ob->add_item(vformat(TTR("Item %d"), ob->get_item_count())); _change_notify(); } int ItemListOptionButtonPlugin::get_item_count() const { - return ob->get_item_count(); } void ItemListOptionButtonPlugin::erase(int p_idx) { - ob->remove_item(p_idx); _change_notify(); } ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() { - - ob = NULL; + ob = nullptr; } /////////////////////////////////////////////////////////////// void ItemListPopupMenuPlugin::set_object(Object *p_object) { - - if (p_object->is_class("MenuButton")) + if (p_object->is_class("MenuButton")) { pp = Object::cast_to<MenuButton>(p_object)->get_popup(); - else + } else { pp = Object::cast_to<PopupMenu>(p_object); + } } bool ItemListPopupMenuPlugin::handles(Object *p_object) const { - return p_object->is_class("PopupMenu") || p_object->is_class("MenuButton"); } int ItemListPopupMenuPlugin::get_flags() const { - return FLAG_ICON | FLAG_CHECKABLE | FLAG_ID | FLAG_ENABLE | FLAG_SEPARATOR; } void ItemListPopupMenuPlugin::add_item() { - pp->add_item(vformat(TTR("Item %d"), pp->get_item_count())); _change_notify(); } int ItemListPopupMenuPlugin::get_item_count() const { - return pp->get_item_count(); } void ItemListPopupMenuPlugin::erase(int p_idx) { - pp->remove_item(p_idx); _change_notify(); } ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() { - - pp = NULL; + pp = nullptr; } /////////////////////////////////////////////////////////////// void ItemListItemListPlugin::set_object(Object *p_object) { - pp = Object::cast_to<ItemList>(p_object); } bool ItemListItemListPlugin::handles(Object *p_object) const { - return p_object->is_class("ItemList"); } int ItemListItemListPlugin::get_flags() const { - return FLAG_ICON | FLAG_ENABLE; } void ItemListItemListPlugin::add_item() { - pp->add_item(vformat(TTR("Item %d"), pp->get_item_count())); _change_notify(); } int ItemListItemListPlugin::get_item_count() const { - return pp->get_item_count(); } void ItemListItemListPlugin::erase(int p_idx) { - pp->remove_item(p_idx); _change_notify(); } ItemListItemListPlugin::ItemListItemListPlugin() { - - pp = NULL; + pp = nullptr; } /////////////////////////////////////////////////////////////// @@ -252,43 +234,40 @@ ItemListItemListPlugin::ItemListItemListPlugin() { /////////////////////////////////////////////////////////////// void ItemListEditor::_node_removed(Node *p_node) { - if (p_node == item_list) { - item_list = NULL; + item_list = nullptr; hide(); dialog->hide(); } } void ItemListEditor::_notification(int p_notification) { - if (p_notification == NOTIFICATION_ENTER_TREE || p_notification == NOTIFICATION_THEME_CHANGED) { - - add_button->set_icon(get_icon("Add", "EditorIcons")); - del_button->set_icon(get_icon("Remove", "EditorIcons")); + add_button->set_icon(get_theme_icon("Add", "EditorIcons")); + del_button->set_icon(get_theme_icon("Remove", "EditorIcons")); } else if (p_notification == NOTIFICATION_READY) { - - get_tree()->connect("node_removed", this, "_node_removed"); + get_tree()->connect("node_removed", callable_mp(this, &ItemListEditor::_node_removed)); } } void ItemListEditor::_add_pressed() { - - if (selected_idx == -1) + if (selected_idx == -1) { return; + } item_plugins[selected_idx]->add_item(); } void ItemListEditor::_delete_pressed() { - - if (selected_idx == -1) + if (selected_idx == -1) { return; + } String current_selected = (String)property_editor->get_selected_path(); - if (current_selected == "") + if (current_selected == "") { return; + } // FIXME: Currently relying on selecting a *property* to derive what item to delete // e.g. you select "1/enabled" to delete item 1. @@ -301,23 +280,20 @@ void ItemListEditor::_delete_pressed() { } void ItemListEditor::_edit_items() { - dialog->popup_centered_clamped(Vector2(425, 1200) * EDSCALE, 0.8); } void ItemListEditor::edit(Node *p_item_list) { - item_list = p_item_list; if (!item_list) { selected_idx = -1; - property_editor->edit(NULL); + property_editor->edit(nullptr); return; } for (int i = 0; i < item_plugins.size(); i++) { if (item_plugins[i]->handles(p_item_list)) { - item_plugins[i]->set_object(p_item_list); property_editor->edit(item_plugins[i]); @@ -329,11 +305,10 @@ void ItemListEditor::edit(Node *p_item_list) { } selected_idx = -1; - property_editor->edit(NULL); + property_editor->edit(nullptr); } bool ItemListEditor::handles(Object *p_object) const { - for (int i = 0; i < item_plugins.size(); i++) { if (item_plugins[i]->handles(p_object)) { return true; @@ -344,22 +319,17 @@ bool ItemListEditor::handles(Object *p_object) const { } void ItemListEditor::_bind_methods() { - - ClassDB::bind_method("_node_removed", &ItemListEditor::_node_removed); - ClassDB::bind_method("_edit_items", &ItemListEditor::_edit_items); - ClassDB::bind_method("_add_button", &ItemListEditor::_add_pressed); - ClassDB::bind_method("_delete_button", &ItemListEditor::_delete_pressed); } ItemListEditor::ItemListEditor() { - selected_idx = -1; - item_list = NULL; + item_list = nullptr; - toolbar_button = memnew(ToolButton); + toolbar_button = memnew(Button); + toolbar_button->set_flat(true); toolbar_button->set_text(TTR("Items")); add_child(toolbar_button); - toolbar_button->connect("pressed", this, "_edit_items"); + toolbar_button->connect("pressed", callable_mp(this, &ItemListEditor::_edit_items)); dialog = memnew(AcceptDialog); dialog->set_title(TTR("Item List Editor")); @@ -376,14 +346,14 @@ ItemListEditor::ItemListEditor() { add_button = memnew(Button); add_button->set_text(TTR("Add")); hbc->add_child(add_button); - add_button->connect("pressed", this, "_add_button"); + add_button->connect("pressed", callable_mp(this, &ItemListEditor::_add_pressed)); hbc->add_spacer(); del_button = memnew(Button); del_button->set_text(TTR("Delete")); hbc->add_child(del_button); - del_button->connect("pressed", this, "_delete_button"); + del_button->connect("pressed", callable_mp(this, &ItemListEditor::_delete_pressed)); property_editor = memnew(EditorInspector); vbc->add_child(property_editor); @@ -391,34 +361,29 @@ ItemListEditor::ItemListEditor() { } ItemListEditor::~ItemListEditor() { - - for (int i = 0; i < item_plugins.size(); i++) + for (int i = 0; i < item_plugins.size(); i++) { memdelete(item_plugins[i]); + } } void ItemListEditorPlugin::edit(Object *p_object) { - item_list_editor->edit(Object::cast_to<Node>(p_object)); } bool ItemListEditorPlugin::handles(Object *p_object) const { - return item_list_editor->handles(p_object); } void ItemListEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { item_list_editor->show(); } else { - item_list_editor->hide(); - item_list_editor->edit(NULL); + item_list_editor->edit(nullptr); } } ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) { - editor = p_node; item_list_editor = memnew(ItemListEditor); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(item_list_editor); diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 8a73367bf7..87586904a3 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -40,7 +40,6 @@ #include "scene/gui/popup_menu.h" class ItemListPlugin : public Object { - GDCLASS(ItemListPlugin, Object); protected: @@ -66,8 +65,8 @@ public: virtual void set_item_text(int p_idx, const String &p_text) {} virtual String get_item_text(int p_idx) const { return ""; }; - virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) {} - virtual Ref<Texture> get_item_icon(int p_idx) const { return Ref<Texture>(); }; + virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) {} + virtual Ref<Texture2D> get_item_icon(int p_idx) const { return Ref<Texture2D>(); }; virtual void set_item_checkable(int p_idx, bool p_check) {} virtual void set_item_radio_checkable(int p_idx, bool p_check) {} @@ -96,72 +95,70 @@ public: /////////////////////////////////////////////////////////////// class ItemListOptionButtonPlugin : public ItemListPlugin { - GDCLASS(ItemListOptionButtonPlugin, ItemListPlugin); OptionButton *ob; public: - virtual void set_object(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual int get_flags() const; + virtual void set_object(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual int get_flags() const override; - virtual void set_item_text(int p_idx, const String &p_text) { ob->set_item_text(p_idx, p_text); } - virtual String get_item_text(int p_idx) const { return ob->get_item_text(p_idx); } + virtual void set_item_text(int p_idx, const String &p_text) override { ob->set_item_text(p_idx, p_text); } + virtual String get_item_text(int p_idx) const override { return ob->get_item_text(p_idx); } - virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) { ob->set_item_icon(p_idx, p_tex); } - virtual Ref<Texture> get_item_icon(int p_idx) const { return ob->get_item_icon(p_idx); } + virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { ob->set_item_icon(p_idx, p_tex); } + virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return ob->get_item_icon(p_idx); } - virtual void set_item_enabled(int p_idx, int p_enabled) { ob->set_item_disabled(p_idx, !p_enabled); } - virtual bool is_item_enabled(int p_idx) const { return !ob->is_item_disabled(p_idx); } + virtual void set_item_enabled(int p_idx, int p_enabled) override { ob->set_item_disabled(p_idx, !p_enabled); } + virtual bool is_item_enabled(int p_idx) const override { return !ob->is_item_disabled(p_idx); } - virtual void set_item_id(int p_idx, int p_id) { ob->set_item_id(p_idx, p_id); } - virtual int get_item_id(int p_idx) const { return ob->get_item_id(p_idx); } + virtual void set_item_id(int p_idx, int p_id) override { ob->set_item_id(p_idx, p_id); } + virtual int get_item_id(int p_idx) const override { return ob->get_item_id(p_idx); } - virtual void add_item(); - virtual int get_item_count() const; - virtual void erase(int p_idx); + virtual void add_item() override; + virtual int get_item_count() const override; + virtual void erase(int p_idx) override; ItemListOptionButtonPlugin(); }; class ItemListPopupMenuPlugin : public ItemListPlugin { - GDCLASS(ItemListPopupMenuPlugin, ItemListPlugin); PopupMenu *pp; public: - virtual void set_object(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual int get_flags() const; + virtual void set_object(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual int get_flags() const override; - virtual void set_item_text(int p_idx, const String &p_text) { pp->set_item_text(p_idx, p_text); } - virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); } + virtual void set_item_text(int p_idx, const String &p_text) override { pp->set_item_text(p_idx, p_text); } + virtual String get_item_text(int p_idx) const override { return pp->get_item_text(p_idx); } - virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) { pp->set_item_icon(p_idx, p_tex); } - virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); } + virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { pp->set_item_icon(p_idx, p_tex); } + virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return pp->get_item_icon(p_idx); } - virtual void set_item_checkable(int p_idx, bool p_check) { pp->set_item_as_checkable(p_idx, p_check); } - virtual void set_item_radio_checkable(int p_idx, bool p_check) { pp->set_item_as_radio_checkable(p_idx, p_check); } - virtual bool is_item_checkable(int p_idx) const { return pp->is_item_checkable(p_idx); } - virtual bool is_item_radio_checkable(int p_idx) const { return pp->is_item_radio_checkable(p_idx); } + virtual void set_item_checkable(int p_idx, bool p_check) override { pp->set_item_as_checkable(p_idx, p_check); } + virtual void set_item_radio_checkable(int p_idx, bool p_check) override { pp->set_item_as_radio_checkable(p_idx, p_check); } + virtual bool is_item_checkable(int p_idx) const override { return pp->is_item_checkable(p_idx); } + virtual bool is_item_radio_checkable(int p_idx) const override { return pp->is_item_radio_checkable(p_idx); } - virtual void set_item_checked(int p_idx, bool p_checked) { pp->set_item_checked(p_idx, p_checked); } - virtual bool is_item_checked(int p_idx) const { return pp->is_item_checked(p_idx); } + virtual void set_item_checked(int p_idx, bool p_checked) override { pp->set_item_checked(p_idx, p_checked); } + virtual bool is_item_checked(int p_idx) const override { return pp->is_item_checked(p_idx); } - virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } - virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } + virtual void set_item_enabled(int p_idx, int p_enabled) override { pp->set_item_disabled(p_idx, !p_enabled); } + virtual bool is_item_enabled(int p_idx) const override { return !pp->is_item_disabled(p_idx); } - virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_id); } - virtual int get_item_id(int p_idx) const { return pp->get_item_id(p_idx); } + virtual void set_item_id(int p_idx, int p_id) override { pp->set_item_id(p_idx, p_id); } + virtual int get_item_id(int p_idx) const override { return pp->get_item_id(p_idx); } - virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx, p_separator); } - virtual bool is_item_separator(int p_idx) const { return pp->is_item_separator(p_idx); } + virtual void set_item_separator(int p_idx, bool p_separator) override { pp->set_item_as_separator(p_idx, p_separator); } + virtual bool is_item_separator(int p_idx) const override { return pp->is_item_separator(p_idx); } - virtual void add_item(); - virtual int get_item_count() const; - virtual void erase(int p_idx); + virtual void add_item() override; + virtual int get_item_count() const override; + virtual void erase(int p_idx) override; ItemListPopupMenuPlugin(); }; @@ -169,28 +166,27 @@ public: /////////////////////////////////////////////////////////////// class ItemListItemListPlugin : public ItemListPlugin { - GDCLASS(ItemListItemListPlugin, ItemListPlugin); ItemList *pp; public: - virtual void set_object(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual int get_flags() const; + virtual void set_object(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual int get_flags() const override; - virtual void set_item_text(int p_idx, const String &p_text) { pp->set_item_text(p_idx, p_text); } - virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); } + virtual void set_item_text(int p_idx, const String &p_text) override { pp->set_item_text(p_idx, p_text); } + virtual String get_item_text(int p_idx) const override { return pp->get_item_text(p_idx); } - virtual void set_item_icon(int p_idx, const Ref<Texture> &p_tex) { pp->set_item_icon(p_idx, p_tex); } - virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); } + virtual void set_item_icon(int p_idx, const Ref<Texture2D> &p_tex) override { pp->set_item_icon(p_idx, p_tex); } + virtual Ref<Texture2D> get_item_icon(int p_idx) const override { return pp->get_item_icon(p_idx); } - virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } - virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } + virtual void set_item_enabled(int p_idx, int p_enabled) override { pp->set_item_disabled(p_idx, !p_enabled); } + virtual bool is_item_enabled(int p_idx) const override { return !pp->is_item_disabled(p_idx); } - virtual void add_item(); - virtual int get_item_count() const; - virtual void erase(int p_idx); + virtual void add_item() override; + virtual int get_item_count() const override; + virtual void erase(int p_idx) override; ItemListItemListPlugin(); }; @@ -198,12 +194,11 @@ public: /////////////////////////////////////////////////////////////// class ItemListEditor : public HBoxContainer { - GDCLASS(ItemListEditor, HBoxContainer); Node *item_list; - ToolButton *toolbar_button; + Button *toolbar_button; AcceptDialog *dialog; EditorInspector *property_editor; @@ -235,18 +230,17 @@ public: }; class ItemListEditorPlugin : public EditorPlugin { - GDCLASS(ItemListEditorPlugin, EditorPlugin); ItemListEditor *item_list_editor; EditorNode *editor; public: - virtual String get_name() const { return "ItemList"; } - 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); + virtual String get_name() const override { return "ItemList"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; ItemListEditorPlugin(EditorNode *p_node); ~ItemListEditorPlugin(); diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp index 22df287f97..e422140efa 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.cpp +++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -31,10 +31,8 @@ #include "light_occluder_2d_editor_plugin.h" Ref<OccluderPolygon2D> LightOccluder2DEditor::_ensure_occluder() const { - Ref<OccluderPolygon2D> occluder = node->get_occluder_polygon(); if (!occluder.is_valid()) { - occluder = Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D)); node->set_occluder_polygon(occluder); } @@ -42,64 +40,59 @@ Ref<OccluderPolygon2D> LightOccluder2DEditor::_ensure_occluder() const { } Node2D *LightOccluder2DEditor::_get_node() const { - return node; } void LightOccluder2DEditor::_set_node(Node *p_polygon) { - node = Object::cast_to<LightOccluder2D>(p_polygon); } bool LightOccluder2DEditor::_is_line() const { - Ref<OccluderPolygon2D> occluder = node->get_occluder_polygon(); - if (occluder.is_valid()) + if (occluder.is_valid()) { return !occluder->is_closed(); - else + } else { return false; + } } int LightOccluder2DEditor::_get_polygon_count() const { - Ref<OccluderPolygon2D> occluder = node->get_occluder_polygon(); - if (occluder.is_valid()) + if (occluder.is_valid()) { return occluder->get_polygon().size(); - else + } else { return 0; + } } Variant LightOccluder2DEditor::_get_polygon(int p_idx) const { - Ref<OccluderPolygon2D> occluder = node->get_occluder_polygon(); - if (occluder.is_valid()) + if (occluder.is_valid()) { return occluder->get_polygon(); - else + } else { return Variant(Vector<Vector2>()); + } } void LightOccluder2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { - Ref<OccluderPolygon2D> occluder = _ensure_occluder(); occluder->set_polygon(p_polygon); } void LightOccluder2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { - Ref<OccluderPolygon2D> occluder = _ensure_occluder(); undo_redo->add_do_method(occluder.ptr(), "set_polygon", p_polygon); undo_redo->add_undo_method(occluder.ptr(), "set_polygon", p_previous); } bool LightOccluder2DEditor::_has_resource() const { - return node && node->get_occluder_polygon().is_valid(); } void LightOccluder2DEditor::_create_resource() { - - if (!node) + if (!node) { return; + } undo_redo->create_action(TTR("Create Occluder Polygon")); undo_redo->add_do_method(node, "set_occluder_polygon", Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D))); @@ -111,8 +104,7 @@ void LightOccluder2DEditor::_create_resource() { LightOccluder2DEditor::LightOccluder2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { - - node = NULL; + node = nullptr; } LightOccluder2DEditorPlugin::LightOccluder2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h index 74ae9e0889..e034a41ddc 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.h +++ b/editor/plugins/light_occluder_2d_editor_plugin.h @@ -35,7 +35,6 @@ #include "scene/2d/light_occluder_2d.h" class LightOccluder2DEditor : public AbstractPolygon2DEditor { - GDCLASS(LightOccluder2DEditor, AbstractPolygon2DEditor); LightOccluder2D *node; @@ -43,25 +42,24 @@ class LightOccluder2DEditor : public AbstractPolygon2DEditor { Ref<OccluderPolygon2D> _ensure_occluder() const; protected: - virtual Node2D *_get_node() const; - virtual void _set_node(Node *p_polygon); + virtual Node2D *_get_node() const override; + virtual void _set_node(Node *p_polygon) override; - virtual bool _is_line() const; - virtual int _get_polygon_count() const; - virtual Variant _get_polygon(int p_idx) const; - virtual void _set_polygon(int p_idx, const Variant &p_polygon) const; + virtual bool _is_line() const override; + virtual int _get_polygon_count() const override; + virtual Variant _get_polygon(int p_idx) const override; + virtual void _set_polygon(int p_idx, const Variant &p_polygon) const override; - virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon); + virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) override; - virtual bool _has_resource() const; - virtual void _create_resource(); + virtual bool _has_resource() const override; + virtual void _create_resource() override; public: LightOccluder2DEditor(EditorNode *p_editor); }; class LightOccluder2DEditorPlugin : public AbstractPolygon2DEditorPlugin { - GDCLASS(LightOccluder2DEditorPlugin, AbstractPolygon2DEditorPlugin); public: diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index 4ac9d0af3b..77eeb19d26 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -31,32 +31,26 @@ #include "line_2d_editor_plugin.h" Node2D *Line2DEditor::_get_node() const { - return node; } void Line2DEditor::_set_node(Node *p_line) { - node = Object::cast_to<Line2D>(p_line); } bool Line2DEditor::_is_line() const { - return true; } Variant Line2DEditor::_get_polygon(int p_idx) const { - return _get_node()->get("points"); } void Line2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { - _get_node()->set("points", p_polygon); } void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { - Node2D *node = _get_node(); undo_redo->add_do_method(node, "set_points", p_polygon); undo_redo->add_undo_method(node, "set_points", p_previous); @@ -64,7 +58,7 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con Line2DEditor::Line2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { - node = NULL; + node = nullptr; } Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/line_2d_editor_plugin.h b/editor/plugins/line_2d_editor_plugin.h index ef54dbc3f7..b3bc9df3a5 100644 --- a/editor/plugins/line_2d_editor_plugin.h +++ b/editor/plugins/line_2d_editor_plugin.h @@ -35,26 +35,24 @@ #include "scene/2d/line_2d.h" class Line2DEditor : public AbstractPolygon2DEditor { - GDCLASS(Line2DEditor, AbstractPolygon2DEditor); Line2D *node; protected: - virtual Node2D *_get_node() const; - virtual void _set_node(Node *p_line); + virtual Node2D *_get_node() const override; + virtual void _set_node(Node *p_line) override; - virtual bool _is_line() const; - virtual Variant _get_polygon(int p_idx) const; - virtual void _set_polygon(int p_idx, const Variant &p_polygon) const; - virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon); + virtual bool _is_line() const override; + virtual Variant _get_polygon(int p_idx) const override; + virtual void _set_polygon(int p_idx, const Variant &p_polygon) const override; + virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) override; public: Line2DEditor(EditorNode *p_editor); }; class Line2DEditorPlugin : public AbstractPolygon2DEditorPlugin { - GDCLASS(Line2DEditorPlugin, AbstractPolygon2DEditorPlugin); public: diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 750f814319..e49cfd51f7 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -31,35 +31,33 @@ #include "material_editor_plugin.h" #include "editor/editor_scale.h" -#include "scene/gui/viewport_container.h" +#include "scene/gui/subviewport_container.h" #include "scene/resources/particles_material.h" +#include "scene/resources/sky_material.h" void MaterialEditor::_notification(int p_what) { - 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")); + light_1_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight1", "EditorIcons")); + light_1_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight1Off", "EditorIcons")); + light_2_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight2", "EditorIcons")); + light_2_switch->set_pressed_texture(get_theme_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")); + sphere_switch->set_normal_texture(get_theme_icon("MaterialPreviewSphereOff", "EditorIcons")); + sphere_switch->set_pressed_texture(get_theme_icon("MaterialPreviewSphere", "EditorIcons")); + box_switch->set_normal_texture(get_theme_icon("MaterialPreviewCubeOff", "EditorIcons")); + box_switch->set_pressed_texture(get_theme_icon("MaterialPreviewCube", "EditorIcons")); first_enter = false; } } if (p_what == NOTIFICATION_DRAW) { - - Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons"); + Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons"); Size2 size = get_size(); draw_texture_rect(checkerboard, Rect2(Point2(), size), true); @@ -67,20 +65,17 @@ void MaterialEditor::_notification(int p_what) { } 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()); } @@ -94,6 +89,7 @@ void MaterialEditor::_button_pressed(Node *p_button) { sphere_instance->hide(); box_switch->set_pressed(true); sphere_switch->set_pressed(false); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", false); } if (p_button == sphere_switch) { @@ -101,48 +97,46 @@ void MaterialEditor::_button_pressed(Node *p_button) { sphere_instance->show(); box_switch->set_pressed(false); sphere_switch->set_pressed(true); + EditorSettings::get_singleton()->set_project_metadata("inspector_options", "material_preview_on_sphere", true); } } void MaterialEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_button_pressed"), &MaterialEditor::_button_pressed); } MaterialEditor::MaterialEditor() { - - vc = memnew(ViewportContainer); + vc = memnew(SubViewportContainer); 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 + viewport = memnew(SubViewport); + Ref<World3D> world_3d; + world_3d.instance(); + viewport->set_world_3d(world_3d); //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 = memnew(Camera3D); 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 = memnew(DirectionalLight3D); light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); - light2 = memnew(DirectionalLight); + light2 = memnew(DirectionalLight3D); 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); + sphere_instance = memnew(MeshInstance3D); viewport->add_child(sphere_instance); - box_instance = memnew(MeshInstance); + box_instance = memnew(MeshInstance3D); viewport->add_child(box_instance); Transform box_xform; @@ -156,7 +150,6 @@ MaterialEditor::MaterialEditor() { 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); @@ -171,13 +164,13 @@ MaterialEditor::MaterialEditor() { 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)); + sphere_switch->connect("pressed", callable_mp(this, &MaterialEditor::_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)); + box_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(box_switch)); hb->add_spacer(); @@ -187,29 +180,37 @@ MaterialEditor::MaterialEditor() { 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_1_switch->connect("pressed", callable_mp(this, &MaterialEditor::_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)); + light_2_switch->connect("pressed", callable_mp(this, &MaterialEditor::_button_pressed), varray(light_2_switch)); first_enter = true; + + if (EditorSettings::get_singleton()->get_project_metadata("inspector_options", "material_preview_on_sphere", true)) { + box_instance->hide(); + } else { + box_instance->show(); + sphere_instance->hide(); + box_switch->set_pressed(true); + sphere_switch->set_pressed(false); + } } /////////////////////// bool EditorInspectorPluginMaterial::can_handle(Object *p_object) { - Material *material = Object::cast_to<Material>(p_object); - if (!material) + 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; @@ -223,30 +224,30 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() { env.instance(); - Ref<ProceduralSky> proc_sky = memnew(ProceduralSky(true)); - env->set_sky(proc_sky); - env->set_background(Environment::BG_COLOR_SKY); + Ref<Sky> sky = memnew(Sky()); + env->set_sky(sky); + env->set_background(Environment::BG_COLOR); + env->set_ambient_source(Environment::AMBIENT_SOURCE_SKY); + env->set_reflection_source(Environment::REFLECTION_SOURCE_SKY); } MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) { - Ref<EditorInspectorPluginMaterial> plugin; plugin.instance(); add_inspector_plugin(plugin); } -String SpatialMaterialConversionPlugin::converts_to() const { - +String StandardMaterial3DConversionPlugin::converts_to() const { return "ShaderMaterial"; } -bool SpatialMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { - Ref<SpatialMaterial> mat = p_resource; +bool StandardMaterial3DConversionPlugin::handles(const Ref<Resource> &p_resource) const { + Ref<StandardMaterial3D> mat = p_resource; return mat.is_valid(); } -Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { - Ref<SpatialMaterial> mat = p_resource; +Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p_resource) const { + Ref<StandardMaterial3D> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; @@ -255,24 +256,23 @@ Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_re Ref<Shader> shader; shader.instance(); - String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid()); + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); shader->set_code(code); smat->set_shader(shader); List<PropertyInfo> params; - VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { - - // Texture parameter has to be treated specially since SpatialMaterial saved it + // Texture parameter has to be treated specially since StandardMaterial3D saved it // as RID but ShaderMaterial needs Texture itself - Ref<Texture> texture = mat->get_texture_by_name(E->get().name); + Ref<Texture2D> texture = mat->get_texture_by_name(E->get().name); if (texture.is_valid()) { smat->set_shader_param(E->get().name, texture); } else { - Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); smat->set_shader_param(E->get().name, value); } } @@ -282,16 +282,15 @@ Ref<Resource> SpatialMaterialConversionPlugin::convert(const Ref<Resource> &p_re } String ParticlesMaterialConversionPlugin::converts_to() const { - return "ShaderMaterial"; } -bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { +bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { Ref<ParticlesMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { +Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { Ref<ParticlesMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); @@ -301,17 +300,17 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_ Ref<Shader> shader; shader.instance(); - String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid()); + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); shader->set_code(code); smat->set_shader(shader); List<PropertyInfo> params; - VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { - Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); smat->set_shader_param(E->get().name, value); } @@ -320,16 +319,15 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_ } String CanvasItemMaterialConversionPlugin::converts_to() const { - return "ShaderMaterial"; } -bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { +bool CanvasItemMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { Ref<CanvasItemMaterial> mat = p_resource; return mat.is_valid(); } -Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { +Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { Ref<CanvasItemMaterial> mat = p_resource; ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); @@ -339,17 +337,128 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p Ref<Shader> shader; shader.instance(); - String code = VS::get_singleton()->shader_get_code(mat->get_shader_rid()); + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); + + shader->set_code(code); + + smat->set_shader(shader); + + List<PropertyInfo> params; + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + + for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + smat->set_shader_param(E->get().name, value); + } + + smat->set_render_priority(mat->get_render_priority()); + return smat; +} + +String ProceduralSkyMaterialConversionPlugin::converts_to() const { + return "ShaderMaterial"; +} + +bool ProceduralSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { + Ref<ProceduralSkyMaterial> mat = p_resource; + return mat.is_valid(); +} + +Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { + Ref<ProceduralSkyMaterial> mat = p_resource; + ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); + + Ref<ShaderMaterial> smat; + smat.instance(); + + Ref<Shader> shader; + shader.instance(); + + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); + + shader->set_code(code); + + smat->set_shader(shader); + + List<PropertyInfo> params; + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + + for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + smat->set_shader_param(E->get().name, value); + } + + smat->set_render_priority(mat->get_render_priority()); + return smat; +} + +String PanoramaSkyMaterialConversionPlugin::converts_to() const { + return "ShaderMaterial"; +} + +bool PanoramaSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { + Ref<PanoramaSkyMaterial> mat = p_resource; + return mat.is_valid(); +} + +Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { + Ref<PanoramaSkyMaterial> mat = p_resource; + ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); + + Ref<ShaderMaterial> smat; + smat.instance(); + + Ref<Shader> shader; + shader.instance(); + + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); + + shader->set_code(code); + + smat->set_shader(shader); + + List<PropertyInfo> params; + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + + for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + smat->set_shader_param(E->get().name, value); + } + + smat->set_render_priority(mat->get_render_priority()); + return smat; +} + +String PhysicalSkyMaterialConversionPlugin::converts_to() const { + return "ShaderMaterial"; +} + +bool PhysicalSkyMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const { + Ref<PhysicalSkyMaterial> mat = p_resource; + return mat.is_valid(); +} + +Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const { + Ref<PhysicalSkyMaterial> mat = p_resource; + ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); + + Ref<ShaderMaterial> smat; + smat.instance(); + + Ref<Shader> shader; + shader.instance(); + + String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); shader->set_code(code); smat->set_shader(shader); List<PropertyInfo> params; - VS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); + RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), ¶ms); for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { - Variant value = VS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); + Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E->get().name); smat->set_shader_param(E->get().name, value); } diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 7f0a373dc7..a6df790620 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -36,24 +36,23 @@ #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/3d/camera_3d.h" +#include "scene/3d/light_3d.h" +#include "scene/3d/mesh_instance_3d.h" #include "scene/resources/material.h" -class ViewportContainer; +class SubViewportContainer; class MaterialEditor : public Control { - GDCLASS(MaterialEditor, Control); - ViewportContainer *vc; - Viewport *viewport; - MeshInstance *sphere_instance; - MeshInstance *box_instance; - DirectionalLight *light1; - DirectionalLight *light2; - Camera *camera; + SubViewportContainer *vc; + SubViewport *viewport; + MeshInstance3D *sphere_instance; + MeshInstance3D *box_instance; + DirectionalLight3D *light1; + DirectionalLight3D *light2; + Camera3D *camera; Ref<SphereMesh> sphere_mesh; Ref<CubeMesh> box_mesh; @@ -84,47 +83,73 @@ class EditorInspectorPluginMaterial : public EditorInspectorPlugin { Ref<Environment> env; public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; EditorInspectorPluginMaterial(); }; class MaterialEditorPlugin : public EditorPlugin { - GDCLASS(MaterialEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "Material"; } + virtual String get_name() const override { return "Material"; } MaterialEditorPlugin(EditorNode *p_node); }; -class SpatialMaterialConversionPlugin : public EditorResourceConversionPlugin { - GDCLASS(SpatialMaterialConversionPlugin, EditorResourceConversionPlugin); +class StandardMaterial3DConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(StandardMaterial3DConversionPlugin, EditorResourceConversionPlugin); public: - virtual String converts_to() const; - virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; }; class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin { GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin); public: - virtual String converts_to() const; - virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; }; class CanvasItemMaterialConversionPlugin : public EditorResourceConversionPlugin { GDCLASS(CanvasItemMaterialConversionPlugin, EditorResourceConversionPlugin); public: - virtual String converts_to() const; - virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; +}; + +class ProceduralSkyMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(ProceduralSkyMaterialConversionPlugin, EditorResourceConversionPlugin); + +public: + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; +}; + +class PanoramaSkyMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(PanoramaSkyMaterialConversionPlugin, EditorResourceConversionPlugin); + +public: + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; +}; + +class PhysicalSkyMaterialConversionPlugin : public EditorResourceConversionPlugin { + GDCLASS(PhysicalSkyMaterialConversionPlugin, EditorResourceConversionPlugin); + +public: + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; }; #endif // MATERIAL_EDITOR_PLUGIN_H diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index d06e5b6349..9d396467c3 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -33,15 +33,13 @@ #include "editor/editor_scale.h" void MeshEditor::_gui_input(Ref<InputEvent> p_event) { - Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { - rot_x -= mm->get_relative().y * 0.01; rot_y -= mm->get_relative().x * 0.01; - if (rot_x < -Math_PI / 2) + if (rot_x < -Math_PI / 2) { rot_x = -Math_PI / 2; - else if (rot_x > Math_PI / 2) { + } else if (rot_x > Math_PI / 2) { rot_x = Math_PI / 2; } _update_rotation(); @@ -49,25 +47,22 @@ void MeshEditor::_gui_input(Ref<InputEvent> p_event) { } void MeshEditor::_notification(int p_what) { - 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")); + light_1_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight1", "EditorIcons")); + light_1_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight1Off", "EditorIcons")); + light_2_switch->set_normal_texture(get_theme_icon("MaterialPreviewLight2", "EditorIcons")); + light_2_switch->set_pressed_texture(get_theme_icon("MaterialPreviewLight2Off", "EditorIcons")); first_enter = false; } } } void MeshEditor::_update_rotation() { - Transform t; t.basis.rotate(Vector3(0, 1, 0), -rot_y); t.basis.rotate(Vector3(1, 0, 0), -rot_x); @@ -75,7 +70,6 @@ void MeshEditor::_update_rotation() { } void MeshEditor::edit(Ref<Mesh> p_mesh) { - mesh = p_mesh; mesh_instance->set_mesh(mesh); @@ -98,7 +92,6 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) { } void MeshEditor::_button_pressed(Node *p_button) { - if (p_button == light_1_switch) { light1->set_visible(!light_1_switch->is_pressed()); } @@ -109,38 +102,35 @@ void MeshEditor::_button_pressed(Node *p_button) { } void MeshEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &MeshEditor::_gui_input); - ClassDB::bind_method(D_METHOD("_button_pressed"), &MeshEditor::_button_pressed); } MeshEditor::MeshEditor() { - - viewport = memnew(Viewport); - Ref<World> world; - world.instance(); - viewport->set_world(world); //use own world + viewport = memnew(SubViewport); + Ref<World3D> world_3d; + world_3d.instance(); + viewport->set_world_3d(world_3d); //use own world add_child(viewport); viewport->set_disable_input(true); viewport->set_msaa(Viewport::MSAA_2X); set_stretch(true); - camera = memnew(Camera); + camera = memnew(Camera3D); camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1))); camera->set_perspective(45, 0.1, 10); viewport->add_child(camera); - light1 = memnew(DirectionalLight); + light1 = memnew(DirectionalLight3D); light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); - light2 = memnew(DirectionalLight); + light2 = memnew(DirectionalLight3D); 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); - rotation = memnew(Spatial); + rotation = memnew(Node3D); viewport->add_child(rotation); - mesh_instance = memnew(MeshInstance); + mesh_instance = memnew(MeshInstance3D); rotation->add_child(mesh_instance); set_custom_minimum_size(Size2(1, 150) * EDSCALE); @@ -157,12 +147,12 @@ MeshEditor::MeshEditor() { 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_1_switch->connect("pressed", callable_mp(this, &MeshEditor::_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)); + light_2_switch->connect("pressed", callable_mp(this, &MeshEditor::_button_pressed), varray(light_2_switch)); first_enter = true; @@ -173,12 +163,10 @@ MeshEditor::MeshEditor() { /////////////////////// bool EditorInspectorPluginMesh::can_handle(Object *p_object) { - - return Object::cast_to<Mesh>(p_object) != NULL; + return Object::cast_to<Mesh>(p_object) != nullptr; } void EditorInspectorPluginMesh::parse_begin(Object *p_object) { - Mesh *mesh = Object::cast_to<Mesh>(p_object); if (!mesh) { return; @@ -191,7 +179,6 @@ void EditorInspectorPluginMesh::parse_begin(Object *p_object) { } MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) { - 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 87c4a1776b..1fb0babb10 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -33,25 +33,24 @@ #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/gui/viewport_container.h" +#include "scene/3d/camera_3d.h" +#include "scene/3d/light_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/gui/subviewport_container.h" #include "scene/resources/material.h" -class MeshEditor : public ViewportContainer { - - GDCLASS(MeshEditor, ViewportContainer); +class MeshEditor : public SubViewportContainer { + GDCLASS(MeshEditor, SubViewportContainer); float rot_x; float rot_y; - Viewport *viewport; - MeshInstance *mesh_instance; - Spatial *rotation; - DirectionalLight *light1; - DirectionalLight *light2; - Camera *camera; + SubViewport *viewport; + MeshInstance3D *mesh_instance; + Node3D *rotation; + DirectionalLight3D *light1; + DirectionalLight3D *light2; + Camera3D *camera; Ref<Mesh> mesh; @@ -77,16 +76,15 @@ class EditorInspectorPluginMesh : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginMesh, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; }; class MeshEditorPlugin : public EditorPlugin { - GDCLASS(MeshEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "Mesh"; } + virtual String get_name() const override { return "Mesh"; } MeshEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 25329906a9..5b241deab0 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* mesh_instance_editor_plugin.cpp */ +/* mesh_instance_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,65 +28,57 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "mesh_instance_editor_plugin.h" +#include "mesh_instance_3d_editor_plugin.h" #include "editor/editor_scale.h" -#include "scene/3d/collision_shape.h" -#include "scene/3d/navigation_mesh.h" -#include "scene/3d/physics_body.h" +#include "node_3d_editor_plugin.h" +#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/navigation_region_3d.h" +#include "scene/3d/physics_body_3d.h" #include "scene/gui/box_container.h" -#include "spatial_editor_plugin.h" - -void MeshInstanceEditor::_node_removed(Node *p_node) { +void MeshInstance3DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; + node = nullptr; options->hide(); } } -void MeshInstanceEditor::edit(MeshInstance *p_mesh) { - +void MeshInstance3DEditor::edit(MeshInstance3D *p_mesh) { node = p_mesh; } -void MeshInstanceEditor::_menu_option(int p_option) { - +void MeshInstance3DEditor::_menu_option(int p_option) { Ref<Mesh> mesh = node->get_mesh(); if (mesh.is_null()) { err_dialog->set_text(TTR("Mesh is empty!")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } switch (p_option) { - case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: - case MENU_OPTION_CREATE_STATIC_CONVEX_BODY: { - - bool trimesh_shape = (p_option == MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); - + case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: { EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection(); UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.empty()) { - Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape(); - if (shape.is_null()) + Ref<Shape3D> shape = mesh->create_trimesh_shape(); + if (shape.is_null()) { + err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape.")); + err_dialog->popup_centered(); return; + } - CollisionShape *cshape = memnew(CollisionShape); + CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shape); - StaticBody *body = memnew(StaticBody); + StaticBody3D *body = memnew(StaticBody3D); body->add_child(cshape); Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner(); - if (trimesh_shape) - ur->create_action(TTR("Create Static Trimesh Body")); - else - ur->create_action(TTR("Create Static Convex Body")); - + ur->create_action(TTR("Create Static Trimesh Body")); ur->add_do_method(node, "add_child", body); ur->add_do_method(body, "set_owner", owner); ur->add_do_method(cshape, "set_owner", owner); @@ -99,22 +91,24 @@ void MeshInstanceEditor::_menu_option(int p_option) { ur->create_action(TTR("Create Static Trimesh Body")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - MeshInstance *instance = Object::cast_to<MeshInstance>(E->get()); - if (!instance) + MeshInstance3D *instance = Object::cast_to<MeshInstance3D>(E->get()); + if (!instance) { continue; + } Ref<Mesh> m = instance->get_mesh(); - if (m.is_null()) + if (m.is_null()) { continue; + } - Ref<Shape> shape = trimesh_shape ? m->create_trimesh_shape() : m->create_convex_shape(); - if (shape.is_null()) + Ref<Shape3D> shape = m->create_trimesh_shape(); + if (shape.is_null()) { continue; + } - CollisionShape *cshape = memnew(CollisionShape); + CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shape); - StaticBody *body = memnew(StaticBody); + StaticBody3D *body = memnew(StaticBody3D); body->add_child(cshape); Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner(); @@ -131,19 +125,20 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: { - if (node == get_tree()->get_edited_scene_root()) { err_dialog->set_text(TTR("This doesn't work on scene root!")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } - Ref<Shape> shape = mesh->create_trimesh_shape(); - if (shape.is_null()) + Ref<Shape3D> shape = mesh->create_trimesh_shape(); + if (shape.is_null()) { return; + } - CollisionShape *cshape = memnew(CollisionShape); + CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shape); + cshape->set_transform(node->get_transform()); Node *owner = node->get_owner(); @@ -158,28 +153,59 @@ void MeshInstanceEditor::_menu_option(int p_option) { ur->add_undo_method(node->get_parent(), "remove_child", cshape); ur->commit_action(); } break; - case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: { + case MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE: { + if (node == get_tree()->get_edited_scene_root()) { + err_dialog->set_text(TTR("Can't create a single convex collision shape for the scene root.")); + err_dialog->popup_centered(); + return; + } + + Ref<Shape3D> shape = mesh->create_convex_shape(); + + if (shape.is_null()) { + err_dialog->set_text(TTR("Couldn't create a single convex collision shape.")); + err_dialog->popup_centered(); + return; + } + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Create Single Convex Shape")); + + CollisionShape3D *cshape = memnew(CollisionShape3D); + cshape->set_shape(shape); + cshape->set_transform(node->get_transform()); + + Node *owner = node->get_owner(); + + ur->add_do_method(node->get_parent(), "add_child", cshape); + ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); + ur->add_do_method(cshape, "set_owner", owner); + ur->add_do_reference(cshape); + ur->add_undo_method(node->get_parent(), "remove_child", cshape); + + ur->commit_action(); + + } break; + case MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES: { if (node == get_tree()->get_edited_scene_root()) { - err_dialog->set_text(TTR("This doesn't work on scene root!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Can't create multiple convex collision shapes for the scene root.")); + err_dialog->popup_centered(); return; } - Vector<Ref<Shape> > shapes = mesh->convex_decompose(); + Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(); if (!shapes.size()) { - err_dialog->set_text(TTR("Failed creating shapes!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Couldn't create any collision shapes.")); + err_dialog->popup_centered(); return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Create Convex Shape(s)")); + ur->create_action(TTR("Create Multiple Convex Shapes")); for (int i = 0; i < shapes.size(); i++) { - - CollisionShape *cshape = memnew(CollisionShape); + CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shapes[i]); cshape->set_transform(node->get_transform()); @@ -196,14 +222,14 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_NAVMESH: { - Ref<NavigationMesh> nmesh = memnew(NavigationMesh); - if (nmesh.is_null()) + if (nmesh.is_null()) { return; + } nmesh->create_from_mesh(mesh); - NavigationMeshInstance *nmi = memnew(NavigationMeshInstance); + NavigationRegion3D *nmi = memnew(NavigationRegion3D); nmi->set_navigation_mesh(nmesh); Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner(); @@ -220,22 +246,20 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_OUTLINE_MESH: { - outline_dialog->popup_centered(Vector2(200, 90)); } break; case MENU_OPTION_CREATE_UV2: { - 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(); + err_dialog->popup_centered(); return; } 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(); + err_dialog->popup_centered(); return; } @@ -244,7 +268,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { Ref<Mesh> mesh2 = node->get_mesh(); if (!mesh2.is_valid()) { err_dialog->set_text(TTR("No mesh to debug.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } _create_uv_lines(0); @@ -253,7 +277,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { Ref<Mesh> mesh2 = node->get_mesh(); if (!mesh2.is_valid()) { err_dialog->set_text(TTR("No mesh to debug.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } _create_uv_lines(1); @@ -261,20 +285,20 @@ void MeshInstanceEditor::_menu_option(int p_option) { } } -struct MeshInstanceEditorEdgeSort { - +struct MeshInstance3DEditorEdgeSort { Vector2 a; Vector2 b; - bool operator<(const MeshInstanceEditorEdgeSort &p_b) const { - if (a == p_b.a) + bool operator<(const MeshInstance3DEditorEdgeSort &p_b) const { + if (a == p_b.a) { return b < p_b.b; - else + } else { return a < p_b.a; + } } - MeshInstanceEditorEdgeSort() {} - MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) { + MeshInstance3DEditorEdgeSort() {} + MeshInstance3DEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) { if (p_a < p_b) { a = p_a; b = p_b; @@ -285,48 +309,43 @@ struct MeshInstanceEditorEdgeSort { } }; -void MeshInstanceEditor::_create_uv_lines(int p_layer) { - +void MeshInstance3DEditor::_create_uv_lines(int p_layer) { Ref<Mesh> mesh = node->get_mesh(); ERR_FAIL_COND(!mesh.is_valid()); - Set<MeshInstanceEditorEdgeSort> edges; + Set<MeshInstance3DEditorEdgeSort> edges; uv_lines.clear(); for (int i = 0; i < mesh->get_surface_count(); i++) { - if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { continue; + } Array a = mesh->surface_get_arrays(i); - PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2]; + Vector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2]; if (uv.size() == 0) { err_dialog->set_text(TTR("Model has no UV in this layer")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } - PoolVector<Vector2>::Read r = uv.read(); + const Vector2 *r = uv.ptr(); - PoolVector<int> indices = a[Mesh::ARRAY_INDEX]; - PoolVector<int>::Read ri; + Vector<int> indices = a[Mesh::ARRAY_INDEX]; + const int *ri = nullptr; int ic; - bool use_indices; if (indices.size()) { ic = indices.size(); - ri = indices.read(); - use_indices = true; + ri = indices.ptr(); } else { ic = uv.size(); - use_indices = false; } for (int j = 0; j < ic; j += 3) { - for (int k = 0; k < 3; k++) { - - MeshInstanceEditorEdgeSort edge; - if (use_indices) { + MeshInstance3DEditorEdgeSort edge; + if (ri) { edge.a = r[ri[j + k]]; edge.b = r[ri[j + ((k + 1) % 3)]]; } else { @@ -334,8 +353,9 @@ void MeshInstanceEditor::_create_uv_lines(int p_layer) { edge.b = r[j + ((k + 1) % 3)]; } - if (edges.has(edge)) + if (edges.has(edge)) { continue; + } uv_lines.push_back(edge.a); uv_lines.push_back(edge.b); @@ -344,13 +364,13 @@ void MeshInstanceEditor::_create_uv_lines(int p_layer) { } } - debug_uv_dialog->popup_centered_minsize(); + debug_uv_dialog->popup_centered(); } -void MeshInstanceEditor::_debug_uv_draw() { - - if (uv_lines.size() == 0) +void MeshInstance3DEditor::_debug_uv_draw() { + if (uv_lines.size() == 0) { return; + } debug_uv->set_clip_contents(true); debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0)); @@ -358,34 +378,33 @@ void MeshInstanceEditor::_debug_uv_draw() { debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7)); } -void MeshInstanceEditor::_create_outline_mesh() { - +void MeshInstance3DEditor::_create_outline_mesh() { Ref<Mesh> mesh = node->get_mesh(); if (mesh.is_null()) { - err_dialog->set_text(TTR("MeshInstance lacks a Mesh!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("MeshInstance3D lacks a Mesh.")); + err_dialog->popup_centered(); return; } if (mesh->get_surface_count() == 0) { - err_dialog->set_text(TTR("Mesh has not surface to create outlines from!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Mesh has not surface to create outlines from.")); + err_dialog->popup_centered(); return; } else if (mesh->get_surface_count() == 1 && mesh->surface_get_primitive_type(0) != Mesh::PRIMITIVE_TRIANGLES) { - err_dialog->set_text(TTR("Mesh primitive type is not PRIMITIVE_TRIANGLES!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Mesh primitive type is not PRIMITIVE_TRIANGLES.")); + err_dialog->popup_centered(); return; } Ref<Mesh> mesho = mesh->create_outline(outline_size->get_value()); if (mesho.is_null()) { - err_dialog->set_text(TTR("Could not create outline!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Could not create outline.")); + err_dialog->popup_centered(); return; } - MeshInstance *mi = memnew(MeshInstance); + MeshInstance3D *mi = memnew(MeshInstance3D); mi->set_mesh(mesho); Node *owner = node->get_owner(); if (get_tree()->get_edited_scene_root() == node) { @@ -404,36 +423,37 @@ void MeshInstanceEditor::_create_outline_mesh() { ur->commit_action(); } -void MeshInstanceEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option); - ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh); - ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw); +void MeshInstance3DEditor::_bind_methods() { } -MeshInstanceEditor::MeshInstanceEditor() { - +MeshInstance3DEditor::MeshInstance3DEditor() { options = memnew(MenuButton); options->set_switch_on_hover(true); - SpatialEditor::get_singleton()->add_control_to_menu_panel(options); + Node3DEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text(TTR("Mesh")); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MeshInstance3D", "EditorIcons")); options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection.")); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE); - options->get_popup()->add_item(TTR("Create Convex Collision Sibling(s)"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection.")); + options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection.")); + options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between the two above options.")); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Outline Mesh..."), MENU_OPTION_CREATE_OUTLINE_MESH); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a static outline mesh. The outline mesh will have its normals flipped automatically.\nThis can be used instead of the StandardMaterial Grow property when using that property isn't possible.")); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->connect("id_pressed", callable_mp(this, &MeshInstance3DEditor::_menu_option)); outline_dialog = memnew(ConfirmationDialog); outline_dialog->set_title(TTR("Create Outline Mesh")); @@ -451,7 +471,7 @@ MeshInstanceEditor::MeshInstanceEditor() { outline_dialog_vbc->add_margin_child(TTR("Outline Size:"), outline_size); add_child(outline_dialog); - outline_dialog->connect("confirmed", this, "_create_outline_mesh"); + outline_dialog->connect("confirmed", callable_mp(this, &MeshInstance3DEditor::_create_outline_mesh)); err_dialog = memnew(AcceptDialog); add_child(err_dialog); @@ -461,39 +481,34 @@ MeshInstanceEditor::MeshInstanceEditor() { add_child(debug_uv_dialog); debug_uv = memnew(Control); debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); - debug_uv->connect("draw", this, "_debug_uv_draw"); + debug_uv->connect("draw", callable_mp(this, &MeshInstance3DEditor::_debug_uv_draw)); debug_uv_dialog->add_child(debug_uv); } -void MeshInstanceEditorPlugin::edit(Object *p_object) { - - mesh_editor->edit(Object::cast_to<MeshInstance>(p_object)); +void MeshInstance3DEditorPlugin::edit(Object *p_object) { + mesh_editor->edit(Object::cast_to<MeshInstance3D>(p_object)); } -bool MeshInstanceEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("MeshInstance"); +bool MeshInstance3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("MeshInstance3D"); } -void MeshInstanceEditorPlugin::make_visible(bool p_visible) { - +void MeshInstance3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { mesh_editor->options->show(); } else { - mesh_editor->options->hide(); - mesh_editor->edit(NULL); + mesh_editor->edit(nullptr); } } -MeshInstanceEditorPlugin::MeshInstanceEditorPlugin(EditorNode *p_node) { - +MeshInstance3DEditorPlugin::MeshInstance3DEditorPlugin(EditorNode *p_node) { editor = p_node; - mesh_editor = memnew(MeshInstanceEditor); + mesh_editor = memnew(MeshInstance3DEditor); editor->get_viewport()->add_child(mesh_editor); mesh_editor->options->hide(); } -MeshInstanceEditorPlugin::~MeshInstanceEditorPlugin() { +MeshInstance3DEditorPlugin::~MeshInstance3DEditorPlugin() { } diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h index 5c95676fc4..77a2b8ec34 100644 --- a/editor/plugins/mesh_instance_editor_plugin.h +++ b/editor/plugins/mesh_instance_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* mesh_instance_editor_plugin.h */ +/* mesh_instance_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,19 +33,18 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/mesh_instance.h" +#include "scene/3d/mesh_instance_3d.h" #include "scene/gui/spin_box.h" -class MeshInstanceEditor : public Control { - - GDCLASS(MeshInstanceEditor, Control); +class MeshInstance3DEditor : public Control { + GDCLASS(MeshInstance3DEditor, Control); enum Menu { MENU_OPTION_CREATE_STATIC_TRIMESH_BODY, - MENU_OPTION_CREATE_STATIC_CONVEX_BODY, MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE, - MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE, + MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE, + MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES, MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_OUTLINE_MESH, MENU_OPTION_CREATE_UV2, @@ -53,7 +52,7 @@ class MeshInstanceEditor : public Control { MENU_OPTION_DEBUG_UV2, }; - MeshInstance *node; + MeshInstance3D *node; MenuButton *options; @@ -70,7 +69,7 @@ class MeshInstanceEditor : public Control { void _create_outline_mesh(); void _create_uv_lines(int p_layer); - friend class MeshInstanceEditorPlugin; + friend class MeshInstance3DEditorPlugin; void _debug_uv_draw(); @@ -79,26 +78,25 @@ protected: static void _bind_methods(); public: - void edit(MeshInstance *p_mesh); - MeshInstanceEditor(); + void edit(MeshInstance3D *p_mesh); + MeshInstance3DEditor(); }; -class MeshInstanceEditorPlugin : public EditorPlugin { - - GDCLASS(MeshInstanceEditorPlugin, EditorPlugin); +class MeshInstance3DEditorPlugin : public EditorPlugin { + GDCLASS(MeshInstance3DEditorPlugin, EditorPlugin); - MeshInstanceEditor *mesh_editor; + MeshInstance3DEditor *mesh_editor; EditorNode *editor; public: - virtual String get_name() const { return "MeshInstance"; } - 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); - - MeshInstanceEditorPlugin(EditorNode *p_node); - ~MeshInstanceEditorPlugin(); + virtual String get_name() const override { return "MeshInstance3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + MeshInstance3DEditorPlugin(EditorNode *p_node); + ~MeshInstance3DEditorPlugin(); }; #endif // MESH_EDITOR_PLUGIN_H diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 92898ff9c3..374a8c8290 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -33,26 +33,23 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "main/main.h" -#include "scene/3d/mesh_instance.h" -#include "scene/3d/navigation_mesh.h" -#include "scene/3d/physics_body.h" -#include "scene/main/viewport.h" +#include "node_3d_editor_plugin.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/navigation_region_3d.h" +#include "scene/3d/physics_body_3d.h" +#include "scene/main/window.h" #include "scene/resources/packed_scene.h" -#include "spatial_editor_plugin.h" void MeshLibraryEditor::edit(const Ref<MeshLibrary> &p_mesh_library) { - mesh_library = p_mesh_library; - if (mesh_library.is_valid()) + if (mesh_library.is_valid()) { menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), !mesh_library->has_meta("_editor_source_scene")); + } } void MeshLibraryEditor::_menu_confirm() { - switch (option) { - case MENU_OPTION_REMOVE_ITEM: { - mesh_library->remove_item(to_erase); } break; case MENU_OPTION_UPDATE_FROM_SCENE: { @@ -67,31 +64,32 @@ void MeshLibraryEditor::_menu_confirm() { } void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge) { - - if (!p_merge) + if (!p_merge) { p_library->clear(); + } - Map<int, MeshInstance *> mesh_instances; + Map<int, MeshInstance3D *> mesh_instances; for (int i = 0; i < p_scene->get_child_count(); i++) { - Node *child = p_scene->get_child(i); - if (!Object::cast_to<MeshInstance>(child)) { + if (!Object::cast_to<MeshInstance3D>(child)) { if (child->get_child_count() > 0) { child = child->get_child(0); - if (!Object::cast_to<MeshInstance>(child)) { + if (!Object::cast_to<MeshInstance3D>(child)) { continue; } - } else + } else { continue; + } } - MeshInstance *mi = Object::cast_to<MeshInstance>(child); + MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(child); Ref<Mesh> mesh = mi->get_mesh(); - if (mesh.is_null()) + if (mesh.is_null()) { continue; + } mesh = mesh->duplicate(); for (int j = 0; j < mesh->get_surface_count(); ++j) { @@ -104,7 +102,6 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, int id = p_library->find_item_by_name(mi->get_name()); if (id < 0) { - id = p_library->get_last_unused_item_id(); p_library->create_item(id); p_library->set_item_name(id, mi->get_name()); @@ -116,28 +113,29 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, Vector<MeshLibrary::ShapeData> collisions; for (int j = 0; j < mi->get_child_count(); j++) { - Node *child2 = mi->get_child(j); - if (!Object::cast_to<StaticBody>(child2)) + if (!Object::cast_to<StaticBody3D>(child2)) { continue; + } - StaticBody *sb = Object::cast_to<StaticBody>(child2); + StaticBody3D *sb = Object::cast_to<StaticBody3D>(child2); List<uint32_t> shapes; sb->get_shape_owners(&shapes); for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) { - if (sb->is_shape_owner_disabled(E->get())) + if (sb->is_shape_owner_disabled(E->get())) { continue; + } //Transform shape_transform = sb->shape_owner_get_transform(E->get()); //shape_transform.set_origin(shape_transform.get_origin() - phys_offset); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { - - Ref<Shape> collision = sb->shape_owner_get_shape(E->get(), k); - if (!collision.is_valid()) + Ref<Shape3D> collision = sb->shape_owner_get_shape(E->get(), k); + if (!collision.is_valid()) { continue; + } MeshLibrary::ShapeData shape_data; shape_data.shape = collision; shape_data.local_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get()); @@ -152,13 +150,15 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, 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)) + if (!Object::cast_to<NavigationRegion3D>(child2)) { continue; - NavigationMeshInstance *sb = Object::cast_to<NavigationMeshInstance>(child2); + } + NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2); navmesh = sb->get_navigation_mesh(); navmesh_transform = sb->get_transform(); - if (!navmesh.is_null()) + if (!navmesh.is_null()) { break; + } } if (!navmesh.is_null()) { p_library->set_item_navmesh(id, navmesh); @@ -168,26 +168,21 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, //generate previews! - if (1) { - - Vector<Ref<Mesh> > meshes; + if (true) { + Vector<Ref<Mesh>> meshes; Vector<Transform> transforms; Vector<int> ids = p_library->get_item_list(); for (int i = 0; i < ids.size(); i++) { - if (mesh_instances.find(ids[i])) { - meshes.push_back(p_library->get_item_mesh(ids[i])); transforms.push_back(mesh_instances[ids[i]]->get_transform()); } } - Vector<Ref<Texture> > textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EditorSettings::get_singleton()->get("editors/grid_map/preview_size")); + Vector<Ref<Texture2D>> textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EditorSettings::get_singleton()->get("editors/grid_map/preview_size")); int j = 0; for (int i = 0; i < ids.size(); i++) { - if (mesh_instances.find(ids[i])) { - p_library->set_item_preview(ids[i], textures[j]); j++; } @@ -196,7 +191,6 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, } void MeshLibraryEditor::_import_scene_cbk(const String &p_str) { - Ref<PackedScene> ps = ResourceLoader::load(p_str, "PackedScene"); ERR_FAIL_COND(ps.is_null()); Node *scene = ps->instance(); @@ -211,36 +205,28 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) { } Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge) { - _import_scene(p_base_scene, ml, p_merge); return OK; } void MeshLibraryEditor::_menu_cbk(int p_option) { - option = p_option; switch (p_option) { - case MENU_OPTION_ADD_ITEM: { - mesh_library->create_item(mesh_library->get_last_unused_item_id()); } break; case MENU_OPTION_REMOVE_ITEM: { - String p = editor->get_inspector()->get_selected_path(); if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) { - to_erase = p.get_slice("/", 3).to_int(); cd->set_text(vformat(TTR("Remove item %d?"), to_erase)); cd->popup_centered(Size2(300, 60)); } } break; case MENU_OPTION_IMPORT_FROM_SCENE: { - - file->popup_centered_ratio(); + file->popup_file_dialog(); } break; case MENU_OPTION_UPDATE_FROM_SCENE: { - cd->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene")))); cd->popup_centered(Size2(500, 60)); } break; @@ -248,64 +234,56 @@ void MeshLibraryEditor::_menu_cbk(int p_option) { } void MeshLibraryEditor::_bind_methods() { - - ClassDB::bind_method("_menu_cbk", &MeshLibraryEditor::_menu_cbk); - ClassDB::bind_method("_menu_confirm", &MeshLibraryEditor::_menu_confirm); - ClassDB::bind_method("_import_scene_cbk", &MeshLibraryEditor::_import_scene_cbk); } MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) { - file = memnew(EditorFileDialog); - file->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); //not for now? List<String> extensions; ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions); file->clear_filters(); file->set_title(TTR("Import Scene")); for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } add_child(file); - file->connect("file_selected", this, "_import_scene_cbk"); + file->connect("file_selected", callable_mp(this, &MeshLibraryEditor::_import_scene_cbk)); menu = memnew(MenuButton); - SpatialEditor::get_singleton()->add_control_to_menu_panel(menu); + Node3DEditor::get_singleton()->add_control_to_menu_panel(menu); menu->set_position(Point2(1, 1)); menu->set_text(TTR("Mesh Library")); - menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshLibrary", "EditorIcons")); + menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MeshLibrary", "EditorIcons")); menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM); menu->get_popup()->add_separator(); menu->get_popup()->add_item(TTR("Import from Scene"), MENU_OPTION_IMPORT_FROM_SCENE); menu->get_popup()->add_item(TTR("Update from Scene"), MENU_OPTION_UPDATE_FROM_SCENE); menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), true); - menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); + menu->get_popup()->connect("id_pressed", callable_mp(this, &MeshLibraryEditor::_menu_cbk)); menu->hide(); editor = p_editor; cd = memnew(ConfirmationDialog); add_child(cd); - cd->get_ok()->connect("pressed", this, "_menu_confirm"); + cd->get_ok()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_confirm)); } void MeshLibraryEditorPlugin::edit(Object *p_node) { - if (Object::cast_to<MeshLibrary>(p_node)) { mesh_library_editor->edit(Object::cast_to<MeshLibrary>(p_node)); mesh_library_editor->show(); - } else + } else { mesh_library_editor->hide(); + } } bool MeshLibraryEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("MeshLibrary"); } void MeshLibraryEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { mesh_library_editor->show(); mesh_library_editor->get_menu_button()->show(); @@ -316,7 +294,6 @@ void MeshLibraryEditorPlugin::make_visible(bool p_visible) { } MeshLibraryEditorPlugin::MeshLibraryEditorPlugin(EditorNode *p_node) { - EDITOR_DEF("editors/grid_map/preview_size", 64); mesh_library_editor = memnew(MeshLibraryEditor(p_node)); diff --git a/editor/plugins/mesh_library_editor_plugin.h b/editor/plugins/mesh_library_editor_plugin.h index 74b0a280e3..ea13303740 100644 --- a/editor/plugins/mesh_library_editor_plugin.h +++ b/editor/plugins/mesh_library_editor_plugin.h @@ -35,7 +35,6 @@ #include "scene/resources/mesh_library.h" class MeshLibraryEditor : public Control { - GDCLASS(MeshLibraryEditor, Control); Ref<MeshLibrary> mesh_library; @@ -74,18 +73,17 @@ public: }; class MeshLibraryEditorPlugin : public EditorPlugin { - GDCLASS(MeshLibraryEditorPlugin, EditorPlugin); MeshLibraryEditor *mesh_library_editor; EditorNode *editor; public: - virtual String get_name() const { return "MeshLibrary"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); + virtual String get_name() const override { return "MeshLibrary"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_node) override; + virtual bool handles(Object *p_node) const override; + virtual void make_visible(bool p_visible) override; MeshLibraryEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index 5dc222f84c..bd1384967f 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -30,113 +30,101 @@ #include "multimesh_editor_plugin.h" -#include "scene/3d/mesh_instance.h" +#include "node_3d_editor_plugin.h" +#include "scene/3d/mesh_instance_3d.h" #include "scene/gui/box_container.h" -#include "spatial_editor_plugin.h" void MultiMeshEditor::_node_removed(Node *p_node) { - if (p_node == node) { - node = NULL; + node = nullptr; hide(); } } void MultiMeshEditor::_populate() { - - if (!node) + if (!node) { return; + } Ref<Mesh> mesh; if (mesh_source->get_text() == "") { - Ref<MultiMesh> multimesh; multimesh = node->get_multimesh(); if (multimesh.is_null()) { - err_dialog->set_text(TTR("No mesh source specified (and no MultiMesh set in node).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } if (multimesh->get_mesh().is_null()) { - err_dialog->set_text(TTR("No mesh source specified (and MultiMesh contains no Mesh).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } mesh = multimesh->get_mesh(); } else { - Node *ms_node = node->get_node(mesh_source->get_text()); if (!ms_node) { - err_dialog->set_text(TTR("Mesh source is invalid (invalid path).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } - MeshInstance *ms_instance = Object::cast_to<MeshInstance>(ms_node); + MeshInstance3D *ms_instance = Object::cast_to<MeshInstance3D>(ms_node); if (!ms_instance) { - - err_dialog->set_text(TTR("Mesh source is invalid (not a MeshInstance).")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Mesh source is invalid (not a MeshInstance3D).")); + err_dialog->popup_centered(); return; } mesh = ms_instance->get_mesh(); if (mesh.is_null()) { - err_dialog->set_text(TTR("Mesh source is invalid (contains no Mesh resource).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } } if (surface_source->get_text() == "") { - err_dialog->set_text(TTR("No surface source specified.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } Node *ss_node = node->get_node(surface_source->get_text()); if (!ss_node) { - err_dialog->set_text(TTR("Surface source is invalid (invalid path).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } - GeometryInstance *ss_instance = Object::cast_to<MeshInstance>(ss_node); + GeometryInstance3D *ss_instance = Object::cast_to<MeshInstance3D>(ss_node); if (!ss_instance) { - err_dialog->set_text(TTR("Surface source is invalid (no geometry).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } Transform geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform(); - PoolVector<Face3> geometry = ss_instance->get_faces(VisualInstance::FACES_SOLID); + Vector<Face3> geometry = ss_instance->get_faces(VisualInstance3D::FACES_SOLID); if (geometry.size() == 0) { - err_dialog->set_text(TTR("Surface source is invalid (no faces).")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } //make all faces local int gc = geometry.size(); - PoolVector<Face3>::Write w = geometry.write(); + Face3 *w = geometry.ptrw(); for (int i = 0; i < gc; i++) { for (int j = 0; j < 3; j++) { @@ -144,21 +132,19 @@ void MultiMeshEditor::_populate() { } } - w.release(); - - PoolVector<Face3> faces = geometry; + Vector<Face3> faces = geometry; int facecount = faces.size(); ERR_FAIL_COND_MSG(!facecount, "Parent has no solid faces to populate."); - PoolVector<Face3>::Read r = faces.read(); + const Face3 *r = faces.ptr(); float area_accum = 0; Map<float, int> triangle_area_map; for (int i = 0; i < facecount; i++) { - float area = r[i].get_area(); - if (area < CMP_EPSILON) + if (area < CMP_EPSILON) { continue; + } triangle_area_map[area_accum] = i; area_accum += area; } @@ -172,7 +158,7 @@ void MultiMeshEditor::_populate() { int instance_count = populate_amount->get_value(); multimesh->set_transform_format(MultiMesh::TRANSFORM_3D); - multimesh->set_color_format(MultiMesh::COLOR_NONE); + multimesh->set_use_colors(false); multimesh->set_instance_count(instance_count); float _tilt_random = populate_tilt_random->get_value(); @@ -190,7 +176,6 @@ void MultiMeshEditor::_populate() { } for (int i = 0; i < instance_count; i++) { - float areapos = Math::random(0.0f, area_accum); Map<float, int>::Element *E = triangle_area_map.find_closest(areapos); @@ -229,23 +214,19 @@ void MultiMeshEditor::_populate() { } void MultiMeshEditor::_browsed(const NodePath &p_path) { - NodePath path = node->get_path_to(get_node(p_path)); - if (browsing_source) + if (browsing_source) { mesh_source->set_text(path); - else + } else { surface_source->set_text(path); + } } void MultiMeshEditor::_menu_option(int p_option) { - switch (p_option) { - case MENU_OPTION_POPULATE: { - if (_last_pp_node != node) { - surface_source->set_text(".."); mesh_source->set_text(".."); populate_axis->select(1); @@ -263,41 +244,34 @@ void MultiMeshEditor::_menu_option(int p_option) { } } -void MultiMeshEditor::edit(MultiMeshInstance *p_multimesh) { - +void MultiMeshEditor::edit(MultiMeshInstance3D *p_multimesh) { node = p_multimesh; } void MultiMeshEditor::_browse(bool p_source) { - browsing_source = p_source; std->get_scene_tree()->set_marked(node, false); - std->popup_centered_ratio(); - if (p_source) + std->popup_scenetree_dialog(); + if (p_source) { std->set_title(TTR("Select a Source Mesh:")); - else + } else { std->set_title(TTR("Select a Target Surface:")); + } } void MultiMeshEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &MultiMeshEditor::_menu_option); - ClassDB::bind_method("_populate", &MultiMeshEditor::_populate); - ClassDB::bind_method("_browsed", &MultiMeshEditor::_browsed); - ClassDB::bind_method("_browse", &MultiMeshEditor::_browse); } MultiMeshEditor::MultiMeshEditor() { - options = memnew(MenuButton); options->set_switch_on_hover(true); - SpatialEditor::get_singleton()->add_control_to_menu_panel(options); + Node3DEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text("MultiMesh"); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance", "EditorIcons")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("MultiMeshInstance3D", "EditorIcons")); options->get_popup()->add_item(TTR("Populate Surface")); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->connect("id_pressed", callable_mp(this, &MultiMeshEditor::_menu_option)); populate_dialog = memnew(ConfirmationDialog); populate_dialog->set_title(TTR("Populate MultiMesh")); @@ -315,7 +289,7 @@ MultiMeshEditor::MultiMeshEditor() { Button *b = memnew(Button); hbc->add_child(b); b->set_text(".."); - b->connect("pressed", this, "_browse", make_binds(false)); + b->connect("pressed", callable_mp(this, &MultiMeshEditor::_browse), make_binds(false)); vbc->add_margin_child(TTR("Target Surface:"), hbc); @@ -327,7 +301,7 @@ MultiMeshEditor::MultiMeshEditor() { hbc->add_child(b); b->set_text(".."); vbc->add_margin_child(TTR("Source Mesh:"), hbc); - b->connect("pressed", this, "_browse", make_binds(true)); + b->connect("pressed", callable_mp(this, &MultiMeshEditor::_browse), make_binds(true)); populate_axis = memnew(OptionButton); populate_axis->add_item(TTR("X-Axis")); @@ -373,40 +347,35 @@ MultiMeshEditor::MultiMeshEditor() { populate_dialog->get_ok()->set_text(TTR("Populate")); - populate_dialog->get_ok()->connect("pressed", this, "_populate"); + populate_dialog->get_ok()->connect("pressed", callable_mp(this, &MultiMeshEditor::_populate)); std = memnew(SceneTreeDialog); populate_dialog->add_child(std); - std->connect("selected", this, "_browsed"); + std->connect("selected", callable_mp(this, &MultiMeshEditor::_browsed)); - _last_pp_node = NULL; + _last_pp_node = nullptr; err_dialog = memnew(AcceptDialog); add_child(err_dialog); } void MultiMeshEditorPlugin::edit(Object *p_object) { - - multimesh_editor->edit(Object::cast_to<MultiMeshInstance>(p_object)); + multimesh_editor->edit(Object::cast_to<MultiMeshInstance3D>(p_object)); } bool MultiMeshEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("MultiMeshInstance"); + return p_object->is_class("MultiMeshInstance3D"); } void MultiMeshEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { multimesh_editor->options->show(); } else { - multimesh_editor->options->hide(); - multimesh_editor->edit(NULL); + multimesh_editor->edit(nullptr); } } MultiMeshEditorPlugin::MultiMeshEditorPlugin(EditorNode *p_node) { - editor = p_node; multimesh_editor = memnew(MultiMeshEditor); editor->get_viewport()->add_child(multimesh_editor); diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h index 2c7b98cfbc..d1f8a3b74a 100644 --- a/editor/plugins/multimesh_editor_plugin.h +++ b/editor/plugins/multimesh_editor_plugin.h @@ -33,22 +33,21 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/multimesh_instance.h" +#include "scene/3d/multimesh_instance_3d.h" #include "scene/gui/spin_box.h" class MultiMeshEditor : public Control { - GDCLASS(MultiMeshEditor, Control); friend class MultiMeshEditorPlugin; AcceptDialog *err_dialog; MenuButton *options; - MultiMeshInstance *_last_pp_node; + MultiMeshInstance3D *_last_pp_node; bool browsing_source; Panel *panel; - MultiMeshInstance *node; + MultiMeshInstance3D *node; LineEdit *surface_source; LineEdit *mesh_source; @@ -78,23 +77,22 @@ protected: static void _bind_methods(); public: - void edit(MultiMeshInstance *p_multimesh); + void edit(MultiMeshInstance3D *p_multimesh); MultiMeshEditor(); }; class MultiMeshEditorPlugin : public EditorPlugin { - GDCLASS(MultiMeshEditorPlugin, EditorPlugin); MultiMeshEditor *multimesh_editor; EditorNode *editor; public: - virtual String get_name() const { return "MultiMesh"; } - 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); + virtual String get_name() const override { return "MultiMesh"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; MultiMeshEditorPlugin(EditorNode *p_node); ~MultiMeshEditorPlugin(); diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index c4e61f2488..8cf9f01fa0 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -31,10 +31,8 @@ #include "navigation_polygon_editor_plugin.h" Ref<NavigationPolygon> NavigationPolygonEditor::_ensure_navpoly() const { - Ref<NavigationPolygon> navpoly = node->get_navigation_polygon(); if (!navpoly.is_valid()) { - navpoly = Ref<NavigationPolygon>(memnew(NavigationPolygon)); node->set_navigation_polygon(navpoly); } @@ -42,42 +40,38 @@ Ref<NavigationPolygon> NavigationPolygonEditor::_ensure_navpoly() const { } Node2D *NavigationPolygonEditor::_get_node() const { - return node; } void NavigationPolygonEditor::_set_node(Node *p_polygon) { - - node = Object::cast_to<NavigationPolygonInstance>(p_polygon); + node = Object::cast_to<NavigationRegion2D>(p_polygon); } int NavigationPolygonEditor::_get_polygon_count() const { - Ref<NavigationPolygon> navpoly = node->get_navigation_polygon(); - if (navpoly.is_valid()) + if (navpoly.is_valid()) { return navpoly->get_outline_count(); - else + } else { return 0; + } } Variant NavigationPolygonEditor::_get_polygon(int p_idx) const { - Ref<NavigationPolygon> navpoly = node->get_navigation_polygon(); - if (navpoly.is_valid()) + if (navpoly.is_valid()) { return navpoly->get_outline(p_idx); - else + } else { return Variant(Vector<Vector2>()); + } } void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { - Ref<NavigationPolygon> navpoly = _ensure_navpoly(); navpoly->set_outline(p_idx, p_polygon); navpoly->make_polygons_from_outlines(); } void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { - Ref<NavigationPolygon> navpoly = _ensure_navpoly(); undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count()); @@ -86,7 +80,6 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { } void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { - Ref<NavigationPolygon> navpoly = _ensure_navpoly(); undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx); undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx); @@ -95,7 +88,6 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { } void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { - Ref<NavigationPolygon> navpoly = _ensure_navpoly(); undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon); undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous); @@ -104,14 +96,13 @@ void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_pr } bool NavigationPolygonEditor::_has_resource() const { - return node && node->get_navigation_polygon().is_valid(); } void NavigationPolygonEditor::_create_resource() { - - if (!node) + if (!node) { return; + } undo_redo->create_action(TTR("Create Navigation Polygon")); undo_redo->add_do_method(node, "set_navigation_polygon", Ref<NavigationPolygon>(memnew(NavigationPolygon))); @@ -123,9 +114,9 @@ void NavigationPolygonEditor::_create_resource() { NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { - node = NULL; + node = nullptr; } NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) : - AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationPolygonInstance") { + AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationRegion2D") { } diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h index 1cab336381..3c5a7c2829 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.h +++ b/editor/plugins/navigation_polygon_editor_plugin.h @@ -32,37 +32,35 @@ #define NAVIGATIONPOLYGONEDITORPLUGIN_H #include "editor/plugins/abstract_polygon_2d_editor.h" -#include "scene/2d/navigation_polygon.h" +#include "scene/2d/navigation_region_2d.h" class NavigationPolygonEditor : public AbstractPolygon2DEditor { - GDCLASS(NavigationPolygonEditor, AbstractPolygon2DEditor); - NavigationPolygonInstance *node; + NavigationRegion2D *node; Ref<NavigationPolygon> _ensure_navpoly() const; protected: - virtual Node2D *_get_node() const; - virtual void _set_node(Node *p_polygon); + virtual Node2D *_get_node() const override; + virtual void _set_node(Node *p_polygon) override; - virtual int _get_polygon_count() const; - virtual Variant _get_polygon(int p_idx) const; - virtual void _set_polygon(int p_idx, const Variant &p_polygon) const; + virtual int _get_polygon_count() const override; + virtual Variant _get_polygon(int p_idx) const override; + virtual void _set_polygon(int p_idx, const Variant &p_polygon) const override; - virtual void _action_add_polygon(const Variant &p_polygon); - virtual void _action_remove_polygon(int p_idx); - virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon); + virtual void _action_add_polygon(const Variant &p_polygon) override; + virtual void _action_remove_polygon(int p_idx) override; + virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) override; - virtual bool _has_resource() const; - virtual void _create_resource(); + virtual bool _has_resource() const override; + virtual void _create_resource() override; public: NavigationPolygonEditor(EditorNode *p_editor); }; class NavigationPolygonEditorPlugin : public AbstractPolygon2DEditorPlugin { - GDCLASS(NavigationPolygonEditorPlugin, AbstractPolygon2DEditorPlugin); public: diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 31e6b65640..d28bbadf39 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* spatial_editor_plugin.cpp */ +/* node_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,27 +28,27 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "spatial_editor_plugin.h" +#include "node_3d_editor_plugin.h" +#include "core/input/input.h" #include "core/math/camera_matrix.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/print_string.h" #include "core/project_settings.h" #include "core/sort_array.h" +#include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/node_3d_editor_gizmos.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" -#include "editor/script_editor_debugger.h" -#include "editor/spatial_editor_gizmos.h" -#include "scene/3d/camera.h" -#include "scene/3d/collision_shape.h" -#include "scene/3d/mesh_instance.h" -#include "scene/3d/physics_body.h" -#include "scene/3d/visual_instance.h" -#include "scene/gui/viewport_container.h" +#include "scene/3d/camera_3d.h" +#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics_body_3d.h" +#include "scene/3d/visual_instance_3d.h" +#include "scene/gui/subviewport_container.h" #include "scene/resources/packed_scene.h" #include "scene/resources/surface_tool.h" @@ -76,20 +76,194 @@ #define MIN_FOV 0.01 #define MAX_FOV 179 -void SpatialEditorViewport::_update_camera(float p_interp_delta) { +void ViewportRotationControl::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + axis_menu_options.clear(); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_RIGHT); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_TOP); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_FRONT); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_LEFT); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_BOTTOM); + axis_menu_options.push_back(Node3DEditorViewport::VIEW_REAR); + + axis_colors.clear(); + axis_colors.push_back(get_theme_color("axis_x_color", "Editor")); + axis_colors.push_back(get_theme_color("axis_y_color", "Editor")); + axis_colors.push_back(get_theme_color("axis_z_color", "Editor")); + update(); + + if (!is_connected("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited))) { + connect("mouse_exited", callable_mp(this, &ViewportRotationControl::_on_mouse_exited)); + } + } + + if (p_what == NOTIFICATION_DRAW && viewport != nullptr) { + _draw(); + } +} + +void ViewportRotationControl::_draw() { + Vector2i center = get_size() / 2.0; + float radius = get_size().x / 2.0; + + if (focused_axis > -2 || orbiting) { + draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25)); + } + + Vector<Axis2D> axis_to_draw; + _get_sorted_axis(axis_to_draw); + for (int i = 0; i < axis_to_draw.size(); ++i) { + _draw_axis(axis_to_draw[i]); + } +} + +void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) { + bool focused = focused_axis == p_axis.axis; + bool positive = p_axis.axis < 3; + bool front = (Math::abs(p_axis.z_axis) <= 0.001 && positive) || p_axis.z_axis > 0.001; + int direction = p_axis.axis % 3; + + Color axis_color = axis_colors[direction]; + + if (!front) { + axis_color = axis_color.darkened(0.4); + } + Color c = focused ? Color(0.9, 0.9, 0.9) : axis_color; + + if (positive) { + Vector2i center = get_size() / 2.0; + draw_line(center, p_axis.screen_point, c, 1.5 * EDSCALE); + } + + if (front) { + String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z"); + draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c); + draw_char(get_theme_font("rotation_control", "EditorFonts"), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", Color(0.3, 0.3, 0.3)); + } else { + draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * (0.55 + (0.2 * (1.0 + p_axis.z_axis))), c); + } +} + +void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) { + Vector2i center = get_size() / 2.0; + float radius = get_size().x / 2.0; + + float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE; + Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse(); + + for (int i = 0; i < 3; ++i) { + Vector3 axis_3d = camera_basis.get_axis(i); + Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius; + + if (Math::abs(axis_3d.z) < 1.0) { + Axis2D pos_axis; + pos_axis.axis = i; + pos_axis.screen_point = center + axis_vector; + pos_axis.z_axis = axis_3d.z; + r_axis.push_back(pos_axis); + + Axis2D neg_axis; + neg_axis.axis = i + 3; + neg_axis.screen_point = center - axis_vector; + neg_axis.z_axis = -axis_3d.z; + r_axis.push_back(neg_axis); + } else { + // Special case when the camera is aligned with one axis + Axis2D axis; + axis.axis = i + (axis_3d.z < 0 ? 0 : 3); + axis.screen_point = center; + axis.z_axis = 1.0; + r_axis.push_back(axis); + } + } + + r_axis.sort_custom<Axis2DCompare>(); +} + +void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) { + const Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + Vector2 pos = mb->get_position(); + if (mb->is_pressed()) { + if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) { + orbiting = true; + } + } else { + if (focused_axis > -1) { + viewport->_menu_option(axis_menu_options[focused_axis]); + _update_focus(); + } + orbiting = false; + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse_position(orbiting_mouse_start); + } + } + } + + const Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (orbiting) { + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_VISIBLE) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + orbiting_mouse_start = mm->get_global_position(); + } + viewport->_nav_orbit(mm, viewport->_get_warped_mouse_motion(mm)); + focused_axis = -1; + } else { + _update_focus(); + } + } +} + +void ViewportRotationControl::_update_focus() { + int original_focus = focused_axis; + focused_axis = -2; + Vector2 mouse_pos = get_local_mouse_position(); + + if (mouse_pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) { + focused_axis = -1; + } - bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; + Vector<Axis2D> axes; + _get_sorted_axis(axes); + + for (int i = 0; i < axes.size(); i++) { + const Axis2D &axis = axes[i]; + if (mouse_pos.distance_to(axis.screen_point) < AXIS_CIRCLE_RADIUS) { + focused_axis = axis.axis; + } + } + + if (focused_axis != original_focus) { + update(); + } +} + +void ViewportRotationControl::_on_mouse_exited() { + focused_axis = -2; + update(); +} + +void ViewportRotationControl::set_viewport(Node3DEditorViewport *p_viewport) { + viewport = p_viewport; +} + +void ViewportRotationControl::_bind_methods() { + ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input); +} + +void Node3DEditorViewport::_update_camera(float p_interp_delta) { + bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; Cursor old_camera_cursor = camera_cursor; camera_cursor = cursor; if (p_interp_delta > 0) { - //------- // Perform smoothing if (is_freelook_active()) { - // Higher inertia should increase "lag" (lerp with factor between 0 and 1) // Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1. real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia"); @@ -97,18 +271,25 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) { real_t factor = (1.0 / inertia) * p_interp_delta; // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos - camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1)); + camera_cursor.eye_pos = old_camera_cursor.eye_pos.lerp(cursor.eye_pos, CLAMP(factor, 0, 1)); float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); orbit_inertia = MAX(0.0001, orbit_inertia); camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); + if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) { + camera_cursor.x_rot = cursor.x_rot; + } + + if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) { + camera_cursor.y_rot = cursor.y_rot; + } + Vector3 forward = to_camera_transform(camera_cursor).basis.xform(Vector3(0, 0, -1)); camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance; } else { - //when not being manipulated, move softly float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia"); float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia"); @@ -131,7 +312,15 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) { camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia))); - camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia))); + if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) { + camera_cursor.x_rot = cursor.x_rot; + } + + if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) { + camera_cursor.y_rot = cursor.y_rot; + } + + camera_cursor.pos = old_camera_cursor.pos.lerp(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia))); camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia))); } } @@ -139,62 +328,63 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) { //------- // Apply camera transform - float tolerance = 0.001; + real_t tolerance = 0.001; bool equal = true; - if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) { + if (!Math::is_equal_approx(old_camera_cursor.x_rot, camera_cursor.x_rot, tolerance) || !Math::is_equal_approx(old_camera_cursor.y_rot, camera_cursor.y_rot, tolerance)) { equal = false; - } - - if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) { + } else if (!old_camera_cursor.pos.is_equal_approx(camera_cursor.pos)) { equal = false; - } - - if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) { + } else if (!Math::is_equal_approx(old_camera_cursor.distance, camera_cursor.distance, tolerance)) { equal = false; } if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) { - camera->set_global_transform(to_camera_transform(camera_cursor)); - if (orthogonal) - camera->set_orthogonal(2 * cursor.distance, 0.1, 8192); - else + if (orthogonal) { + float half_fov = Math::deg2rad(get_fov()) / 2.0; + float height = 2.0 * cursor.distance * Math::tan(half_fov); + camera->set_orthogonal(height, get_znear(), get_zfar()); + } else { camera->set_perspective(get_fov(), get_znear(), get_zfar()); + } update_transform_gizmo_view(); + rotation_control->update(); } + spatial_editor->update_grid(); } -Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) const { +Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const { Transform camera_transform; camera_transform.translate(p_cursor.pos); camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot); camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot); - if (orthogonal) - camera_transform.translate(0, 0, 4096); - else + if (orthogonal) { + camera_transform.translate(0, 0, (get_zfar() - get_znear()) / 2.0); + } else { camera_transform.translate(0, 0, p_cursor.distance); + } return camera_transform; } -int SpatialEditorViewport::get_selected_count() const { - +int Node3DEditorViewport::get_selected_count() const { Map<Node *, Object *> &selection = editor_selection->get_selection(); int count = 0; for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->key()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->key()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } count++; } @@ -202,79 +392,74 @@ int SpatialEditorViewport::get_selected_count() const { return count; } -float SpatialEditorViewport::get_znear() const { - +float Node3DEditorViewport::get_znear() const { return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z); } -float SpatialEditorViewport::get_zfar() const { +float Node3DEditorViewport::get_zfar() const { return CLAMP(spatial_editor->get_zfar(), MIN_Z, MAX_Z); } -float SpatialEditorViewport::get_fov() const { +float Node3DEditorViewport::get_fov() const { return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV); } -Transform SpatialEditorViewport::_get_camera_transform() const { - +Transform Node3DEditorViewport::_get_camera_transform() const { return camera->get_global_transform(); } -Vector3 SpatialEditorViewport::_get_camera_position() const { - +Vector3 Node3DEditorViewport::_get_camera_position() const { return _get_camera_transform().origin; } -Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) { - - return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink(); +Point2 Node3DEditorViewport::_point_to_screen(const Vector3 &p_point) { + return camera->unproject_position(p_point) * subviewport_container->get_stretch_shrink(); } -Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const { - - return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink()); +Vector3 Node3DEditorViewport::_get_ray_pos(const Vector2 &p_pos) const { + return camera->project_ray_origin(p_pos / subviewport_container->get_stretch_shrink()); } -Vector3 SpatialEditorViewport::_get_camera_normal() const { - +Vector3 Node3DEditorViewport::_get_camera_normal() const { return -_get_camera_transform().basis.get_axis(2); } -Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const { - - return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink()); +Vector3 Node3DEditorViewport::_get_ray(const Vector2 &p_pos) const { + return camera->project_ray_normal(p_pos / subviewport_container->get_stretch_shrink()); } -void SpatialEditorViewport::_clear_selected() { - +void Node3DEditorViewport::_clear_selected() { editor_selection->clear(); } -void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) { - - if (!clicked) +void Node3DEditorViewport::_select_clicked(bool p_append, bool p_single, bool p_allow_locked) { + if (clicked.is_null()) { return; + } Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked)); - Spatial *selected = Object::cast_to<Spatial>(node); - if (!selected) + Node3D *selected = Object::cast_to<Node3D>(node); + if (!selected) { return; + } - // Replace the node by the group if grouped - while (node && node != editor->get_edited_scene()->get_parent()) { - Spatial *selected_tmp = Object::cast_to<Spatial>(node); - if (selected_tmp && node->has_meta("_edit_group_")) { - selected = selected_tmp; + if (!p_allow_locked) { + // Replace the node by the group if grouped + while (node && node != editor->get_edited_scene()->get_parent()) { + Node3D *selected_tmp = Object::cast_to<Node3D>(node); + if (selected_tmp && node->has_meta("_edit_group_")) { + selected = selected_tmp; + } + node = node->get_parent(); } - node = node->get_parent(); } - if (!_is_node_locked(selected)) + if (p_allow_locked || !_is_node_locked(selected)) { _select(selected, clicked_wants_append, true); + } } -void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) { - +void Node3DEditorViewport::_select(Node *p_node, bool p_append, bool p_single) { if (!p_append) { editor_selection->clear(); } @@ -283,42 +468,46 @@ void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) //erase editor_selection->remove_node(p_node); } else { - editor_selection->add_node(p_node); } if (p_single) { - if (Engine::get_singleton()->is_editor_hint()) + if (Engine::get_singleton()->is_editor_hint()) { editor->call("edit_node", p_node); + } } } -ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) { - - if (r_gizmo_handle) +ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) { + if (r_gizmo_handle) { *r_gizmo_handle = -1; + } Vector3 ray = _get_ray(p_pos); Vector3 pos = _get_ray_pos(p_pos); - Vector2 shrinked_pos = p_pos / viewport_container->get_stretch_shrink(); + Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink(); + + if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) { + RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray); + } - Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<EditorSpatialGizmo> > found_gizmos; + Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world_3d()->get_scenario()); + Set<Ref<EditorNode3DGizmo>> found_gizmos; Node *edited_scene = get_tree()->get_edited_scene_root(); - ObjectID closest = 0; - Node *item = NULL; + ObjectID closest; + Node *item = nullptr; float closest_dist = 1e20; int selected_handle = -1; for (int i = 0; i < instances.size(); i++) { + Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); - Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i])); - - if (!spat) + if (!spat) { continue; + } - Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); + Ref<EditorNode3DGizmo> seg = spat->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -331,16 +520,17 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, int handle = -1; bool inters = seg->intersect_ray(camera, shrinked_pos, point, normal, &handle, p_alt_select); - if (!inters) + if (!inters) { continue; + } float dist = pos.distance_to(point); - if (dist < 0) + if (dist < 0) { continue; + } if (dist < closest_dist) { - item = Object::cast_to<Node>(spat); while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) { item = item->get_owner(); @@ -352,60 +542,65 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, } } - if (!item) - return 0; + if (!item) { + return ObjectID(); + } if (!editor_selection->is_selected(item) || (r_gizmo_handle && selected_handle >= 0)) { - - if (r_gizmo_handle) + if (r_gizmo_handle) { *r_gizmo_handle = selected_handle; + } } return closest; } -void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) { - +void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) { Vector3 ray = _get_ray(p_pos); Vector3 pos = _get_ray_pos(p_pos); - Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<EditorSpatialGizmo> > found_gizmos; + Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world_3d()->get_scenario()); + Set<Ref<EditorNode3DGizmo>> found_gizmos; r_includes_current = false; for (int i = 0; i < instances.size(); i++) { + Node3D *spat = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); - Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i])); - - if (!spat) + if (!spat) { continue; + } - Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); + Ref<EditorNode3DGizmo> seg = spat->get_gizmo(); - if (!seg.is_valid()) + if (!seg.is_valid()) { continue; + } - if (found_gizmos.has(seg)) + if (found_gizmos.has(seg)) { continue; + } found_gizmos.insert(seg); Vector3 point; Vector3 normal; int handle = -1; - bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select); + bool inters = seg->intersect_ray(camera, p_pos, point, normal, nullptr, p_alt_select); - if (!inters) + if (!inters) { continue; + } float dist = pos.distance_to(point); - if (dist < 0) + if (dist < 0) { continue; + } - if (editor_selection->is_selected(spat)) + if (editor_selection->is_selected(spat)) { r_includes_current = true; + } _RayResult res; res.item = spat; @@ -414,14 +609,14 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl results.push_back(res); } - if (results.empty()) + if (results.empty()) { return; + } results.sort(); } -Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) { - +Vector3 Node3DEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) { CameraMatrix cm; if (orthogonal) { cm.set_orthogonal(camera->get_size(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar()); @@ -439,10 +634,10 @@ Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) { return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_he.y, -(get_znear() + p_vector3.z))); } -void SpatialEditorViewport::_select_region() { - - if (cursor.region_begin == cursor.region_end) +void Node3DEditorViewport::_select_region() { + if (cursor.region_begin == cursor.region_end) { return; //nothing really + } float z_offset = MAX(0.0, 5.0 - get_znear()); @@ -470,7 +665,6 @@ void SpatialEditorViewport::_select_region() { Vector3 cam_pos = _get_camera_position(); for (int i = 0; i < 4; i++) { - Vector3 a = _get_screen_to_space(box[i]); Vector3 b = _get_screen_to_space(box[(i + 1) % 4]); if (orthogonal) { @@ -480,28 +674,24 @@ void SpatialEditorViewport::_select_region() { } } - if (!orthogonal) { - Plane near(cam_pos, -_get_camera_normal()); - near.d -= get_znear(); - - frustum.push_back(near); + Plane near(cam_pos, -_get_camera_normal()); + near.d -= get_znear(); + frustum.push_back(near); - Plane far = -near; - far.d += get_zfar(); + Plane far = -near; + far.d += get_zfar(); + frustum.push_back(far); - frustum.push_back(far); - } - - Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario()); + Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario()); Vector<Node *> selected; Node *edited_scene = get_tree()->get_edited_scene_root(); for (int i = 0; i < instances.size(); i++) { - - Spatial *sp = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i])); - if (!sp || _is_node_locked(sp)) + Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i])); + if (!sp || _is_node_locked(sp)) { continue; + } Node *item = Object::cast_to<Node>(sp); while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) { @@ -509,10 +699,10 @@ void SpatialEditorViewport::_select_region() { } // Replace the node by the group if grouped - if (item->is_class("Spatial")) { - Spatial *sel = Object::cast_to<Spatial>(item); + if (item->is_class("Node3D")) { + Node3D *sel = Object::cast_to<Node3D>(item); while (item && item != editor->get_edited_scene()->get_parent()) { - Spatial *selected_tmp = Object::cast_to<Spatial>(item); + Node3D *selected_tmp = Object::cast_to<Node3D>(item); if (selected_tmp && item->has_meta("_edit_group_")) { sel = selected_tmp; } @@ -521,14 +711,19 @@ void SpatialEditorViewport::_select_region() { item = sel; } - if (selected.find(item) != -1) continue; + if (selected.find(item) != -1) { + continue; + } - if (_is_node_locked(item)) continue; + if (_is_node_locked(item)) { + continue; + } - Ref<EditorSpatialGizmo> seg = sp->get_gizmo(); + Ref<EditorNode3DGizmo> seg = sp->get_gizmo(); - if (!seg.is_valid()) + if (!seg.is_valid()) { continue; + } if (seg->intersect_frustum(camera, frustum)) { selected.push_back(item); @@ -541,20 +736,23 @@ void SpatialEditorViewport::_select_region() { } } -void SpatialEditorViewport::_update_name() { - +void Node3DEditorViewport::_update_name() { String view_mode = orthogonal ? TTR("Orthogonal") : TTR("Perspective"); - if (name != "") + if (auto_orthogonal) { + view_mode += " [auto]"; + } + + if (name != "") { view_menu->set_text(name + " " + view_mode); - else + } else { view_menu->set_text(view_mode); + } view_menu->set_size(Vector2(0, 0)); // resets the button size } -void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { - +void Node3DEditorViewport::_compute_edit(const Point2 &p_point) { _edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y)); _edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y)); _edit.plane = TRANSFORM_VIEW; @@ -564,14 +762,15 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } se->original = se->sp->get_global_gizmo_transform(); se->original_local = se->sp->get_local_gizmo_transform(); @@ -579,37 +778,45 @@ void SpatialEditorViewport::_compute_edit(const Point2 &p_point) { } static int _get_key_modifier_setting(const String &p_property) { - switch (EditorSettings::get_singleton()->get(p_property).operator int()) { - - case 0: return 0; - case 1: return KEY_SHIFT; - case 2: return KEY_ALT; - case 3: return KEY_META; - case 4: return KEY_CONTROL; + case 0: + return 0; + case 1: + return KEY_SHIFT; + case 2: + return KEY_ALT; + case 3: + return KEY_META; + case 4: + return KEY_CONTROL; } return 0; } static int _get_key_modifier(Ref<InputEventWithModifiers> e) { - if (e->get_shift()) + if (e->get_shift()) { return KEY_SHIFT; - if (e->get_alt()) + } + if (e->get_alt()) { return KEY_ALT; - if (e->get_control()) + } + if (e->get_control()) { return KEY_CONTROL; - if (e->get_metakey()) + } + if (e->get_metakey()) { return KEY_META; + } return 0; } -bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) { - - if (!spatial_editor->is_gizmo_visible()) +bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) { + if (!spatial_editor->is_gizmo_visible()) { return false; + } if (get_selected_count() == 0) { - if (p_highlight_only) + if (p_highlight_only) { spatial_editor->select_gizmo_highlight_axis(-1); + } return false; } @@ -619,19 +826,17 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig Transform gt = spatial_editor->get_gizmo_transform(); float gs = gizmo_scale; - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) { - + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { int col_axis = -1; float col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5)); float grabber_radius = gs * GIZMO_ARROW_SIZE; Vector3 r; - if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { + if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { float d = r.distance_to(ray_pos); if (d < col_d) { col_d = d; @@ -646,7 +851,6 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); @@ -656,10 +860,8 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); if (plane.intersects_ray(ray_pos, ray, &r)) { - float dist = r.distance_to(grabber_pos); if (dist < (gs * GIZMO_PLANE_SIZE)) { - float d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; @@ -673,9 +875,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } if (col_axis != -1) { - if (p_highlight_only) { - spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_translate ? 6 : 0)); } else { @@ -688,22 +888,20 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } } - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) { - + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { int col_axis = -1; float col_d = 1e20; for (int i = 0; i < 3; i++) { - Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); Vector3 r; - if (!plane.intersects_ray(ray_pos, ray, &r)) + if (!plane.intersects_ray(ray_pos, ray, &r)) { continue; + } float dist = r.distance_to(gt.origin); if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) { - float d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; @@ -713,9 +911,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } if (col_axis != -1) { - if (p_highlight_only) { - spatial_editor->select_gizmo_highlight_axis(col_axis + 3); } else { //handle rotate @@ -727,19 +923,17 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } } - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) { - + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { int col_axis = -1; float col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET; float grabber_radius = gs * GIZMO_ARROW_SIZE; Vector3 r; - if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { + if (Geometry3D::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) { float d = r.distance_to(ray_pos); if (d < col_d) { col_d = d; @@ -754,7 +948,6 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig col_d = 1e20; for (int i = 0; i < 3; i++) { - Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized(); Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized(); @@ -764,10 +957,8 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig Plane plane(gt.origin, gt.basis.get_axis(i).normalized()); if (plane.intersects_ray(ray_pos, ray, &r)) { - float dist = r.distance_to(grabber_pos); if (dist < (gs * GIZMO_PLANE_SIZE)) { - float d = ray_pos.distance_to(r); if (d < col_d) { col_d = d; @@ -781,9 +972,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } if (col_axis != -1) { - if (p_highlight_only) { - spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9)); } else { @@ -796,43 +985,42 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig } } - if (p_highlight_only) + if (p_highlight_only) { spatial_editor->select_gizmo_highlight_axis(-1); + } return false; } -void SpatialEditorViewport::_surface_mouse_enter() { - - if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) +void Node3DEditorViewport::_surface_mouse_enter() { + if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { surface->grab_focus(); + } } -void SpatialEditorViewport::_surface_mouse_exit() { - +void Node3DEditorViewport::_surface_mouse_exit() { _remove_preview(); } -void SpatialEditorViewport::_surface_focus_enter() { - +void Node3DEditorViewport::_surface_focus_enter() { view_menu->set_disable_shortcuts(false); } -void SpatialEditorViewport::_surface_focus_exit() { - +void Node3DEditorViewport::_surface_focus_exit() { view_menu->set_disable_shortcuts(true); } -bool SpatialEditorViewport ::_is_node_locked(const Node *p_node) { + +bool Node3DEditorViewport ::_is_node_locked(const Node *p_node) { return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_"); } -void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) { +void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) { _find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift()); Node *scene = editor->get_edited_scene(); for (int i = 0; i < selection_results.size(); i++) { - Spatial *item = selection_results[i].item; + Node3D *item = selection_results[i].item; if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) { //invalid result selection_results.remove(i); @@ -843,51 +1031,71 @@ void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) { clicked_wants_append = b->get_shift(); if (selection_results.size() == 1) { - clicked = selection_results[0].item->get_instance_id(); selection_results.clear(); - if (clicked) { - _select_clicked(clicked_wants_append, true); - clicked = 0; + if (clicked.is_valid()) { + _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != Node3DEditor::TOOL_MODE_LIST_SELECT); + clicked = ObjectID(); } } else if (!selection_results.empty()) { - NodePath root_path = get_tree()->get_edited_scene_root()->get_path(); StringName root_name = root_path.get_name(root_path.get_name_count() - 1); for (int i = 0; i < selection_results.size(); i++) { + Node3D *spat = selection_results[i].item; - Spatial *spat = selection_results[i].item; - - Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node"); + Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node"); String node_path = "/" + root_name + "/" + root_path.rel_path_to(spat->get_path()); - selection_menu->add_item(spat->get_name()); + int locked = 0; + if (_is_node_locked(spat)) { + locked = 1; + } else { + Node *ed_scene = editor->get_edited_scene(); + Node *node = spat; + + while (node && node != ed_scene->get_parent()) { + Node3D *selected_tmp = Object::cast_to<Node3D>(node); + if (selected_tmp && node->has_meta("_edit_group_")) { + locked = 2; + } + node = node->get_parent(); + } + } + + String suffix = String(); + if (locked == 1) { + suffix = " (" + TTR("Locked") + ")"; + } else if (locked == 2) { + suffix = " (" + TTR("Grouped") + ")"; + } + selection_menu->add_item((String)spat->get_name() + suffix); selection_menu->set_item_icon(i, icon); selection_menu->set_item_metadata(i, node_path); selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path); } - selection_menu->set_global_position(b->get_global_position()); + selection_menu->set_position(get_screen_transform().xform(b->get_position())); selection_menu->popup(); } } -void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { - - if (previewing) +void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { + if (previewing) { return; //do NONE + } { EditorNode *en = editor; EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding(); if (!force_input_forwarding_list->empty()) { bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true); - if (discard) + if (discard) { return; + } } } { @@ -895,8 +1103,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { EditorPluginList *over_plugin_list = en->get_editor_plugins_over(); if (!over_plugin_list->empty()) { bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false); - if (discard) + if (discard) { return; + } } } @@ -907,37 +1116,36 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor(); switch (b->get_button_index()) { - case BUTTON_WHEEL_UP: { - if (is_freelook_active()) + if (is_freelook_active()) { scale_freelook_speed(zoom_factor); - else + } else { scale_cursor_distance(1.0 / zoom_factor); + } } break; case BUTTON_WHEEL_DOWN: { - if (is_freelook_active()) + if (is_freelook_active()) { scale_freelook_speed(1.0 / zoom_factor); - else + } else { scale_cursor_distance(zoom_factor); + } } break; case BUTTON_RIGHT: { - NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); if (b->is_pressed() && _edit.gizmo.is_valid()) { //restore _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true); - _edit.gizmo = Ref<EditorSpatialGizmo>(); + _edit.gizmo = Ref<EditorNode3DGizmo>(); } if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) { - if (b->get_alt()) { - - if (nav_scheme == NAVIGATION_MAYA) + if (nav_scheme == NAVIGATION_MAYA) { break; + } _list_select(b); return; @@ -951,14 +1159,15 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } sp->set_global_transform(se->original); } @@ -985,32 +1194,25 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; case BUTTON_MIDDLE: { - if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) { - switch (_edit.plane) { - case TRANSFORM_VIEW: { - _edit.plane = TRANSFORM_X_AXIS; set_message(TTR("X-Axis Transform."), 2); name = ""; _update_name(); } break; case TRANSFORM_X_AXIS: { - _edit.plane = TRANSFORM_Y_AXIS; set_message(TTR("Y-Axis Transform."), 2); } break; case TRANSFORM_Y_AXIS: { - _edit.plane = TRANSFORM_Z_AXIS; set_message(TTR("Z-Axis Transform."), 2); } break; case TRANSFORM_Z_AXIS: { - _edit.plane = TRANSFORM_VIEW; set_message(TTR("View Plane Transform."), 2); @@ -1023,15 +1225,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } break; case BUTTON_LEFT: { - if (b->is_pressed()) { - NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->get_alt()) { break; } - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_LIST_SELECT) { + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_LIST_SELECT) { _list_select(b); break; } @@ -1050,15 +1250,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (can_select_gizmos && spatial_editor->get_selected()) { - - Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorNode3DGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { int handle = -1; Vector3 point; Vector3 normal; bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->get_shift()); if (inters && handle != -1) { - _edit.gizmo = seg; _edit.gizmo_handle = handle; _edit.gizmo_initial_value = seg->get_handle_value(handle); @@ -1067,37 +1265,38 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } - if (_gizmo_select(_edit.mouse_pos)) + if (_gizmo_select(_edit.mouse_pos)) { break; + } - clicked = 0; + clicked = ObjectID(); clicked_includes_current = false; - if ((spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) { - + if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) { /* HANDLE ROTATION */ - if (get_selected_count() == 0) + if (get_selected_count() == 0) { break; //bye + } //handle rotate _edit.mode = TRANSFORM_ROTATE; _compute_edit(b->get_position()); break; } - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) { - - if (get_selected_count() == 0) + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { + if (get_selected_count() == 0) { break; //bye + } //handle translate _edit.mode = TRANSFORM_TRANSLATE; _compute_edit(b->get_position()); break; } - if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) { - - if (get_selected_count() == 0) + if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE) { + if (get_selected_count() == 0) { break; //bye + } //handle scale _edit.mode = TRANSFORM_SCALE; _compute_edit(b->get_position()); @@ -1114,10 +1313,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { clicked_wants_append = b->get_shift(); - if (!clicked) { - - if (!clicked_wants_append) + if (clicked.is_null()) { + if (!clicked_wants_append) { _clear_selected(); + } //default to regionselect cursor.region_select = true; @@ -1125,14 +1324,11 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { cursor.region_end = b->get_position(); } - if (clicked && gizmo_handle >= 0) { - - Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked)); + if (clicked.is_valid() && gizmo_handle >= 0) { + Node3D *spa = Object::cast_to<Node3D>(ObjectDB::get_instance(clicked)); if (spa) { - - Ref<EditorSpatialGizmo> seg = spa->get_gizmo(); + Ref<EditorNode3DGizmo> seg = spa->get_gizmo(); if (seg.is_valid()) { - _edit.gizmo = seg; _edit.gizmo_handle = gizmo_handle; _edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle); @@ -1143,22 +1339,21 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { surface->update(); } else { - if (_edit.gizmo.is_valid()) { - _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false); - _edit.gizmo = Ref<EditorSpatialGizmo>(); + _edit.gizmo = Ref<EditorNode3DGizmo>(); break; } - if (clicked) { + if (clicked.is_valid()) { _select_clicked(clicked_wants_append, true); // Processing was deferred. - clicked = 0; + clicked = ObjectID(); } if (cursor.region_select) { - - if (!clicked_wants_append) _clear_selected(); + if (!clicked_wants_append) { + _clear_selected(); + } _select_region(); cursor.region_select = false; @@ -1166,21 +1361,21 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (_edit.mode != TRANSFORM_NONE) { - static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" }; undo_redo->create_action(_transform_name[_edit.mode]); List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); undo_redo->add_undo_method(sp, "set_global_transform", se->original); @@ -1200,14 +1395,11 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - _edit.mouse_pos = m->get_position(); if (spatial_editor->get_selected()) { - - Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorNode3DGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { - int selected_handle = -1; int handle = -1; @@ -1215,21 +1407,20 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Vector3 normal; bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, false); if (inters && handle != -1) { - selected_handle = handle; } if (selected_handle != spatial_editor->get_over_gizmo_handle()) { spatial_editor->set_over_gizmo_handle(selected_handle); spatial_editor->get_selected()->update_gizmo(); - if (selected_handle != -1) + if (selected_handle != -1) { spatial_editor->select_gizmo_highlight_axis(-1); + } } } } if (spatial_editor->get_over_gizmo_handle() == -1 && !(m->get_button_mask() & 1) && !_edit.gizmo.is_valid()) { - _gizmo_select(_edit.mouse_pos, true); } @@ -1237,14 +1428,12 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { NavigationMode nav_mode = NAVIGATION_NONE; if (_edit.gizmo.is_valid()) { - _edit.gizmo->set_handle(_edit.gizmo_handle, camera, m->get_position()); Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle); String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle); set_message(n + ": " + String(v)); } else if (m->get_button_mask() & BUTTON_MASK_LEFT) { - if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) { nav_mode = NAVIGATION_ORBIT; } else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_shift()) { @@ -1254,16 +1443,14 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) { nav_mode = NAVIGATION_ORBIT; } else { - if (clicked) { - + if (clicked.is_valid()) { if (!clicked_includes_current) { - _select_clicked(clicked_wants_append, true); // Processing was deferred. } _compute_edit(_edit.mouse_pos); - clicked = 0; + clicked = ObjectID(); _edit.mode = TRANSFORM_TRANSLATE; } @@ -1274,8 +1461,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { return; } - if (_edit.mode == TRANSFORM_NONE) + if (_edit.mode == TRANSFORM_NONE) { return; + } Vector3 ray_pos = _get_ray_pos(m->get_position()); Vector3 ray = _get_ray(m->get_position()); @@ -1283,9 +1471,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { int snap_step_decimals = Math::range_step_decimals(snap); switch (_edit.mode) { - case TRANSFORM_SCALE: { - Vector3 motion_mask; Plane plane; bool plane_mv = false; @@ -1325,22 +1511,21 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } Vector3 intersection; - if (!plane.intersects_ray(ray_pos, ray, &intersection)) + if (!plane.intersects_ray(ray_pos, ray, &intersection)) { break; + } Vector3 click; - if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) + if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) { break; + } Vector3 motion = intersection - click; if (_edit.plane != TRANSFORM_VIEW) { - if (!plane_mv) { - motion = motion_mask.dot(motion) * motion_mask; } else { - // Alternative planar scaling mode if (_get_key_modifier(m) != KEY_SHIFT) { motion = motion_mask.dot(motion) * motion_mask; @@ -1350,8 +1535,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else { float center_click_dist = click.distance_to(_edit.center); float center_inters_dist = intersection.distance_to(_edit.center); - if (center_click_dist == 0) + if (center_click_dist == 0) { break; + } float scale = center_inters_dist - center_click_dist; motion = Vector3(scale, scale, scale); @@ -1372,13 +1558,12 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); + Node3D *sp = Object::cast_to<Node3D>(E->get()); if (!sp) { continue; } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); if (!se) { continue; } @@ -1394,7 +1579,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Vector3 local_scale; if (local_coords) { - Basis g = original.basis.orthonormalized(); Vector3 local_motion = g.inverse().xform(motion); @@ -1408,13 +1592,11 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Basis check = original_local.basis; check.scale(local_scale); if (check.determinant() != 0) { - // Apply scale sp->set_scale(local_scale); } } else { - if (_edit.snap || spatial_editor->is_snap_enabled()) { motion.snap(Vector3(snap, snap, snap)); } @@ -1433,7 +1615,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; case TRANSFORM_TRANSLATE: { - Vector3 motion_mask; Plane plane; bool plane_mv = false; @@ -1469,12 +1650,14 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } Vector3 intersection; - if (!plane.intersects_ray(ray_pos, ray, &intersection)) + if (!plane.intersects_ray(ray_pos, ray, &intersection)) { break; + } Vector3 click; - if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) + if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) { break; + } Vector3 motion = intersection - click; if (_edit.plane != TRANSFORM_VIEW) { @@ -1497,13 +1680,12 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")"); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); + Node3D *sp = Object::cast_to<Node3D>(E->get()); if (!sp) { continue; } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); if (!se) { continue; } @@ -1516,7 +1698,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Transform t; if (local_coords) { - if (_edit.snap || spatial_editor->is_snap_enabled()) { Basis g = original.basis.orthonormalized(); Vector3 local_motion = g.inverse().xform(motion); @@ -1526,7 +1707,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else { - if (_edit.snap || spatial_editor->is_snap_enabled()) { motion.snap(Vector3(snap, snap, snap)); } @@ -1543,7 +1723,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; case TRANSFORM_ROTATE: { - Plane plane; Vector3 axis; @@ -1570,12 +1749,14 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } Vector3 intersection; - if (!plane.intersects_ray(ray_pos, ray, &intersection)) + if (!plane.intersects_ray(ray_pos, ray, &intersection)) { break; + } Vector3 click; - if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) + if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) { break; + } Vector3 y_axis = (click - _edit.center).normalized(); Vector3 x_axis = plane.normal.cross(y_axis).normalized(); @@ -1595,14 +1776,15 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } if (sp->has_meta("_edit_lock_")) { continue; @@ -1611,7 +1793,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Transform t; if (local_coords) { - Transform original_local = se->original_local; Basis rot = Basis(axis, angle); @@ -1623,7 +1804,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { sp->set_scale(original_local.basis.get_scale()); // re-apply original scale } else { - Transform original = se->original; Transform r; Transform base = Transform(Basis(), _edit.center); @@ -1645,7 +1825,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) { - if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) { nav_mode = NAVIGATION_ZOOM; } else if (freelook_active) { @@ -1655,9 +1834,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) { - if (nav_scheme == NAVIGATION_GODOT) { - const int mod = _get_key_modifier(m); if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { @@ -1670,8 +1847,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else if (nav_scheme == NAVIGATION_MAYA) { - if (m->get_alt()) + if (m->get_alt()) { nav_mode = NAVIGATION_PAN; + } } } else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) { @@ -1718,21 +1896,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventMagnifyGesture> magnify_gesture = p_event; if (magnify_gesture.is_valid()) { - - if (is_freelook_active()) + if (is_freelook_active()) { scale_freelook_speed(magnify_gesture->get_factor()); - else + } else { scale_cursor_distance(1.0 / magnify_gesture->get_factor()); + } } Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid()) { - NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); NavigationMode nav_mode = NAVIGATION_NONE; if (nav_scheme == NAVIGATION_GODOT) { - const int mod = _get_key_modifier(pan_gesture); if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { @@ -1745,28 +1921,29 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } else if (nav_scheme == NAVIGATION_MAYA) { - if (pan_gesture->get_alt()) + if (pan_gesture->get_alt()) { nav_mode = NAVIGATION_PAN; + } } switch (nav_mode) { case NAVIGATION_PAN: { - _nav_pan(m, pan_gesture->get_delta()); + _nav_pan(pan_gesture, pan_gesture->get_delta()); } break; case NAVIGATION_ZOOM: { - _nav_zoom(m, pan_gesture->get_delta()); + _nav_zoom(pan_gesture, pan_gesture->get_delta()); } break; case NAVIGATION_ORBIT: { - _nav_orbit(m, pan_gesture->get_delta()); + _nav_orbit(pan_gesture, pan_gesture->get_delta()); } break; case NAVIGATION_LOOK: { - _nav_look(m, pan_gesture->get_delta()); + _nav_look(pan_gesture, pan_gesture->get_delta()); } break; @@ -1778,8 +1955,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { - if (!k->is_pressed()) + if (!k->is_pressed()) { return; + } if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { if (_edit.mode != TRANSFORM_NONE) { @@ -1822,8 +2000,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { _menu_option(VIEW_ALIGN_ROTATION_WITH_VIEW); } if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) { - if (!get_selected_count() || _edit.mode != TRANSFORM_NONE) + if (!get_selected_count() || _edit.mode != TRANSFORM_NONE) { return; + } if (!AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) { set_message(TTR("Keying is disabled (no key inserted).")); @@ -1833,10 +2012,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform()); } @@ -1848,113 +2027,132 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) { set_freelook_active(!is_freelook_active()); - } else if (k->get_scancode() == KEY_ESCAPE) { + } else if (k->get_keycode() == KEY_ESCAPE) { set_freelook_active(false); } - if (k->get_scancode() == KEY_SPACE) { - if (!k->is_pressed()) emit_signal("toggle_maximize_view", this); + if (k->get_keycode() == KEY_SPACE) { + if (!k->is_pressed()) { + emit_signal("toggle_maximize_view", this); + } } } // freelook uses most of the useful shortcuts, like save, so its ok // to consider freelook active as end of the line for future events. - if (freelook_active) + if (freelook_active) { accept_event(); + } } -void SpatialEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { - +void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); real_t pan_speed = 1 / 150.0; int pan_speed_modifier = 10; - if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) + if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) { pan_speed *= pan_speed_modifier; + } Transform camera_transform; camera_transform.translate(cursor.pos); camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot); - Vector3 translation(-p_relative.x * pan_speed, p_relative.y * pan_speed, 0); + const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis"); + const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); + Vector3 translation( + (invert_x_axis ? -1 : 1) * -p_relative.x * pan_speed, + (invert_y_axis ? -1 : 1) * p_relative.y * pan_speed, + 0); translation *= cursor.distance / DISTANCE_DEFAULT; camera_transform.translate(translation); cursor.pos = camera_transform.origin; } -void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { - +void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int(); real_t zoom_speed = 1 / 80.0; int zoom_speed_modifier = 10; - if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) + if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift()) { zoom_speed *= zoom_speed_modifier; + } NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int(); if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) { - if (p_relative.x > 0) + if (p_relative.x > 0) { scale_cursor_distance(1 - p_relative.x * zoom_speed); - else if (p_relative.x < 0) + } else if (p_relative.x < 0) { scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed)); + } } else { - if (p_relative.y > 0) + if (p_relative.y > 0) { scale_cursor_distance(1 + p_relative.y * zoom_speed); - else if (p_relative.y < 0) + } else if (p_relative.y < 0) { scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed)); + } } } -void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { - +void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { if (lock_rotation) { _nav_pan(p_event, p_relative); return; } - real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); - real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); - bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); + if (orthogonal && auto_orthogonal) { + _menu_option(VIEW_PERSPECTIVE); + } + + const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); + const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); + const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); + const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis"); if (invert_y_axis) { cursor.x_rot -= p_relative.y * radians_per_pixel; } else { cursor.x_rot += p_relative.y * radians_per_pixel; } - cursor.y_rot += p_relative.x * radians_per_pixel; - if (cursor.x_rot > Math_PI / 2.0) - cursor.x_rot = Math_PI / 2.0; - if (cursor.x_rot < -Math_PI / 2.0) - cursor.x_rot = -Math_PI / 2.0; + // Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented. + cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57); + + if (invert_x_axis) { + cursor.y_rot -= p_relative.x * radians_per_pixel; + } else { + cursor.y_rot += p_relative.x * radians_per_pixel; + } name = ""; _update_name(); } -void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { - +void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { if (orthogonal) { _nav_pan(p_event, p_relative); return; } - real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); - real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); - bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); + if (orthogonal && auto_orthogonal) { + _menu_option(VIEW_PERSPECTIVE); + } + + const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity"); + const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); + const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag". - Transform prev_camera_transform = to_camera_transform(cursor); + const Transform prev_camera_transform = to_camera_transform(cursor); if (invert_y_axis) { cursor.x_rot -= p_relative.y * radians_per_pixel; } else { cursor.x_rot += p_relative.y * radians_per_pixel; } + // Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented. + cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57); + cursor.y_rot += p_relative.x * radians_per_pixel; - if (cursor.x_rot > Math_PI / 2.0) - cursor.x_rot = Math_PI / 2.0; - if (cursor.x_rot < -Math_PI / 2.0) - cursor.x_rot = -Math_PI / 2.0; // Look is like the opposite of Orbit: the focus point rotates around the camera Transform camera_transform = to_camera_transform(cursor); @@ -1967,8 +2165,7 @@ void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, cons _update_name(); } -void SpatialEditorViewport::set_freelook_active(bool active_now) { - +void Node3DEditorViewport::set_freelook_active(bool active_now) { if (!freelook_active && active_now) { // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential cursor = camera_cursor; @@ -1985,51 +2182,60 @@ void SpatialEditorViewport::set_freelook_active(bool active_now) { freelook_speed = base_speed * cursor.distance; } + previous_mouse_position = get_local_mouse_position(); + // Hide mouse like in an FPS (warping doesn't work) - OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_CAPTURED); + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); } else if (freelook_active && !active_now) { // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential cursor = camera_cursor; // Restore mouse - OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_VISIBLE); + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + + // Restore the previous mouse position when leaving freelook mode. + // This is done because leaving `Input.MOUSE_MODE_CAPTURED` will center the cursor + // due to OS limitations. + warp_mouse(previous_mouse_position); } freelook_active = active_now; } -void SpatialEditorViewport::scale_cursor_distance(real_t scale) { - +void Node3DEditorViewport::scale_cursor_distance(real_t scale) { // Prevents zero distance which would short-circuit any scaling - if (cursor.distance < ZOOM_MIN_DISTANCE) + if (cursor.distance < ZOOM_MIN_DISTANCE) { cursor.distance = ZOOM_MIN_DISTANCE; + } cursor.distance *= scale; - if (cursor.distance < ZOOM_MIN_DISTANCE) + if (cursor.distance < ZOOM_MIN_DISTANCE) { cursor.distance = ZOOM_MIN_DISTANCE; + } zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S; surface->update(); } -void SpatialEditorViewport::scale_freelook_speed(real_t scale) { - +void Node3DEditorViewport::scale_freelook_speed(real_t scale) { // Prevents zero distance which would short-circuit any scaling - if (freelook_speed < FREELOOK_MIN_SPEED) + if (freelook_speed < FREELOOK_MIN_SPEED) { freelook_speed = FREELOOK_MIN_SPEED; + } freelook_speed *= scale; - if (freelook_speed < FREELOOK_MIN_SPEED) + if (freelook_speed < FREELOOK_MIN_SPEED) { freelook_speed = FREELOOK_MIN_SPEED; + } zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S; surface->update(); } -Point2i SpatialEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { +Point2i Node3DEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const { Point2i relative; if (bool(EDITOR_DEF("editors/3d/navigation/warped_mouse_panning", false))) { relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect()); @@ -2040,28 +2246,45 @@ Point2i SpatialEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMous } static bool is_shortcut_pressed(const String &p_path) { - Ref<ShortCut> shortcut = ED_GET_SHORTCUT(p_path); + Ref<Shortcut> shortcut = ED_GET_SHORTCUT(p_path); if (shortcut.is_null()) { return false; } InputEventKey *k = Object::cast_to<InputEventKey>(shortcut->get_shortcut().ptr()); - if (k == NULL) { + if (k == nullptr) { return false; } const Input &input = *Input::get_singleton(); - int scancode = k->get_scancode(); - return input.is_key_pressed(scancode); + int keycode = k->get_keycode(); + return input.is_key_pressed(keycode); } -void SpatialEditorViewport::_update_freelook(real_t delta) { - +void Node3DEditorViewport::_update_freelook(real_t delta) { if (!is_freelook_active()) { return; } - const Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1)); + const FreelookNavigationScheme navigation_scheme = (FreelookNavigationScheme)EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_navigation_scheme").operator int(); + + Vector3 forward; + if (navigation_scheme == FREELOOK_FULLY_AXIS_LOCKED) { + // Forward/backward keys will always go straight forward/backward, never moving on the Y axis. + forward = Vector3(0, 0, -1).rotated(Vector3(0, 1, 0), camera->get_rotation().y); + } else { + // Forward/backward keys will be relative to the camera pitch. + forward = camera->get_transform().basis.xform(Vector3(0, 0, -1)); + } + const Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0)); - const Vector3 up = camera->get_transform().basis.xform(Vector3(0, 1, 0)); + + Vector3 up; + if (navigation_scheme == FREELOOK_PARTIALLY_AXIS_LOCKED || navigation_scheme == FREELOOK_FULLY_AXIS_LOCKED) { + // Up/down keys will always go up/down regardless of camera pitch. + up = Vector3(0, 1, 0); + } else { + // Up/down keys will be relative to the camera pitch. + up = camera->get_transform().basis.xform(Vector3(0, 1, 0)); + } Vector3 direction; @@ -2098,51 +2321,42 @@ void SpatialEditorViewport::_update_freelook(real_t delta) { cursor.eye_pos += motion; } -void SpatialEditorViewport::set_message(String p_message, float p_time) { - +void Node3DEditorViewport::set_message(String p_message, float p_time) { message = p_message; message_time = p_time; } -void SpatialEditorPlugin::edited_scene_changed() { - for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { - SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i); +void Node3DEditorPlugin::edited_scene_changed() { + for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) { + Node3DEditorViewport *viewport = Node3DEditor::get_singleton()->get_editor_viewport(i); if (viewport->is_visible()) { viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED); } } } -void SpatialEditorViewport::_notification(int p_what) { - +void Node3DEditorViewport::_notification(int p_what) { if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - bool visible = is_visible_in_tree(); set_process(visible); if (visible) { + orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL)); + _update_name(); _update_camera(0); } else { set_freelook_active(false); } call_deferred("update_transform_gizmo_view"); + rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo")); } if (p_what == NOTIFICATION_RESIZED) { - call_deferred("update_transform_gizmo_view"); } - if (p_what == NOTIFICATION_READY) { - // The crosshair icon doesn't depend on the editor theme. - crosshair->set_texture(get_icon("Crosshair", "EditorIcons")); - // Set the anchors and margins after changing the icon to ensure it's centered correctly. - crosshair->set_anchors_and_margins_preset(PRESET_CENTER); - } - if (p_what == NOTIFICATION_PROCESS) { - real_t delta = get_process_delta_time(); if (zoom_indicator_delay > 0) { @@ -2155,16 +2369,16 @@ void SpatialEditorViewport::_notification(int p_what) { _update_freelook(delta); Node *scene_root = editor->get_scene_tree_dock()->get_editor_data()->get_edited_scene_root(); - if (previewing_cinema && scene_root != NULL) { - Camera *cam = scene_root->get_viewport()->get_camera(); - if (cam != NULL && cam != previewing) { + if (previewing_cinema && scene_root != nullptr) { + Camera3D *cam = scene_root->get_viewport()->get_camera(); + if (cam != nullptr && cam != previewing) { //then switch the viewport's camera to the scene's viewport camera - if (previewing != NULL) { - previewing->disconnect("tree_exited", this, "_preview_exited_scene"); + if (previewing != nullptr) { + previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); } previewing = cam; - previewing->connect("tree_exited", this, "_preview_exited_scene"); - VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera()); + previewing->connect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera()); surface->update(); } } @@ -2177,20 +2391,30 @@ void SpatialEditorViewport::_notification(int p_what) { bool exist = false; for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { + Node3D *sp = Object::cast_to<Node3D>(E->key()); + if (!sp) { + continue; + } - Spatial *sp = Object::cast_to<Spatial>(E->key()); - if (!sp) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } + + Transform t = sp->get_global_gizmo_transform(); - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + exist = true; + if (se->last_xform == t && !se->last_xform_dirty) { continue; + } + changed = true; + se->last_xform_dirty = false; + se->last_xform = t; - VisualInstance *vi = Object::cast_to<VisualInstance>(sp); + VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp); se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp); - Transform t = sp->get_global_gizmo_transform(); t.translate(se->aabb.position); // apply AABB scaling before item's global transform @@ -2198,12 +2422,7 @@ void SpatialEditorViewport::_notification(int p_what) { aabb_s.scale(se->aabb.size); t.basis = t.basis * aabb_s; - exist = true; - if (se->last_xform == t) - continue; - changed = true; - se->last_xform = t; - VisualServer::get_singleton()->instance_set_transform(se->sbox_instance, t); + RenderingServer::get_singleton()->instance_set_transform(se->sbox_instance, t); } if (changed || (spatial_editor->is_gizmo_visible() && !exist)) { @@ -2211,15 +2430,15 @@ void SpatialEditorViewport::_notification(int p_what) { } if (message_time > 0) { - if (message != last_message) { surface->update(); last_message = message; } message_time -= get_physics_process_delta_time(); - if (message_time < 0) + if (message_time < 0) { surface->update(); + } } //update shadow atlas if changed @@ -2238,22 +2457,23 @@ void SpatialEditorViewport::_notification(int p_what) { bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); - if (shrink != (viewport_container->get_stretch_shrink() > 1)) { - viewport_container->set_stretch_shrink(shrink ? 2 : 1); + if (shrink != (subviewport_container->get_stretch_shrink() > 1)) { + subviewport_container->set_stretch_shrink(shrink ? 2 : 1); } //update msaa if changed - int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); + int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/screen_filters/msaa"); viewport->set_msaa(Viewport::MSAA(msaa_mode)); - - bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr"); - viewport->set_hdr(hdr); + int ssaa_mode = GLOBAL_GET("rendering/quality/screen_filters/screen_space_aa"); + viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); - info_label->set_visible(show_info); + if (show_info != info_label->is_visible()) { + info_label->set_visible(show_info); + } - Camera *current_camera; + Camera3D *current_camera; if (previewing) { current_camera = previewing; @@ -2261,10 +2481,6 @@ void SpatialEditorViewport::_notification(int p_what) { current_camera = camera; } - // Display the crosshair only while freelooking. Hide it otherwise, - // as the crosshair can be distracting. - crosshair->set_visible(freelook_active); - if (show_info) { String text; text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n"; @@ -2278,17 +2494,45 @@ void SpatialEditorViewport::_notification(int p_what) { text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n"; text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n"; text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME)); + info_label->set_text(text); } // FPS Counter. - bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); - fps_label->set_visible(show_fps); - + bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); + + if (show_fps != fps_label->is_visible()) { + fps_label->set_visible(show_fps); + RS::get_singleton()->viewport_set_measure_render_time(viewport->get_viewport_rid(), show_fps); + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + cpu_time_history[i] = 0; + gpu_time_history[i] = 0; + } + cpu_time_history_index = 0; + cpu_time_history_index = 0; + } if (show_fps) { + cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid()); + cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY; + float cpu_time = 0.0; + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + cpu_time += cpu_time_history[i]; + } + cpu_time /= FRAME_TIME_HISTORY; + + gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid()); + gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY; + float gpu_time = 0.0; + for (int i = 0; i < FRAME_TIME_HISTORY; i++) { + gpu_time += gpu_time_history[i]; + } + gpu_time /= FRAME_TIME_HISTORY; + String text; - const float temp_fps = Engine::get_singleton()->get_frames_per_second(); - text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2))); + text += TTR("CPU Time") + ": " + String::num(cpu_time, 1) + " ms\n"; + text += TTR("GPU Time") + ": " + String::num(gpu_time, 1) + " ms\n"; + text += TTR("FPS") + ": " + itos(1000.0 / gpu_time); + fps_label->set_text(text); } @@ -2306,55 +2550,51 @@ void SpatialEditorViewport::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE) { - - surface->connect("draw", this, "_draw"); - surface->connect("gui_input", this, "_sinput"); - surface->connect("mouse_entered", this, "_surface_mouse_enter"); - surface->connect("mouse_exited", this, "_surface_mouse_exit"); - surface->connect("focus_entered", this, "_surface_focus_enter"); - surface->connect("focus_exited", this, "_surface_focus_exit"); + surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw)); + surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput)); + surface->connect("mouse_entered", callable_mp(this, &Node3DEditorViewport::_surface_mouse_enter)); + surface->connect("mouse_exited", callable_mp(this, &Node3DEditorViewport::_surface_mouse_exit)); + surface->connect("focus_entered", callable_mp(this, &Node3DEditorViewport::_surface_focus_enter)); + surface->connect("focus_exited", callable_mp(this, &Node3DEditorViewport::_surface_focus_exit)); _init_gizmo_instance(index); } if (p_what == NOTIFICATION_EXIT_TREE) { - _finish_gizmo_instances(); } if (p_what == NOTIFICATION_THEME_CHANGED) { + view_menu->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons")); + preview_camera->set_icon(get_theme_icon("Camera3D", "EditorIcons")); - view_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons")); - preview_camera->set_icon(get_icon("Camera", "EditorIcons")); - - view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); + view_menu->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + view_menu->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + view_menu->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + view_menu->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + view_menu->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); - preview_camera->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - preview_camera->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - preview_camera->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - preview_camera->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); + preview_camera->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + preview_camera->add_theme_style_override("hover", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + preview_camera->add_theme_style_override("pressed", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + preview_camera->add_theme_style_override("focus", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + preview_camera->add_theme_style_override("disabled", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); - info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); - locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles")); + info_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + fps_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + cinema_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); + locked_label->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("Information3dViewport", "EditorStyles")); } } -static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture> icon) { - +static void draw_indicator_bar(Control &surface, real_t fill, const Ref<Texture2D> icon, const Ref<Font> font, const String &text) { // Adjust bar size from control height - Vector2 surface_size = surface.get_size(); - real_t h = surface_size.y / 2.0; - real_t y = (surface_size.y - h) / 2.0; + const Vector2 surface_size = surface.get_size(); + const real_t h = surface_size.y / 2.0; + const real_t y = (surface_size.y - h) / 2.0; - Rect2 r(10, y, 6, h); - real_t sy = r.size.y * fill; + const Rect2 r(10 * EDSCALE, y, 6 * EDSCALE, h); + const real_t sy = r.size.y * fill; // Note: because this bar appears over the viewport, it has to stay readable for any background color // Draw both neutral dark and bright colors to account this @@ -2362,13 +2602,15 @@ static void draw_indicator_bar(Control &surface, real_t fill, Ref<Texture> icon) surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6)); surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE)); - Vector2 icon_size = icon->get_size(); - Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2); + const Vector2 icon_size = icon->get_size(); + const Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2 * EDSCALE); surface.draw_texture(icon, icon_pos); -} -void SpatialEditorViewport::_draw() { + // Draw text below the bar (for speed/zoom information). + surface.draw_string(font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), text); +} +void Node3DEditorViewport::_draw() { EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over(); if (!over_plugin_list->empty()) { over_plugin_list->forward_spatial_draw_over_viewport(surface); @@ -2382,7 +2624,7 @@ void SpatialEditorViewport::_draw() { if (surface->has_focus()) { Size2 size = surface->get_size(); Rect2 r = Rect2(Point2(), size); - get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r); + get_theme_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r); } if (cursor.region_select) { @@ -2390,11 +2632,11 @@ void SpatialEditorViewport::_draw() { surface->draw_rect( selection_rect, - get_color("box_selection_fill_color", "Editor")); + get_theme_color("box_selection_fill_color", "Editor")); surface->draw_rect( selection_rect, - get_color("box_selection_stroke_color", "Editor"), + get_theme_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE)); } @@ -2402,7 +2644,7 @@ void SpatialEditorViewport::_draw() { RID ci = surface->get_canvas_item(); if (message_time > 0) { - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); Point2 msgpos = Point2(5, get_size().y - 20); font->draw(ci, msgpos + Point2(1, 1), message, Color(0, 0, 0, 0.8)); font->draw(ci, msgpos + Point2(-1, -1), message, Color(0, 0, 0, 0.8)); @@ -2410,18 +2652,15 @@ void SpatialEditorViewport::_draw() { } if (_edit.mode == TRANSFORM_ROTATE) { - Point2 center = _point_to_screen(_edit.center); - VisualServer::get_singleton()->canvas_item_add_line( + RenderingServer::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); + get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.6), + Math::round(2 * EDSCALE)); } if (previewing) { - Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); float aspect = ss.aspect(); Size2 s = get_size(); @@ -2429,15 +2668,13 @@ void SpatialEditorViewport::_draw() { Rect2 draw_rect; switch (previewing->get_keep_aspect_mode()) { - case Camera::KEEP_WIDTH: { - + case Camera3D::KEEP_WIDTH: { draw_rect.size = Size2(s.width, s.width / aspect); draw_rect.position.x = 0; draw_rect.position.y = (s.height - draw_rect.size.y) * 0.5; } break; - case Camera::KEEP_HEIGHT: { - + case Camera3D::KEEP_HEIGHT: { draw_rect.size = Size2(s.height * aspect, s.height); draw_rect.position.y = 0; draw_rect.position.x = (s.width - draw_rect.size.x) * 0.5; @@ -2450,9 +2687,7 @@ void SpatialEditorViewport::_draw() { surface->draw_rect(draw_rect, Color(0.6, 0.6, 0.1, 0.5), false, Math::round(2 * EDSCALE)); } else { - if (zoom_indicator_delay > 0.0) { - if (is_freelook_active()) { // Show speed @@ -2465,10 +2700,18 @@ void SpatialEditorViewport::_draw() { // There is no real maximum speed so that factor can become negative, // Let's make it look asymptotic instead (will decrease slower and slower). - if (logscale_t < 0.25) + if (logscale_t < 0.25) { logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0); + } - draw_indicator_bar(*surface, 1.0 - logscale_t, get_icon("ViewportSpeed", "EditorIcons")); + // Display the freelook speed to help the user get a better sense of scale. + const int precision = freelook_speed < 1.0 ? 2 : 1; + draw_indicator_bar( + *surface, + 1.0 - logscale_t, + get_theme_icon("ViewportSpeed", "EditorIcons"), + get_theme_font("font", "Label"), + vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision))); } } else { @@ -2483,88 +2726,92 @@ void SpatialEditorViewport::_draw() { // There is no real maximum distance so that factor can become negative, // Let's make it look asymptotic instead (will decrease slower and slower). - if (logscale_t < 0.25) + if (logscale_t < 0.25) { logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0); + } - draw_indicator_bar(*surface, logscale_t, get_icon("ViewportZoom", "EditorIcons")); + // Display the zoom center distance to help the user get a better sense of scale. + const int precision = cursor.distance < 1.0 ? 2 : 1; + draw_indicator_bar( + *surface, + logscale_t, + get_theme_icon("ViewportZoom", "EditorIcons"), + get_theme_font("font", "Label"), + vformat("%s u", String::num(cursor.distance).pad_decimals(precision))); } } } } } -void SpatialEditorViewport::_menu_option(int p_option) { - +void Node3DEditorViewport::_menu_option(int p_option) { switch (p_option) { - case VIEW_TOP: { - cursor.y_rot = 0; cursor.x_rot = Math_PI / 2.0; set_message(TTR("Top View."), 2); name = TTR("Top"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_BOTTOM: { - cursor.y_rot = 0; cursor.x_rot = -Math_PI / 2.0; set_message(TTR("Bottom View."), 2); name = TTR("Bottom"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_LEFT: { - cursor.x_rot = 0; cursor.y_rot = Math_PI / 2.0; set_message(TTR("Left View."), 2); name = TTR("Left"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_RIGHT: { - cursor.x_rot = 0; cursor.y_rot = -Math_PI / 2.0; set_message(TTR("Right View."), 2); name = TTR("Right"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_FRONT: { - cursor.x_rot = 0; cursor.y_rot = 0; set_message(TTR("Front View."), 2); name = TTR("Front"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_REAR: { - cursor.x_rot = 0; cursor.y_rot = Math_PI; set_message(TTR("Rear View."), 2); name = TTR("Rear"); + _set_auto_orthogonal(); _update_name(); } break; case VIEW_CENTER_TO_ORIGIN: { - cursor.pos = Vector3(0, 0, 0); } break; case VIEW_CENTER_TO_SELECTION: { - focus_selection(); } break; case VIEW_ALIGN_TRANSFORM_WITH_VIEW: { - - if (!get_selected_count()) + if (!get_selected_count()) { break; + } Transform camera_transform = camera->get_global_transform(); @@ -2573,14 +2820,15 @@ void SpatialEditorViewport::_menu_option(int p_option) { undo_redo->create_action(TTR("Align Transform with View")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } Transform xform; if (orthogonal) { @@ -2595,13 +2843,12 @@ void SpatialEditorViewport::_menu_option(int p_option) { undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform()); } undo_redo->commit_action(); - focus_selection(); } break; case VIEW_ALIGN_ROTATION_WITH_VIEW: { - - if (!get_selected_count()) + if (!get_selected_count()) { break; + } Transform camera_transform = camera->get_global_transform(); @@ -2609,14 +2856,15 @@ void SpatialEditorViewport::_menu_option(int p_option) { undo_redo->create_action(TTR("Align Rotation with View")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_rotation()); undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation()); @@ -2625,41 +2873,47 @@ void SpatialEditorViewport::_menu_option(int p_option) { } break; case VIEW_ENVIRONMENT: { - int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; if (current) { - camera->set_environment(RES()); } else { - - camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment()); + camera->set_environment(Node3DEditor::get_singleton()->get_viewport_environment()); } view_menu->get_popup()->set_item_checked(idx, current); } break; case VIEW_PERSPECTIVE: { - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false); orthogonal = false; + auto_orthogonal = false; call_deferred("update_transform_gizmo_view"); _update_name(); } break; case VIEW_ORTHOGONAL: { - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true); orthogonal = true; + auto_orthogonal = false; call_deferred("update_transform_gizmo_view"); _update_name(); } break; + case VIEW_AUTO_ORTHOGONAL: { + int idx = view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL); + bool current = view_menu->get_popup()->is_item_checked(idx); + current = !current; + view_menu->get_popup()->set_item_checked(idx, current); + if (auto_orthogonal) { + auto_orthogonal = false; + _update_name(); + } + } break; case VIEW_LOCK_ROTATION: { - int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION); bool current = view_menu->get_popup()->is_item_checked(idx); lock_rotation = !current; @@ -2672,7 +2926,6 @@ void SpatialEditorViewport::_menu_option(int p_option) { } break; case VIEW_AUDIO_LISTENER: { - int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; @@ -2681,16 +2934,14 @@ void SpatialEditorViewport::_menu_option(int p_option) { } break; case VIEW_AUDIO_DOPPLER: { - int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; - camera->set_doppler_tracking(current ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED); + camera->set_doppler_tracking(current ? Camera3D::DOPPLER_TRACKING_IDLE_STEP : Camera3D::DOPPLER_TRACKING_DISABLED); view_menu->get_popup()->set_item_checked(idx, current); } break; case VIEW_CINEMATIC_PREVIEW: { - int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; @@ -2701,178 +2952,225 @@ void SpatialEditorViewport::_menu_option(int p_option) { if (current) { preview_camera->hide(); } else { - if (previewing != NULL) + if (previewing != nullptr) { preview_camera->show(); + } } } break; case VIEW_GIZMOS: { - int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; - if (current) + if (current) { camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER)); - else + } else { camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_GRID_LAYER)); + } view_menu->get_popup()->set_item_checked(idx, current); } break; case VIEW_HALF_RESOLUTION: { - int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION); bool current = view_menu->get_popup()->is_item_checked(idx); current = !current; view_menu->get_popup()->set_item_checked(idx, current); } break; case VIEW_INFORMATION: { - int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION); bool current = view_menu->get_popup()->is_item_checked(idx); view_menu->get_popup()->set_item_checked(idx, !current); } break; - case VIEW_FPS: { - - int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); + case VIEW_FRAME_TIME: { + int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME); bool current = view_menu->get_popup()->is_item_checked(idx); view_menu->get_popup()->set_item_checked(idx, !current); } break; - case VIEW_DISPLAY_NORMAL: { - - viewport->set_debug_draw(Viewport::DEBUG_DRAW_DISABLED); - - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false); - } break; - case VIEW_DISPLAY_WIREFRAME: { - - viewport->set_debug_draw(Viewport::DEBUG_DRAW_WIREFRAME); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), true); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false); - - } break; - case VIEW_DISPLAY_OVERDRAW: { - - viewport->set_debug_draw(Viewport::DEBUG_DRAW_OVERDRAW); - VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), true); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false); - - } break; - case VIEW_DISPLAY_SHADELESS: { - - viewport->set_debug_draw(Viewport::DEBUG_DRAW_UNSHADED); - VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false); - view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), true); + case VIEW_DISPLAY_NORMAL: + case VIEW_DISPLAY_WIREFRAME: + case VIEW_DISPLAY_OVERDRAW: + case VIEW_DISPLAY_SHADELESS: + case VIEW_DISPLAY_LIGHTING: + case VIEW_DISPLAY_NORMAL_BUFFER: + case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS: + case VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS: + case VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO: + case VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING: + case VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION: + case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE: + case VIEW_DISPLAY_DEBUG_SSAO: + case VIEW_DISPLAY_DEBUG_PSSM_SPLITS: + case VIEW_DISPLAY_DEBUG_DECAL_ATLAS: + case VIEW_DISPLAY_DEBUG_SDFGI: + case VIEW_DISPLAY_DEBUG_SDFGI_PROBES: + case VIEW_DISPLAY_DEBUG_GI_BUFFER: { + static const int display_options[] = { + VIEW_DISPLAY_NORMAL, + VIEW_DISPLAY_WIREFRAME, + VIEW_DISPLAY_OVERDRAW, + VIEW_DISPLAY_SHADELESS, + VIEW_DISPLAY_LIGHTING, + VIEW_DISPLAY_NORMAL_BUFFER, + VIEW_DISPLAY_WIREFRAME, + VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, + VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, + VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO, + VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING, + VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION, + VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, + VIEW_DISPLAY_DEBUG_SSAO, + VIEW_DISPLAY_DEBUG_GI_BUFFER, + VIEW_DISPLAY_DEBUG_PSSM_SPLITS, + VIEW_DISPLAY_DEBUG_DECAL_ATLAS, + VIEW_DISPLAY_DEBUG_SDFGI, + VIEW_DISPLAY_DEBUG_SDFGI_PROBES, + VIEW_MAX + }; + static const Viewport::DebugDraw debug_draw_modes[] = { + Viewport::DEBUG_DRAW_DISABLED, + Viewport::DEBUG_DRAW_WIREFRAME, + Viewport::DEBUG_DRAW_OVERDRAW, + Viewport::DEBUG_DRAW_UNSHADED, + Viewport::DEBUG_DRAW_LIGHTING, + Viewport::DEBUG_DRAW_NORMAL_BUFFER, + Viewport::DEBUG_DRAW_WIREFRAME, + Viewport::DEBUG_DRAW_SHADOW_ATLAS, + Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS, + Viewport::DEBUG_DRAW_GI_PROBE_ALBEDO, + Viewport::DEBUG_DRAW_GI_PROBE_LIGHTING, + Viewport::DEBUG_DRAW_GI_PROBE_EMISSION, + Viewport::DEBUG_DRAW_SCENE_LUMINANCE, + Viewport::DEBUG_DRAW_SSAO, + Viewport::DEBUG_DRAW_GI_BUFFER, + Viewport::DEBUG_DRAW_PSSM_SPLITS, + Viewport::DEBUG_DRAW_DECAL_ATLAS, + Viewport::DEBUG_DRAW_SDFGI, + Viewport::DEBUG_DRAW_SDFGI_PROBES, + }; + + int idx = 0; + + while (display_options[idx] != VIEW_MAX) { + int id = display_options[idx]; + int item_idx = view_menu->get_popup()->get_item_index(id); + if (item_idx != -1) { + view_menu->get_popup()->set_item_checked(item_idx, id == p_option); + } + item_idx = display_submenu->get_item_index(id); + if (item_idx != -1) { + display_submenu->set_item_checked(item_idx, id == p_option); + } + if (id == p_option) { + viewport->set_debug_draw(debug_draw_modes[idx]); + } + idx++; + } } break; } } -void SpatialEditorViewport::_preview_exited_scene() { +void Node3DEditorViewport::_set_auto_orthogonal() { + if (!orthogonal && view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL))) { + _menu_option(VIEW_ORTHOGONAL); + auto_orthogonal = true; + } +} - preview_camera->disconnect("toggled", this, "_toggle_camera_preview"); +void Node3DEditorViewport::_preview_exited_scene() { + preview_camera->disconnect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview)); preview_camera->set_pressed(false); _toggle_camera_preview(false); - preview_camera->connect("toggled", this, "_toggle_camera_preview"); + preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview)); view_menu->show(); } -void SpatialEditorViewport::_init_gizmo_instance(int p_idx) { - +void Node3DEditorViewport::_init_gizmo_instance(int p_idx) { uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx); for (int i = 0; i < 3; i++) { - move_gizmo_instance[i] = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid()); - VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer); - - move_plane_gizmo_instance[i] = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid()); - VS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer); - - rotate_gizmo_instance[i] = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid()); - VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer); - - scale_gizmo_instance[i] = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid()); - VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer); - - scale_plane_gizmo_instance[i] = VS::get_singleton()->instance_create(); - VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid()); - VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); - } -} - -void SpatialEditorViewport::_finish_gizmo_instances() { - + move_gizmo_instance[i] = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid()); + RS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer); + + move_plane_gizmo_instance[i] = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid()); + RS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer); + + rotate_gizmo_instance[i] = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid()); + RS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer); + + scale_gizmo_instance[i] = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid()); + RS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer); + + scale_plane_gizmo_instance[i] = RS::get_singleton()->instance_create(); + RS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid()); + RS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer); + } +} + +void Node3DEditorViewport::_finish_gizmo_instances() { for (int i = 0; i < 3; i++) { - VS::get_singleton()->free(move_gizmo_instance[i]); - VS::get_singleton()->free(move_plane_gizmo_instance[i]); - VS::get_singleton()->free(rotate_gizmo_instance[i]); - VS::get_singleton()->free(scale_gizmo_instance[i]); - VS::get_singleton()->free(scale_plane_gizmo_instance[i]); + RS::get_singleton()->free(move_gizmo_instance[i]); + RS::get_singleton()->free(move_plane_gizmo_instance[i]); + RS::get_singleton()->free(rotate_gizmo_instance[i]); + RS::get_singleton()->free(scale_gizmo_instance[i]); + RS::get_singleton()->free(scale_plane_gizmo_instance[i]); } } -void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) { +void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { ERR_FAIL_COND(p_activate && !preview); ERR_FAIL_COND(!p_activate && !previewing); - if (!p_activate) { + rotation_control->set_visible(!p_activate); - previewing->disconnect("tree_exiting", this, "_preview_exited_scene"); - previewing = NULL; - VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore - if (!preview) + if (!p_activate) { + previewing->disconnect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + previewing = nullptr; + RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore + if (!preview) { preview_camera->hide(); + } view_menu->set_disabled(false); surface->update(); } else { - previewing = preview; - previewing->connect("tree_exiting", this, "_preview_exited_scene"); - VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace + previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace view_menu->set_disabled(true); surface->update(); } } -void SpatialEditorViewport::_toggle_cinema_preview(bool p_activate) { +void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) { previewing_cinema = p_activate; if (!previewing_cinema) { - if (previewing != NULL) - previewing->disconnect("tree_exited", this, "_preview_exited_scene"); + if (previewing != nullptr) { + previewing->disconnect("tree_exited", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + } - previewing = NULL; - VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore + previewing = nullptr; + RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore preview_camera->set_pressed(false); if (!preview) { preview_camera->hide(); @@ -2884,38 +3182,37 @@ void SpatialEditorViewport::_toggle_cinema_preview(bool p_activate) { } } -void SpatialEditorViewport::_selection_result_pressed(int p_result) { - - if (selection_results.size() <= p_result) +void Node3DEditorViewport::_selection_result_pressed(int p_result) { + if (selection_results.size() <= p_result) { return; + } clicked = selection_results[p_result].item->get_instance_id(); - if (clicked) { - _select_clicked(clicked_wants_append, true); - clicked = 0; + if (clicked.is_valid()) { + _select_clicked(clicked_wants_append, true, spatial_editor->get_tool_mode() != Node3DEditor::TOOL_MODE_LIST_SELECT); + clicked = ObjectID(); } } -void SpatialEditorViewport::_selection_menu_hide() { - +void Node3DEditorViewport::_selection_menu_hide() { selection_results.clear(); selection_menu->clear(); selection_menu->set_size(Vector2(0, 0)); } -void SpatialEditorViewport::set_can_preview(Camera *p_preview) { - +void Node3DEditorViewport::set_can_preview(Camera3D *p_preview) { preview = p_preview; - if (!preview_camera->is_pressed() && !previewing_cinema) + if (!preview_camera->is_pressed() && !previewing_cinema) { preview_camera->set_visible(p_preview); + } } -void SpatialEditorViewport::update_transform_gizmo_view() { - - if (!is_visible_in_tree()) +void Node3DEditorViewport::update_transform_gizmo_view() { + if (!is_visible_in_tree()) { return; + } Transform xform = spatial_editor->get_gizmo_transform(); @@ -2923,11 +3220,11 @@ void SpatialEditorViewport::update_transform_gizmo_view() { if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) { for (int i = 0; i < 3; i++) { - VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); - VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); - VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); - VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); - VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); + RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false); + RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false); + RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false); + RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false); + RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false); } return; } @@ -2935,12 +3232,13 @@ void SpatialEditorViewport::update_transform_gizmo_view() { Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized(); Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized(); Plane p(camera_xform.origin, camz); - float gizmo_d = Math::abs(p.distance_to(xform.origin)); + float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON); float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y; float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y; float dd = Math::abs(d0 - d1); - if (dd == 0) + if (dd == 0) { dd = 0.0001; + } float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); // At low viewport heights, multiply the gizmo scale based on the viewport height. @@ -2948,51 +3246,68 @@ void SpatialEditorViewport::update_transform_gizmo_view() { const int viewport_base_height = 400 * MAX(1, EDSCALE); gizmo_scale = (gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) * - MIN(viewport_base_height, viewport_container->get_size().height) / viewport_base_height / - viewport_container->get_stretch_shrink(); + MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height / + subviewport_container->get_stretch_shrink(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; xform.basis.scale(scale); for (int i = 0; i < 3; i++) { - VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform); - VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE)); - VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform); - VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE)); - VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform); - VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE)); - VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform); - VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); - VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); - VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE)); + RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); + RenderingServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)); + RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE)); + RenderingServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); + RenderingServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform); + RenderingServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SCALE)); } } -void SpatialEditorViewport::set_state(const Dictionary &p_state) { - - if (p_state.has("position")) +void Node3DEditorViewport::set_state(const Dictionary &p_state) { + if (p_state.has("position")) { cursor.pos = p_state["position"]; - if (p_state.has("x_rotation")) + } + if (p_state.has("x_rotation")) { cursor.x_rot = p_state["x_rotation"]; - if (p_state.has("y_rotation")) + } + if (p_state.has("y_rotation")) { cursor.y_rot = p_state["y_rotation"]; - if (p_state.has("distance")) + } + if (p_state.has("distance")) { cursor.distance = p_state["distance"]; + } if (p_state.has("use_orthogonal")) { bool orth = p_state["use_orthogonal"]; - if (orth) + if (orth) { _menu_option(VIEW_ORTHOGONAL); - else + } else { _menu_option(VIEW_PERSPECTIVE); + } + } + if (p_state.has("view_name")) { + name = p_state["view_name"]; + _update_name(); + } + if (p_state.has("auto_orthogonal")) { + auto_orthogonal = p_state["auto_orthogonal"]; + _update_name(); + } + if (p_state.has("auto_orthogonal_enabled")) { + bool enabled = p_state["auto_orthogonal_enabled"]; + view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), enabled); } if (p_state.has("display_mode")) { int display = p_state["display_mode"]; int idx = view_menu->get_popup()->get_item_index(display); - if (!view_menu->get_popup()->is_item_checked(idx)) + if (!view_menu->get_popup()->is_item_checked(idx)) { _menu_option(display); + } } if (p_state.has("lock_rotation")) { lock_rotation = p_state["lock_rotation"]; @@ -3003,8 +3318,9 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { if (p_state.has("use_environment")) { bool env = p_state["use_environment"]; - if (env != camera->get_environment().is_valid()) + if (env != camera->get_environment().is_valid()) { _menu_option(VIEW_ENVIRONMENT); + } } if (p_state.has("listener")) { bool listener = p_state["listener"]; @@ -3017,29 +3333,32 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { bool doppler = p_state["doppler"]; int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER); - camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED); + camera->set_doppler_tracking(doppler ? Camera3D::DOPPLER_TRACKING_IDLE_STEP : Camera3D::DOPPLER_TRACKING_DISABLED); view_menu->get_popup()->set_item_checked(idx, doppler); } if (p_state.has("gizmos")) { bool gizmos = p_state["gizmos"]; int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS); - if (view_menu->get_popup()->is_item_checked(idx) != gizmos) + if (view_menu->get_popup()->is_item_checked(idx) != gizmos) { _menu_option(VIEW_GIZMOS); + } } if (p_state.has("information")) { bool information = p_state["information"]; int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION); - if (view_menu->get_popup()->is_item_checked(idx) != information) + if (view_menu->get_popup()->is_item_checked(idx) != information) { _menu_option(VIEW_INFORMATION); + } } - if (p_state.has("fps")) { - bool fps = p_state["fps"]; + if (p_state.has("frame_time")) { + bool fps = p_state["frame_time"]; - int idx = view_menu->get_popup()->get_item_index(VIEW_FPS); - if (view_menu->get_popup()->is_item_checked(idx) != fps) - _menu_option(VIEW_FPS); + int idx = view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME); + if (view_menu->get_popup()->is_item_checked(idx) != fps) { + _menu_option(VIEW_FRAME_TIME); + } } if (p_state.has("half_res")) { bool half_res = p_state["half_res"]; @@ -3054,98 +3373,87 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, previewing_cinema); } - if (preview_camera->is_connected("toggled", this, "_toggle_camera_preview")) { - preview_camera->disconnect("toggled", this, "_toggle_camera_preview"); + if (preview_camera->is_connected("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview))) { + preview_camera->disconnect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview)); } if (p_state.has("previewing")) { Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]); - if (Object::cast_to<Camera>(pv)) { - 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 + if (Object::cast_to<Camera3D>(pv)) { + previewing = Object::cast_to<Camera3D>(pv); + previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); + RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace view_menu->set_disabled(true); surface->update(); preview_camera->set_pressed(true); preview_camera->show(); } } - preview_camera->connect("toggled", this, "_toggle_camera_preview"); + preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview)); } -Dictionary SpatialEditorViewport::get_state() const { - +Dictionary Node3DEditorViewport::get_state() const { Dictionary d; d["position"] = cursor.pos; d["x_rotation"] = cursor.x_rot; d["y_rotation"] = cursor.y_rot; d["distance"] = cursor.distance; d["use_environment"] = camera->get_environment().is_valid(); - d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; - if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL))) + d["use_orthogonal"] = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; + d["view_name"] = name; + d["auto_orthogonal"] = auto_orthogonal; + d["auto_orthogonal_enabled"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL)); + if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL))) { d["display_mode"] = VIEW_DISPLAY_NORMAL; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME))) { d["display_mode"] = VIEW_DISPLAY_WIREFRAME; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW))) { d["display_mode"] = VIEW_DISPLAY_OVERDRAW; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) { d["display_mode"] = VIEW_DISPLAY_SHADELESS; + } d["listener"] = viewport->is_audio_listener(); d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); - d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)); - d["half_res"] = viewport_container->get_stretch_shrink() > 1; + d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); + d["half_res"] = subviewport_container->get_stretch_shrink() > 1; d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW)); - if (previewing) + if (previewing) { d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); - if (lock_rotation) + } + if (lock_rotation) { d["lock_rotation"] = lock_rotation; + } return d; } -void SpatialEditorViewport::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_draw"), &SpatialEditorViewport::_draw); - - ClassDB::bind_method(D_METHOD("_surface_mouse_enter"), &SpatialEditorViewport::_surface_mouse_enter); - ClassDB::bind_method(D_METHOD("_surface_mouse_exit"), &SpatialEditorViewport::_surface_mouse_exit); - ClassDB::bind_method(D_METHOD("_surface_focus_enter"), &SpatialEditorViewport::_surface_focus_enter); - ClassDB::bind_method(D_METHOD("_surface_focus_exit"), &SpatialEditorViewport::_surface_focus_exit); - ClassDB::bind_method(D_METHOD("_sinput"), &SpatialEditorViewport::_sinput); - ClassDB::bind_method(D_METHOD("_menu_option"), &SpatialEditorViewport::_menu_option); - ClassDB::bind_method(D_METHOD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview); - ClassDB::bind_method(D_METHOD("_preview_exited_scene"), &SpatialEditorViewport::_preview_exited_scene); - ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &SpatialEditorViewport::update_transform_gizmo_view); - ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &SpatialEditorViewport::_selection_result_pressed); - ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &SpatialEditorViewport::_selection_menu_hide); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpatialEditorViewport::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw); +void Node3DEditorViewport::_bind_methods() { + ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred. + ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw"), &Node3DEditorViewport::drop_data_fw); ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); } -void SpatialEditorViewport::reset() { - +void Node3DEditorViewport::reset() { orthogonal = false; + auto_orthogonal = false; lock_rotation = false; message_time = 0; message = ""; last_message = ""; name = ""; - cursor.x_rot = 0.5; - cursor.y_rot = 0.5; - cursor.distance = 4; - cursor.region_select = false; - cursor.pos = Vector3(); + cursor = Cursor(); _update_name(); } -void SpatialEditorViewport::focus_selection() { - if (!get_selected_count()) +void Node3DEditorViewport::focus_selection() { + if (!get_selected_count()) { return; + } Vector3 center; int count = 0; @@ -3153,14 +3461,15 @@ void SpatialEditorViewport::focus_selection() { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } center += sp->get_global_gizmo_transform().origin; count++; @@ -3173,20 +3482,20 @@ void SpatialEditorViewport::focus_selection() { cursor.pos = center; } -void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) { +void Node3DEditorViewport::assign_pending_data_pointers(Node3D *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) { preview_node = p_preview_node; preview_bounds = p_preview_bounds; accept = p_accept; } -Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const { +Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const { const float MAX_DISTANCE = 10; Vector3 world_ray = _get_ray(p_pos); Vector3 world_pos = _get_ray_pos(p_pos); - Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<EditorSpatialGizmo> > found_gizmos; + Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world_3d()->get_scenario()); + Set<Ref<EditorNode3DGizmo>> found_gizmos; float closest_dist = MAX_DISTANCE; @@ -3194,13 +3503,13 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const Vector3 normal = Vector3(0.0, 0.0, 0.0); for (int i = 0; i < instances.size(); i++) { + MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(instances[i])); - MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(ObjectDB::get_instance(instances[i])); - - if (!mesh_instance) + if (!mesh_instance) { continue; + } - Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo(); + Ref<EditorNode3DGizmo> seg = mesh_instance->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -3210,15 +3519,17 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const Vector3 hit_point; Vector3 hit_normal; - bool inters = seg->intersect_ray(camera, p_pos, hit_point, hit_normal, NULL, false); + bool inters = seg->intersect_ray(camera, p_pos, hit_point, hit_normal, nullptr, false); - if (!inters) + if (!inters) { continue; + } float dist = world_pos.distance_to(hit_point); - if (dist < 0) + if (dist < 0) { continue; + } if (dist < closest_dist) { closest_dist = dist; @@ -3228,28 +3539,29 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const } Vector3 offset = Vector3(); for (int i = 0; i < 3; i++) { - if (normal[i] > 0.0) + if (normal[i] > 0.0) { offset[i] = (preview_bounds->get_size()[i] - (preview_bounds->get_size()[i] + preview_bounds->get_position()[i])); - else if (normal[i] < 0.0) + } else if (normal[i] < 0.0) { offset[i] = -(preview_bounds->get_size()[i] + preview_bounds->get_position()[i]); + } } return point + offset; } -AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform) { +AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_toplevel_transform) { AABB bounds; - const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_parent); + const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_parent); if (mesh_instance) { bounds = mesh_instance->get_aabb(); } for (int i = 0; i < p_parent->get_child_count(); i++) { - Spatial *child = Object::cast_to<Spatial>(p_parent->get_child(i)); + Node3D *child = Object::cast_to<Node3D>(p_parent->get_child(i)); if (child) { AABB child_bounds = _calculate_spatial_bounds(child, false); - if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Spatial")) { + if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Node3D")) { bounds = child_bounds; } else { bounds.merge_with(child_bounds); @@ -3257,7 +3569,7 @@ AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, b } } - if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Spatial")) { + if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Node3D")) { bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4)); } @@ -3268,16 +3580,16 @@ AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, b return bounds; } -void SpatialEditorViewport::_create_preview(const Vector<String> &files) const { +void Node3DEditorViewport::_create_preview(const Vector<String> &files) const { for (int i = 0; i < files.size(); i++) { String path = files[i]; RES res = ResourceLoader::load(path); ERR_CONTINUE(res.is_null()); Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != NULL || scene != NULL) { - if (mesh != NULL) { - MeshInstance *mesh_instance = memnew(MeshInstance); + if (mesh != nullptr || scene != nullptr) { + if (mesh != nullptr) { + MeshInstance3D *mesh_instance = memnew(MeshInstance3D); mesh_instance->set_mesh(mesh); preview_node->add_child(mesh_instance); } else { @@ -3294,7 +3606,7 @@ void SpatialEditorViewport::_create_preview(const Vector<String> &files) const { *preview_bounds = _calculate_spatial_bounds(preview_node); } -void SpatialEditorViewport::_remove_preview() { +void Node3DEditorViewport::_remove_preview() { if (preview_node->get_parent()) { for (int i = preview_node->get_child_count() - 1; i >= 0; i--) { Node *node = preview_node->get_child(i); @@ -3305,7 +3617,7 @@ void SpatialEditorViewport::_remove_preview() { } } -bool SpatialEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) { +bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) { if (p_desired_node->get_filename() == p_target_scene_path) { return true; } @@ -3320,18 +3632,18 @@ bool SpatialEditorViewport::_cyclical_dependency_exists(const String &p_target_s return false; } -bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { +bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { RES res = ResourceLoader::load(path); ERR_FAIL_COND_V(res.is_null(), false); Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - Node *instanced_scene = NULL; + Node *instanced_scene = nullptr; - if (mesh != NULL || scene != NULL) { - if (mesh != NULL) { - MeshInstance *mesh_instance = memnew(MeshInstance); + if (mesh != nullptr || scene != nullptr) { + if (mesh != nullptr) { + MeshInstance3D *mesh_instance = memnew(MeshInstance3D); mesh_instance->set_mesh(mesh); mesh_instance->set_name(path.get_file().get_basename()); instanced_scene = mesh_instance; @@ -3344,7 +3656,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P } } - if (instanced_scene == NULL) { + if (instanced_scene == nullptr) { return false; } @@ -3355,7 +3667,7 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P } } - if (scene != NULL) { + if (scene != nullptr) { instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); } @@ -3365,23 +3677,28 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); String new_name = parent->validate_child_name(instanced_scene); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); - - Transform global_transform; - Spatial *parent_spatial = Object::cast_to<Spatial>(parent); - if (parent_spatial) - global_transform = parent_spatial->get_global_gizmo_transform(); + EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); + editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); + editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + + Node3D *node3d = Object::cast_to<Node3D>(instanced_scene); + if (node3d) { + Transform global_transform; + Node3D *parent_node3d = Object::cast_to<Node3D>(parent); + if (parent_node3d) { + global_transform = parent_node3d->get_global_gizmo_transform(); + } - global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); + global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); + global_transform.basis *= node3d->get_transform().basis; - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform); + editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform); + } return true; } -void SpatialEditorViewport::_perform_drop_data() { +void Node3DEditorViewport::_perform_drop_data() { _remove_preview(); Vector<String> error_files; @@ -3396,7 +3713,7 @@ void SpatialEditorViewport::_perform_drop_data() { } Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - if (mesh != NULL || scene != NULL) { + if (mesh != nullptr || scene != nullptr) { bool success = _create_instance(target_node, path, drop_pos); if (!success) { error_files.push_back(path); @@ -3412,13 +3729,12 @@ void SpatialEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); - accept->popup_centered_minsize(); + accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data())); + accept->popup_centered(); } } -bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - +bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { bool can_instance = false; if (!preview_node->is_inside_tree()) { @@ -3474,9 +3790,10 @@ bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Varian return can_instance; } -void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - if (!can_drop_data_fw(p_point, p_data, p_from)) +void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + if (!can_drop_data_fw(p_point, p_data, p_from)) { return; + } bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); @@ -3493,14 +3810,14 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p list.push_back(root_node); } else { accept->set_text(TTR("No parent to instance a child at.")); - accept->popup_centered_minsize(); + accept->popup_centered(); _remove_preview(); return; } } if (list.size() != 1) { accept->set_text(TTR("This operation requires a single selected node.")); - accept->popup_centered_minsize(); + accept->popup_centered(); _remove_preview(); return; } @@ -3514,12 +3831,14 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p _perform_drop_data(); } -SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) { +Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index) { + cpu_time_history_index = 0; + gpu_time_history_index = 0; _edit.mode = TRANSFORM_NONE; _edit.plane = TRANSFORM_VIEW; _edit.edited_gizmo = 0; - _edit.snap = 1; + _edit.snap = true; _edit.gizmo_handle = 0; index = p_index; @@ -3527,20 +3846,21 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed editor_data = editor->get_scene_tree_dock()->get_editor_data(); editor_selection = editor->get_editor_selection(); undo_redo = editor->get_undo_redo(); - clicked = 0; + clicked_includes_current = false; orthogonal = false; + auto_orthogonal = false; lock_rotation = false; message_time = 0; zoom_indicator_delay = 0.0; spatial_editor = p_spatial_editor; - ViewportContainer *c = memnew(ViewportContainer); - viewport_container = c; + SubViewportContainer *c = memnew(SubViewportContainer); + subviewport_container = c; c->set_stretch(true); add_child(c); c->set_anchors_and_margins_preset(Control::PRESET_WIDE); - viewport = memnew(Viewport); + viewport = memnew(SubViewport); viewport->set_disable_input(true); c->add_child(viewport); @@ -3549,17 +3869,13 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed add_child(surface); surface->set_anchors_and_margins_preset(Control::PRESET_WIDE); surface->set_clip_contents(true); - camera = memnew(Camera); + camera = memnew(Camera3D); camera->set_disable_gizmo(true); camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER)); viewport->add_child(camera); camera->make_current(); surface->set_focus_mode(FOCUS_ALL); - crosshair = memnew(TextureRect); - crosshair->set_mouse_filter(MOUSE_FILTER_IGNORE); - surface->add_child(crosshair); - VBoxContainer *vbox = memnew(VBoxContainer); surface->add_child(vbox); vbox->set_position(Point2(10, 10) * EDSCALE); @@ -3569,6 +3885,9 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed vbox->add_child(view_menu); view_menu->set_h_size_flags(0); + display_submenu = memnew(PopupMenu); + view_menu->get_popup()->add_child(display_submenu); + view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT); @@ -3579,19 +3898,45 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE); view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true); + view_menu->get_popup()->add_check_item(TTR("Auto Orthogonal Enabled"), VIEW_AUTO_ORTHOGONAL); + view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), true); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW); + view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_lighting", TTR("Display Lighting")), VIEW_DISPLAY_LIGHTING); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true); + display_submenu->add_radio_check_item(TTR("Directional Shadow Splits"), VIEW_DISPLAY_DEBUG_PSSM_SPLITS); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("Normal Buffer"), VIEW_DISPLAY_NORMAL_BUFFER); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("Shadow Atlas"), VIEW_DISPLAY_DEBUG_SHADOW_ATLAS); + display_submenu->add_radio_check_item(TTR("Directional Shadow"), VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("Decal Atlas"), VIEW_DISPLAY_DEBUG_DECAL_ATLAS); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("GIProbe Lighting"), VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING); + display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO); + display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("SDFGI Cascades"), VIEW_DISPLAY_DEBUG_SDFGI); + display_submenu->add_radio_check_item(TTR("SDFGI Probes"), VIEW_DISPLAY_DEBUG_SDFGI_PROBES); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO); + display_submenu->add_separator(); + display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER); + display_submenu->set_name("display_advanced"); + view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); - view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View Frame Time")), VIEW_FRAME_TIME); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); @@ -3608,12 +3953,15 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW); view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW); - view_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - + view_menu->get_popup()->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option)); + display_submenu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option)); view_menu->set_disable_shortcuts(true); - - if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { - // Alternate display modes only work when using the GLES3 renderer; make this explicit. +#ifndef _MSC_VER +#warning this needs to be fixed +#endif + //if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) { + if (false) { + // Alternate display modes only work when using the Vulkan renderer; make this explicit. const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL); const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME); const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW); @@ -3644,11 +3992,11 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed vbox->add_child(preview_camera); preview_camera->set_h_size_flags(0); preview_camera->hide(); - preview_camera->connect("toggled", this, "_toggle_camera_preview"); - previewing = NULL; + preview_camera->connect("toggled", callable_mp(this, &Node3DEditorViewport::_toggle_camera_preview)); + previewing = nullptr; gizmo_scale = 1.0; - preview_node = NULL; + preview_node = nullptr; info_label = memnew(Label); info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE); @@ -3665,7 +4013,7 @@ 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_tooltip(TTR("Note: The FPS is estimated on a 60hz refresh rate.")); fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show. surface->add_child(fps_label); fps_label->hide(); @@ -3689,16 +4037,38 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed locked_label->set_text(TTR("View Rotation Locked")); locked_label->hide(); - accept = NULL; + top_right_vbox = memnew(VBoxContainer); + top_right_vbox->set_anchors_and_margins_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE); + top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN); + + rotation_control = memnew(ViewportRotationControl); + rotation_control->set_custom_minimum_size(Size2(80, 80) * EDSCALE); + rotation_control->set_h_size_flags(SIZE_SHRINK_END); + rotation_control->set_viewport(this); + top_right_vbox->add_child(rotation_control); + + fps_label = memnew(Label); + fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE); + 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. + top_right_vbox->add_child(fps_label); + fps_label->hide(); + + surface->add_child(top_right_vbox); + + accept = nullptr; freelook_active = false; freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed"); selection_menu = memnew(PopupMenu); add_child(selection_menu); - selection_menu->set_custom_minimum_size(Size2(100, 0) * EDSCALE); - selection_menu->connect("id_pressed", this, "_selection_result_pressed"); - selection_menu->connect("popup_hide", this, "_selection_menu_hide"); + selection_menu->set_min_size(Size2(100, 0) * EDSCALE); + selection_menu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_selection_result_pressed)); + selection_menu->connect("popup_hide", callable_mp(this, &Node3DEditorViewport::_selection_menu_hide)); if (p_index == 0) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true); @@ -3708,22 +4078,20 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed name = ""; _update_name(); - EditorSettings::get_singleton()->connect("settings_changed", this, "update_transform_gizmo_view"); + EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &Node3DEditorViewport::update_transform_gizmo_view)); } ////////////////////////////////////////////////////////////// -void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) { - +void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { - if (mb->is_pressed()) { Vector2 size = get_size(); - int h_sep = get_constant("separation", "HSplitContainer"); - int v_sep = get_constant("separation", "VSplitContainer"); + int h_sep = get_theme_constant("separation", "HSplitContainer"); + int v_sep = get_theme_constant("separation", "VSplitContainer"); int mid_w = size.width * ratio_h; int mid_h = size.height * ratio_v; @@ -3737,25 +4105,21 @@ void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) switch (view) { case VIEW_USE_1_VIEWPORT: { - dragging_h = false; dragging_v = false; } break; case VIEW_USE_2_VIEWPORTS: { - dragging_h = false; } break; case VIEW_USE_2_VIEWPORTS_ALT: { - dragging_v = false; } break; case VIEW_USE_3_VIEWPORTS: case VIEW_USE_3_VIEWPORTS_ALT: case VIEW_USE_4_VIEWPORTS: { - // Do nothing. } break; @@ -3769,12 +4133,11 @@ void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (view == VIEW_USE_3_VIEWPORTS || view == VIEW_USE_3_VIEWPORTS_ALT || view == VIEW_USE_4_VIEWPORTS) { Vector2 size = get_size(); - int h_sep = get_constant("separation", "HSplitContainer"); - int v_sep = get_constant("separation", "VSplitContainer"); + int h_sep = get_theme_constant("separation", "HSplitContainer"); + int v_sep = get_theme_constant("separation", "VSplitContainer"); int mid_w = size.width * ratio_h; int mid_h = size.height * ratio_v; @@ -3806,28 +4169,25 @@ void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) } } -void SpatialEditorViewportContainer::_notification(int p_what) { - +void Node3DEditorViewportContainer::_notification(int p_what) { if (p_what == NOTIFICATION_MOUSE_ENTER || p_what == NOTIFICATION_MOUSE_EXIT) { - mouseover = (p_what == NOTIFICATION_MOUSE_ENTER); update(); } if (p_what == NOTIFICATION_DRAW && mouseover) { + Ref<Texture2D> h_grabber = get_theme_icon("grabber", "HSplitContainer"); + Ref<Texture2D> v_grabber = get_theme_icon("grabber", "VSplitContainer"); - Ref<Texture> h_grabber = get_icon("grabber", "HSplitContainer"); - Ref<Texture> v_grabber = get_icon("grabber", "VSplitContainer"); - - Ref<Texture> hdiag_grabber = get_icon("GuiViewportHdiagsplitter", "EditorIcons"); - Ref<Texture> vdiag_grabber = get_icon("GuiViewportVdiagsplitter", "EditorIcons"); - Ref<Texture> vh_grabber = get_icon("GuiViewportVhsplitter", "EditorIcons"); + Ref<Texture2D> hdiag_grabber = get_theme_icon("GuiViewportHdiagsplitter", "EditorIcons"); + Ref<Texture2D> vdiag_grabber = get_theme_icon("GuiViewportVdiagsplitter", "EditorIcons"); + Ref<Texture2D> vh_grabber = get_theme_icon("GuiViewportVhsplitter", "EditorIcons"); Vector2 size = get_size(); - int h_sep = get_constant("separation", "HSplitContainer"); + int h_sep = get_theme_constant("separation", "HSplitContainer"); - int v_sep = get_constant("separation", "VSplitContainer"); + int v_sep = get_theme_constant("separation", "VSplitContainer"); int mid_w = size.width * ratio_h; int mid_h = size.height * ratio_v; @@ -3836,26 +4196,21 @@ void SpatialEditorViewportContainer::_notification(int p_what) { int size_bottom = size.height - mid_h - v_sep / 2; switch (view) { - case VIEW_USE_1_VIEWPORT: { - // Nothing to show. } break; case VIEW_USE_2_VIEWPORTS: { - draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2)); set_default_cursor_shape(CURSOR_VSPLIT); } break; case VIEW_USE_2_VIEWPORTS_ALT: { - draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2)); set_default_cursor_shape(CURSOR_HSPLIT); } break; case VIEW_USE_3_VIEWPORTS: { - if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) { draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4)); set_default_cursor_shape(CURSOR_DRAG); @@ -3869,7 +4224,6 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_3_VIEWPORTS_ALT: { - if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) { draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2)); set_default_cursor_shape(CURSOR_DRAG); @@ -3883,7 +4237,6 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_4_VIEWPORTS: { - Vector2 half(mid_w, mid_h); if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) { draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0); @@ -3901,11 +4254,10 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } if (p_what == NOTIFICATION_SORT_CHILDREN) { - - SpatialEditorViewport *viewports[4]; + Node3DEditorViewport *viewports[4]; int vc = 0; for (int i = 0; i < get_child_count(); i++) { - viewports[vc] = Object::cast_to<SpatialEditorViewport>(get_child(i)); + viewports[vc] = Object::cast_to<Node3DEditorViewport>(get_child(i)); if (viewports[vc]) { vc++; } @@ -3921,9 +4273,9 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } return; } - int h_sep = get_constant("separation", "HSplitContainer"); + int h_sep = get_theme_constant("separation", "HSplitContainer"); - int v_sep = get_constant("separation", "VSplitContainer"); + int v_sep = get_theme_constant("separation", "VSplitContainer"); int mid_w = size.width * ratio_h; int mid_h = size.height * ratio_v; @@ -3935,12 +4287,9 @@ void SpatialEditorViewportContainer::_notification(int p_what) { int size_bottom = size.height - mid_h - v_sep / 2; switch (view) { - case VIEW_USE_1_VIEWPORT: { - viewports[0]->show(); for (int i = 1; i < 4; i++) { - viewports[i]->hide(); } @@ -3948,13 +4297,12 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_2_VIEWPORTS: { - for (int i = 0; i < 4; i++) { - - if (i == 1 || i == 3) + if (i == 1 || i == 3) { viewports[i]->hide(); - else + } else { viewports[i]->show(); + } } fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top))); @@ -3962,26 +4310,24 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_2_VIEWPORTS_ALT: { - for (int i = 0; i < 4; i++) { - - if (i == 1 || i == 3) + if (i == 1 || i == 3) { viewports[i]->hide(); - else + } else { viewports[i]->show(); + } } fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height))); fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height))); } break; case VIEW_USE_3_VIEWPORTS: { - for (int i = 0; i < 4; i++) { - - if (i == 1) + if (i == 1) { viewports[i]->hide(); - else + } else { viewports[i]->show(); + } } fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top))); @@ -3990,13 +4336,12 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_3_VIEWPORTS_ALT: { - for (int i = 0; i < 4; i++) { - - if (i == 1) + if (i == 1) { viewports[i]->hide(); - else + } else { viewports[i]->show(); + } } fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top))); @@ -4005,9 +4350,7 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } break; case VIEW_USE_4_VIEWPORTS: { - for (int i = 0; i < 4; i++) { - viewports[i]->show(); } @@ -4021,24 +4364,20 @@ void SpatialEditorViewportContainer::_notification(int p_what) { } } -void SpatialEditorViewportContainer::set_view(View p_view) { - +void Node3DEditorViewportContainer::set_view(View p_view) { view = p_view; queue_sort(); } -SpatialEditorViewportContainer::View SpatialEditorViewportContainer::get_view() { - +Node3DEditorViewportContainer::View Node3DEditorViewportContainer::get_view() { return view; } -void SpatialEditorViewportContainer::_bind_methods() { - - ClassDB::bind_method("_gui_input", &SpatialEditorViewportContainer::_gui_input); +void Node3DEditorViewportContainer::_bind_methods() { + ClassDB::bind_method("_gui_input", &Node3DEditorViewportContainer::_gui_input); } -SpatialEditorViewportContainer::SpatialEditorViewportContainer() { - +Node3DEditorViewportContainer::Node3DEditorViewportContainer() { set_clip_contents(true); view = VIEW_USE_1_VIEWPORT; mouseover = false; @@ -4052,18 +4391,16 @@ SpatialEditorViewportContainer::SpatialEditorViewportContainer() { /////////////////////////////////////////////////////////////////// -SpatialEditor *SpatialEditor::singleton = NULL; - -SpatialEditorSelectedItem::~SpatialEditorSelectedItem() { +Node3DEditor *Node3DEditor::singleton = nullptr; - if (sbox_instance.is_valid()) - VisualServer::get_singleton()->free(sbox_instance); +Node3DEditorSelectedItem::~Node3DEditorSelectedItem() { + if (sbox_instance.is_valid()) { + RenderingServer::get_singleton()->free(sbox_instance); + } } -void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { - +void Node3DEditor::select_gizmo_highlight_axis(int p_axis) { for (int i = 0; i < 3; i++) { - move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]); move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]); rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]); @@ -4072,8 +4409,7 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { } } -void SpatialEditor::update_transform_gizmo() { - +void Node3DEditor::update_transform_gizmo() { List<Node *> &selection = editor_selection->get_selected_node_list(); AABB center; bool first = true; @@ -4082,14 +4418,15 @@ void SpatialEditor::update_transform_gizmo() { bool local_gizmo_coords = are_local_coords_enabled(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } Transform xf = se->sp->get_global_gizmo_transform(); @@ -4118,7 +4455,7 @@ void SpatialEditor::update_transform_gizmo() { void _update_all_gizmos(Node *p_node) { for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - Spatial *spatial_node = Object::cast_to<Spatial>(p_node->get_child(i)); + Node3D *spatial_node = Object::cast_to<Node3D>(p_node->get_child(i)); if (spatial_node) { spatial_node->update_gizmo(); } @@ -4127,30 +4464,29 @@ void _update_all_gizmos(Node *p_node) { } } -void SpatialEditor::update_all_gizmos(Node *p_node) { +void Node3DEditor::update_all_gizmos(Node *p_node) { if (!p_node) { p_node = SceneTree::get_singleton()->get_root(); } _update_all_gizmos(p_node); } -Object *SpatialEditor::_get_editor_data(Object *p_what) { - - Spatial *sp = Object::cast_to<Spatial>(p_what); - if (!sp) - return NULL; +Object *Node3DEditor::_get_editor_data(Object *p_what) { + Node3D *sp = Object::cast_to<Node3D>(p_what); + if (!sp) { + return nullptr; + } - SpatialEditorSelectedItem *si = memnew(SpatialEditorSelectedItem); + Node3DEditorSelectedItem *si = memnew(Node3DEditorSelectedItem); si->sp = sp; - si->sbox_instance = VisualServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world()->get_scenario()); - VS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, VS::SHADOW_CASTING_SETTING_OFF); + si->sbox_instance = RenderingServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, RS::SHADOW_CASTING_SETTING_OFF); return si; } -void SpatialEditor::_generate_selection_box() { - +void Node3DEditor::_generate_selection_box() { AABB aabb(Vector3(), Vector3(1, 1, 1)); aabb.grow_by(aabb.get_longest_axis_size() / 20.0); @@ -4158,33 +4494,31 @@ void SpatialEditor::_generate_selection_box() { st->begin(Mesh::PRIMITIVE_LINES); for (int i = 0; i < 12; i++) { - Vector3 a, b; aabb.get_edge(i, a, b); st->add_color(Color(1.0, 1.0, 0.8, 0.8)); st->add_vertex(a); st->add_color(Color(1.0, 1.0, 0.8, 0.4)); - st->add_vertex(a.linear_interpolate(b, 0.2)); + st->add_vertex(a.lerp(b, 0.2)); st->add_color(Color(1.0, 1.0, 0.8, 0.4)); - st->add_vertex(a.linear_interpolate(b, 0.8)); + st->add_vertex(a.lerp(b, 0.8)); st->add_color(Color(1.0, 1.0, 0.8, 0.8)); st->add_vertex(b); } - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D); + mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); mat->set_albedo(Color(1, 1, 1)); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); st->set_material(mat); selection_box = st->commit(); } -Dictionary SpatialEditor::get_state() const { - +Dictionary Node3DEditor::get_state() const { Dictionary d; d["snap_enabled"] = snap_enabled; @@ -4195,18 +4529,19 @@ Dictionary SpatialEditor::get_state() const { d["local_coords"] = tool_option_button[TOOL_OPT_LOCAL_COORDS]->is_pressed(); int vc = 0; - if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT))) + if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT))) { vc = 1; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS))) { vc = 2; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS))) { vc = 3; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS))) { vc = 4; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT))) { vc = 5; - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT))) { vc = 6; + } d["viewport_mode"] = vc; Array vpdata; @@ -4224,7 +4559,9 @@ Dictionary SpatialEditor::get_state() const { Dictionary gizmos_status; for (int i = 0; i < gizmo_plugins_by_name.size(); i++) { - if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue; + 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_by_name[i]->get_name(); gizmos_status[name] = state; @@ -4234,8 +4571,8 @@ Dictionary SpatialEditor::get_state() const { return d; } -void SpatialEditor::set_state(const Dictionary &p_state) { +void Node3DEditor::set_state(const Dictionary &p_state) { Dictionary d = p_state; if (d.has("snap_enabled")) { @@ -4243,14 +4580,19 @@ void SpatialEditor::set_state(const Dictionary &p_state) { tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(d["snap_enabled"]); } - if (d.has("translate_snap")) - snap_translate->set_text(d["translate_snap"]); + if (d.has("translate_snap")) { + snap_translate_value = d["translate_snap"]; + } - if (d.has("rotate_snap")) - snap_rotate->set_text(d["rotate_snap"]); + if (d.has("rotate_snap")) { + snap_rotate_value = d["rotate_snap"]; + } - if (d.has("scale_snap")) - snap_scale->set_text(d["scale_snap"]); + if (d.has("scale_snap")) { + snap_scale_value = d["scale_snap"]; + } + + _snap_update(); if (d.has("local_coords")) { tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(d["local_coords"]); @@ -4260,18 +4602,19 @@ void SpatialEditor::set_state(const Dictionary &p_state) { if (d.has("viewport_mode")) { int vc = d["viewport_mode"]; - if (vc == 1) + if (vc == 1) { _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); - else if (vc == 2) + } else if (vc == 2) { _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS); - else if (vc == 3) + } else if (vc == 3) { _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS); - else if (vc == 4) + } else if (vc == 4) { _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS); - else if (vc == 5) + } else if (vc == 5) { _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT); - else if (vc == 6) + } else if (vc == 6) { _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT); + } } if (d.has("viewports")) { @@ -4287,12 +4630,15 @@ void SpatialEditor::set_state(const Dictionary &p_state) { } } - if (d.has("zfar")) + if (d.has("zfar")) { settings_zfar->set_value(float(d["zfar"])); - if (d.has("znear")) + } + if (d.has("znear")) { settings_znear->set_value(float(d["znear"])); - if (d.has("fov")) + } + if (d.has("fov")) { settings_fov->set_value(float(d["fov"])); + } if (d.has("show_grid")) { bool use = d["show_grid"]; @@ -4306,7 +4652,7 @@ void SpatialEditor::set_state(const Dictionary &p_state) { if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use); - VisualServer::get_singleton()->instance_set_visible(origin_instance, use); + RenderingServer::get_singleton()->instance_set_visible(origin_instance, use); } } @@ -4316,8 +4662,10 @@ void SpatialEditor::set_state(const Dictionary &p_state) { gizmos_status.get_key_list(&keys); 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; + if (!gizmo_plugins_by_name[j]->can_be_hidden()) { + continue; + } + int state = EditorNode3DGizmoPlugin::VISIBLE; for (int i = 0; i < keys.size(); i++) { if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) { state = gizmos_status[keys[i]]; @@ -4331,12 +4679,10 @@ void SpatialEditor::set_state(const Dictionary &p_state) { } } -void SpatialEditor::edit(Spatial *p_spatial) { - +void Node3DEditor::edit(Node3D *p_spatial) { if (p_spatial != selected) { if (selected) { - - Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); + Ref<EditorNode3DGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(false); selected->update_gizmo(); @@ -4347,8 +4693,7 @@ void SpatialEditor::edit(Spatial *p_spatial) { over_gizmo_handle = -1; if (selected) { - - Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); + Ref<EditorNode3DGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(true); selected->update_gizmo(); @@ -4357,8 +4702,19 @@ void SpatialEditor::edit(Spatial *p_spatial) { } } -void SpatialEditor::_xform_dialog_action() { +void Node3DEditor::_snap_changed() { + snap_translate_value = snap_translate->get_text().to_float(); + snap_rotate_value = snap_rotate->get_text().to_float(); + snap_scale_value = snap_scale->get_text().to_float(); +} + +void Node3DEditor::_snap_update() { + snap_translate->set_text(String::num(snap_translate_value)); + snap_rotate->set_text(String::num(snap_rotate_value)); + snap_scale->set_text(String::num(snap_scale_value)); +} +void Node3DEditor::_xform_dialog_action() { Transform t; //translation Vector3 scale; @@ -4366,9 +4722,9 @@ void SpatialEditor::_xform_dialog_action() { Vector3 translate; for (int i = 0; i < 3; i++) { - translate[i] = xform_translate[i]->get_text().to_double(); - rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double()); - scale[i] = xform_scale[i]->get_text().to_double(); + translate[i] = xform_translate[i]->get_text().to_float(); + rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_float()); + scale[i] = xform_scale[i]->get_text().to_float(); } t.basis.scale(scale); @@ -4380,22 +4736,22 @@ void SpatialEditor::_xform_dialog_action() { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *sp = Object::cast_to<Spatial>(E->get()); - if (!sp) + Node3D *sp = Object::cast_to<Node3D>(E->get()); + if (!sp) { continue; + } - SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp); - if (!se) + Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp); + if (!se) { continue; + } bool post = xform_type->get_selected() > 0; Transform tr = sp->get_global_gizmo_transform(); - if (post) + if (post) { tr = tr * t; - else { - + } else { tr.basis = t.basis * tr.basis; tr.origin += t.origin; } @@ -4406,11 +4762,9 @@ void SpatialEditor::_xform_dialog_action() { undo_redo->commit_action(); } -void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { - +void Node3DEditor::_menu_item_toggled(bool pressed, int p_option) { switch (p_option) { case MENU_TOOL_LOCAL_COORDS: { - tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(pressed); update_transform_gizmo(); } break; @@ -4421,36 +4775,34 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { } break; case MENU_TOOL_OVERRIDE_CAMERA: { - ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton(); + using Override = EditorDebuggerNode::CameraOverride; if (pressed) { - using Override = ScriptEditorDebugger::CameraOverride; - debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); } else { - debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + debugger->set_camera_override(Override::OVERRIDE_NONE); } } break; } } -void SpatialEditor::_menu_gizmo_toggled(int p_option) { - +void Node3DEditor::_menu_gizmo_toggled(int p_option) { const int idx = gizmos_menu->get_item_index(p_option); gizmos_menu->toggle_item_multistate(idx); // Change icon const int state = gizmos_menu->get_item_state(idx); switch (state) { - case EditorSpatialGizmoPlugin::VISIBLE: - gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); + case EditorNode3DGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_visible")); break; - case EditorSpatialGizmoPlugin::ON_TOP: - gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); + case EditorNode3DGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_xray")); break; - case EditorSpatialGizmoPlugin::HIDDEN: - gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); + case EditorNode3DGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_theme_icon("visibility_hidden")); break; } @@ -4459,7 +4811,7 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) { update_all_gizmos(); } -void SpatialEditor::_update_camera_override_button(bool p_game_running) { +void Node3DEditor::_update_camera_override_button(bool p_game_running) { Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]; if (p_game_running) { @@ -4472,46 +4824,42 @@ void SpatialEditor::_update_camera_override_button(bool p_game_running) { } } -void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) { - SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport); +void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) { + Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport); - if (!current_viewport) + if (!current_viewport) { return; + } - ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger(); + EditorDebuggerNode *const debugger = EditorDebuggerNode::get_singleton(); camera_override_viewport_id = current_viewport->index; - if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) { - using Override = ScriptEditorDebugger::CameraOverride; + if (debugger->get_camera_override() >= EditorDebuggerNode::OVERRIDE_3D_1) { + using Override = EditorDebuggerNode::CameraOverride; debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id)); } } -void SpatialEditor::_menu_item_pressed(int p_option) { - +void Node3DEditor::_menu_item_pressed(int p_option) { switch (p_option) { - case MENU_TOOL_SELECT: case MENU_TOOL_MOVE: case MENU_TOOL_ROTATE: case MENU_TOOL_SCALE: case MENU_TOOL_LIST_SELECT: { - - for (int i = 0; i < TOOL_MAX; i++) + for (int i = 0; i < TOOL_MAX; i++) { tool_button[i]->set_pressed(i == p_option); + } tool_mode = (ToolMode)p_option; update_transform_gizmo(); } break; case MENU_TRANSFORM_CONFIGURE_SNAP: { - snap_dialog->popup_centered(Size2(200, 180)); } break; case MENU_TRANSFORM_DIALOG: { - for (int i = 0; i < 3; i++) { - xform_translate[i]->set_text("0"); xform_rotate[i]->set_text("0"); xform_scale[i]->set_text("1"); @@ -4521,8 +4869,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_1_VIEWPORT: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_1_VIEWPORT); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_1_VIEWPORT); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false); @@ -4533,8 +4880,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_2_VIEWPORTS: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true); @@ -4545,8 +4891,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_2_VIEWPORTS_ALT: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false); @@ -4557,8 +4902,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_3_VIEWPORTS: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false); @@ -4569,8 +4913,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_3_VIEWPORTS_ALT: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false); @@ -4581,8 +4924,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_4_VIEWPORTS: { - - viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_4_VIEWPORTS); + viewport_base->set_view(Node3DEditorViewportContainer::VIEW_USE_4_VIEWPORTS); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false); @@ -4593,11 +4935,10 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_ORIGIN: { - bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option)); origin_enabled = !is_checked; - VisualServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled); + RenderingServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled); // Update the grid since its appearance depends on whether the origin is enabled _finish_grid(); _init_grid(); @@ -4605,15 +4946,16 @@ void SpatialEditor::_menu_item_pressed(int p_option) { view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled); } break; case MENU_VIEW_GRID: { - bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option)); grid_enabled = !is_checked; for (int i = 0; i < 3; ++i) { if (grid_enable[i]) { - VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled); grid_visible[i] = grid_enabled; + if (grid_instance[i].is_valid()) { + RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled); + } } } @@ -4621,7 +4963,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_CAMERA_SETTINGS: { - settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50)); } break; case MENU_SNAP_TO_FLOOR: { @@ -4633,13 +4974,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *spatial = Object::cast_to<Spatial>(E->get()); - if (!spatial || !spatial->is_visible_in_tree()) + Node3D *spatial = Object::cast_to<Node3D>(E->get()); + if (!spatial || !spatial->is_inside_tree()) { continue; + } - if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true); undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_"); @@ -4647,8 +4989,8 @@ void SpatialEditor::_menu_item_pressed(int p_option) { undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); - undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_do_method(this, "_refresh_menu_icons"); + undo_redo->add_undo_method(this, "_refresh_menu_icons"); undo_redo->commit_action(); } break; case MENU_UNLOCK_SELECTED: { @@ -4657,13 +4999,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *spatial = Object::cast_to<Spatial>(E->get()); - if (!spatial || !spatial->is_visible_in_tree()) + Node3D *spatial = Object::cast_to<Node3D>(E->get()); + if (!spatial || !spatial->is_inside_tree()) { continue; + } - if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_"); undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true); @@ -4671,8 +5014,8 @@ void SpatialEditor::_menu_item_pressed(int p_option) { undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed"); } - undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); - undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_do_method(this, "_refresh_menu_icons"); + undo_redo->add_undo_method(this, "_refresh_menu_icons"); undo_redo->commit_action(); } break; case MENU_GROUP_SELECTED: { @@ -4681,13 +5024,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *spatial = Object::cast_to<Spatial>(E->get()); - if (!spatial || !spatial->is_visible_in_tree()) + Node3D *spatial = Object::cast_to<Node3D>(E->get()); + if (!spatial || !spatial->is_inside_tree()) { continue; + } - if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true); undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_"); @@ -4695,8 +5039,8 @@ void SpatialEditor::_menu_item_pressed(int p_option) { undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); - undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_do_method(this, "_refresh_menu_icons"); + undo_redo->add_undo_method(this, "_refresh_menu_icons"); undo_redo->commit_action(); } break; case MENU_UNGROUP_SELECTED: { @@ -4704,13 +5048,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) { List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - - Spatial *spatial = Object::cast_to<Spatial>(E->get()); - if (!spatial || !spatial->is_visible_in_tree()) + Node3D *spatial = Object::cast_to<Node3D>(E->get()); + if (!spatial || !spatial->is_inside_tree()) { continue; + } - if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { continue; + } undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_"); undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true); @@ -4718,23 +5063,23 @@ void SpatialEditor::_menu_item_pressed(int p_option) { undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed"); } - undo_redo->add_do_method(this, "_refresh_menu_icons", Variant()); - undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant()); + undo_redo->add_do_method(this, "_refresh_menu_icons"); + undo_redo->add_undo_method(this, "_refresh_menu_icons"); undo_redo->commit_action(); } break; } } -void SpatialEditor::_init_indicators() { - +void Node3DEditor::_init_indicators() { { origin_enabled = true; grid_enabled = true; indicator_mat.instance(); - indicator_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - indicator_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - indicator_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); Vector<Color> origin_colors; Vector<Vector3> origin_points; @@ -4745,13 +5090,13 @@ void SpatialEditor::_init_indicators() { Color origin_color; switch (i) { case 0: - origin_color = get_color("axis_x_color", "Editor"); + origin_color = get_theme_color("axis_x_color", "Editor"); break; case 1: - origin_color = get_color("axis_y_color", "Editor"); + origin_color = get_theme_color("axis_y_color", "Editor"); break; case 2: - origin_color = get_color("axis_z_color", "Editor"); + origin_color = get_theme_color("axis_z_color", "Editor"); break; default: origin_color = Color(); @@ -4763,46 +5108,59 @@ void SpatialEditor::_init_indicators() { origin_colors.push_back(origin_color); origin_colors.push_back(origin_color); - origin_points.push_back(axis * 4096); - origin_points.push_back(axis * -4096); + origin_colors.push_back(origin_color); + origin_colors.push_back(origin_color); + origin_colors.push_back(origin_color); + origin_colors.push_back(origin_color); + // To both allow having a large origin size and avoid jitter + // at small scales, we should segment the line into pieces. + // 3 pieces seems to do the trick, and let's use powers of 2. + origin_points.push_back(axis * 1048576); + origin_points.push_back(axis * 1024); + origin_points.push_back(axis * 1024); + origin_points.push_back(axis * -1024); + origin_points.push_back(axis * -1024); + origin_points.push_back(axis * -1048576); } - grid_enable[1] = true; - grid_visible[1] = true; + grid_enable[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane"); + grid_enable[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane"); + grid_enable[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane"); + grid_visible[0] = grid_enable[0]; + grid_visible[1] = grid_enable[1]; + grid_visible[2] = grid_enable[2]; _init_grid(); - origin = VisualServer::get_singleton()->mesh_create(); + origin = RenderingServer::get_singleton()->mesh_create(); Array d; - d.resize(VS::ARRAY_MAX); - d[VisualServer::ARRAY_VERTEX] = origin_points; - d[VisualServer::ARRAY_COLOR] = origin_colors; + d.resize(RS::ARRAY_MAX); + d[RenderingServer::ARRAY_VERTEX] = origin_points; + d[RenderingServer::ARRAY_COLOR] = origin_colors; - VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin, VisualServer::PRIMITIVE_LINES, d); - VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid()); + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin, RenderingServer::PRIMITIVE_LINES, d); + RenderingServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid()); - origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario()); - VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER); + origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); - VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, VS::SHADOW_CASTING_SETTING_OFF); + RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF); } { - //move gizmo for (int i = 0; i < 3; i++) { - Color col; switch (i) { case 0: - col = get_color("axis_x_color", "Editor"); + col = get_theme_color("axis_x_color", "Editor"); break; case 1: - col = get_color("axis_y_color", "Editor"); + col = get_theme_color("axis_y_color", "Editor"); break; case 2: - col = get_color("axis_z_color", "Editor"); + col = get_theme_color("axis_z_color", "Editor"); break; default: col = Color(); @@ -4817,14 +5175,14 @@ void SpatialEditor::_init_indicators() { scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh)); - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D); + mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); mat->set_on_top_of_alpha(); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); mat->set_albedo(col); gizmo_color[i] = mat; - Ref<SpatialMaterial> mat_hl = mat->duplicate(); + Ref<StandardMaterial3D> mat_hl = mat->duplicate(); mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0)); gizmo_color_hl[i] = mat_hl; @@ -4840,7 +5198,6 @@ void SpatialEditor::_init_indicators() { //translate { - Ref<SurfaceTool> surftool = memnew(SurfaceTool); surftool->begin(Mesh::PRIMITIVE_TRIANGLES); @@ -4857,12 +5214,10 @@ void SpatialEditor::_init_indicators() { int arrow_sides = 16; for (int k = 0; k < arrow_sides; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides); Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides); for (int j = 0; j < arrow_points - 1; j++) { - Vector3 points[4] = { ma.xform(arrow[j]), mb.xform(arrow[j]), @@ -4912,24 +5267,23 @@ void SpatialEditor::_init_indicators() { surftool->add_vertex(points[2]); surftool->add_vertex(points[3]); - Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial); - plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D); + plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); plane_mat->set_on_top_of_alpha(); - plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); + plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); plane_mat->set_albedo(col); 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]); - Ref<SpatialMaterial> plane_mat_hl = plane_mat->duplicate(); + Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate(); plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0)); plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides } // Rotate { - Ref<SurfaceTool> surftool = memnew(SurfaceTool); surftool->begin(Mesh::PRIMITIVE_TRIANGLES); @@ -4942,12 +5296,10 @@ void SpatialEditor::_init_indicators() { }; for (int k = 0; k < 64; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / 64); Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64); for (int j = 0; j < 4; j++) { - Vector3 points[4] = { ma.xform(circle[j]), mb.xform(circle[j]), @@ -4987,12 +5339,10 @@ void SpatialEditor::_init_indicators() { int arrow_sides = 4; for (int k = 0; k < 4; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides); Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides); for (int j = 0; j < arrow_points - 1; j++) { - Vector3 points[4] = { ma.xform(arrow[j]), mb.xform(arrow[j]), @@ -5042,17 +5392,17 @@ void SpatialEditor::_init_indicators() { surftool->add_vertex(points[2]); surftool->add_vertex(points[3]); - Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial); - plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + Ref<StandardMaterial3D> plane_mat = memnew(StandardMaterial3D); + plane_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); plane_mat->set_on_top_of_alpha(); - plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED); + plane_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + plane_mat->set_cull_mode(StandardMaterial3D::CULL_DISABLED); plane_mat->set_albedo(col); 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]); - Ref<SpatialMaterial> plane_mat_hl = plane_mat->duplicate(); + Ref<StandardMaterial3D> plane_mat_hl = plane_mat->duplicate(); plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0)); plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides } @@ -5062,133 +5412,210 @@ void SpatialEditor::_init_indicators() { _generate_selection_box(); } -void SpatialEditor::_update_gizmos_menu() { - +void Node3DEditor::_update_gizmos_menu() { gizmos_menu->clear(); for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) { - if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue; + 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); + gizmos_menu->add_multistate_item(plugin_name, 3, plugin_state, i); const int idx = gizmos_menu->get_item_index(i); + gizmos_menu->set_item_tooltip( + idx, + TTR("Click to toggle between visibility states.\n\nOpen eye: Gizmo is visible.\nClosed eye: Gizmo is hidden.\nHalf-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\").")); switch (plugin_state) { - case EditorSpatialGizmoPlugin::VISIBLE: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); + case EditorNode3DGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_visible")); break; - case EditorSpatialGizmoPlugin::ON_TOP: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + case EditorNode3DGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_xray")); break; - case EditorSpatialGizmoPlugin::HIDDEN: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + case EditorNode3DGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_hidden")); break; } } } -void SpatialEditor::_update_gizmos_menu_theme() { +void Node3DEditor::_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; + 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")); + case EditorNode3DGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_visible")); break; - case EditorSpatialGizmoPlugin::ON_TOP: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + case EditorNode3DGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_xray")); break; - case EditorSpatialGizmoPlugin::HIDDEN: - gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + case EditorNode3DGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_theme_icon("visibility_hidden")); break; } } } -void SpatialEditor::_init_grid() { +void Node3DEditor::_init_grid() { + if (!grid_enabled) { + return; + } + Camera3D *camera = get_editor_viewport(0)->camera; + Vector3 camera_position = camera->get_translation(); + if (camera_position == Vector3()) { + return; // Camera3D is invalid, don't draw the grid. + } - PoolVector<Color> grid_colors[3]; - PoolVector<Vector3> grid_points[3]; + Vector<Color> grid_colors[3]; + Vector<Vector3> grid_points[3]; Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color"); Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color"); int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size"); int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps"); - for (int i = 0; i < 3; i++) { - Vector3 axis; - axis[i] = 1; - Vector3 axis_n1; - axis_n1[(i + 1) % 3] = 1; - Vector3 axis_n2; - axis_n2[(i + 2) % 3] = 1; - - for (int j = -grid_size; j <= grid_size; j++) { - Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size; - Vector3 p1_dest = p1 * (-axis_n2 + axis_n1); - Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size; - Vector3 p2_dest = p2 * (-axis_n1 + axis_n2); - - Color line_color = secondary_grid_color; - if (origin_enabled && j == 0) { - // Don't draw the center lines of the grid if the origin is enabled - // The origin would overlap the grid lines in this case, causing flickering - continue; - } else if (j % primary_grid_steps == 0) { - line_color = primary_grid_color; + // Which grid planes are enabled? Which should we generate? + grid_enable[0] = grid_visible[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane"); + grid_enable[1] = grid_visible[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane"); + grid_enable[2] = grid_visible[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane"); + + // Offsets division_level for bigger or smaller grids. + // Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids. + real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias"); + // Default largest grid size is 100m, 10^2 (default value is 2). + int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max"); + // Default smallest grid size is 1cm, 10^-2 (default value is -2). + int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min"); + ERR_FAIL_COND_MSG(division_level_max < division_level_min, "The 3D grid's maximum division level cannot be lower than its minimum division level."); + + if (primary_grid_steps != 10) { // Log10 of 10 is 1. + // Change of base rule, divide by ln(10). + real_t div = Math::log((real_t)primary_grid_steps) / (real_t)2.302585092994045901094; + // Trucation (towards zero) is intentional. + division_level_max = (int)(division_level_max / div); + division_level_min = (int)(division_level_min / div); + } + + for (int a = 0; a < 3; a++) { + if (!grid_enable[a]) { + continue; // If this grid plane is disabled, skip generation. + } + int b = (a + 1) % 3; + int c = (a + 2) % 3; + + real_t division_level = Math::log(Math::abs(camera_position[c])) / Math::log((double)primary_grid_steps) + division_level_bias; + division_level = CLAMP(division_level, division_level_min, division_level_max); + real_t division_level_floored = Math::floor(division_level); + real_t division_level_decimals = division_level - division_level_floored; + + real_t small_step_size = Math::pow(primary_grid_steps, division_level_floored); + real_t large_step_size = small_step_size * primary_grid_steps; + real_t center_a = large_step_size * (int)(camera_position[a] / large_step_size); + real_t center_b = large_step_size * (int)(camera_position[b] / large_step_size); + + real_t bgn_a = center_a - grid_size * small_step_size; + real_t end_a = center_a + grid_size * small_step_size; + real_t bgn_b = center_b - grid_size * small_step_size; + real_t end_b = center_b + grid_size * small_step_size; + + // In each iteration of this loop, draw one line in each direction (so two lines per loop, in each if statement). + for (int i = -grid_size; i <= grid_size; i++) { + Color line_color; + // Is this a primary line? Set the appropriate color. + if (i % primary_grid_steps == 0) { + line_color = primary_grid_color.lerp(secondary_grid_color, division_level_decimals); + } else { + line_color = secondary_grid_color; + line_color.a = line_color.a * (1 - division_level_decimals); + } + // Makes lines farther from the center fade out. + // Due to limitations of lines, any that come near the camera have full opacity always. + // This should eventually be replaced by some kind of "distance fade" system, outside of this function. + // But the effect is still somewhat convincing... + line_color.a *= 1 - (1 - division_level_decimals * 0.9) * (Math::abs(i / (float)grid_size)); + + real_t position_a = center_a + i * small_step_size; + real_t position_b = center_b + i * small_step_size; + + // Don't draw lines over the origin if it's enabled. + if (!(origin_enabled && Math::is_zero_approx(position_a))) { + Vector3 line_bgn = Vector3(); + Vector3 line_end = Vector3(); + line_bgn[a] = position_a; + line_end[a] = position_a; + line_bgn[b] = bgn_b; + line_end[b] = end_b; + grid_points[c].push_back(line_bgn); + grid_points[c].push_back(line_end); + grid_colors[c].push_back(line_color); + grid_colors[c].push_back(line_color); } - grid_points[i].push_back(p1); - grid_points[i].push_back(p1_dest); - grid_colors[i].push_back(line_color); - grid_colors[i].push_back(line_color); - - grid_points[i].push_back(p2); - grid_points[i].push_back(p2_dest); - grid_colors[i].push_back(line_color); - grid_colors[i].push_back(line_color); + if (!(origin_enabled && Math::is_zero_approx(position_b))) { + Vector3 line_bgn = Vector3(); + Vector3 line_end = Vector3(); + line_bgn[b] = position_b; + line_end[b] = position_b; + line_bgn[a] = bgn_a; + line_end[a] = end_a; + grid_points[c].push_back(line_bgn); + grid_points[c].push_back(line_end); + grid_colors[c].push_back(line_color); + grid_colors[c].push_back(line_color); + } } - grid[i] = VisualServer::get_singleton()->mesh_create(); + // Create a mesh from the pushed vector points and colors. + grid[c] = RenderingServer::get_singleton()->mesh_create(); Array d; - d.resize(VS::ARRAY_MAX); - d[VisualServer::ARRAY_VERTEX] = grid_points[i]; - d[VisualServer::ARRAY_COLOR] = grid_colors[i]; - VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], VisualServer::PRIMITIVE_LINES, d); - VisualServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid()); - grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario()); + d.resize(RS::ARRAY_MAX); + d[RenderingServer::ARRAY_VERTEX] = grid_points[c]; + d[RenderingServer::ARRAY_COLOR] = grid_colors[c]; + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(grid[c], RenderingServer::PRIMITIVE_LINES, d); + RenderingServer::get_singleton()->mesh_surface_set_material(grid[c], 0, indicator_mat->get_rid()); + grid_instance[c] = RenderingServer::get_singleton()->instance_create2(grid[c], get_tree()->get_root()->get_world_3d()->get_scenario()); - VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]); - VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << SpatialEditorViewport::GIZMO_GRID_LAYER); + // Yes, the end of this line is supposed to be a. + RenderingServer::get_singleton()->instance_set_visible(grid_instance[c], grid_visible[a]); + RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[c], RS::SHADOW_CASTING_SETTING_OFF); + RS::get_singleton()->instance_set_layer_mask(grid_instance[c], 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); } } -void SpatialEditor::_finish_indicators() { - - VisualServer::get_singleton()->free(origin_instance); - VisualServer::get_singleton()->free(origin); +void Node3DEditor::_finish_indicators() { + RenderingServer::get_singleton()->free(origin_instance); + RenderingServer::get_singleton()->free(origin); _finish_grid(); } -void SpatialEditor::_finish_grid() { +void Node3DEditor::_finish_grid() { for (int i = 0; i < 3; i++) { - VisualServer::get_singleton()->free(grid_instance[i]); - VisualServer::get_singleton()->free(grid[i]); + RenderingServer::get_singleton()->free(grid_instance[i]); + RenderingServer::get_singleton()->free(grid[i]); } } -bool SpatialEditor::is_any_freelook_active() const { +void Node3DEditor::update_grid() { + _finish_grid(); + _init_grid(); +} + +bool Node3DEditor::is_any_freelook_active() const { for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) { - if (viewports[i]->is_freelook_active()) + if (viewports[i]->is_freelook_active()) { return true; + } } return false; } -void SpatialEditor::_refresh_menu_icons() { - +void Node3DEditor::_refresh_menu_icons() { bool all_locked = true; bool all_grouped = true; @@ -5199,13 +5626,13 @@ void SpatialEditor::_refresh_menu_icons() { all_grouped = false; } else { for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_lock_")) { + if (Object::cast_to<Node3D>(E->get()) && !Object::cast_to<Node3D>(E->get())->has_meta("_edit_lock_")) { all_locked = false; break; } } for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_group_")) { + if (Object::cast_to<Node3D>(E->get()) && !Object::cast_to<Node3D>(E->get())->has_meta("_edit_group_")) { all_grouped = false; break; } @@ -5242,35 +5669,35 @@ Set<T *> _get_child_nodes(Node *parent_node) { Set<RID> _get_physics_bodies_rid(Node *node) { Set<RID> rids = Set<RID>(); - PhysicsBody *pb = Node::cast_to<PhysicsBody>(node); + PhysicsBody3D *pb = Node::cast_to<PhysicsBody3D>(node); if (pb) { rids.insert(pb->get_rid()); } - Set<PhysicsBody *> child_nodes = _get_child_nodes<PhysicsBody>(node); - for (Set<PhysicsBody *>::Element *I = child_nodes.front(); I; I = I->next()) { + Set<PhysicsBody3D *> child_nodes = _get_child_nodes<PhysicsBody3D>(node); + for (Set<PhysicsBody3D *>::Element *I = child_nodes.front(); I; I = I->next()) { rids.insert(I->get()->get_rid()); } return rids; } -void SpatialEditor::snap_selected_nodes_to_floor() { +void Node3DEditor::snap_selected_nodes_to_floor() { List<Node *> &selection = editor_selection->get_selected_node_list(); Dictionary snap_data; for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - Spatial *sp = Object::cast_to<Spatial>(E->get()); + Node3D *sp = Object::cast_to<Node3D>(E->get()); if (sp) { Vector3 from = Vector3(); Vector3 position_offset = Vector3(); // Priorities for snapping to floor are CollisionShapes, VisualInstances and then origin - Set<VisualInstance *> vi = _get_child_nodes<VisualInstance>(sp); - Set<CollisionShape *> cs = _get_child_nodes<CollisionShape>(sp); + Set<VisualInstance3D *> vi = _get_child_nodes<VisualInstance3D>(sp); + Set<CollisionShape3D *> cs = _get_child_nodes<CollisionShape3D>(sp); if (cs.size()) { AABB aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb()); - for (Set<CollisionShape *>::Element *I = cs.front(); I; I = I->next()) { + for (Set<CollisionShape3D *>::Element *I = cs.front(); I; I = I->next()) { aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb())); } Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5); @@ -5278,7 +5705,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { position_offset.y = from.y - sp->get_global_transform().origin.y; } else if (vi.size()) { AABB aabb = vi.front()->get()->get_transformed_aabb(); - for (Set<VisualInstance *>::Element *I = vi.front(); I; I = I->next()) { + for (Set<VisualInstance3D *>::Element *I = vi.front(); I; I = I->next()) { aabb.merge_with(I->get()->get_transformed_aabb()); } Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5); @@ -5301,8 +5728,8 @@ void SpatialEditor::snap_selected_nodes_to_floor() { } } - PhysicsDirectSpaceState *ss = get_tree()->get_root()->get_world()->get_direct_space_state(); - PhysicsDirectSpaceState::RayResult result; + PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state(); + PhysicsDirectSpaceState3D::RayResult result; Array keys = snap_data.keys(); @@ -5317,7 +5744,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { // We need to check this before snapping to register the undo/redo action only if needed. for (int i = 0; i < keys.size(); i++) { Node *node = keys[i]; - Spatial *sp = Object::cast_to<Spatial>(node); + Node3D *sp = Object::cast_to<Node3D>(node); Dictionary d = snap_data[node]; Vector3 from = d["from"]; Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); @@ -5334,7 +5761,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { // Perform snapping if at least one node can be snapped for (int i = 0; i < keys.size(); i++) { Node *node = keys[i]; - Spatial *sp = Object::cast_to<Spatial>(node); + Node3D *sp = Object::cast_to<Node3D>(node); Dictionary d = snap_data[node]; Vector3 from = d["from"]; Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); @@ -5359,127 +5786,118 @@ void SpatialEditor::snap_selected_nodes_to_floor() { } } -void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { - - if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack()) +void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) { + if (!is_visible_in_tree()) { return; + } snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL); } -void SpatialEditor::_notification(int p_what) { +void Node3DEditor::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { - - 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")); - tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); - tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); - tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons")); - tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); - tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); - tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons")); - - tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); - tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); - tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons")); - - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon("ListSelect", "EditorIcons")); + tool_button[Node3DEditor::TOOL_LOCK_SELECTED]->set_icon(get_theme_icon("Lock", "EditorIcons")); + tool_button[Node3DEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon("Unlock", "EditorIcons")); + tool_button[Node3DEditor::TOOL_GROUP_SELECTED]->set_icon(get_theme_icon("Group", "EditorIcons")); + tool_button[Node3DEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon("Ungroup", "EditorIcons")); + + tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon("Object", "EditorIcons")); + tool_option_button[Node3DEditor::TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon("Snap", "EditorIcons")); + tool_option_button[Node3DEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_theme_icon("Camera3D", "EditorIcons")); + + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon("Panels1", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon("Panels2", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon("Panels2Alt", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon("Panels3", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon("Panels3Alt", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon("Panels4", "EditorIcons")); _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); _refresh_menu_icons(); - 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"); + get_tree()->connect("node_removed", callable_mp(this, &Node3DEditor::_node_removed)); + EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons)); + editor_selection->connect("selection_changed", callable_mp(this, &Node3DEditor::_refresh_menu_icons)); - editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false)); - editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true)); + editor->connect("stop_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(false)); + editor->connect("play_pressed", callable_mp(this, &Node3DEditor::_update_camera_override_button), make_binds(true)); } else if (p_what == NOTIFICATION_ENTER_TREE) { - _register_all_gizmos(); _update_gizmos_menu(); _init_indicators(); } else if (p_what == NOTIFICATION_THEME_CHANGED) { _update_gizmos_menu_theme(); } else if (p_what == NOTIFICATION_EXIT_TREE) { - _finish_indicators(); } 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")); - tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); - tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); - tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons")); - tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); - tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); - tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons")); - - tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons")); - tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); - - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons")); + tool_button[Node3DEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_theme_icon("ListSelect", "EditorIcons")); + tool_button[Node3DEditor::TOOL_LOCK_SELECTED]->set_icon(get_theme_icon("Lock", "EditorIcons")); + tool_button[Node3DEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_theme_icon("Unlock", "EditorIcons")); + tool_button[Node3DEditor::TOOL_GROUP_SELECTED]->set_icon(get_theme_icon("Group", "EditorIcons")); + tool_button[Node3DEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_theme_icon("Ungroup", "EditorIcons")); + + tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_theme_icon("Object", "EditorIcons")); + tool_option_button[Node3DEditor::TOOL_OPT_USE_SNAP]->set_icon(get_theme_icon("Snap", "EditorIcons")); + + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_theme_icon("Panels1", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_theme_icon("Panels2", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_theme_icon("Panels2Alt", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_theme_icon("Panels3", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_theme_icon("Panels3Alt", "EditorIcons")); + view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_theme_icon("Panels4", "EditorIcons")); // Update grid color by rebuilding grid. _finish_grid(); _init_grid(); } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) { - ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger(); + EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton(); - debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE); + debugger->set_camera_override(EditorDebuggerNode::OVERRIDE_NONE); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false); } } } -void SpatialEditor::add_control_to_menu_panel(Control *p_control) { - +void Node3DEditor::add_control_to_menu_panel(Control *p_control) { hbc_menu->add_child(p_control); } -void SpatialEditor::remove_control_from_menu_panel(Control *p_control) { - +void Node3DEditor::remove_control_from_menu_panel(Control *p_control) { hbc_menu->remove_child(p_control); } -void SpatialEditor::set_can_preview(Camera *p_preview) { - +void Node3DEditor::set_can_preview(Camera3D *p_preview) { for (int i = 0; i < 4; i++) { viewports[i]->set_can_preview(p_preview); } } -VSplitContainer *SpatialEditor::get_shader_split() { - +VSplitContainer *Node3DEditor::get_shader_split() { return shader_split; } -HSplitContainer *SpatialEditor::get_palette_split() { - +HSplitContainer *Node3DEditor::get_palette_split() { return palette_split; } -void SpatialEditor::_request_gizmo(Object *p_obj) { - - Spatial *sp = Object::cast_to<Spatial>(p_obj); - if (!sp) +void Node3DEditor::_request_gizmo(Object *p_obj) { + Node3D *sp = Object::cast_to<Node3D>(p_obj); + if (!sp) { return; + } if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) { - - Ref<EditorSpatialGizmo> seg; + Ref<EditorNode3DGizmo> seg; for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) { seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp); @@ -5498,104 +5916,104 @@ void SpatialEditor::_request_gizmo(Object *p_obj) { } } -void SpatialEditor::_toggle_maximize_view(Object *p_viewport) { - if (!p_viewport) return; - SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport); - if (!current_viewport) return; +void Node3DEditor::_toggle_maximize_view(Object *p_viewport) { + if (!p_viewport) { + return; + } + Node3DEditorViewport *current_viewport = Object::cast_to<Node3DEditorViewport>(p_viewport); + if (!current_viewport) { + return; + } int index = -1; bool maximized = false; for (int i = 0; i < 4; i++) { if (viewports[i] == current_viewport) { index = i; - if (current_viewport->get_global_rect() == viewport_base->get_global_rect()) + if (current_viewport->get_global_rect() == viewport_base->get_global_rect()) { maximized = true; + } break; } } - if (index == -1) return; + if (index == -1) { + return; + } if (!maximized) { - for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { - if (i == (uint32_t)index) + if (i == (uint32_t)index) { viewports[i]->set_anchors_and_margins_preset(Control::PRESET_WIDE); - else + } else { viewports[i]->hide(); + } } } else { - - for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) + for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i]->show(); + } - if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT))) + if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT))) { _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS))) { _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS); - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT))) { _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT); - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS))) { _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS); - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT))) { _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT); - else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS))) + } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS))) { _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS); + } } } -void SpatialEditor::_node_removed(Node *p_node) { - - if (p_node == selected) - selected = NULL; +void Node3DEditor::_node_removed(Node *p_node) { + if (p_node == selected) { + selected = nullptr; + } } -void SpatialEditor::_register_all_gizmos() { - add_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin))); - add_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); - add_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin))); - add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin))); +void Node3DEditor::_register_all_gizmos() { + add_gizmo_plugin(Ref<Camera3DGizmoPlugin>(memnew(Camera3DGizmoPlugin))); + add_gizmo_plugin(Ref<Light3DGizmoPlugin>(memnew(Light3DGizmoPlugin))); + add_gizmo_plugin(Ref<AudioStreamPlayer3DGizmoPlugin>(memnew(AudioStreamPlayer3DGizmoPlugin))); + add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin))); + add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin))); + add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin))); + add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin))); + add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin))); + add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin))); + add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin))); + add_gizmo_plugin(Ref<VehicleWheel3DGizmoPlugin>(memnew(VehicleWheel3DGizmoPlugin))); + add_gizmo_plugin(Ref<VisibilityNotifier3DGizmoPlugin>(memnew(VisibilityNotifier3DGizmoPlugin))); + add_gizmo_plugin(Ref<GPUParticles3DGizmoPlugin>(memnew(GPUParticles3DGizmoPlugin))); + add_gizmo_plugin(Ref<CPUParticles3DGizmoPlugin>(memnew(CPUParticles3DGizmoPlugin))); add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); + add_gizmo_plugin(Ref<DecalGizmoPlugin>(memnew(DecalGizmoPlugin))); add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin))); - add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin))); - add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin))); - add_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin))); -} - -void SpatialEditor::_bind_methods() { - - ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input); - ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed); - ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed); - ClassDB::bind_method("_menu_gizmo_toggled", &SpatialEditor::_menu_gizmo_toggled); - ClassDB::bind_method("_menu_item_toggled", &SpatialEditor::_menu_item_toggled); - ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action); - ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); - ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo); - ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view); - ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons); - ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button); - ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport); + add_gizmo_plugin(Ref<BakedLightmapGizmoPlugin>(memnew(BakedLightmapGizmoPlugin))); + add_gizmo_plugin(Ref<LightmapProbeGizmoPlugin>(memnew(LightmapProbeGizmoPlugin))); + add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin))); + add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin))); + add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin))); + add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin))); + add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin))); +} + +void Node3DEditor::_bind_methods() { + ClassDB::bind_method("_unhandled_key_input", &Node3DEditor::_unhandled_key_input); + ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data); + ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo); + ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons); ADD_SIGNAL(MethodInfo("transform_key_request")); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); ADD_SIGNAL(MethodInfo("item_group_status_changed")); } -void SpatialEditor::clear() { - +void Node3DEditor::clear() { settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0)); settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05)); settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0)); @@ -5604,26 +6022,24 @@ void SpatialEditor::clear() { viewports[i]->reset(); } - VisualServer::get_singleton()->instance_set_visible(origin_instance, true); + RenderingServer::get_singleton()->instance_set_visible(origin_instance, true); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true); for (int i = 0; i < 3; ++i) { if (grid_enable[i]) { - VisualServer::get_singleton()->instance_set_visible(grid_instance[i], true); + RenderingServer::get_singleton()->instance_set_visible(grid_instance[i], true); grid_visible[i] = true; } } for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { - - viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER), i == 0); + viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(Node3DEditorViewport::VIEW_AUDIO_LISTENER), i == 0); viewports[i]->viewport->set_as_audio_listener(i == 0); } view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true); } -SpatialEditor::SpatialEditor(EditorNode *p_editor) { - +Node3DEditor::Node3DEditor(EditorNode *p_editor) { gizmo.visible = true; gizmo.scale = 1.0; @@ -5631,7 +6047,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { undo_redo = p_editor->get_undo_redo(); VBoxContainer *vbc = this; - custom_camera = NULL; + custom_camera = nullptr; singleton = this; editor = p_editor; editor_selection = editor->get_editor_selection(); @@ -5650,109 +6066,113 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { button_binds.resize(1); String sct; - tool_button[TOOL_MODE_SELECT] = memnew(ToolButton); + tool_button[TOOL_MODE_SELECT] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]); tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_SELECT]->set_flat(true); tool_button[TOOL_MODE_SELECT]->set_pressed(true); button_binds.write[0] = MENU_TOOL_SELECT; - tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q)); tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); hbc_menu->add_child(memnew(VSeparator)); - tool_button[TOOL_MODE_MOVE] = memnew(ToolButton); + tool_button[TOOL_MODE_MOVE] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]); tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true); tool_button[TOOL_MODE_MOVE]->set_flat(true); button_binds.write[0] = MENU_TOOL_MOVE; - tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_MODE_MOVE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W)); - tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton); + tool_button[TOOL_MODE_ROTATE] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]); tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true); tool_button[TOOL_MODE_ROTATE]->set_flat(true); button_binds.write[0] = MENU_TOOL_ROTATE; - tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_MODE_ROTATE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E)); - tool_button[TOOL_MODE_SCALE] = memnew(ToolButton); + tool_button[TOOL_MODE_SCALE] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]); tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true); tool_button[TOOL_MODE_SCALE]->set_flat(true); button_binds.write[0] = MENU_TOOL_SCALE; - tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_MODE_SCALE]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R)); hbc_menu->add_child(memnew(VSeparator)); - tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton); + tool_button[TOOL_MODE_LIST_SELECT] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]); tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true); button_binds.write[0] = MENU_TOOL_LIST_SELECT; - tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode).")); - tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton); + tool_button[TOOL_LOCK_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]); + tool_button[TOOL_LOCK_SELECTED]->set_flat(true); button_binds.write[0] = MENU_LOCK_SELECTED; - tool_button[TOOL_LOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); - tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton); + tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]); + tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true); button_binds.write[0] = MENU_UNLOCK_SELECTED; - tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved).")); - tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton); + tool_button[TOOL_GROUP_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]); + tool_button[TOOL_GROUP_SELECTED]->set_flat(true); button_binds.write[0] = MENU_GROUP_SELECTED; - tool_button[TOOL_GROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable.")); - tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton); + tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]); + tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true); button_binds.write[0] = MENU_UNGROUP_SELECTED; - tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); + tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected.")); hbc_menu->add_child(memnew(VSeparator)); - tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton); + tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(Button); hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true); button_binds.write[0] = MENU_TOOL_LOCAL_COORDS; - tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds); + tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T)); - tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton); + tool_option_button[TOOL_OPT_USE_SNAP] = memnew(Button); hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true); tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true); button_binds.write[0] = MENU_TOOL_USE_SNAP; - tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds); + tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds); tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y)); hbc_menu->add_child(memnew(VSeparator)); - tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(Button); hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true); tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true); button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA; - tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds); + tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", callable_mp(this, &Node3DEditor::_menu_item_toggled), button_binds); _update_camera_override_button(false); hbc_menu->add_child(memnew(VSeparator)); // Drag and drop support; - preview_node = memnew(Spatial); + preview_node = memnew(Node3D); preview_bounds = AABB(); ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7); @@ -5783,7 +6203,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); - p->connect("id_pressed", this, "_menu_item_pressed"); + p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed)); view_menu = memnew(MenuButton); view_menu->set_text(TTR("View")); @@ -5815,13 +6235,13 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); - p->connect("id_pressed", this, "_menu_item_pressed"); + p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed)); gizmos_menu = memnew(PopupMenu); p->add_child(gizmos_menu); gizmos_menu->set_name("GizmosMenu"); gizmos_menu->set_hide_on_checkable_item_selection(false); - gizmos_menu->connect("id_pressed", this, "_menu_gizmo_toggled"); + gizmos_menu->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_gizmo_toggled)); /* REST OF MENU */ @@ -5832,39 +6252,43 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { shader_split = memnew(VSplitContainer); shader_split->set_h_size_flags(SIZE_EXPAND_FILL); palette_split->add_child(shader_split); - viewport_base = memnew(SpatialEditorViewportContainer); + viewport_base = memnew(Node3DEditorViewportContainer); shader_split->add_child(viewport_base); viewport_base->set_v_size_flags(SIZE_EXPAND_FILL); for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) { - - viewports[i] = memnew(SpatialEditorViewport(this, editor, i)); - viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view"); - viewports[i]->connect("clicked", this, "_update_camera_override_viewport"); + viewports[i] = memnew(Node3DEditorViewport(this, editor, i)); + viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view)); + viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_update_camera_override_viewport)); viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept); viewport_base->add_child(viewports[i]); } /* SNAP DIALOG */ + snap_translate_value = 1; + snap_rotate_value = 15; + snap_scale_value = 10; + snap_dialog = memnew(ConfirmationDialog); snap_dialog->set_title(TTR("Snap Settings")); add_child(snap_dialog); + snap_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_snap_changed)); + snap_dialog->get_cancel()->connect("pressed", callable_mp(this, &Node3DEditor::_snap_update)); VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer); snap_dialog->add_child(snap_dialog_vbc); snap_translate = memnew(LineEdit); - snap_translate->set_text("1"); snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate); snap_rotate = memnew(LineEdit); - snap_rotate->set_text("15"); snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate); snap_scale = memnew(LineEdit); - snap_scale->set_text("10"); snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale); + _snap_update(); + /* SETTINGS DIALOG */ settings_dialog = memnew(ConfirmationDialog); @@ -5895,6 +6319,10 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500)); settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar); + for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) { + settings_dialog->connect("confirmed", callable_mp(viewports[i], &Node3DEditorViewport::_update_camera), varray(0.0)); + } + /* XFORM DIALOG */ xform_dialog = memnew(ConfirmationDialog); @@ -5912,7 +6340,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { xform_vbc->add_child(xform_hbc); for (int i = 0; i < 3; i++) { - xform_translate[i] = memnew(LineEdit); xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL); xform_hbc->add_child(xform_translate[i]); @@ -5954,11 +6381,11 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { xform_type->add_item(TTR("Post")); xform_vbc->add_child(xform_type); - xform_dialog->connect("confirmed", this, "_xform_dialog_action"); + xform_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_xform_dialog_action)); - scenario_debug = VisualServer::SCENARIO_DEBUG_DISABLED; + scenario_debug = RenderingServer::SCENARIO_DEBUG_DISABLED; - selected = NULL; + selected = nullptr; set_process_unhandled_key_input(true); add_to_group("_spatial_editor_group"); @@ -5966,53 +6393,48 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1")); EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.4); - EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::REAL, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01")); + EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01")); + EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true); over_gizmo_handle = -1; } -SpatialEditor::~SpatialEditor() { +Node3DEditor::~Node3DEditor() { memdelete(preview_node); } -void SpatialEditorPlugin::make_visible(bool p_visible) { - +void Node3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - spatial_editor->show(); spatial_editor->set_process(true); } else { - spatial_editor->hide(); spatial_editor->set_process(false); } } -void SpatialEditorPlugin::edit(Object *p_object) { - spatial_editor->edit(Object::cast_to<Spatial>(p_object)); +void Node3DEditorPlugin::edit(Object *p_object) { + spatial_editor->edit(Object::cast_to<Node3D>(p_object)); } -bool SpatialEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Spatial"); +bool Node3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Node3D"); } -Dictionary SpatialEditorPlugin::get_state() const { +Dictionary Node3DEditorPlugin::get_state() const { return spatial_editor->get_state(); } -void SpatialEditorPlugin::set_state(const Dictionary &p_state) { - +void Node3DEditorPlugin::set_state(const Dictionary &p_state) { spatial_editor->set_state(p_state); } -void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) { - +void Node3DEditor::snap_cursor_to_plane(const Plane &p_plane) { //cursor.pos=p_plane.project(cursor.pos); } -Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const { +Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const { if (is_snap_enabled()) { p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x); p_target.y = Math::snap_scalar(0.0, get_translate_snap(), p_target.y); @@ -6021,52 +6443,49 @@ Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const { return p_target; } -float SpatialEditor::get_translate_snap() const { +float Node3DEditor::get_translate_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_translate->get_text().to_double() / 10.0; + snap_value = snap_translate->get_text().to_float() / 10.0; } else { - snap_value = snap_translate->get_text().to_double(); + snap_value = snap_translate->get_text().to_float(); } return snap_value; } -float SpatialEditor::get_rotate_snap() const { +float Node3DEditor::get_rotate_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_rotate->get_text().to_double() / 3.0; + snap_value = snap_rotate->get_text().to_float() / 3.0; } else { - snap_value = snap_rotate->get_text().to_double(); + snap_value = snap_rotate->get_text().to_float(); } return snap_value; } -float SpatialEditor::get_scale_snap() const { +float Node3DEditor::get_scale_snap() const { float snap_value; if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - snap_value = snap_scale->get_text().to_double() / 2.0; + snap_value = snap_scale->get_text().to_float() / 2.0; } else { - snap_value = snap_scale->get_text().to_double(); + snap_value = snap_scale->get_text().to_float(); } return snap_value; } -void SpatialEditorPlugin::_bind_methods() { - - ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane); +void Node3DEditorPlugin::_bind_methods() { + ClassDB::bind_method("snap_cursor_to_plane", &Node3DEditorPlugin::snap_cursor_to_plane); } -void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) { - +void Node3DEditorPlugin::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 { + bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const { if (p_a->get_priority() == p_b->get_priority()) { return p_a->get_name() < p_b->get_name(); } @@ -6075,13 +6494,12 @@ struct _GizmoPluginPriorityComparator { }; struct _GizmoPluginNameComparator { - - bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { + bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const { return p_a->get_name() < p_b->get_name(); } }; -void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) { +void Node3DEditor::add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) { ERR_FAIL_NULL(p_plugin.ptr()); gizmo_plugins_by_priority.push_back(p_plugin); @@ -6091,40 +6509,38 @@ void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) { gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>(); _update_gizmos_menu(); - SpatialEditor::get_singleton()->update_all_gizmos(); + Node3DEditor::get_singleton()->update_all_gizmos(); } -void SpatialEditor::remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) { +void Node3DEditor::remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin) { gizmo_plugins_by_priority.erase(p_plugin); gizmo_plugins_by_name.erase(p_plugin); _update_gizmos_menu(); } -SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { - +Node3DEditorPlugin::Node3DEditorPlugin(EditorNode *p_node) { editor = p_node; - spatial_editor = memnew(SpatialEditor(p_node)); + spatial_editor = memnew(Node3DEditor(p_node)); spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->get_viewport()->add_child(spatial_editor); spatial_editor->hide(); - spatial_editor->connect("transform_key_request", editor->get_inspector_dock(), "_transform_keyed"); + spatial_editor->connect_compat("transform_key_request", editor->get_inspector_dock(), "_transform_keyed"); } -SpatialEditorPlugin::~SpatialEditorPlugin() { +Node3DEditorPlugin::~Node3DEditorPlugin() { } -void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { - +void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6)); - Vector<Ref<SpatialMaterial> > mats; + Vector<Ref<StandardMaterial3D>> mats; for (int i = 0; i < 4; i++) { bool selected = i % 2 == 1; bool instanced = i < 2; - Ref<SpatialMaterial> material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); Color color = instanced ? instanced_color : p_color; @@ -6133,17 +6549,17 @@ void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color } material->set_albedo(color); - material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN + 1); + material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1); if (p_use_vertex_color) { - material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); } if (p_billboard) { - material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED); } if (p_on_top && selected) { @@ -6156,17 +6572,16 @@ void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color materials[p_name] = mats; } -void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) { - +void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) { Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6)); - Vector<Ref<SpatialMaterial> > icons; + Vector<Ref<StandardMaterial3D>> icons; for (int i = 0; i < 4; i++) { bool selected = i % 2 == 1; bool instanced = i < 2; - Ref<SpatialMaterial> icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); Color color = instanced ? instanced_color : p_albedo; @@ -6176,16 +6591,16 @@ void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const icon->set_albedo(color); - icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - icon->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - icon->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture); - icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); - icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - icon->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); + icon->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); + icon->set_cull_mode(StandardMaterial3D::CULL_DISABLED); + icon->set_depth_draw_mode(StandardMaterial3D::DEPTH_DRAW_DISABLED); + icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture); + icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true); + icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED); + icon->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN); if (p_on_top && selected) { icon->set_on_top_of_alpha(); @@ -6197,75 +6612,78 @@ void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const materials[p_name] = icons; } -void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) { - Ref<SpatialMaterial> handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); +void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) { + Ref<StandardMaterial3D> handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); - Ref<Texture> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons"); + handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true); + Ref<Texture2D> handle_t = Node3DEditor::get_singleton()->get_theme_icon("Editor3DHandle", "EditorIcons"); handle_material->set_point_size(handle_t->get_width()); - handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t); + handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t); handle_material->set_albedo(Color(1, 1, 1)); - handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); + handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); handle_material->set_on_top_of_alpha(); if (p_billboard) { - handle_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + handle_material->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED); handle_material->set_on_top_of_alpha(); } - materials[p_name] = Vector<Ref<SpatialMaterial> >(); + materials[p_name] = Vector<Ref<StandardMaterial3D>>(); materials[p_name].push_back(handle_material); } -void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<SpatialMaterial> p_material) { - materials[p_name] = Vector<Ref<SpatialMaterial> >(); +void EditorNode3DGizmoPlugin::add_material(const String &p_name, Ref<StandardMaterial3D> p_material) { + materials[p_name] = Vector<Ref<StandardMaterial3D>>(); materials[p_name].push_back(p_material); } -Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo) { - ERR_FAIL_COND_V(!materials.has(p_name), Ref<SpatialMaterial>()); - ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<SpatialMaterial>()); +Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo) { + ERR_FAIL_COND_V(!materials.has(p_name), Ref<StandardMaterial3D>()); + ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<StandardMaterial3D>()); - if (p_gizmo.is_null() || materials[p_name].size() == 1) return materials[p_name][0]; + if (p_gizmo.is_null() || materials[p_name].size() == 1) { + return materials[p_name][0]; + } int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0); - Ref<SpatialMaterial> mat = materials[p_name][index]; + Ref<StandardMaterial3D> mat = materials[p_name][index]; if (current_state == ON_TOP && p_gizmo->is_selected()) { - mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true); } else { - mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); + mat->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, false); } return mat; } -String EditorSpatialGizmoPlugin::get_name() const { +String EditorNode3DGizmoPlugin::get_name() const { if (get_script_instance() && get_script_instance()->has_method("get_name")) { return get_script_instance()->call("get_name"); } return TTR("Nameless gizmo"); } -int EditorSpatialGizmoPlugin::get_priority() const { +int EditorNode3DGizmoPlugin::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) { - +Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) { if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) { return get_script_instance()->call("get_gizmo", p_spatial); } - Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial); + Ref<EditorNode3DGizmo> ref = create_gizmo(p_spatial); - if (ref.is_null()) return ref; + if (ref.is_null()) { + return ref; + } ref->set_plugin(this); ref->set_spatial_node(p_spatial); @@ -6275,18 +6693,18 @@ Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) return ref; } -void EditorSpatialGizmoPlugin::_bind_methods() { -#define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorSpatialGizmo") +void EditorNode3DGizmoPlugin::_bind_methods() { +#define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorNode3DGizmo") - BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial"))); - BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); + BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); - ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorSpatialGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorSpatialGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1))); - ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorSpatialGizmoPlugin::create_handle_material, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorSpatialGizmoPlugin::add_material); + ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorNode3DGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorNode3DGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1))); + ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorNode3DGizmoPlugin::create_handle_material, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorNode3DGizmoPlugin::add_material); - ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorSpatialGizmoPlugin::get_material); //, DEFVAL(Ref<EditorSpatialGizmo>())); + ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material); //, DEFVAL(Ref<EditorNode3DGizmo>())); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name")); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_priority")); @@ -6300,7 +6718,7 @@ void EditorSpatialGizmoPlugin::_bind_methods() { hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(hvget); - BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::VECTOR2, "point"))); + BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point"))); MethodInfo cm = MethodInfo("commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel")); cm.default_arguments.push_back(false); BIND_VMETHOD(cm); @@ -6310,103 +6728,104 @@ void EditorSpatialGizmoPlugin::_bind_methods() { #undef GIZMO_REF } -bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { +bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { if (get_script_instance() && get_script_instance()->has_method("has_gizmo")) { return get_script_instance()->call("has_gizmo", p_spatial); } return false; } -Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { - +Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { if (get_script_instance() && get_script_instance()->has_method("create_gizmo")) { return get_script_instance()->call("create_gizmo", p_spatial); } - Ref<EditorSpatialGizmo> ref; - if (has_gizmo(p_spatial)) ref.instance(); + Ref<EditorNode3DGizmo> ref; + if (has_gizmo(p_spatial)) { + ref.instance(); + } return ref; } -bool EditorSpatialGizmoPlugin::can_be_hidden() const { +bool EditorNode3DGizmoPlugin::can_be_hidden() const { if (get_script_instance() && get_script_instance()->has_method("can_be_hidden")) { return get_script_instance()->call("can_be_hidden"); } return true; } -bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const { +bool EditorNode3DGizmoPlugin::is_selectable_when_hidden() const { if (get_script_instance() && get_script_instance()->has_method("is_selectable_when_hidden")) { return get_script_instance()->call("is_selectable_when_hidden"); } return false; } -void EditorSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { +void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { if (get_script_instance() && get_script_instance()->has_method("redraw")) { - Ref<EditorSpatialGizmo> ref(p_gizmo); + Ref<EditorNode3DGizmo> ref(p_gizmo); get_script_instance()->call("redraw", ref); } } -String EditorSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { +String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) { return get_script_instance()->call("get_handle_name", p_gizmo, p_idx); } return ""; } -Variant EditorSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { +Variant EditorNode3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) { return get_script_instance()->call("get_handle_value", p_gizmo, p_idx); } return Variant(); } -void EditorSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { +void EditorNode3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { if (get_script_instance() && get_script_instance()->has_method("set_handle")) { get_script_instance()->call("set_handle", p_gizmo, p_idx, p_camera, p_point); } } -void EditorSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { +void EditorNode3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { if (get_script_instance() && get_script_instance()->has_method("commit_handle")) { get_script_instance()->call("commit_handle", p_gizmo, p_idx, p_restore, p_cancel); } } -bool EditorSpatialGizmoPlugin::is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int p_idx) const { +bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_idx) const { if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) { return get_script_instance()->call("is_handle_highlighted", p_gizmo, p_idx); } return false; } -void EditorSpatialGizmoPlugin::set_state(int p_state) { +void EditorNode3DGizmoPlugin::set_state(int p_state) { current_state = p_state; for (int i = 0; i < current_gizmos.size(); ++i) { current_gizmos[i]->set_hidden(current_state == HIDDEN); } } -int EditorSpatialGizmoPlugin::get_state() const { +int EditorNode3DGizmoPlugin::get_state() const { return current_state; } -void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) { +void EditorNode3DGizmoPlugin::unregister_gizmo(EditorNode3DGizmo *p_gizmo) { current_gizmos.erase(p_gizmo); } -EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() { +EditorNode3DGizmoPlugin::EditorNode3DGizmoPlugin() { current_state = VISIBLE; } -EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() { +EditorNode3DGizmoPlugin::~EditorNode3DGizmoPlugin() { for (int i = 0; i < current_gizmos.size(); ++i) { - current_gizmos[i]->set_plugin(NULL); - current_gizmos[i]->get_spatial_node()->set_gizmo(NULL); + current_gizmos[i]->set_plugin(nullptr); + current_gizmos[i]->get_spatial_node()->set_gizmo(nullptr); } - if (SpatialEditor::get_singleton()) { - SpatialEditor::get_singleton()->update_all_gizmos(); + if (Node3DEditor::get_singleton()) { + Node3DEditor::get_singleton()->update_all_gizmos(); } } diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 5cc2b24cbb..6a8af38742 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* spatial_editor_plugin.h */ +/* node_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,19 +33,20 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/immediate_geometry.h" -#include "scene/3d/light.h" -#include "scene/3d/visual_instance.h" +#include "editor/editor_scale.h" +#include "scene/3d/immediate_geometry_3d.h" +#include "scene/3d/light_3d.h" +#include "scene/3d/visual_instance_3d.h" #include "scene/gui/panel_container.h" -class Camera; -class SpatialEditor; -class EditorSpatialGizmoPlugin; -class ViewportContainer; +class Camera3D; +class Node3DEditor; +class EditorNode3DGizmoPlugin; +class Node3DEditorViewport; +class SubViewportContainer; -class EditorSpatialGizmo : public SpatialGizmo { - - GDCLASS(EditorSpatialGizmo, SpatialGizmo); +class EditorNode3DGizmo : public Node3DGizmo { + GDCLASS(EditorNode3DGizmo, Node3DGizmo); bool selected; bool instanced; @@ -55,7 +56,6 @@ public: bool is_selected() const { return selected; } struct Instance { - RID instance; Ref<ArrayMesh> mesh; Ref<Material> material; @@ -66,14 +66,13 @@ public: bool can_intersect; bool extra_margin; Instance() { - billboard = false; unscaled = false; can_intersect = false; extra_margin = false; } - void create_instance(Spatial *p_base, bool p_hidden = false); + void create_instance(Node3D *p_base, bool p_hidden = false); }; Vector<Vector3> collision_segments; @@ -91,12 +90,12 @@ public: bool valid; bool hidden; - Spatial *base; + Node3D *base; Vector<Instance> instances; - Spatial *spatial_node; - EditorSpatialGizmoPlugin *gizmo_plugin; + Node3D *spatial_node; + EditorNode3DGizmoPlugin *gizmo_plugin; - void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); } + void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Node3D>(p_node)); } protected: static void _bind_methods(); @@ -113,35 +112,73 @@ public: virtual bool is_handle_highlighted(int p_idx) const; virtual String get_handle_name(int p_idx) const; virtual Variant get_handle_value(int p_idx); - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); + virtual void set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void set_spatial_node(Spatial *p_node); - Spatial *get_spatial_node() const { return spatial_node; } - Ref<EditorSpatialGizmoPlugin> get_plugin() const { return gizmo_plugin; } + void set_spatial_node(Node3D *p_node); + Node3D *get_spatial_node() const { return spatial_node; } + Ref<EditorNode3DGizmoPlugin> get_plugin() const { return gizmo_plugin; } Vector3 get_handle_pos(int p_idx) const; - bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); - bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); + bool intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum); + bool intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = nullptr, bool p_sec_first = false); - virtual void clear(); - virtual void create(); - virtual void transform(); - virtual void redraw(); - virtual void free(); + virtual void clear() override; + virtual void create() override; + virtual void transform() override; + virtual void redraw() override; + virtual void free() override; virtual bool is_editable() const; void set_hidden(bool p_hidden); - void set_plugin(EditorSpatialGizmoPlugin *p_plugin); + void set_plugin(EditorNode3DGizmoPlugin *p_plugin); - EditorSpatialGizmo(); - ~EditorSpatialGizmo(); + EditorNode3DGizmo(); + ~EditorNode3DGizmo(); }; -class SpatialEditorViewport : public Control { +class ViewportRotationControl : public Control { + GDCLASS(ViewportRotationControl, Control); + + struct Axis2D { + Vector2i screen_point; + float z_axis = -99.0; + int axis = -1; + }; + + struct Axis2DCompare { + _FORCE_INLINE_ bool operator()(const Axis2D &l, const Axis2D &r) const { + return l.z_axis < r.z_axis; + } + }; + + Node3DEditorViewport *viewport = nullptr; + Vector<Color> axis_colors; + Vector<int> axis_menu_options; + Vector2i orbiting_mouse_start; + bool orbiting = false; + int focused_axis = -2; + + const float AXIS_CIRCLE_RADIUS = 8.0f * EDSCALE; - GDCLASS(SpatialEditorViewport, Control); - friend class SpatialEditor; +protected: + static void _bind_methods(); + void _notification(int p_what); + void _gui_input(Ref<InputEvent> p_event); + void _draw(); + void _draw_axis(const Axis2D &p_axis); + void _get_sorted_axis(Vector<Axis2D> &r_axis); + void _update_focus(); + void _on_mouse_exited(); + +public: + void set_viewport(Node3DEditorViewport *p_viewport); +}; + +class Node3DEditorViewport : public Control { + GDCLASS(Node3DEditorViewport, Control); + friend class Node3DEditor; + friend class ViewportRotationControl; enum { VIEW_TOP, @@ -162,20 +199,39 @@ class SpatialEditorViewport : public Control { VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, VIEW_INFORMATION, - VIEW_FPS, + VIEW_FRAME_TIME, VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, VIEW_DISPLAY_SHADELESS, + VIEW_DISPLAY_LIGHTING, + VIEW_DISPLAY_ADVANCED, + VIEW_DISPLAY_NORMAL_BUFFER, + VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, + VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, + VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO, + VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING, + VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION, + VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, + VIEW_DISPLAY_DEBUG_SSAO, + VIEW_DISPLAY_DEBUG_PSSM_SPLITS, + VIEW_DISPLAY_DEBUG_DECAL_ATLAS, + VIEW_DISPLAY_DEBUG_SDFGI, + VIEW_DISPLAY_DEBUG_SDFGI_PROBES, + VIEW_DISPLAY_DEBUG_GI_BUFFER, VIEW_LOCK_ROTATION, - VIEW_CINEMATIC_PREVIEW + VIEW_CINEMATIC_PREVIEW, + VIEW_AUTO_ORTHOGONAL, + VIEW_MAX }; public: enum { GIZMO_BASE_LAYER = 27, GIZMO_EDIT_LAYER = 26, - GIZMO_GRID_LAYER = 25 + GIZMO_GRID_LAYER = 25, + + FRAME_TIME_HISTORY = 20, }; enum NavigationScheme { @@ -184,11 +240,23 @@ public: NAVIGATION_MODO, }; + enum FreelookNavigationScheme { + FREELOOK_DEFAULT, + FREELOOK_PARTIALLY_AXIS_LOCKED, + FREELOOK_FULLY_AXIS_LOCKED, + }; + private: + float cpu_time_history[FRAME_TIME_HISTORY]; + int cpu_time_history_index; + float gpu_time_history[FRAME_TIME_HISTORY]; + int gpu_time_history_index; + int index; String name; void _menu_option(int p_option); - Spatial *preview_node; + void _set_auto_orthogonal(); + Node3D *preview_node; AABB *preview_bounds; Vector<String> selected_files; AcceptDialog *accept; @@ -202,30 +270,34 @@ private: UndoRedo *undo_redo; CheckBox *preview_camera; - ViewportContainer *viewport_container; + SubViewportContainer *subviewport_container; MenuButton *view_menu; + PopupMenu *display_submenu; Control *surface; - Viewport *viewport; - Camera *camera; + SubViewport *viewport; + Camera3D *camera; bool transforming; bool orthogonal; + bool auto_orthogonal; bool lock_rotation; float gizmo_scale; bool freelook_active; real_t freelook_speed; + Vector2 previous_mouse_position; - TextureRect *crosshair; Label *info_label; - Label *fps_label; Label *cinema_label; Label *locked_label; - struct _RayResult { + VBoxContainer *top_right_vbox; + ViewportRotationControl *rotation_control; + Label *fps_label; - Spatial *item; + struct _RayResult { + Node3D *item; float depth; int handle; _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; } @@ -234,9 +306,9 @@ private: void _update_name(); void _compute_edit(const Point2 &p_point); void _clear_selected(); - void _select_clicked(bool p_append, bool p_single); + void _select_clicked(bool p_append, bool p_single, bool p_allow_locked = false); void _select(Node *p_node, bool p_append, bool p_single); - ObjectID _select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle = NULL, bool p_alt_select = false); + ObjectID _select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle = nullptr, bool p_alt_select = false); void _find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select = false); Vector3 _get_ray_pos(const Vector2 &p_pos) const; Vector3 _get_ray(const Vector2 &p_pos) const; @@ -307,14 +379,13 @@ private: int edited_gizmo; Point2 mouse_pos; bool snap; - Ref<EditorSpatialGizmo> gizmo; + Ref<EditorNode3DGizmo> gizmo; int gizmo_handle; Variant gizmo_initial_value; Vector3 gizmo_initial_pos; } _edit; struct Cursor { - Vector3 pos; float x_rot, y_rot, distance; Vector3 eye_pos; // Used in freelook mode @@ -322,7 +393,9 @@ private: Point2 region_begin, region_end; Cursor() { - x_rot = y_rot = 0.5; + // These rotations place the camera in +X +Y +Z, aka south east, facing north west. + x_rot = 0.5; + y_rot = -0.5; distance = 4; region_select = false; } @@ -359,10 +432,10 @@ private: void _sinput(const Ref<InputEvent> &p_event); void _update_freelook(real_t delta); - SpatialEditor *spatial_editor; + Node3DEditor *spatial_editor; - Camera *previewing; - Camera *preview; + Camera3D *previewing; + Camera3D *preview; bool previewing_cinema; bool _is_node_locked(const Node *p_node); @@ -377,7 +450,7 @@ private: Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const; Vector3 _get_instance_position(const Point2 &p_pos) const; - static AABB _calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform = true); + static AABB _calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_toplevel_transform = true); void _create_preview(const Vector<String> &files) const; void _remove_preview(); bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node); @@ -395,7 +468,7 @@ public: void update_surface() { surface->update(); } void update_transform_gizmo_view(); - void set_can_preview(Camera *p_preview); + void set_can_preview(Camera3D *p_preview); void set_state(const Dictionary &p_state); Dictionary get_state() const; void reset(); @@ -404,35 +477,37 @@ public: void focus_selection(); void assign_pending_data_pointers( - Spatial *p_preview_node, + Node3D *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept); - Viewport *get_viewport_node() { return viewport; } - Camera *get_camera() { return camera; } // return the default camera object. + SubViewport *get_viewport_node() { return viewport; } + Camera3D *get_camera() { return camera; } // return the default camera object. - SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index); + Node3DEditorViewport(Node3DEditor *p_spatial_editor, EditorNode *p_editor, int p_index); }; -class SpatialEditorSelectedItem : public Object { - - GDCLASS(SpatialEditorSelectedItem, Object); +class Node3DEditorSelectedItem : public Object { + GDCLASS(Node3DEditorSelectedItem, Object); public: AABB aabb; Transform original; // original location when moving Transform original_local; Transform last_xform; // last transform - Spatial *sp; + bool last_xform_dirty; + Node3D *sp; RID sbox_instance; - SpatialEditorSelectedItem() { sp = NULL; } - ~SpatialEditorSelectedItem(); + Node3DEditorSelectedItem() { + sp = nullptr; + last_xform_dirty = true; + } + ~Node3DEditorSelectedItem(); }; -class SpatialEditorViewportContainer : public Container { - - GDCLASS(SpatialEditorViewportContainer, Container); +class Node3DEditorViewportContainer : public Container { + GDCLASS(Node3DEditorViewportContainer, Container); public: enum View { @@ -468,12 +543,11 @@ public: void set_view(View p_view); View get_view(); - SpatialEditorViewportContainer(); + Node3DEditorViewportContainer(); }; -class SpatialEditor : public VBoxContainer { - - GDCLASS(SpatialEditor, VBoxContainer); +class Node3DEditor : public VBoxContainer { + GDCLASS(Node3DEditor, VBoxContainer); public: static const unsigned int VIEWPORTS_COUNT = 4; @@ -505,8 +579,8 @@ private: EditorNode *editor; EditorSelection *editor_selection; - SpatialEditorViewportContainer *viewport_base; - SpatialEditorViewport *viewports[VIEWPORTS_COUNT]; + Node3DEditorViewportContainer *viewport_base; + Node3DEditorViewport *viewports[VIEWPORTS_COUNT]; VSplitContainer *shader_split; HSplitContainer *palette_split; @@ -515,7 +589,7 @@ private: ToolMode tool_mode; bool orthogonal; - VisualServer::ScenarioDebugMode scenario_debug; + RenderingServer::ScenarioDebugMode scenario_debug; RID origin; RID origin_instance; @@ -527,27 +601,29 @@ private: bool grid_enabled; Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[3], scale_gizmo[3], scale_plane_gizmo[3]; - Ref<SpatialMaterial> gizmo_color[3]; - Ref<SpatialMaterial> plane_gizmo_color[3]; - Ref<SpatialMaterial> gizmo_color_hl[3]; - Ref<SpatialMaterial> plane_gizmo_color_hl[3]; + Ref<StandardMaterial3D> gizmo_color[3]; + Ref<StandardMaterial3D> plane_gizmo_color[3]; + Ref<StandardMaterial3D> gizmo_color_hl[3]; + Ref<StandardMaterial3D> plane_gizmo_color_hl[3]; int over_gizmo_handle; + float snap_translate_value; + float snap_rotate_value; + float snap_scale_value; Ref<ArrayMesh> selection_box; RID indicators; RID indicators_instance; RID cursor_mesh; RID cursor_instance; - Ref<SpatialMaterial> indicator_mat; - Ref<SpatialMaterial> cursor_material; + Ref<StandardMaterial3D> indicator_mat; + Ref<StandardMaterial3D> cursor_material; // Scene drag and drop support - Spatial *preview_node; + Node3D *preview_node; AABB preview_bounds; struct Gizmo { - bool visible; float scale; Transform transform; @@ -612,6 +688,8 @@ private: SpinBox *settings_znear; SpinBox *settings_zfar; + void _snap_changed(); + void _snap_update(); void _xform_dialog_action(); void _menu_item_pressed(int p_option); void _menu_item_toggled(bool pressed, int p_option); @@ -641,19 +719,19 @@ private: Ref<Environment> viewport_environment; - Spatial *selected; + Node3D *selected; void _request_gizmo(Object *p_obj); - static SpatialEditor *singleton; + static Node3DEditor *singleton; void _node_removed(Node *p_node); - Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_priority; - Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins_by_name; + Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_priority; + Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_name; void _register_all_gizmos(); - SpatialEditor(); + Node3DEditor(); bool is_any_freelook_active() const; @@ -667,7 +745,7 @@ protected: static void _bind_methods(); public: - static SpatialEditor *get_singleton() { return singleton; } + static Node3DEditor *get_singleton() { return singleton; } void snap_cursor_to_plane(const Plane &p_plane); Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const; @@ -680,7 +758,7 @@ public: bool is_gizmo_visible() const { return gizmo.visible; } ToolMode get_tool_mode() const { return tool_mode; } - bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } + bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; } float get_translate_snap() const; float get_rotate_snap() const; @@ -692,8 +770,9 @@ public: Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } + void update_grid(); void update_transform_gizmo(); - void update_all_gizmos(Node *p_node = NULL); + void update_all_gizmos(Node *p_node = nullptr); void snap_selected_nodes_to_floor(); void select_gizmo_highlight_axis(int p_axis); void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } @@ -712,33 +791,32 @@ public: VSplitContainer *get_shader_split(); HSplitContainer *get_palette_split(); - Spatial *get_selected() { return selected; } + Node3D *get_selected() { return selected; } int get_over_gizmo_handle() const { return over_gizmo_handle; } void set_over_gizmo_handle(int idx) { over_gizmo_handle = idx; } - void set_can_preview(Camera *p_preview); + void set_can_preview(Camera3D *p_preview); - SpatialEditorViewport *get_editor_viewport(int p_idx) { - ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL); + Node3DEditorViewport *get_editor_viewport(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr); return viewports[p_idx]; } - void add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin); - void remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin); + void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); + void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); - void edit(Spatial *p_spatial); + void edit(Node3D *p_spatial); void clear(); - SpatialEditor(EditorNode *p_editor); - ~SpatialEditor(); + Node3DEditor(EditorNode *p_editor); + ~Node3DEditor(); }; -class SpatialEditorPlugin : public EditorPlugin { - - GDCLASS(SpatialEditorPlugin, EditorPlugin); +class Node3DEditorPlugin : public EditorPlugin { + GDCLASS(Node3DEditorPlugin, EditorPlugin); - SpatialEditor *spatial_editor; + Node3DEditor *spatial_editor; EditorNode *editor; protected: @@ -747,69 +825,67 @@ protected: public: void snap_cursor_to_plane(const Plane &p_plane); - SpatialEditor *get_spatial_editor() { return spatial_editor; } - virtual String get_name() const { return "3D"; } - bool has_main_screen() const { return true; } - virtual void make_visible(bool p_visible); - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; + Node3DEditor *get_spatial_editor() { return spatial_editor; } + virtual String get_name() const override { return "3D"; } + bool has_main_screen() const override { return true; } + virtual void make_visible(bool p_visible) override; + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; - virtual Dictionary get_state() const; - virtual void set_state(const Dictionary &p_state); - virtual void clear() { spatial_editor->clear(); } + virtual Dictionary get_state() const override; + virtual void set_state(const Dictionary &p_state) override; + virtual void clear() override { spatial_editor->clear(); } - virtual void edited_scene_changed(); + virtual void edited_scene_changed() override; - SpatialEditorPlugin(EditorNode *p_node); - ~SpatialEditorPlugin(); + Node3DEditorPlugin(EditorNode *p_node); + ~Node3DEditorPlugin(); }; -class EditorSpatialGizmoPlugin : public Resource { - - GDCLASS(EditorSpatialGizmoPlugin, Resource); +class EditorNode3DGizmoPlugin : public Resource { + GDCLASS(EditorNode3DGizmoPlugin, Resource); public: static const int VISIBLE = 0; static const int HIDDEN = 1; static const int ON_TOP = 2; -private: +protected: int current_state; - List<EditorSpatialGizmo *> current_gizmos; - HashMap<String, Vector<Ref<SpatialMaterial> > > materials; + List<EditorNode3DGizmo *> current_gizmos; + HashMap<String, Vector<Ref<StandardMaterial3D>>> materials; -protected: static void _bind_methods(); - virtual bool has_gizmo(Spatial *p_spatial); - virtual Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + virtual bool has_gizmo(Node3D *p_spatial); + virtual Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial); public: void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); - void create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); + void create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); void create_handle_material(const String &p_name, bool p_billboard = false); - void add_material(const String &p_name, Ref<SpatialMaterial> p_material); + void add_material(const String &p_name, Ref<StandardMaterial3D> p_material); - Ref<SpatialMaterial> get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo = Ref<EditorSpatialGizmo>()); + Ref<StandardMaterial3D> get_material(const String &p_name, const Ref<EditorNode3DGizmo> &p_gizmo = Ref<EditorNode3DGizmo>()); virtual String get_name() const; virtual int get_priority() const; virtual bool can_be_hidden() const; virtual bool is_selectable_when_hidden() const; - virtual void redraw(EditorSpatialGizmo *p_gizmo); - virtual String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; - virtual Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; - virtual void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); - virtual bool is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + virtual void redraw(EditorNode3DGizmo *p_gizmo); + virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const; + virtual Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const; + virtual void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point); + virtual void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_idx) const; - Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial); + Ref<EditorNode3DGizmo> get_gizmo(Node3D *p_spatial); void set_state(int p_state); int get_state() const; - void unregister_gizmo(EditorSpatialGizmo *p_gizmo); + void unregister_gizmo(EditorNode3DGizmo *p_gizmo); - EditorSpatialGizmoPlugin(); - virtual ~EditorSpatialGizmoPlugin(); + EditorNode3DGizmoPlugin(); + virtual ~EditorNode3DGizmoPlugin(); }; #endif diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp new file mode 100644 index 0000000000..608b5c3104 --- /dev/null +++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* packed_scene_translation_parser_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "packed_scene_translation_parser_plugin.h" + +#include "core/io/resource_loader.h" +#include "scene/resources/packed_scene.h" + +void PackedSceneEditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const { + ResourceLoader::get_recognized_extensions_for_type("PackedScene", r_extensions); +} + +Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) { + // Parse specific scene Node's properties (see in constructor) that are auto-translated by the engine when set. E.g Label's text property. + // These properties are translated with the tr() function in the C++ code when being set or updated. + + Error err; + RES loaded_res = ResourceLoader::load(p_path, "PackedScene", false, &err); + if (err) { + ERR_PRINT("Failed to load " + p_path); + return err; + } + Ref<SceneState> state = Ref<PackedScene>(loaded_res)->get_state(); + + Vector<String> parsed_strings; + String property_name; + Variant property_value; + for (int i = 0; i < state->get_node_count(); i++) { + if (!ClassDB::is_parent_class(state->get_node_type(i), "Control") && !ClassDB::is_parent_class(state->get_node_type(i), "Viewport")) { + continue; + } + + for (int j = 0; j < state->get_node_property_count(i); j++) { + property_name = state->get_node_property_name(i, j); + if (!lookup_properties.has(property_name)) { + continue; + } + + property_value = state->get_node_property_value(i, j); + + if (property_name == "script" && property_value.get_type() == Variant::OBJECT && !property_value.is_null()) { + // Parse built-in script. + Ref<Script> s = Object::cast_to<Script>(property_value); + String extension = s->get_language()->get_extension(); + if (EditorTranslationParser::get_singleton()->can_parse(extension)) { + Vector<String> temp; + Vector<Vector<String>> ids_context_plural; + EditorTranslationParser::get_singleton()->get_parser(extension)->parse_file(s->get_path(), &temp, &ids_context_plural); + parsed_strings.append_array(temp); + r_ids_ctx_plural->append_array(ids_context_plural); + } + } else if (property_name == "filters") { + // Extract FileDialog's filters property with values in format "*.png ; PNG Images","*.gd ; GDScript Files". + Vector<String> str_values = property_value; + for (int k = 0; k < str_values.size(); k++) { + String desc = str_values[k].get_slice(";", 1).strip_edges(); + if (!desc.empty()) { + parsed_strings.push_back(desc); + } + } + } else if (property_value.get_type() == Variant::STRING) { + String str_value = String(property_value); + // Prevent reading text containing only spaces. + if (!str_value.strip_edges().empty()) { + parsed_strings.push_back(str_value); + } + } + } + } + + r_ids->append_array(parsed_strings); + + return OK; +} + +PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlugin() { + // Scene Node's properties containing strings that will be fetched for translation. + lookup_properties.insert("text"); + lookup_properties.insert("hint_tooltip"); + lookup_properties.insert("placeholder_text"); + lookup_properties.insert("dialog_text"); + lookup_properties.insert("filters"); + lookup_properties.insert("script"); + + //Add exception list (to prevent false positives) + //line edit, text edit, richtextlabel + //Set<String> exception_list; + //exception_list.insert("RichTextLabel"); +} diff --git a/editor/plugins/packed_scene_translation_parser_plugin.h b/editor/plugins/packed_scene_translation_parser_plugin.h new file mode 100644 index 0000000000..a0ffdf692c --- /dev/null +++ b/editor/plugins/packed_scene_translation_parser_plugin.h @@ -0,0 +1,49 @@ +/*************************************************************************/ +/* packed_scene_translation_parser_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H +#define PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H + +#include "editor/editor_translation_parser.h" + +class PackedSceneEditorTranslationParserPlugin : public EditorTranslationParserPlugin { + GDCLASS(PackedSceneEditorTranslationParserPlugin, EditorTranslationParserPlugin); + + // Scene Node's properties that contain translation strings. + Set<String> lookup_properties; + +public: + virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) override; + virtual void get_recognized_extensions(List<String> *r_extensions) const override; + + PackedSceneEditorTranslationParserPlugin(); +}; + +#endif // PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 3737dbdd57..f79098ce5d 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -37,11 +37,8 @@ #include "editor/editor_settings.h" void Path2DEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - //button_create->set_icon( get_icon("Edit","EditorIcons")); //button_edit->set_icon( get_icon("MovePoint","EditorIcons")); //set_pressed_button(button_edit); @@ -49,44 +46,43 @@ void Path2DEditor::_notification(int p_what) { } break; case NOTIFICATION_PHYSICS_PROCESS: { - } break; } } -void Path2DEditor::_node_removed(Node *p_node) { +void Path2DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; + node = nullptr; hide(); } } bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { - if (!node) + if (!node) { return false; + } - if (!node->is_visible_in_tree()) + if (!node->is_visible_in_tree()) { return false; + } - if (!node->get_curve().is_valid()) + if (!node->get_curve().is_valid()) { return false; + } real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); Vector2 gpoint = mb->get_position(); Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position()))); if (mb->is_pressed() && action == ACTION_NONE) { - Ref<Curve2D> curve = node->get_curve(); for (int i = 0; i < curve->get_point_count(); i++) { - real_t dist_to_p = gpoint.distance_to(xform.xform(curve->get_point_position(i))); real_t dist_to_p_out = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_out(i))); real_t dist_to_p_in = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_in(i))); @@ -104,7 +100,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else if (mode == MODE_EDIT || mode == MODE_EDIT_CURVE) { // In/out controls can be moved in multiple modes. if (dist_to_p_out < grab_threshold && i < (curve->get_point_count() - 1)) { - action = ACTION_MOVING_OUT; action_point = i; moving_from = curve->get_point_out(i); @@ -112,7 +107,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { orig_in_length = curve->get_point_in(action_point).length(); return true; } else if (dist_to_p_in < grab_threshold && i > 0) { - action = ACTION_MOVING_IN; action_point = i; moving_from = curve->get_point_in(i); @@ -126,7 +120,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for point deletion. if ((mb->get_button_index() == BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == BUTTON_LEFT && mode == MODE_DELETE)) { if (dist_to_p < grab_threshold) { - undo_redo->create_action(TTR("Remove Point from Curve")); undo_redo->add_do_method(curve.ptr(), "remove_point", i); undo_redo->add_undo_method(curve.ptr(), "add_point", curve->get_point_position(i), curve->get_point_in(i), curve->get_point_out(i), i); @@ -135,7 +128,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); return true; } else if (dist_to_p_out < grab_threshold) { - undo_redo->create_action(TTR("Remove Out-Control from Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_out", i, Vector2()); undo_redo->add_undo_method(curve.ptr(), "set_point_out", i, curve->get_point_out(i)); @@ -144,7 +136,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); return true; } else if (dist_to_p_in < grab_threshold) { - undo_redo->create_action(TTR("Remove In-Control from Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_in", i, Vector2()); undo_redo->add_undo_method(curve.ptr(), "set_point_in", i, curve->get_point_in(i)); @@ -159,7 +150,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for point creation. if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) { - Ref<Curve2D> curve = node->get_curve(); undo_redo->create_action(TTR("Add Point to Curve")); @@ -189,11 +179,13 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { 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)); - if (mbLength >= curve->get_closest_offset(curve->get_point_position(i)) && mbLength <= compareLength) + if (mbLength >= curve->get_closest_offset(curve->get_point_position(i)) && mbLength <= compareLength) { insertion_point = i; + } } - if (insertion_point == -1) + if (insertion_point == -1) { 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(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1); @@ -216,18 +208,15 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { // Check for point movement completion. if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && action != ACTION_NONE) { - Ref<Curve2D> curve = node->get_curve(); Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from); switch (action) { - case ACTION_NONE: // N/A, handled in above condition. break; case ACTION_MOVING_POINT: { - undo_redo->create_action(TTR("Move Point in Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint); undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from); @@ -238,7 +227,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } break; case ACTION_MOVING_IN: { - undo_redo->create_action(TTR("Move In-Control in Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, new_pos); undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, moving_from); @@ -254,7 +242,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } break; case ACTION_MOVING_OUT: { - undo_redo->create_action(TTR("Move Out-Control in Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, new_pos); undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, moving_from); @@ -279,7 +266,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (action == ACTION_NONE && mode == MODE_EDIT) { // Handle Edge Follow bool old_edge = on_edge; @@ -288,8 +274,12 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 gpoint = mm->get_position(); Ref<Curve2D> curve = node->get_curve(); - if (curve == NULL) return true; - if (curve->get_point_count() < 2) return true; + if (curve == nullptr) { + return true; + } + if (curve->get_point_count() < 2) { + return true; + } // Find edge edge_point = xform.xform(curve->get_closest_point(xform.affine_inverse().xform(mm->get_position()))); @@ -334,7 +324,6 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from); switch (action) { - case ACTION_NONE: // N/A, handled in above condition. break; @@ -346,15 +335,17 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { case ACTION_MOVING_IN: { curve->set_point_in(action_point, new_pos); - if (mirror_handle_angle) + if (mirror_handle_angle) { curve->set_point_out(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length)); + } } break; case ACTION_MOVING_OUT: { curve->set_point_out(action_point, new_pos); - if (mirror_handle_angle) + if (mirror_handle_angle) { curve->set_point_in(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length)); + } } break; } @@ -367,18 +358,18 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - - if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) + if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) { return; + } Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - const Ref<Texture> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons"); - const Ref<Texture> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons"); + const Ref<Texture2D> path_sharp_handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons"); + const Ref<Texture2D> path_smooth_handle = get_theme_icon("EditorPathSmoothHandle", "EditorIcons"); // Both handle icons must be of the same size const Size2 handle_size = path_sharp_handle->get_size(); - const Ref<Texture> curve_handle = get_icon("EditorCurveHandle", "EditorIcons"); + const Ref<Texture2D> curve_handle = get_theme_icon("EditorCurveHandle", "EditorIcons"); const Size2 curve_handle_size = curve_handle->get_size(); Ref<Curve2D> curve = node->get_curve(); @@ -396,8 +387,8 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { if (point != pointout) { smooth = true; // Draw the line with a dark and light color to be visible on all backgrounds - vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); - vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE)); + vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE)); vpc->draw_texture_rect(curve_handle, Rect2(pointout - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); } } @@ -407,8 +398,8 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { if (point != pointin) { smooth = true; // Draw the line with a dark and light color to be visible on all backgrounds - vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); - vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE)); + vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE)); vpc->draw_texture_rect(curve_handle, Rect2(pointin - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); } } @@ -420,86 +411,79 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } if (on_edge) { - Ref<Texture> add_handle = get_icon("EditorHandleAdd", "EditorIcons"); + Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons"); p_overlay->draw_texture(add_handle, edge_point - add_handle->get_size() * 0.5); } } void Path2DEditor::_node_visibility_changed() { - if (!node) + if (!node) { return; + } canvas_item_editor->update_viewport(); } void Path2DEditor::edit(Node *p_path2d) { - if (!canvas_item_editor) { canvas_item_editor = CanvasItemEditor::get_singleton(); } if (p_path2d) { - node = Object::cast_to<Path2D>(p_path2d); - if (!node->is_connected("visibility_changed", this, "_node_visibility_changed")) - node->connect("visibility_changed", this, "_node_visibility_changed"); + if (!node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) { + node->connect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed)); + } } else { - // node may have been deleted at this point - if (node && node->is_connected("visibility_changed", this, "_node_visibility_changed")) - node->disconnect("visibility_changed", this, "_node_visibility_changed"); - node = NULL; + if (node && node->is_connected("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed))) { + node->disconnect("visibility_changed", callable_mp(this, &Path2DEditor::_node_visibility_changed)); + } + node = nullptr; } } void Path2DEditor::_bind_methods() { - //ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Path2DEditor::_node_visibility_changed); - ClassDB::bind_method(D_METHOD("_mode_selected"), &Path2DEditor::_mode_selected); - ClassDB::bind_method(D_METHOD("_handle_option_pressed"), &Path2DEditor::_handle_option_pressed); } void Path2DEditor::_mode_selected(int p_mode) { - if (p_mode == MODE_CREATE) { - curve_create->set_pressed(true); curve_edit->set_pressed(false); curve_edit_curve->set_pressed(false); curve_del->set_pressed(false); } else if (p_mode == MODE_EDIT) { - curve_create->set_pressed(false); curve_edit->set_pressed(true); curve_edit_curve->set_pressed(false); curve_del->set_pressed(false); } else if (p_mode == MODE_EDIT_CURVE) { - curve_create->set_pressed(false); curve_edit->set_pressed(false); curve_edit_curve->set_pressed(true); curve_del->set_pressed(false); } else if (p_mode == MODE_DELETE) { - curve_create->set_pressed(false); curve_edit->set_pressed(false); curve_edit_curve->set_pressed(false); curve_del->set_pressed(true); } else if (p_mode == ACTION_CLOSE) { - //? - if (!node->get_curve().is_valid()) + if (!node->get_curve().is_valid()) { return; - if (node->get_curve()->get_point_count() < 3) + } + if (node->get_curve()->get_point_count() < 3) { return; + } Vector2 begin = node->get_curve()->get_point_position(0); Vector2 end = node->get_curve()->get_point_position(node->get_curve()->get_point_count() - 1); - if (begin.distance_to(end) < CMP_EPSILON) + if (begin.distance_to(end) < CMP_EPSILON) { return; + } undo_redo->create_action(TTR("Remove Point from Curve")); undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin); @@ -514,7 +498,6 @@ void Path2DEditor::_mode_selected(int p_mode) { } void Path2DEditor::_handle_option_pressed(int p_option) { - PopupMenu *pm; pm = handle_menu->get_popup(); @@ -534,8 +517,7 @@ void Path2DEditor::_handle_option_pressed(int p_option) { } Path2DEditor::Path2DEditor(EditorNode *p_editor) { - - canvas_item_editor = NULL; + canvas_item_editor = nullptr; editor = p_editor; undo_redo = editor->get_undo_redo(); mirror_handle_angle = true; @@ -550,39 +532,44 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) { sep = memnew(VSeparator); base_hb->add_child(sep); - curve_edit = memnew(ToolButton); - curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons")); + curve_edit = memnew(Button); + curve_edit->set_flat(true); + curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons")); curve_edit->set_toggle_mode(true); curve_edit->set_focus_mode(Control::FOCUS_NONE); curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point")); - curve_edit->connect("pressed", this, "_mode_selected", varray(MODE_EDIT)); + curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT)); base_hb->add_child(curve_edit); - curve_edit_curve = memnew(ToolButton); - curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCurve", "EditorIcons")); + curve_edit_curve = memnew(Button); + curve_edit_curve->set_flat(true); + curve_edit_curve->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCurve", "EditorIcons")); curve_edit_curve->set_toggle_mode(true); curve_edit_curve->set_focus_mode(Control::FOCUS_NONE); curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)")); - curve_edit_curve->connect("pressed", this, "_mode_selected", varray(MODE_EDIT_CURVE)); + curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_EDIT_CURVE)); base_hb->add_child(curve_edit_curve); - curve_create = memnew(ToolButton); - curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons")); + curve_create = memnew(Button); + curve_create->set_flat(true); + curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons")); curve_create->set_toggle_mode(true); curve_create->set_focus_mode(Control::FOCUS_NONE); curve_create->set_tooltip(TTR("Add Point (in empty space)")); - curve_create->connect("pressed", this, "_mode_selected", varray(MODE_CREATE)); + curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_CREATE)); base_hb->add_child(curve_create); - curve_del = memnew(ToolButton); - curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons")); + curve_del = memnew(Button); + curve_del->set_flat(true); + curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons")); curve_del->set_toggle_mode(true); curve_del->set_focus_mode(Control::FOCUS_NONE); curve_del->set_tooltip(TTR("Delete Point")); - curve_del->connect("pressed", this, "_mode_selected", varray(MODE_DELETE)); + curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(MODE_DELETE)); base_hb->add_child(curve_del); - curve_close = memnew(ToolButton); - curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveClose", "EditorIcons")); + curve_close = memnew(Button); + curve_close->set_flat(true); + curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons")); curve_close->set_focus_mode(Control::FOCUS_NONE); curve_close->set_tooltip(TTR("Close Curve")); - curve_close->connect("pressed", this, "_mode_selected", varray(ACTION_CLOSE)); + curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected), varray(ACTION_CLOSE)); base_hb->add_child(curve_close); PopupMenu *menu; @@ -596,7 +583,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) { menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); menu->add_check_item(TTR("Mirror Handle Lengths")); menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); - menu->connect("id_pressed", this, "_handle_option_pressed"); + menu->connect("id_pressed", callable_mp(this, &Path2DEditor::_handle_option_pressed)); base_hb->hide(); @@ -604,31 +591,26 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) { } void Path2DEditorPlugin::edit(Object *p_object) { - path2d_editor->edit(Object::cast_to<Node>(p_object)); } bool Path2DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("Path2D"); } void Path2DEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { path2d_editor->show(); path2d_editor->base_hb->show(); } else { - path2d_editor->hide(); path2d_editor->base_hb->hide(); - path2d_editor->edit(NULL); + path2d_editor->edit(nullptr); } } Path2DEditorPlugin::Path2DEditorPlugin(EditorNode *p_node) { - editor = p_node; path2d_editor = memnew(Path2DEditor(p_node)); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(path2d_editor); diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index aae0e11c99..6a7dffc7f8 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -34,12 +34,10 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "scene/2d/path_2d.h" -#include "scene/gui/tool_button.h" class CanvasItemEditor; class Path2DEditor : public HBoxContainer { - GDCLASS(Path2DEditor, HBoxContainer); UndoRedo *undo_redo; @@ -61,11 +59,11 @@ class Path2DEditor : public HBoxContainer { }; Mode mode; - ToolButton *curve_create; - ToolButton *curve_edit; - ToolButton *curve_edit_curve; - ToolButton *curve_del; - ToolButton *curve_close; + Button *curve_create; + Button *curve_edit; + Button *curve_edit_curve; + Button *curve_del; + Button *curve_close; MenuButton *handle_menu; bool mirror_handle_angle; @@ -112,21 +110,20 @@ public: }; class Path2DEditorPlugin : public EditorPlugin { - GDCLASS(Path2DEditorPlugin, EditorPlugin); Path2DEditor *path2d_editor; EditorNode *editor; public: - virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return path2d_editor->forward_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { path2d_editor->forward_canvas_draw_over_viewport(p_overlay); } - - virtual String get_name() const { return "Path2D"; } - 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); + virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return path2d_editor->forward_gui_input(p_event); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { path2d_editor->forward_canvas_draw_over_viewport(p_overlay); } + + virtual String get_name() const override { return "Path2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; Path2DEditorPlugin(EditorNode *p_node); ~Path2DEditorPlugin(); diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 67889bc074..f53130c24d 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* path_editor_plugin.cpp */ +/* path_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "path_editor_plugin.h" +#include "path_3d_editor_plugin.h" +#include "core/math/geometry_2d.h" +#include "core/math/geometry_3d.h" #include "core/os/keyboard.h" +#include "node_3d_editor_plugin.h" #include "scene/resources/curve.h" -#include "spatial_editor_plugin.h" - -String PathSpatialGizmo::get_handle_name(int p_idx) const { +String Path3DGizmo::get_handle_name(int p_idx) const { Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return ""; + } if (p_idx < c->get_point_count()) { - return TTR("Curve Point #") + itos(p_idx); } @@ -50,21 +51,22 @@ String PathSpatialGizmo::get_handle_name(int p_idx) const { int idx = p_idx / 2; int t = p_idx % 2; String n = TTR("Curve Point #") + itos(idx); - if (t == 0) + if (t == 0) { n += " In"; - else + } else { n += " Out"; + } return n; } -Variant PathSpatialGizmo::get_handle_value(int p_idx) { +Variant Path3DGizmo::get_handle_value(int p_idx) { Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return Variant(); + } if (p_idx < c->get_point_count()) { - original = c->get_point_position(p_idx); return original; } @@ -75,20 +77,22 @@ Variant PathSpatialGizmo::get_handle_value(int p_idx) { int t = p_idx % 2; Vector3 ofs; - if (t == 0) + if (t == 0) { ofs = c->get_point_in(idx); - else + } else { ofs = c->get_point_out(idx); + } original = ofs + c->get_point_position(idx); return ofs; } -void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void Path3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point) { Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return; + } Transform gt = path->get_global_transform(); Transform gi = gt.affine_inverse(); @@ -97,15 +101,13 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p // Setting curve point positions if (p_idx < c->get_point_count()) { - Plane p(gt.xform(original), p_camera->get_transform().basis.get_axis(2)); Vector3 inters; if (p.intersects_ray(ray_from, ray_dir, &inters)) { - - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - float snap = SpatialEditor::get_singleton()->get_translate_snap(); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + float snap = Node3DEditor::get_singleton()->get_translate_snap(); inters.snap(Vector3(snap, snap, snap)); } @@ -129,43 +131,42 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p // Setting curve in/out positions if (p.intersects_ray(ray_from, ray_dir, &inters)) { - - if (!PathEditorPlugin::singleton->is_handle_clicked()) { + if (!Path3DEditorPlugin::singleton->is_handle_clicked()) { orig_in_length = c->get_point_in(idx).length(); orig_out_length = c->get_point_out(idx).length(); - PathEditorPlugin::singleton->set_handle_clicked(true); + Path3DEditorPlugin::singleton->set_handle_clicked(true); } Vector3 local = gi.xform(inters) - base; - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - float snap = SpatialEditor::get_singleton()->get_translate_snap(); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + float snap = Node3DEditor::get_singleton()->get_translate_snap(); local.snap(Vector3(snap, snap, snap)); } if (t == 0) { c->set_point_in(idx, local); - if (PathEditorPlugin::singleton->mirror_angle_enabled()) - c->set_point_out(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length)); + if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) { + c->set_point_out(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length)); + } } else { c->set_point_out(idx, local); - if (PathEditorPlugin::singleton->mirror_angle_enabled()) - c->set_point_in(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_in_length)); + if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) { + c->set_point_in(idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_in_length)); + } } } } -void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - +void Path3DGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return; + } - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); if (p_idx < c->get_point_count()) { - if (p_cancel) { - c->set_point_position(p_idx, p_restore); return; } @@ -192,9 +193,9 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx)); ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore); - if (PathEditorPlugin::singleton->mirror_angle_enabled()) { - ur->add_do_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length)); - ur->add_undo_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length)); + if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) { + ur->add_do_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length)); + ur->add_undo_method(c.ptr(), "set_point_out", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length)); } ur->commit_action(); @@ -209,38 +210,38 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx)); ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore); - if (PathEditorPlugin::singleton->mirror_angle_enabled()) { - ur->add_do_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length)); - ur->add_undo_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length)); + if (Path3DEditorPlugin::singleton->mirror_angle_enabled()) { + ur->add_do_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length)); + ur->add_undo_method(c.ptr(), "set_point_in", idx, Path3DEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length)); } ur->commit_action(); } } -void PathSpatialGizmo::redraw() { - +void Path3DGizmo::redraw() { clear(); - Ref<SpatialMaterial> path_material = gizmo_plugin->get_material("path_material", this); - Ref<SpatialMaterial> path_thin_material = gizmo_plugin->get_material("path_thin_material", this); - Ref<SpatialMaterial> handles_material = gizmo_plugin->get_material("handles"); + Ref<StandardMaterial3D> path_material = gizmo_plugin->get_material("path_material", this); + Ref<StandardMaterial3D> path_thin_material = gizmo_plugin->get_material("path_thin_material", this); + Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles"); Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return; + } - PoolVector<Vector3> v3a = c->tessellate(); - //PoolVector<Vector3> v3a=c->get_baked_points(); + Vector<Vector3> v3a = c->tessellate(); + //Vector<Vector3> v3a=c->get_baked_points(); int v3s = v3a.size(); - if (v3s == 0) + if (v3s == 0) { return; + } Vector<Vector3> v3p; - PoolVector<Vector3>::Read r = v3a.read(); + const Vector3 *r = v3a.ptr(); // BUG: the following won't work when v3s, avoid drawing as a temporary workaround. for (int i = 0; i < v3s - 1; i++) { - v3p.push_back(r[i]); v3p.push_back(r[i + 1]); //v3p.push_back(r[i]); @@ -252,13 +253,12 @@ void PathSpatialGizmo::redraw() { add_collision_segments(v3p); } - if (PathEditorPlugin::singleton->get_edited_path() == path) { + if (Path3DEditorPlugin::singleton->get_edited_path() == path) { v3p.clear(); Vector<Vector3> handles; Vector<Vector3> sec_handles; for (int i = 0; i < c->get_point_count(); i++) { - Vector3 p = c->get_point_position(i); handles.push_back(p); if (i > 0) { @@ -286,19 +286,19 @@ void PathSpatialGizmo::redraw() { } } -PathSpatialGizmo::PathSpatialGizmo(Path *p_path) { - +Path3DGizmo::Path3DGizmo(Path3D *p_path) { path = p_path; set_spatial_node(p_path); } -bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { - - if (!path) +bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { + if (!path) { return false; + } Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return false; + } Transform gt = path->get_global_transform(); Transform it = gt.affine_inverse(); @@ -307,15 +307,15 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - Point2 mbpos(mb->get_position().x, mb->get_position().y); - if (!mb->is_pressed()) + if (!mb->is_pressed()) { set_handle_clicked(false); + } if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) { //click into curve, break it down - PoolVector<Vector3> v3a = c->tessellate(); + Vector<Vector3> v3a = c->tessellate(); int idx = 0; int rc = v3a.size(); int closest_seg = -1; @@ -323,19 +323,20 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp float closest_d = 1e20; if (rc >= 2) { - PoolVector<Vector3>::Read r = v3a.read(); + const Vector3 *r = v3a.ptr(); - if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) + if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) { return false; //nope, existing + } for (int i = 0; i < c->get_point_count() - 1; i++) { //find the offset and point index of the place to break up int j = idx; - if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist) + if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist) { return false; //nope, existing + } while (j < rc && c->get_point_position(i + 1) != r[j]) { - Vector3 from = r[j]; Vector3 to = r[j + 1]; real_t cdist = from.distance_to(to); @@ -345,31 +346,32 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp Vector2 s[2]; s[0] = p_camera->unproject_position(from); s[1] = p_camera->unproject_position(to); - Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos, s); + Vector2 inters = Geometry2D::get_closest_point_to_segment(mbpos, s); float d = inters.distance_to(mbpos); if (d < 10 && d < closest_d) { - closest_d = d; closest_seg = i; Vector3 ray_from = p_camera->project_ray_origin(mbpos); Vector3 ray_dir = p_camera->project_ray_normal(mbpos); Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb); + Geometry3D::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb); closest_seg_point = it.xform(rb); } } j++; } - if (idx == j) + if (idx == j) { idx++; //force next - else + } else { idx = j; //swap + } - if (j == rc) + if (j == rc) { break; + } } } @@ -384,19 +386,18 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp return true; } else { - Vector3 org; - if (c->get_point_count() == 0) + if (c->get_point_count() == 0) { org = path->get_transform().get_origin(); - else + } else { org = gt.xform(c->get_point_position(c->get_point_count() - 1)); + } Plane p(org, p_camera->get_transform().basis.get_axis(2)); Vector3 ray_from = p_camera->project_ray_origin(mbpos); Vector3 ray_dir = p_camera->project_ray_normal(mbpos); Vector3 inters; if (p.intersects_ray(ray_from, ray_dir, &inters)) { - ur->create_action(TTR("Add Point to Curve")); ur->add_do_method(c.ptr(), "add_point", it.xform(inters), Vector3(), Vector3(), -1); ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count()); @@ -408,7 +409,6 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp } } else if (mb->is_pressed() && ((mb->get_button_index() == BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == BUTTON_RIGHT && curve_edit->is_pressed()))) { - for (int i = 0; i < c->get_point_count(); i++) { real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos); real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos); @@ -417,7 +417,6 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp // Find the offset and point index of the place to break up. // Also check for the control points. if (dist_to_p < click_dist) { - UndoRedo *ur = editor->get_undo_redo(); ur->create_action(TTR("Remove Path Point")); ur->add_do_method(c.ptr(), "remove_point", i); @@ -425,7 +424,6 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp ur->commit_action(); return true; } else if (dist_to_p_out < click_dist) { - UndoRedo *ur = editor->get_undo_redo(); ur->create_action(TTR("Remove Out-Control Point")); ur->add_do_method(c.ptr(), "set_point_out", i, Vector3()); @@ -433,7 +431,6 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp ur->commit_action(); return true; } else if (dist_to_p_in < click_dist) { - UndoRedo *ur = editor->get_undo_redo(); ur->create_action(TTR("Remove In-Control Point")); ur->add_do_method(c.ptr(), "set_point_in", i, Vector3()); @@ -448,19 +445,17 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp return false; } -void PathEditorPlugin::edit(Object *p_object) { - +void Path3DEditorPlugin::edit(Object *p_object) { if (p_object) { - path = Object::cast_to<Path>(p_object); + path = Object::cast_to<Path3D>(p_object); if (path) { - if (path->get_curve().is_valid()) { path->get_curve()->emit_signal("changed"); } } } else { - Path *pre = path; - path = NULL; + Path3D *pre = path; + path = nullptr; if (pre) { pre->get_curve()->emit_signal("changed"); } @@ -468,15 +463,12 @@ void PathEditorPlugin::edit(Object *p_object) { //collision_polygon_editor->edit(Object::cast_to<Node>(p_object)); } -bool PathEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Path"); +bool Path3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Path3D"); } -void PathEditorPlugin::make_visible(bool p_visible) { - +void Path3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - curve_create->show(); curve_edit->show(); curve_del->show(); @@ -484,7 +476,6 @@ void PathEditorPlugin::make_visible(bool p_visible) { handle_menu->show(); sep->show(); } else { - curve_create->hide(); curve_edit->hide(); curve_del->hide(); @@ -493,8 +484,8 @@ void PathEditorPlugin::make_visible(bool p_visible) { sep->hide(); { - Path *pre = path; - path = NULL; + Path3D *pre = path; + path = nullptr; if (pre && pre->get_curve().is_valid()) { pre->get_curve()->emit_signal("changed"); } @@ -502,25 +493,24 @@ void PathEditorPlugin::make_visible(bool p_visible) { } } -void PathEditorPlugin::_mode_changed(int p_idx) { - +void Path3DEditorPlugin::_mode_changed(int p_idx) { curve_create->set_pressed(p_idx == 0); curve_edit->set_pressed(p_idx == 1); curve_del->set_pressed(p_idx == 2); } -void PathEditorPlugin::_close_curve() { - +void Path3DEditorPlugin::_close_curve() { Ref<Curve3D> c = path->get_curve(); - if (c.is_null()) + if (c.is_null()) { return; - if (c->get_point_count() < 2) + } + if (c->get_point_count() < 2) { return; + } c->add_point(c->get_point_position(0), c->get_point_in(0), c->get_point_out(0)); } -void PathEditorPlugin::_handle_option_pressed(int p_option) { - +void Path3DEditorPlugin::_handle_option_pressed(int p_option) { PopupMenu *pm; pm = handle_menu->get_popup(); @@ -539,82 +529,79 @@ void PathEditorPlugin::_handle_option_pressed(int p_option) { } } -void PathEditorPlugin::_notification(int p_what) { - +void Path3DEditorPlugin::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - - curve_create->connect("pressed", this, "_mode_changed", make_binds(0)); - curve_edit->connect("pressed", this, "_mode_changed", make_binds(1)); - curve_del->connect("pressed", this, "_mode_changed", make_binds(2)); - curve_close->connect("pressed", this, "_close_curve"); + curve_create->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(0)); + curve_edit->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(1)); + curve_del->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_mode_changed), make_binds(2)); + curve_close->connect("pressed", callable_mp(this, &Path3DEditorPlugin::_close_curve)); } } -void PathEditorPlugin::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_mode_changed"), &PathEditorPlugin::_mode_changed); - ClassDB::bind_method(D_METHOD("_close_curve"), &PathEditorPlugin::_close_curve); - ClassDB::bind_method(D_METHOD("_handle_option_pressed"), &PathEditorPlugin::_handle_option_pressed); +void Path3DEditorPlugin::_bind_methods() { } -PathEditorPlugin *PathEditorPlugin::singleton = NULL; +Path3DEditorPlugin *Path3DEditorPlugin::singleton = nullptr; -PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { - - path = NULL; +Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) { + path = nullptr; editor = p_node; singleton = this; mirror_handle_angle = true; mirror_handle_length = true; - Ref<PathSpatialGizmoPlugin> gizmo_plugin; + Ref<Path3DGizmoPlugin> gizmo_plugin; gizmo_plugin.instance(); - SpatialEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); + Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); sep = memnew(VSeparator); sep->hide(); - SpatialEditor::get_singleton()->add_control_to_menu_panel(sep); - curve_edit = memnew(ToolButton); - curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons")); + Node3DEditor::get_singleton()->add_control_to_menu_panel(sep); + curve_edit = memnew(Button); + curve_edit->set_flat(true); + curve_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons")); curve_edit->set_toggle_mode(true); curve_edit->hide(); curve_edit->set_focus_mode(Control::FOCUS_NONE); curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point")); - SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_edit); - curve_create = memnew(ToolButton); - curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons")); + Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit); + curve_create = memnew(Button); + curve_create->set_flat(true); + curve_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons")); curve_create->set_toggle_mode(true); curve_create->hide(); curve_create->set_focus_mode(Control::FOCUS_NONE); curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)")); - SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_create); - curve_del = memnew(ToolButton); - curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons")); + Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create); + curve_del = memnew(Button); + curve_del->set_flat(true); + curve_del->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons")); curve_del->set_toggle_mode(true); curve_del->hide(); curve_del->set_focus_mode(Control::FOCUS_NONE); curve_del->set_tooltip(TTR("Delete Point")); - SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_del); - curve_close = memnew(ToolButton); - curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveClose", "EditorIcons")); + Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del); + curve_close = memnew(Button); + curve_close->set_flat(true); + curve_close->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveClose", "EditorIcons")); curve_close->hide(); curve_close->set_focus_mode(Control::FOCUS_NONE); curve_close->set_tooltip(TTR("Close Curve")); - SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_close); + Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close); PopupMenu *menu; handle_menu = memnew(MenuButton); handle_menu->set_text(TTR("Options")); handle_menu->hide(); - SpatialEditor::get_singleton()->add_control_to_menu_panel(handle_menu); + Node3DEditor::get_singleton()->add_control_to_menu_panel(handle_menu); menu = handle_menu->get_popup(); menu->add_check_item(TTR("Mirror Handle Angles")); menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); menu->add_check_item(TTR("Mirror Handle Lengths")); menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); - menu->connect("id_pressed", this, "_handle_option_pressed"); + menu->connect("id_pressed", callable_mp(this, &Path3DEditorPlugin::_handle_option_pressed)); curve_edit->set_pressed(true); /* @@ -628,28 +615,29 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { */ } -PathEditorPlugin::~PathEditorPlugin() { +Path3DEditorPlugin::~Path3DEditorPlugin() { } -Ref<EditorSpatialGizmo> PathSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { - Ref<PathSpatialGizmo> ref; +Ref<EditorNode3DGizmo> Path3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { + Ref<Path3DGizmo> ref; - Path *path = Object::cast_to<Path>(p_spatial); - if (path) ref = Ref<PathSpatialGizmo>(memnew(PathSpatialGizmo(path))); + Path3D *path = Object::cast_to<Path3D>(p_spatial); + if (path) { + ref = Ref<Path3DGizmo>(memnew(Path3DGizmo(path))); + } return ref; } -String PathSpatialGizmoPlugin::get_name() const { - return "Path"; +String Path3DGizmoPlugin::get_name() const { + return "Path3D"; } -int PathSpatialGizmoPlugin::get_priority() const { +int Path3DGizmoPlugin::get_priority() const { return -1; } -PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { - +Path3DGizmoPlugin::Path3DGizmoPlugin() { Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); create_material("path_material", path_color); create_material("path_thin_material", Color(0.5, 0.5, 0.5)); diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h index 8ff83911f8..be275944a6 100644 --- a/editor/plugins/path_editor_plugin.h +++ b/editor/plugins/path_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* path_editor_plugin.h */ +/* path_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,55 +31,52 @@ #ifndef PATH_EDITOR_PLUGIN_H #define PATH_EDITOR_PLUGIN_H -#include "editor/spatial_editor_gizmos.h" -#include "scene/3d/path.h" +#include "editor/node_3d_editor_gizmos.h" +#include "scene/3d/path_3d.h" -class PathSpatialGizmo : public EditorSpatialGizmo { +class Path3DGizmo : public EditorNode3DGizmo { + GDCLASS(Path3DGizmo, EditorNode3DGizmo); - GDCLASS(PathSpatialGizmo, EditorSpatialGizmo); - - Path *path; + Path3D *path; mutable Vector3 original; mutable float orig_in_length; mutable float orig_out_length; public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx); - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + virtual String get_handle_name(int p_idx) const override; + virtual Variant get_handle_value(int p_idx) override; + virtual void set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point) override; + virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false) override; - virtual void redraw(); - PathSpatialGizmo(Path *p_path = NULL); + virtual void redraw() override; + Path3DGizmo(Path3D *p_path = nullptr); }; -class PathSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - - GDCLASS(PathSpatialGizmoPlugin, EditorSpatialGizmoPlugin); +class Path3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(Path3DGizmoPlugin, EditorNode3DGizmoPlugin); protected: - Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + Ref<EditorNode3DGizmo> create_gizmo(Node3D *p_spatial) override; public: - String get_name() const; - int get_priority() const; - PathSpatialGizmoPlugin(); + String get_name() const override; + int get_priority() const override; + Path3DGizmoPlugin(); }; -class PathEditorPlugin : public EditorPlugin { - - GDCLASS(PathEditorPlugin, EditorPlugin); +class Path3DEditorPlugin : public EditorPlugin { + GDCLASS(Path3DEditorPlugin, EditorPlugin); Separator *sep; - ToolButton *curve_create; - ToolButton *curve_edit; - ToolButton *curve_del; - ToolButton *curve_close; + Button *curve_create; + Button *curve_edit; + Button *curve_del; + Button *curve_close; MenuButton *handle_menu; EditorNode *editor; - Path *path; + Path3D *path; void _mode_changed(int p_idx); void _close_curve(); @@ -98,26 +95,24 @@ protected: static void _bind_methods(); public: - Path *get_edited_path() { return path; } + Path3D *get_edited_path() { return path; } - static PathEditorPlugin *singleton; - virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); + static Path3DEditorPlugin *singleton; + virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override; - //virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); } - //virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); - virtual String get_name() const { return "Path"; } - 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); + virtual String get_name() const override { return "Path3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; bool mirror_angle_enabled() { return mirror_handle_angle; } bool mirror_length_enabled() { return mirror_handle_length; } bool is_handle_clicked() { return handle_clicked; } void set_handle_clicked(bool clicked) { handle_clicked = clicked; } - PathEditorPlugin(EditorNode *p_node); - ~PathEditorPlugin(); + Path3DEditorPlugin(EditorNode *p_node); + ~Path3DEditorPlugin(); }; #endif // PATH_EDITOR_PLUGIN_H diff --git a/editor/plugins/physical_bone_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp index 28099a927b..30bf827b3c 100644 --- a/editor/plugins/physical_bone_plugin.cpp +++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* physical_bone_plugin.cpp */ +/* physical_bone_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,51 +28,46 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "physical_bone_plugin.h" -#include "editor/plugins/spatial_editor_plugin.h" -#include "scene/3d/physics_body.h" +#include "physical_bone_3d_editor_plugin.h" -void PhysicalBoneEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_on_toggle_button_transform_joint", "is_pressed"), &PhysicalBoneEditor::_on_toggle_button_transform_joint); -} +#include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/3d/physics_body_3d.h" -void PhysicalBoneEditor::_on_toggle_button_transform_joint(bool p_is_pressed) { +void PhysicalBone3DEditor::_bind_methods() { +} +void PhysicalBone3DEditor::_on_toggle_button_transform_joint(bool p_is_pressed) { _set_move_joint(); } -void PhysicalBoneEditor::_set_move_joint() { +void PhysicalBone3DEditor::_set_move_joint() { if (selected) { selected->_set_gizmo_move_joint(button_transform_joint->is_pressed()); } } -PhysicalBoneEditor::PhysicalBoneEditor(EditorNode *p_editor) : - editor(p_editor), - selected(NULL) { - +PhysicalBone3DEditor::PhysicalBone3DEditor(EditorNode *p_editor) : + editor(p_editor) { spatial_editor_hb = memnew(HBoxContainer); spatial_editor_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); spatial_editor_hb->set_alignment(BoxContainer::ALIGN_BEGIN); - SpatialEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb); + Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb); spatial_editor_hb->add_child(memnew(VSeparator)); - button_transform_joint = memnew(ToolButton); + button_transform_joint = memnew(Button); + button_transform_joint->set_flat(true); spatial_editor_hb->add_child(button_transform_joint); button_transform_joint->set_text(TTR("Move Joint")); - button_transform_joint->set_icon(SpatialEditor::get_singleton()->get_icon("PhysicalBone", "EditorIcons")); + button_transform_joint->set_icon(Node3DEditor::get_singleton()->get_theme_icon("PhysicalBone3D", "EditorIcons")); button_transform_joint->set_toggle_mode(true); - button_transform_joint->connect("toggled", this, "_on_toggle_button_transform_joint"); + button_transform_joint->connect("toggled", callable_mp(this, &PhysicalBone3DEditor::_on_toggle_button_transform_joint)); hide(); } -PhysicalBoneEditor::~PhysicalBoneEditor() {} - -void PhysicalBoneEditor::set_selected(PhysicalBone *p_pb) { - +void PhysicalBone3DEditor::set_selected(PhysicalBone3D *p_pb) { button_transform_joint->set_pressed(false); _set_move_joint(); @@ -80,33 +75,30 @@ void PhysicalBoneEditor::set_selected(PhysicalBone *p_pb) { _set_move_joint(); } -void PhysicalBoneEditor::hide() { +void PhysicalBone3DEditor::hide() { spatial_editor_hb->hide(); } -void PhysicalBoneEditor::show() { +void PhysicalBone3DEditor::show() { spatial_editor_hb->show(); } -PhysicalBonePlugin::PhysicalBonePlugin(EditorNode *p_editor) : +PhysicalBone3DEditorPlugin::PhysicalBone3DEditorPlugin(EditorNode *p_editor) : editor(p_editor), - selected(NULL), physical_bone_editor(editor) {} -void PhysicalBonePlugin::make_visible(bool p_visible) { +void PhysicalBone3DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - physical_bone_editor.show(); } else { - physical_bone_editor.hide(); - physical_bone_editor.set_selected(NULL); - selected = NULL; + physical_bone_editor.set_selected(nullptr); + selected = nullptr; } } -void PhysicalBonePlugin::edit(Object *p_node) { - selected = static_cast<PhysicalBone *>(p_node); // Trust it +void PhysicalBone3DEditorPlugin::edit(Object *p_node) { + selected = static_cast<PhysicalBone3D *>(p_node); // Trust it ERR_FAIL_COND(!selected); physical_bone_editor.set_selected(selected); diff --git a/editor/plugins/physical_bone_plugin.h b/editor/plugins/physical_bone_3d_editor_plugin.h index 459a67db05..bdfcca8878 100644 --- a/editor/plugins/physical_bone_plugin.h +++ b/editor/plugins/physical_bone_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* physical_bone_plugin.h */ +/* physical_bone_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,14 +33,14 @@ #include "editor/editor_node.h" -class PhysicalBoneEditor : public Object { - GDCLASS(PhysicalBoneEditor, Object); +class PhysicalBone3DEditor : public Object { + GDCLASS(PhysicalBone3DEditor, Object); EditorNode *editor; HBoxContainer *spatial_editor_hb; - ToolButton *button_transform_joint; + Button *button_transform_joint; - PhysicalBone *selected; + PhysicalBone3D *selected = nullptr; protected: static void _bind_methods(); @@ -50,29 +50,29 @@ private: void _set_move_joint(); public: - PhysicalBoneEditor(EditorNode *p_editor); - ~PhysicalBoneEditor(); + PhysicalBone3DEditor(EditorNode *p_editor); + ~PhysicalBone3DEditor() {} - void set_selected(PhysicalBone *p_pb); + void set_selected(PhysicalBone3D *p_pb); void hide(); void show(); }; -class PhysicalBonePlugin : public EditorPlugin { - GDCLASS(PhysicalBonePlugin, EditorPlugin); +class PhysicalBone3DEditorPlugin : public EditorPlugin { + GDCLASS(PhysicalBone3DEditorPlugin, EditorPlugin); EditorNode *editor; - PhysicalBone *selected; - PhysicalBoneEditor physical_bone_editor; + PhysicalBone3D *selected = nullptr; + PhysicalBone3DEditor physical_bone_editor; public: - virtual String get_name() const { return "PhysicalBone"; } - virtual bool handles(Object *p_object) const { return p_object->is_class("PhysicalBone"); } - virtual void make_visible(bool p_visible); - virtual void edit(Object *p_node); + virtual String get_name() const override { return "PhysicalBone3D"; } + virtual bool handles(Object *p_object) const override { return p_object->is_class("PhysicalBone3D"); } + virtual void make_visible(bool p_visible) override; + virtual void edit(Object *p_node) override; - PhysicalBonePlugin(EditorNode *p_editor); + PhysicalBone3DEditorPlugin(EditorNode *p_editor); }; #endif diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 35c0142d4b..dd1194d020 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -31,31 +31,28 @@ #include "polygon_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "core/input/input.h" +#include "core/math/geometry_2d.h" #include "core/os/file_access.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "scene/2d/skeleton_2d.h" Node2D *Polygon2DEditor::_get_node() const { - return node; } 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 { - return node->get_offset(); } int Polygon2DEditor::_get_polygon_count() const { - if (node->get_internal_vertex_count() > 0) { return 0; //do not edit if internal vertices exist } else { @@ -64,40 +61,35 @@ int Polygon2DEditor::_get_polygon_count() const { } void Polygon2DEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - - uv_edit_draw->add_style_override("panel", get_stylebox("bg", "Tree")); - bone_scroll->add_style_override("bg", get_stylebox("bg", "Tree")); + uv_edit_draw->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + bone_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree")); } break; case NOTIFICATION_READY: { - - button_uv->set_icon(get_icon("Uv", "EditorIcons")); - - uv_button[UV_MODE_CREATE]->set_icon(get_icon("Edit", "EditorIcons")); - uv_button[UV_MODE_CREATE_INTERNAL]->set_icon(get_icon("EditInternal", "EditorIcons")); - uv_button[UV_MODE_REMOVE_INTERNAL]->set_icon(get_icon("RemoveInternal", "EditorIcons")); - uv_button[UV_MODE_EDIT_POINT]->set_icon(get_icon("ToolSelect", "EditorIcons")); - uv_button[UV_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons")); - uv_button[UV_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons")); - uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); - uv_button[UV_MODE_ADD_POLYGON]->set_icon(get_icon("Edit", "EditorIcons")); - uv_button[UV_MODE_REMOVE_POLYGON]->set_icon(get_icon("Close", "EditorIcons")); - uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_icon("PaintVertex", "EditorIcons")); - uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_icon("UnpaintVertex", "EditorIcons")); - - b_snap_grid->set_icon(get_icon("Grid", "EditorIcons")); - b_snap_enable->set_icon(get_icon("SnapGrid", "EditorIcons")); - uv_icon_zoom->set_texture(get_icon("Zoom", "EditorIcons")); + button_uv->set_icon(get_theme_icon("Uv", "EditorIcons")); + + uv_button[UV_MODE_CREATE]->set_icon(get_theme_icon("Edit", "EditorIcons")); + uv_button[UV_MODE_CREATE_INTERNAL]->set_icon(get_theme_icon("EditInternal", "EditorIcons")); + uv_button[UV_MODE_REMOVE_INTERNAL]->set_icon(get_theme_icon("RemoveInternal", "EditorIcons")); + uv_button[UV_MODE_EDIT_POINT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + uv_button[UV_MODE_MOVE]->set_icon(get_theme_icon("ToolMove", "EditorIcons")); + uv_button[UV_MODE_ROTATE]->set_icon(get_theme_icon("ToolRotate", "EditorIcons")); + uv_button[UV_MODE_SCALE]->set_icon(get_theme_icon("ToolScale", "EditorIcons")); + uv_button[UV_MODE_ADD_POLYGON]->set_icon(get_theme_icon("Edit", "EditorIcons")); + uv_button[UV_MODE_REMOVE_POLYGON]->set_icon(get_theme_icon("Close", "EditorIcons")); + uv_button[UV_MODE_PAINT_WEIGHT]->set_icon(get_theme_icon("PaintVertex", "EditorIcons")); + uv_button[UV_MODE_CLEAR_WEIGHT]->set_icon(get_theme_icon("UnpaintVertex", "EditorIcons")); + + b_snap_grid->set_icon(get_theme_icon("Grid", "EditorIcons")); + b_snap_enable->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); + uv_icon_zoom->set_texture(get_theme_icon("Zoom", "EditorIcons")); uv_vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); uv_hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); } break; case NOTIFICATION_VISIBILITY_CHANGED: { - if (!is_visible()) { uv_edit->hide(); } @@ -106,11 +98,10 @@ void Polygon2DEditor::_notification(int p_what) { } void Polygon2DEditor::_sync_bones() { - - Skeleton2D *skeleton = NULL; + Skeleton2D *skeleton = nullptr; if (!node->has_node(node->get_skeleton())) { error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node")); - error->popup_centered_minsize(); + error->popup_centered(); } else { Node *sn = node->get_node(node->get_skeleton()); skeleton = Object::cast_to<Skeleton2D>(sn); @@ -121,16 +112,16 @@ void Polygon2DEditor::_sync_bones() { if (!skeleton) { error->set_text(TTR("The skeleton property of the Polygon2D does not point to a Skeleton2D node")); - error->popup_centered_minsize(); + error->popup_centered(); } else { for (int i = 0; i < skeleton->get_bone_count(); i++) { NodePath path = skeleton->get_path_to(skeleton->get_bone(i)); - PoolVector<float> weights; + Vector<float> weights; int wc = node->get_polygon().size(); for (int j = 0; j < prev_bones.size(); j += 2) { NodePath pvp = prev_bones[j]; - PoolVector<float> pv = prev_bones[j + 1]; + Vector<float> pv = prev_bones[j + 1]; if (pvp == path && pv.size() == wc) { weights = pv; } @@ -138,7 +129,7 @@ void Polygon2DEditor::_sync_bones() { if (weights.size() == 0) { //create them weights.resize(node->get_polygon().size()); - PoolVector<float>::Write w = weights.write(); + float *w = weights.ptrw(); for (int j = 0; j < wc; j++) { w[j] = 0.0; } @@ -161,7 +152,6 @@ void Polygon2DEditor::_sync_bones() { } void Polygon2DEditor::_update_bone_list() { - NodePath selected; while (bone_scroll_vb->get_child_count()) { CheckBox *cb = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(0)); @@ -189,10 +179,11 @@ void Polygon2DEditor::_update_bone_list() { cb->set_focus_mode(FOCUS_NONE); bone_scroll_vb->add_child(cb); - if (np == selected || bone_scroll_vb->get_child_count() < 2) + if (np == selected || bone_scroll_vb->get_child_count() < 2) { cb->set_pressed(true); + } - cb->connect("pressed", this, "_bone_paint_selected", varray(i)); + cb->connect("pressed", callable_mp(this, &Polygon2DEditor::_bone_paint_selected), varray(i)); } uv_edit_draw->update(); @@ -203,7 +194,6 @@ void Polygon2DEditor::_bone_paint_selected(int p_index) { } void Polygon2DEditor::_uv_edit_mode_select(int p_mode) { - if (p_mode == 0) { //uv uv_button[UV_MODE_CREATE]->hide(); @@ -274,27 +264,22 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) { } void Polygon2DEditor::_uv_edit_popup_hide() { - - EditorSettings::get_singleton()->set("interface/dialogs/uv_editor_bounds", uv_edit->get_rect()); + EditorSettings::get_singleton()->set("interface/dialogs/uv_editor_bounds", Rect2(uv_edit->get_position(), uv_edit->get_size())); _cancel_editing(); } void Polygon2DEditor::_menu_option(int p_option) { - switch (p_option) { - case MODE_EDIT_UV: { - if (node->get_texture().is_null()) { - error->set_text(TTR("No texture in this polygon.\nSet a texture to be able to edit UV.")); - error->popup_centered_minsize(); + error->popup_centered(); return; } - PoolVector<Vector2> points = node->get_polygon(); - PoolVector<Vector2> uvs = node->get_uv(); + Vector<Vector2> points = node->get_polygon(); + Vector<Vector2> uvs = node->get_uv(); if (uvs.size() != points.size()) { undo_redo->create_action(TTR("Create UV Map")); undo_redo->add_do_method(node, "set_uv", points); @@ -304,18 +289,19 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } - if (EditorSettings::get_singleton()->has_setting("interface/dialogs/uv_editor_bounds")) + if (EditorSettings::get_singleton()->has_setting("interface/dialogs/uv_editor_bounds")) { uv_edit->popup(EditorSettings::get_singleton()->get("interface/dialogs/uv_editor_bounds")); - else + } else { uv_edit->popup_centered_ratio(0.85); + } _update_bone_list(); } break; case UVEDIT_POLYGON_TO_UV: { - - PoolVector<Vector2> points = node->get_polygon(); - if (points.size() == 0) + Vector<Vector2> points = node->get_polygon(); + if (points.size() == 0) { break; - PoolVector<Vector2> uvs = node->get_uv(); + } + Vector<Vector2> uvs = node->get_uv(); undo_redo->create_action(TTR("Create UV Map")); undo_redo->add_do_method(node, "set_uv", points); undo_redo->add_undo_method(node, "set_uv", uvs); @@ -324,11 +310,11 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } break; case UVEDIT_UV_TO_POLYGON: { - - PoolVector<Vector2> points = node->get_polygon(); - PoolVector<Vector2> uvs = node->get_uv(); - if (uvs.size() == 0) + Vector<Vector2> points = node->get_polygon(); + Vector<Vector2> uvs = node->get_uv(); + if (uvs.size() == 0) { break; + } undo_redo->create_action(TTR("Create Polygon")); undo_redo->add_do_method(node, "set_polygon", uvs); @@ -338,30 +324,27 @@ void Polygon2DEditor::_menu_option(int p_option) { undo_redo->commit_action(); } break; case UVEDIT_UV_CLEAR: { - - PoolVector<Vector2> uvs = node->get_uv(); - if (uvs.size() == 0) + Vector<Vector2> uvs = node->get_uv(); + if (uvs.size() == 0) { break; + } undo_redo->create_action(TTR("Create UV Map")); - undo_redo->add_do_method(node, "set_uv", PoolVector<Vector2>()); + undo_redo->add_do_method(node, "set_uv", Vector<Vector2>()); undo_redo->add_undo_method(node, "set_uv", uvs); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); } break; case UVEDIT_GRID_SETTINGS: { - - grid_settings->popup_centered_minsize(); + grid_settings->popup_centered(); } break; default: { - AbstractPolygon2DEditor::_menu_option(p_option); } break; } } void Polygon2DEditor::_cancel_editing() { - if (uv_create) { uv_drag = false; uv_create = false; @@ -386,18 +369,18 @@ void Polygon2DEditor::_cancel_editing() { } void Polygon2DEditor::_update_polygon_editing_state() { - - if (!_get_node()) + if (!_get_node()) { return; + } - if (node->get_internal_vertex_count() > 0) + 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 + } else { disable_polygon_editing(false, String()); + } } void Polygon2DEditor::_commit_action() { - // 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"); @@ -442,7 +425,6 @@ void Polygon2DEditor::_set_snap_step_y(float p_val) { } void Polygon2DEditor::_uv_mode(int p_mode) { - polygon_create.clear(); uv_drag = false; uv_create = false; @@ -454,9 +436,9 @@ void Polygon2DEditor::_uv_mode(int p_mode) { } void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { - - if (!_get_node()) + if (!_get_node()) { return; + } Transform2D mtx; mtx.elements[2] = -uv_draw_ofs; @@ -465,11 +447,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_LEFT) { - if (mb->is_pressed()) { - uv_drag_from = snap_point(Vector2(mb->get_position().x, mb->get_position().y)); uv_drag = true; points_prev = node->get_uv(); @@ -482,9 +461,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_move_current = uv_mode; if (uv_move_current == UV_MODE_CREATE) { - if (!uv_create) { - points_prev.resize(0); Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y))); points_prev.push_back(tuv); @@ -506,10 +483,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_edit_draw->update(); } else { - Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y))); - if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < 8) { + // Close the polygon if selected point is near start. Threshold for closing scaled by zoom level + if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < (8 / uv_draw_zoom)) { undo_redo->create_action(TTR("Create Polygon & UV")); undo_redo->add_do_method(node, "set_uv", node->get_uv()); undo_redo->add_undo_method(node, "set_uv", uv_create_uv_prev); @@ -544,7 +521,6 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (uv_move_current == UV_MODE_CREATE_INTERNAL) { - uv_create_uv_prev = node->get_uv(); uv_create_poly_prev = node->get_polygon(); uv_create_colors_prev = node->get_vertex_colors(); @@ -567,7 +543,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_do_method(node, "set_vertex_colors", uv_create_colors_prev); undo_redo->add_undo_method(node, "set_vertex_colors", node->get_vertex_colors()); for (int i = 0; i < node->get_bone_count(); i++) { - PoolVector<float> bonew = node->get_bone_weights(i); + Vector<float> bonew = node->get_bone_weights(i); bonew.push_back(0); undo_redo->add_do_method(node, "set_bone_weights", i, bonew); undo_redo->add_undo_method(node, "set_bone_weights", i, node->get_bone_weights(i)); @@ -582,21 +558,20 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (uv_move_current == UV_MODE_REMOVE_INTERNAL) { - uv_create_uv_prev = node->get_uv(); uv_create_poly_prev = node->get_polygon(); uv_create_colors_prev = node->get_vertex_colors(); uv_create_bones_prev = node->call("_get_bones"); int internal_vertices = node->get_internal_vertex_count(); - if (internal_vertices <= 0) + if (internal_vertices <= 0) { return; + } int closest = -1; float closest_dist = 1e20; for (int i = points_prev.size() - internal_vertices; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(uv_create_poly_prev[i]); float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); if (dist < 8 && dist < closest_dist) { @@ -605,8 +580,9 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } - if (closest == -1) + if (closest == -1) { return; + } uv_create_poly_prev.remove(closest); uv_create_uv_prev.remove(closest); @@ -622,7 +598,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_do_method(node, "set_vertex_colors", uv_create_colors_prev); undo_redo->add_undo_method(node, "set_vertex_colors", node->get_vertex_colors()); for (int i = 0; i < node->get_bone_count(); i++) { - PoolVector<float> bonew = node->get_bone_weights(i); + Vector<float> bonew = node->get_bone_weights(i); bonew.remove(closest); undo_redo->add_do_method(node, "set_bone_weights", i, bonew); undo_redo->add_undo_method(node, "set_bone_weights", i, node->get_bone_weights(i)); @@ -637,20 +613,18 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (uv_move_current == UV_MODE_EDIT_POINT) { - - if (mb->get_shift() && mb->get_command()) + if (mb->get_shift() && mb->get_command()) { uv_move_current = UV_MODE_SCALE; - else if (mb->get_shift()) + } else if (mb->get_shift()) { uv_move_current = UV_MODE_MOVE; - else if (mb->get_command()) + } else if (mb->get_command()) { uv_move_current = UV_MODE_ROTATE; + } } if (uv_move_current == UV_MODE_EDIT_POINT) { - point_drag_index = -1; for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(points_prev[i]); if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) { uv_drag_from = tuv; @@ -664,12 +638,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (uv_move_current == UV_MODE_ADD_POLYGON) { - int closest = -1; float closest_dist = 1e20; for (int i = 0; i < points_prev.size(); i++) { - Vector2 tuv = mtx.xform(points_prev[i]); float dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)); if (dist < 8 && dist < closest_dist) { @@ -683,7 +655,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { //close if (polygon_create.size() < 3) { error->set_text(TTR("Invalid Polygon (need 3 different vertices)")); - error->popup_centered_minsize(); + error->popup_centered(); } else { Array polygons = node->get_polygons(); polygons = polygons.duplicate(); //copy because its a reference @@ -712,17 +684,18 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { int erase_index = -1; for (int i = polygons.size() - 1; i >= 0; i--) { - PoolVector<int> points = polygons[i]; + Vector<int> points = polygons[i]; Vector<Vector2> polys; polys.resize(points.size()); for (int j = 0; j < polys.size(); j++) { int idx = points[j]; - if (idx < 0 || idx >= points_prev.size()) + if (idx < 0 || idx >= points_prev.size()) { continue; + } polys.write[j] = mtx.xform(points_prev[idx]); } - if (Geometry::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) { + if (Geometry2D::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) { erase_index = i; break; } @@ -740,7 +713,6 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (uv_move_current == UV_MODE_PAINT_WEIGHT || uv_move_current == UV_MODE_CLEAR_WEIGHT) { - int bone_selected = -1; for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); @@ -751,57 +723,54 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == points_prev.size()) { - prev_weights = node->get_bone_weights(bone_selected); bone_painting = true; bone_painting_bone = bone_selected; } } + } else { + if (uv_drag && !uv_create) { + if (uv_edit_mode[0]->is_pressed()) { // Edit UV. + undo_redo->create_action(TTR("Transform UV Map")); + undo_redo->add_do_method(node, "set_uv", node->get_uv()); + undo_redo->add_undo_method(node, "set_uv", points_prev); + undo_redo->add_do_method(uv_edit_draw, "update"); + undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->commit_action(); + } else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon. + undo_redo->create_action(TTR("Transform Polygon")); + undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); + undo_redo->add_undo_method(node, "set_polygon", points_prev); + undo_redo->add_do_method(uv_edit_draw, "update"); + undo_redo->add_undo_method(uv_edit_draw, "update"); + undo_redo->commit_action(); + } - } else if (uv_drag && !uv_create) { + uv_drag = false; + } - if (uv_edit_mode[0]->is_pressed()) { // Edit UV. - undo_redo->create_action(TTR("Transform UV Map")); - undo_redo->add_do_method(node, "set_uv", node->get_uv()); - undo_redo->add_undo_method(node, "set_uv", points_prev); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); - undo_redo->commit_action(); - } else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon. - undo_redo->create_action(TTR("Transform Polygon")); - undo_redo->add_do_method(node, "set_polygon", node->get_polygon()); - undo_redo->add_undo_method(node, "set_polygon", points_prev); + if (bone_painting) { + undo_redo->create_action(TTR("Paint Bone Weights")); + undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone)); + undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); + bone_painting = false; } - - uv_drag = false; - } else if (bone_painting) { - - undo_redo->create_action(TTR("Paint Bone Weights")); - undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone)); - undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights); - undo_redo->add_do_method(uv_edit_draw, "update"); - undo_redo->add_undo_method(uv_edit_draw, "update"); - undo_redo->commit_action(); - bone_painting = false; } - } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { - _cancel_editing(); - if (bone_painting) + if (bone_painting) { node->set_bone_weights(bone_painting_bone, prev_weights); + } uv_edit_draw->update(); } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { - uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * mb->get_factor()))); } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { - uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * mb->get_factor()))); } } @@ -809,30 +778,24 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseMotion> mm = p_input; if (mm.is_valid()) { - if ((mm->get_button_mask() & BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - Vector2 drag(mm->get_relative().x, mm->get_relative().y); uv_hscroll->set_value(uv_hscroll->get_value() - drag.x); uv_vscroll->set_value(uv_vscroll->get_value() - drag.y); } else if (uv_drag) { - Vector2 uv_drag_to = mm->get_position(); uv_drag_to = snap_point(uv_drag_to); // FIXME: Only works correctly with 'UV_MODE_EDIT_POINT', it's imprecise with the rest. Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from); switch (uv_move_current) { - case UV_MODE_CREATE: { - if (uv_create) { uv_create_to = mtx.affine_inverse().xform(snap_point(Vector2(mm->get_position().x, mm->get_position().y))); } } break; case UV_MODE_EDIT_POINT: { - - PoolVector<Vector2> uv_new = points_prev; + Vector<Vector2> uv_new = points_prev; uv_new.set(point_drag_index, uv_new[point_drag_index] + drag); if (uv_edit_mode[0]->is_pressed()) { //edit uv @@ -842,10 +805,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } break; case UV_MODE_MOVE: { - - PoolVector<Vector2> uv_new = points_prev; - for (int i = 0; i < uv_new.size(); i++) + Vector<Vector2> uv_new = points_prev; + for (int i = 0; i < uv_new.size(); i++) { uv_new.set(i, uv_new[i] + drag); + } if (uv_edit_mode[0]->is_pressed()) { //edit uv node->set_uv(uv_new); @@ -854,12 +817,12 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } break; case UV_MODE_ROTATE: { - Vector2 center; - PoolVector<Vector2> uv_new = points_prev; + Vector<Vector2> uv_new = points_prev; - for (int i = 0; i < uv_new.size(); i++) + for (int i = 0; i < uv_new.size(); i++) { center += points_prev[i]; + } center /= uv_new.size(); float angle = (uv_drag_from - mtx.xform(center)).normalized().angle_to((uv_drag_to - mtx.xform(center)).normalized()); @@ -877,18 +840,19 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } } break; case UV_MODE_SCALE: { - Vector2 center; - PoolVector<Vector2> uv_new = points_prev; + Vector<Vector2> uv_new = points_prev; - for (int i = 0; i < uv_new.size(); i++) + for (int i = 0; i < uv_new.size(); i++) { center += points_prev[i]; + } center /= uv_new.size(); float from_dist = uv_drag_from.distance_to(mtx.xform(center)); float to_dist = uv_drag_to.distance_to(mtx.xform(center)); - if (from_dist < 2) + if (from_dist < 2) { break; + } float scale = to_dist / from_dist; @@ -906,7 +870,6 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } break; case UV_MODE_PAINT_WEIGHT: case UV_MODE_CLEAR_WEIGHT: { - bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); } break; default: { @@ -914,7 +877,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } if (bone_painting) { - PoolVector<float> painted_weights = node->get_bone_weights(bone_painting_bone); + Vector<float> painted_weights = node->get_bone_weights(bone_painting_bone); { int pc = painted_weights.size(); @@ -925,9 +888,9 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { amount = -amount; } - PoolVector<float>::Write w = painted_weights.write(); - PoolVector<float>::Read r = prev_weights.read(); - PoolVector<Vector2>::Read rv = points_prev.read(); + float *w = painted_weights.ptrw(); + const float *r = prev_weights.ptr(); + const Vector2 *rv = points_prev.ptr(); for (int i = 0; i < pc; i++) { if (mtx.xform(rv[i]).distance_to(bone_paint_pos) < radius) { @@ -952,22 +915,20 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { Ref<InputEventMagnifyGesture> magnify_gesture = p_input; if (magnify_gesture.is_valid()) { - uv_zoom->set_value(uv_zoom->get_value() * magnify_gesture->get_factor()); } Ref<InputEventPanGesture> pan_gesture = p_input; if (pan_gesture.is_valid()) { - uv_hscroll->set_value(uv_hscroll->get_value() + uv_hscroll->get_page() * pan_gesture->get_delta().x / 8); uv_vscroll->set_value(uv_vscroll->get_value() + uv_vscroll->get_page() * pan_gesture->get_delta().y / 8); } } void Polygon2DEditor::_uv_scroll_changed(float) { - - if (updating_uv_scroll) + if (updating_uv_scroll) { return; + } uv_draw_ofs.x = uv_hscroll->get_value(); uv_draw_ofs.y = uv_vscroll->get_value(); @@ -976,13 +937,14 @@ void Polygon2DEditor::_uv_scroll_changed(float) { } void Polygon2DEditor::_uv_draw() { - - if (!uv_edit->is_visible() || !_get_node()) + if (!uv_edit->is_visible() || !_get_node()) { return; + } - Ref<Texture> base_tex = node->get_texture(); - if (base_tex.is_null()) + Ref<Texture2D> base_tex = node->get_texture(); + if (base_tex.is_null()) { return; + } String warning; @@ -990,9 +952,9 @@ void Polygon2DEditor::_uv_draw() { mtx.elements[2] = -uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom)); - VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx); + RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), mtx); uv_edit_draw->draw_texture(base_tex, Point2()); - VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D()); + RS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(), Transform2D()); if (snap_show_grid) { Color grid_color = Color(1.0, 1.0, 1.0, 0.15); @@ -1002,10 +964,12 @@ void Polygon2DEditor::_uv_draw() { if (snap_step.x != 0) { for (int i = 0; i < s.width; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / snap_step.x)); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { uv_edit_draw->draw_line(Point2(i, 0), Point2(i, s.height), grid_color, Math::round(EDSCALE)); + } last_cell = cell; } } @@ -1013,10 +977,12 @@ void Polygon2DEditor::_uv_draw() { if (snap_step.y != 0) { for (int i = 0; i < s.height; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / snap_step.y)); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { uv_edit_draw->draw_line(Point2(0, i), Point2(s.width, i), grid_color, Math::round(EDSCALE)); + } last_cell = cell; } } @@ -1024,14 +990,14 @@ void Polygon2DEditor::_uv_draw() { Array polygons = node->get_polygons(); - PoolVector<Vector2> uvs; + Vector<Vector2> uvs; if (uv_edit_mode[0]->is_pressed()) { //edit uv uvs = node->get_uv(); } else { //edit polygon uvs = node->get_polygon(); } - PoolVector<float>::Read weight_r; + const float *weight_r = nullptr; if (uv_edit_mode[3]->is_pressed()) { int bone_selected = -1; @@ -1044,13 +1010,12 @@ void Polygon2DEditor::_uv_draw() { } if (bone_selected != -1 && node->get_bone_weights(bone_selected).size() == uvs.size()) { - - weight_r = node->get_bone_weights(bone_selected).read(); + weight_r = node->get_bone_weights(bone_selected).ptr(); } } // All UV points are sharp, so use the sharp handle icon - Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); + Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons"); Color poly_line_color = Color(0.9, 0.5, 0.5); if (polygons.size() || polygon_create.size()) { @@ -1074,11 +1039,10 @@ void Polygon2DEditor::_uv_draw() { } 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, Math::round(EDSCALE), true); + uv_edit_draw->draw_line(mtx.xform(points_prev[i]), mtx.xform(points_prev[next]), prev_color, Math::round(EDSCALE)); } Vector2 next_point = uvs[next]; @@ -1086,28 +1050,29 @@ void Polygon2DEditor::_uv_draw() { 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, Math::round(EDSCALE), true); + uv_edit_draw->draw_line(mtx.xform(uvs[i]), mtx.xform(next_point), poly_line_color, Math::round(EDSCALE)); } rect.expand_to(mtx.basis_xform(uvs[i])); } for (int i = 0; i < polygons.size(); i++) { - - PoolVector<int> points = polygons[i]; + Vector<int> points = polygons[i]; Vector<Vector2> polypoints; for (int j = 0; j < points.size(); j++) { int next = (j + 1) % points.size(); int idx = points[j]; int idx_next = points[next]; - if (idx < 0 || idx >= uvs.size()) + if (idx < 0 || idx >= uvs.size()) { continue; + } polypoints.push_back(mtx.xform(uvs[idx])); - if (idx_next < 0 || idx_next >= uvs.size()) + if (idx_next < 0 || idx_next >= uvs.size()) { continue; - uv_edit_draw->draw_line(mtx.xform(uvs[idx]), mtx.xform(uvs[idx_next]), polygon_line_color, Math::round(EDSCALE), true); + } + uv_edit_draw->draw_line(mtx.xform(uvs[idx]), mtx.xform(uvs[idx_next]), polygon_line_color, Math::round(EDSCALE)); } if (points.size() >= 3) { uv_edit_draw->draw_polygon(polypoints, polygon_fill_color); @@ -1115,8 +1080,7 @@ void Polygon2DEditor::_uv_draw() { } for (int i = 0; i < uvs.size(); i++) { - - if (weight_r.ptr()) { + if (weight_r) { Vector2 draw_pos = mtx.xform(uvs[i]); float weight = weight_r[i]; uv_edit_draw->draw_rect(Rect2(draw_pos - Vector2(2, 2) * EDSCALE, Vector2(5, 5) * EDSCALE), Color(weight, weight, weight, 1.0), Math::round(EDSCALE)); @@ -1134,12 +1098,11 @@ void Polygon2DEditor::_uv_draw() { 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), polygon_line_color, Math::round(EDSCALE), true); + uv_edit_draw->draw_line(mtx.xform(from), mtx.xform(to), polygon_line_color, Math::round(EDSCALE)); } } if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) { - NodePath bone_path; for (int i = 0; i < bone_scroll_vb->get_child_count(); i++) { CheckBox *c = Object::cast_to<CheckBox>(bone_scroll_vb->get_child(i)); @@ -1155,20 +1118,20 @@ void Polygon2DEditor::_uv_draw() { Skeleton2D *skeleton = Object::cast_to<Skeleton2D>(node->get_node(skeleton_path)); if (skeleton) { for (int i = 0; i < skeleton->get_bone_count(); i++) { - Bone2D *bone = skeleton->get_bone(i); - if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) + if (bone->get_rest() == Transform2D(0, 0, 0, 0, 0, 0)) { continue; //not set + } bool current = bone_path == skeleton->get_path_to(bone); bool found_child = false; for (int j = 0; j < bone->get_child_count(); j++) { - Bone2D *n = Object::cast_to<Bone2D>(bone->get_child(j)); - if (!n) + if (!n) { continue; + } found_child = true; @@ -1233,23 +1196,8 @@ void Polygon2DEditor::_uv_draw() { } void Polygon2DEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_uv_mode"), &Polygon2DEditor::_uv_mode); - ClassDB::bind_method(D_METHOD("_uv_draw"), &Polygon2DEditor::_uv_draw); - ClassDB::bind_method(D_METHOD("_uv_input"), &Polygon2DEditor::_uv_input); - ClassDB::bind_method(D_METHOD("_uv_scroll_changed"), &Polygon2DEditor::_uv_scroll_changed); - ClassDB::bind_method(D_METHOD("_set_use_snap"), &Polygon2DEditor::_set_use_snap); - ClassDB::bind_method(D_METHOD("_set_show_grid"), &Polygon2DEditor::_set_show_grid); - ClassDB::bind_method(D_METHOD("_set_snap_off_x"), &Polygon2DEditor::_set_snap_off_x); - ClassDB::bind_method(D_METHOD("_set_snap_off_y"), &Polygon2DEditor::_set_snap_off_y); - ClassDB::bind_method(D_METHOD("_set_snap_step_x"), &Polygon2DEditor::_set_snap_step_x); - ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &Polygon2DEditor::_set_snap_step_y); - ClassDB::bind_method(D_METHOD("_uv_edit_mode_select"), &Polygon2DEditor::_uv_edit_mode_select); - 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); } Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { @@ -1263,24 +1211,23 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { - - node = NULL; + node = nullptr; snap_offset = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_offset", Vector2()); snap_step = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_step", Vector2(10, 10)); use_snap = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "snap_enabled", false); snap_show_grid = EditorSettings::get_singleton()->get_project_metadata("polygon_2d_uv_editor", "show_grid", false); - button_uv = memnew(ToolButton); + button_uv = memnew(Button); + button_uv->set_flat(true); add_child(button_uv); button_uv->set_tooltip(TTR("Open Polygon 2D UV editor.")); - button_uv->connect("pressed", this, "_menu_option", varray(MODE_EDIT_UV)); + button_uv->connect("pressed", callable_mp(this, &Polygon2DEditor::_menu_option), varray(MODE_EDIT_UV)); uv_mode = UV_MODE_EDIT_POINT; uv_edit = memnew(AcceptDialog); add_child(uv_edit); uv_edit->set_title(TTR("Polygon 2D UV Editor")); - uv_edit->set_resizable(true); - uv_edit->connect("popup_hide", this, "_uv_edit_popup_hide"); + uv_edit->connect("cancelled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide)); VBoxContainer *uv_main_vb = memnew(VBoxContainer); uv_edit->add_child(uv_main_vb); @@ -1288,16 +1235,16 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_edit_group.instance(); - uv_edit_mode[0] = memnew(ToolButton); + uv_edit_mode[0] = memnew(Button); uv_mode_hb->add_child(uv_edit_mode[0]); uv_edit_mode[0]->set_toggle_mode(true); - uv_edit_mode[1] = memnew(ToolButton); + uv_edit_mode[1] = memnew(Button); uv_mode_hb->add_child(uv_edit_mode[1]); uv_edit_mode[1]->set_toggle_mode(true); - uv_edit_mode[2] = memnew(ToolButton); + uv_edit_mode[2] = memnew(Button); uv_mode_hb->add_child(uv_edit_mode[2]); uv_edit_mode[2]->set_toggle_mode(true); - uv_edit_mode[3] = memnew(ToolButton); + uv_edit_mode[3] = memnew(Button); uv_mode_hb->add_child(uv_edit_mode[3]); uv_edit_mode[3]->set_toggle_mode(true); @@ -1312,20 +1259,19 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_edit_mode[2]->set_button_group(uv_edit_group); uv_edit_mode[3]->set_button_group(uv_edit_group); - uv_edit_mode[0]->connect("pressed", this, "_uv_edit_mode_select", varray(0)); - uv_edit_mode[1]->connect("pressed", this, "_uv_edit_mode_select", varray(1)); - uv_edit_mode[2]->connect("pressed", this, "_uv_edit_mode_select", varray(2)); - uv_edit_mode[3]->connect("pressed", this, "_uv_edit_mode_select", varray(3)); + uv_edit_mode[0]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_edit_mode_select), varray(0)); + uv_edit_mode[1]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_edit_mode_select), varray(1)); + uv_edit_mode[2]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_edit_mode_select), varray(2)); + uv_edit_mode[3]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_edit_mode_select), varray(3)); uv_mode_hb->add_child(memnew(VSeparator)); uv_main_vb->add_child(uv_mode_hb); for (int i = 0; i < UV_MODE_MAX; i++) { - - uv_button[i] = memnew(ToolButton); + uv_button[i] = memnew(Button); uv_button[i]->set_toggle_mode(true); uv_mode_hb->add_child(uv_button[i]); - uv_button[i]->connect("pressed", this, "_uv_mode", varray(i)); + uv_button[i]->connect("pressed", callable_mp(this, &Polygon2DEditor::_uv_mode), varray(i)); uv_button[i]->set_focus_mode(FOCUS_NONE); } @@ -1388,27 +1334,29 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_menu->get_popup()->add_item(TTR("Clear UV"), UVEDIT_UV_CLEAR); uv_menu->get_popup()->add_separator(); uv_menu->get_popup()->add_item(TTR("Grid Settings"), UVEDIT_GRID_SETTINGS); - uv_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + uv_menu->get_popup()->connect("id_pressed", callable_mp(this, &Polygon2DEditor::_menu_option)); uv_mode_hb->add_child(memnew(VSeparator)); - b_snap_enable = memnew(ToolButton); + b_snap_enable = memnew(Button); + b_snap_enable->set_flat(true); uv_mode_hb->add_child(b_snap_enable); b_snap_enable->set_text(TTR("Snap")); b_snap_enable->set_focus_mode(FOCUS_NONE); b_snap_enable->set_toggle_mode(true); b_snap_enable->set_pressed(use_snap); b_snap_enable->set_tooltip(TTR("Enable Snap")); - b_snap_enable->connect("toggled", this, "_set_use_snap"); + b_snap_enable->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_use_snap)); - b_snap_grid = memnew(ToolButton); + b_snap_grid = memnew(Button); + b_snap_grid->set_flat(true); uv_mode_hb->add_child(b_snap_grid); b_snap_grid->set_text(TTR("Grid")); b_snap_grid->set_focus_mode(FOCUS_NONE); b_snap_grid->set_toggle_mode(true); b_snap_grid->set_pressed(snap_show_grid); b_snap_grid->set_tooltip(TTR("Show Grid")); - b_snap_grid->connect("toggled", this, "_set_show_grid"); + b_snap_grid->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_show_grid)); grid_settings = memnew(AcceptDialog); grid_settings->set_title(TTR("Configure Grid:")); @@ -1422,7 +1370,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_x->set_step(1); sb_off_x->set_value(snap_offset.x); sb_off_x->set_suffix("px"); - sb_off_x->connect("value_changed", this, "_set_snap_off_x"); + sb_off_x->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_off_x)); grid_settings_vb->add_margin_child(TTR("Grid Offset X:"), sb_off_x); SpinBox *sb_off_y = memnew(SpinBox); @@ -1431,7 +1379,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_off_y->set_step(1); sb_off_y->set_value(snap_offset.y); sb_off_y->set_suffix("px"); - sb_off_y->connect("value_changed", this, "_set_snap_off_y"); + sb_off_y->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_off_y)); grid_settings_vb->add_margin_child(TTR("Grid Offset Y:"), sb_off_y); SpinBox *sb_step_x = memnew(SpinBox); @@ -1440,7 +1388,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_x->set_step(1); sb_step_x->set_value(snap_step.x); sb_step_x->set_suffix("px"); - sb_step_x->connect("value_changed", this, "_set_snap_step_x"); + sb_step_x->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_step_x)); grid_settings_vb->add_margin_child(TTR("Grid Step X:"), sb_step_x); SpinBox *sb_step_y = memnew(SpinBox); @@ -1449,7 +1397,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sb_step_y->set_step(1); sb_step_y->set_value(snap_step.y); sb_step_y->set_suffix("px"); - sb_step_y->connect("value_changed", this, "_set_snap_step_y"); + sb_step_y->connect("value_changed", callable_mp(this, &Polygon2DEditor::_set_snap_step_y)); grid_settings_vb->add_margin_child(TTR("Grid Step Y:"), sb_step_y); uv_mode_hb->add_child(memnew(VSeparator)); @@ -1469,16 +1417,16 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_zoom->share(uv_zoom_value); uv_zoom_value->set_custom_minimum_size(Size2(50, 0)); uv_mode_hb->add_child(uv_zoom_value); - uv_zoom->connect("value_changed", this, "_uv_scroll_changed"); + uv_zoom->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); uv_vscroll = memnew(VScrollBar); uv_vscroll->set_step(0.001); uv_edit_draw->add_child(uv_vscroll); - uv_vscroll->connect("value_changed", this, "_uv_scroll_changed"); + uv_vscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); uv_hscroll = memnew(HScrollBar); uv_hscroll->set_step(0.001); uv_edit_draw->add_child(uv_hscroll); - uv_hscroll->connect("value_changed", this, "_uv_scroll_changed"); + uv_hscroll->connect("value_changed", callable_mp(this, &Polygon2DEditor::_uv_scroll_changed)); bone_scroll_main_vb = memnew(VBoxContainer); bone_scroll_main_vb->hide(); @@ -1486,7 +1434,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : sync_bones = memnew(Button(TTR("Sync Bones to Polygon"))); bone_scroll_main_vb->add_child(sync_bones); sync_bones->set_h_size_flags(0); - sync_bones->connect("pressed", this, "_sync_bones"); + sync_bones->connect("pressed", callable_mp(this, &Polygon2DEditor::_sync_bones)); uv_main_hsc->add_child(bone_scroll_main_vb); bone_scroll = memnew(ScrollContainer); bone_scroll->set_v_scroll(true); @@ -1496,8 +1444,8 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : bone_scroll_vb = memnew(VBoxContainer); bone_scroll->add_child(bone_scroll_vb); - uv_edit_draw->connect("draw", this, "_uv_draw"); - uv_edit_draw->connect("gui_input", this, "_uv_input"); + uv_edit_draw->connect("draw", callable_mp(this, &Polygon2DEditor::_uv_draw)); + uv_edit_draw->connect("gui_input", callable_mp(this, &Polygon2DEditor::_uv_input)); uv_draw_zoom = 1.0; point_drag_index = -1; uv_drag = false; diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 1454a03325..77580a5604 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -35,7 +35,6 @@ #include "scene/gui/scroll_container.h" class Polygon2DEditor : public AbstractPolygon2DEditor { - GDCLASS(Polygon2DEditor, AbstractPolygon2DEditor); enum Mode { @@ -61,16 +60,16 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { UV_MODE_MAX }; - ToolButton *uv_edit_mode[4]; + Button *uv_edit_mode[4]; Ref<ButtonGroup> uv_edit_group; Polygon2D *node; UVMode uv_mode; AcceptDialog *uv_edit; - ToolButton *uv_button[UV_MODE_MAX]; - ToolButton *b_snap_enable; - ToolButton *b_snap_grid; + Button *uv_button[UV_MODE_MAX]; + Button *b_snap_enable; + Button *b_snap_grid; Panel *uv_edit_draw; HSlider *uv_zoom; SpinBox *uv_zoom_value; @@ -88,7 +87,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Label *bone_paint_radius_label; bool bone_painting; int bone_painting_bone; - PoolVector<float> prev_weights; + Vector<float> prev_weights; Vector2 bone_paint_pos; AcceptDialog *grid_settings; @@ -97,10 +96,10 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { Vector2 uv_draw_ofs; float uv_draw_zoom; - PoolVector<Vector2> points_prev; - PoolVector<Vector2> uv_create_uv_prev; - PoolVector<Vector2> uv_create_poly_prev; - PoolVector<Color> uv_create_colors_prev; + Vector<Vector2> points_prev; + Vector<Vector2> uv_create_uv_prev; + Vector<Vector2> uv_create_poly_prev; + Vector<Color> uv_create_colors_prev; int uv_create_prev_internal_vertices; Array uv_create_bones_prev; Array polygons_prev; @@ -116,14 +115,14 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { AcceptDialog *error; - ToolButton *button_uv; + Button *button_uv; bool use_snap; bool snap_show_grid; Vector2 snap_offset; Vector2 snap_step; - virtual void _menu_option(int p_option); + virtual void _menu_option(int p_option) override; void _cancel_editing(); void _update_polygon_editing_state(); @@ -144,16 +143,16 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { void _uv_edit_popup_hide(); void _bone_paint_selected(int p_index); - int _get_polygon_count() const; + int _get_polygon_count() const override; protected: - virtual Node2D *_get_node() const; - virtual void _set_node(Node *p_polygon); + virtual Node2D *_get_node() const override; + virtual void _set_node(Node *p_polygon) override; - virtual Vector2 _get_offset(int p_idx) const; + virtual Vector2 _get_offset(int p_idx) const override; - virtual bool _has_uv() const { return true; }; - virtual void _commit_action(); + virtual bool _has_uv() const override { return true; }; + virtual void _commit_action() override; void _notification(int p_what); static void _bind_methods(); @@ -165,7 +164,6 @@ public: }; class Polygon2DEditorPlugin : public AbstractPolygon2DEditorPlugin { - GDCLASS(Polygon2DEditorPlugin, AbstractPolygon2DEditorPlugin); public: diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index fb04f50827..9ab5bfd8a3 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -39,13 +39,11 @@ void ResourcePreloaderEditor::_gui_input(Ref<InputEvent> p_event) { } void ResourcePreloaderEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - load->set_icon(get_icon("Folder", "EditorIcons")); + load->set_icon(get_theme_icon("Folder", "EditorIcons")); } if (p_what == NOTIFICATION_READY) { - //NodePath("/root")->connect("node_removed", this,"_node_removed",Vector<Variant>(),true); } @@ -54,9 +52,7 @@ void ResourcePreloaderEditor::_notification(int p_what) { } void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) { - for (int i = 0; i < p_paths.size(); i++) { - String path = p_paths[i]; RES resource; @@ -67,7 +63,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) dialog->set_title(TTR("Error!")); //dialog->get_cancel()->set_text("Close"); dialog->get_ok()->set_text(TTR("Close")); - dialog->popup_centered_minsize(); + dialog->popup_centered(); return; ///beh should show an error i guess } @@ -89,24 +85,23 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) } void ResourcePreloaderEditor::_load_pressed() { - loading_scene = false; file->clear_filters(); List<String> extensions; ResourceLoader::get_recognized_extensions_for_type("", &extensions); - for (int i = 0; i < extensions.size(); i++) + for (int i = 0; i < extensions.size(); i++) { file->add_filter("*." + extensions[i]); + } - file->set_mode(EditorFileDialog::MODE_OPEN_FILES); - - file->popup_centered_ratio(); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); + file->popup_file_dialog(); } void ResourcePreloaderEditor::_item_edited() { - - if (!tree->get_selected()) + if (!tree->get_selected()) { return; + } TreeItem *s = tree->get_selected(); @@ -114,11 +109,11 @@ void ResourcePreloaderEditor::_item_edited() { // renamed String old_name = s->get_metadata(0); String new_name = s->get_text(0); - if (old_name == new_name) + if (old_name == new_name) { return; + } if (new_name == "" || new_name.find("\\") != -1 || new_name.find("/") != -1 || preloader->has_resource(new_name)) { - s->set_text(0, old_name); return; } @@ -136,7 +131,6 @@ void ResourcePreloaderEditor::_item_edited() { } void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) { - undo_redo->create_action(TTR("Delete Resource")); undo_redo->add_do_method(preloader, "remove_resource", p_to_remove); undo_redo->add_undo_method(preloader, "add_resource", p_to_remove, preloader->get_resource(p_to_remove)); @@ -146,21 +140,22 @@ void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) { } void ResourcePreloaderEditor::_paste_pressed() { - RES r = EditorSettings::get_singleton()->get_resource_clipboard(); if (!r.is_valid()) { dialog->set_text(TTR("Resource clipboard is empty!")); dialog->set_title(TTR("Error!")); dialog->get_ok()->set_text(TTR("Close")); - dialog->popup_centered_minsize(); + dialog->popup_centered(); return; ///beh should show an error i guess } String name = r->get_name(); - if (name == "") + if (name == "") { name = r->get_path().get_file(); - if (name == "") + } + if (name == "") { name = r->get_class(); + } String basename = name; int counter = 1; @@ -178,10 +173,9 @@ void ResourcePreloaderEditor::_paste_pressed() { } void ResourcePreloaderEditor::_update_library() { - tree->clear(); tree->set_hide_root(true); - TreeItem *root = tree->create_item(NULL); + TreeItem *root = tree->create_item(nullptr); List<StringName> rnames; preloader->get_resource_list(&rnames); @@ -194,7 +188,6 @@ void ResourcePreloaderEditor::_update_library() { names.sort(); for (List<String>::Element *E = names.front(); E; E = E->next()) { - TreeItem *ti = tree->create_item(root); ti->set_cell_mode(0, TreeItem::CELL_MODE_STRING); ti->set_editable(0, true); @@ -215,18 +208,17 @@ void ResourcePreloaderEditor::_update_library() { ti->set_selectable(1, false); if (type == "PackedScene") { - ti->add_button(1, get_icon("InstanceOptions", "EditorIcons"), BUTTON_OPEN_SCENE, false, TTR("Open in Editor")); + ti->add_button(1, get_theme_icon("InstanceOptions", "EditorIcons"), BUTTON_OPEN_SCENE, false, TTR("Open in Editor")); } else { - ti->add_button(1, get_icon("Load", "EditorIcons"), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor")); + ti->add_button(1, get_theme_icon("Load", "EditorIcons"), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor")); } - ti->add_button(1, get_icon("Remove", "EditorIcons"), BUTTON_REMOVE, false, TTR("Remove")); + ti->add_button(1, get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE, false, TTR("Remove")); } //player->add_resource("default",resource); } void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) { - TreeItem *item = Object::cast_to<TreeItem>(p_item); ERR_FAIL_COND(!item); @@ -244,42 +236,42 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column, } void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) { - preloader = p_preloader; if (p_preloader) { _update_library(); } else { - hide(); set_physics_process(false); } } Variant ResourcePreloaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - TreeItem *ti = tree->get_item_at_position(p_point); - if (!ti) + if (!ti) { return Variant(); + } String name = ti->get_metadata(0); RES res = preloader->get_resource(name); - if (!res.is_valid()) + if (!res.is_valid()) { return Variant(); + } return EditorNode::get_singleton()->drag_resource(res, p_from); } bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return false; + } - if (d.has("from") && (Object *)(d["from"]) == tree) + if (d.has("from") && (Object *)(d["from"]) == tree) { return false; + } if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; @@ -288,7 +280,6 @@ bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Vari } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; return files.size() != 0; @@ -297,20 +288,20 @@ bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Vari } void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - - if (!can_drop_data_fw(p_point, p_data, p_from)) + if (!can_drop_data_fw(p_point, p_data, p_from)) { return; + } Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return; + } if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; if (r.is_valid()) { - String basename; if (r->get_name() != "") { basename = r->get_name(); @@ -337,7 +328,6 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; _files_load_request(files); @@ -345,14 +335,8 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant } void ResourcePreloaderEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &ResourcePreloaderEditor::_gui_input); - ClassDB::bind_method(D_METHOD("_load_pressed"), &ResourcePreloaderEditor::_load_pressed); - ClassDB::bind_method(D_METHOD("_item_edited"), &ResourcePreloaderEditor::_item_edited); - ClassDB::bind_method(D_METHOD("_paste_pressed"), &ResourcePreloaderEditor::_paste_pressed); - ClassDB::bind_method(D_METHOD("_files_load_request"), &ResourcePreloaderEditor::_files_load_request); ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library); - ClassDB::bind_method(D_METHOD("_cell_button_pressed"), &ResourcePreloaderEditor::_cell_button_pressed); ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw); @@ -361,7 +345,6 @@ void ResourcePreloaderEditor::_bind_methods() { } ResourcePreloaderEditor::ResourcePreloaderEditor() { - //add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("panel","Panel")); VBoxContainer *vbc = memnew(VBoxContainer); @@ -382,7 +365,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { add_child(file); tree = memnew(Tree); - tree->connect("button_pressed", this, "_cell_button_pressed"); + tree->connect("button_pressed", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed)); tree->set_columns(2); tree->set_column_min_width(0, 2); tree->set_column_min_width(1, 3); @@ -396,39 +379,37 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { dialog = memnew(AcceptDialog); add_child(dialog); - load->connect("pressed", this, "_load_pressed"); - paste->connect("pressed", this, "_paste_pressed"); - file->connect("files_selected", this, "_files_load_request"); - tree->connect("item_edited", this, "_item_edited"); + load->connect("pressed", callable_mp(this, &ResourcePreloaderEditor::_load_pressed)); + paste->connect("pressed", callable_mp(this, &ResourcePreloaderEditor::_paste_pressed)); + file->connect("files_selected", callable_mp(this, &ResourcePreloaderEditor::_files_load_request)); + tree->connect("item_edited", callable_mp(this, &ResourcePreloaderEditor::_item_edited)); loading_scene = false; } void ResourcePreloaderEditorPlugin::edit(Object *p_object) { - preloader_editor->set_undo_redo(&get_undo_redo()); ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object); - if (!s) + if (!s) { return; + } preloader_editor->edit(s); } bool ResourcePreloaderEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("ResourcePreloader"); } void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { //preloader_editor->show(); button->show(); editor->make_bottom_panel_item_visible(preloader_editor); //preloader_editor->set_process(true); } else { - - if (preloader_editor->is_visible_in_tree()) + if (preloader_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } button->hide(); //preloader_editor->hide(); //preloader_editor->set_process(false); @@ -436,7 +417,6 @@ void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) { } ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node) { - editor = p_node; preloader_editor = memnew(ResourcePreloaderEditor); preloader_editor->set_custom_minimum_size(Size2(0, 250) * EDSCALE); diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h index 88e9cf4956..ddfb54c40b 100644 --- a/editor/plugins/resource_preloader_editor_plugin.h +++ b/editor/plugins/resource_preloader_editor_plugin.h @@ -39,7 +39,6 @@ #include "scene/main/resource_preloader.h" class ResourcePreloaderEditor : public PanelContainer { - GDCLASS(ResourcePreloaderEditor, PanelContainer); enum { @@ -87,7 +86,6 @@ public: }; class ResourcePreloaderEditorPlugin : public EditorPlugin { - GDCLASS(ResourcePreloaderEditorPlugin, EditorPlugin); ResourcePreloaderEditor *preloader_editor; @@ -95,11 +93,11 @@ class ResourcePreloaderEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "ResourcePreloader"; } - 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); + virtual String get_name() const override { return "ResourcePreloader"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; ResourcePreloaderEditorPlugin(EditorNode *p_node); ~ResourcePreloaderEditorPlugin(); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 3489537fa4..e107435373 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -30,13 +30,13 @@ #include "root_motion_editor_plugin.h" #include "editor/editor_node.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" void EditorPropertyRootMotion::_confirmed() { - TreeItem *ti = filters->get_selected(); - if (!ti) + if (!ti) { return; + } NodePath path = ti->get_metadata(0); emit_changed(get_edited_property(), path); @@ -45,7 +45,6 @@ void EditorPropertyRootMotion::_confirmed() { } void EditorPropertyRootMotion::_node_assign() { - NodePath current = get_edited_object()->get(get_edited_property()); AnimationTree *atree = Object::cast_to<AnimationTree>(get_edited_object()); @@ -72,7 +71,6 @@ void EditorPropertyRootMotion::_node_assign() { player->get_animation_list(&animations); for (List<StringName>::Element *E = animations.front(); E; E = E->next()) { - Ref<Animation> anim = player->get_animation(E->get()); for (int i = 0; i < anim->get_track_count(); i++) { paths.insert(anim->track_get_path(i)); @@ -86,9 +84,8 @@ void EditorPropertyRootMotion::_node_assign() { Map<String, TreeItem *> parenthood; for (Set<String>::Element *E = paths.front(); E; E = E->next()) { - NodePath path = E->get(); - TreeItem *ti = NULL; + TreeItem *ti = nullptr; String accum; for (int i = 0; i < path.get_name_count(); i++) { String name = path.get_name(i); @@ -117,18 +114,18 @@ void EditorPropertyRootMotion::_node_assign() { } } - Node *node = NULL; + Node *node = nullptr; if (base->has_node(accum)) { node = base->get_node(accum); } - if (!node) + if (!node) { continue; //no node, can't edit + } if (path.get_subname_count()) { - String concat = path.get_concatenated_subnames(); - Skeleton *skeleton = Object::cast_to<Skeleton>(node); + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); if (skeleton && skeleton->find_bone(concat) != -1) { //path in skeleton const String &bone = concat; @@ -152,7 +149,7 @@ void EditorPropertyRootMotion::_node_assign() { ti->set_text(0, F->get()); ti->set_selectable(0, true); ti->set_editable(0, false); - ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons")); ti->set_metadata(0, accum); } else { ti = parenthood[accum]; @@ -161,7 +158,7 @@ void EditorPropertyRootMotion::_node_assign() { ti->set_selectable(0, true); ti->set_text(0, concat); - ti->set_icon(0, get_icon("BoneAttachment", "EditorIcons")); + ti->set_icon(0, get_theme_icon("BoneAttachment3D", "EditorIcons")); ti->set_metadata(0, path); if (path == current) { ti->select(0); @@ -194,25 +191,23 @@ void EditorPropertyRootMotion::_node_assign() { } void EditorPropertyRootMotion::_node_clear() { - emit_changed(get_edited_property(), NodePath()); update_property(); } void EditorPropertyRootMotion::update_property() { - NodePath p = get_edited_object()->get(get_edited_property()); assign->set_tooltip(p); if (p == NodePath()) { - assign->set_icon(Ref<Texture>()); + assign->set_icon(Ref<Texture2D>()); assign->set_text(TTR("Assign...")); assign->set_flat(false); return; } assign->set_flat(true); - Node *base_node = NULL; + Node *base_node = nullptr; if (base_hint != NodePath()) { if (get_tree()->get_root()->has_node(base_hint)) { base_node = get_tree()->get_root()->get_node(base_hint); @@ -222,7 +217,7 @@ void EditorPropertyRootMotion::update_property() { } if (!base_node || !base_node->has_node(p)) { - assign->set_icon(Ref<Texture>()); + assign->set_icon(Ref<Texture2D>()); assign->set_text(p); return; } @@ -235,53 +230,47 @@ void EditorPropertyRootMotion::update_property() { } void EditorPropertyRootMotion::setup(const NodePath &p_base_hint) { - base_hint = p_base_hint; } void EditorPropertyRootMotion::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - Ref<Texture> t = get_icon("Clear", "EditorIcons"); + Ref<Texture2D> t = get_theme_icon("Clear", "EditorIcons"); clear->set_icon(t); } } void EditorPropertyRootMotion::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_confirmed"), &EditorPropertyRootMotion::_confirmed); - ClassDB::bind_method(D_METHOD("_node_assign"), &EditorPropertyRootMotion::_node_assign); - ClassDB::bind_method(D_METHOD("_node_clear"), &EditorPropertyRootMotion::_node_clear); } EditorPropertyRootMotion::EditorPropertyRootMotion() { - HBoxContainer *hbc = memnew(HBoxContainer); add_child(hbc); assign = memnew(Button); assign->set_flat(true); assign->set_h_size_flags(SIZE_EXPAND_FILL); assign->set_clip_text(true); - assign->connect("pressed", this, "_node_assign"); + assign->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_assign)); hbc->add_child(assign); clear = memnew(Button); clear->set_flat(true); - clear->connect("pressed", this, "_node_clear"); + clear->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_clear)); hbc->add_child(clear); filter_dialog = memnew(ConfirmationDialog); add_child(filter_dialog); filter_dialog->set_title(TTR("Edit Filtered Tracks:")); - filter_dialog->connect("confirmed", this, "_confirmed"); + filter_dialog->connect("confirmed", callable_mp(this, &EditorPropertyRootMotion::_confirmed)); filters = memnew(Tree); filter_dialog->add_child(filters); filters->set_v_size_flags(SIZE_EXPAND_FILL); filters->set_hide_root(true); - filters->connect("item_activated", this, "_confirmed"); + filters->connect("item_activated", callable_mp(this, &EditorPropertyRootMotion::_confirmed)); //filters->connect("item_edited", this, "_filter_edited"); } + ////////////////////////// bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) { @@ -292,8 +281,7 @@ void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) { //do none } -bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { - +bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) { EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion); if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) { diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h index 8a7691de5d..cc19228470 100644 --- a/editor/plugins/root_motion_editor_plugin.h +++ b/editor/plugins/root_motion_editor_plugin.h @@ -54,7 +54,7 @@ protected: void _notification(int p_what); public: - virtual void update_property(); + virtual void update_property() override; void setup(const NodePath &p_base_hint); EditorPropertyRootMotion(); }; @@ -63,10 +63,10 @@ class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin { GDCLASS(EditorInspectorRootMotionPlugin, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); - virtual void parse_end(); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual void parse_end() override; }; #endif // ROOT_MOTION_EDITOR_PLUGIN_H diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index f13abd47a9..be8ddf789b 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -30,12 +30,13 @@ #include "script_editor_plugin.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" #include "core/os/file_access.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/project_settings.h" +#include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_run_script.h" #include "editor/editor_scale.h" @@ -44,16 +45,174 @@ #include "editor/find_in_files.h" #include "editor/node_dock.h" #include "editor/plugins/shader_editor_plugin.h" -#include "editor/script_editor_debugger.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/scene_string_names.h" #include "script_text_editor.h" +#include "servers/display_server.h" #include "text_editor.h" +/*** SYNTAX HIGHLIGHTER ****/ + +String EditorSyntaxHighlighter::_get_name() const { + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_get_name")) { + return si->call("_get_name"); + } + return "Unnamed"; +} + +Array EditorSyntaxHighlighter::_get_supported_languages() const { + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_get_supported_languages")) { + return si->call("_get_supported_languages"); + } + return Array(); +} + +Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const { + Ref<EditorSyntaxHighlighter> syntax_highlighter; + syntax_highlighter.instance(); + if (get_script_instance()) { + syntax_highlighter->set_script(get_script_instance()->get_script()); + } + return syntax_highlighter; +} + +void EditorSyntaxHighlighter::_bind_methods() { + ClassDB::bind_method(D_METHOD("_get_edited_resource"), &EditorSyntaxHighlighter::_get_edited_resource); + + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_supported_languages")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_supported_extentions")); +} + +//// + +void EditorStandardSyntaxHighlighter::_update_cache() { + highlighter->set_text_edit(text_edit); + highlighter->clear_keyword_colors(); + highlighter->clear_member_keyword_colors(); + highlighter->clear_color_regions(); + + highlighter->set_symbol_color(EDITOR_GET("text_editor/highlighting/symbol_color")); + highlighter->set_function_color(EDITOR_GET("text_editor/highlighting/function_color")); + highlighter->set_number_color(EDITOR_GET("text_editor/highlighting/number_color")); + highlighter->set_member_variable_color(EDITOR_GET("text_editor/highlighting/member_variable_color")); + + /* Engine types. */ + const Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); + List<StringName> types; + ClassDB::get_class_list(&types); + for (List<StringName>::Element *E = types.front(); E; E = E->next()) { + String n = E->get(); + if (n.begins_with("_")) { + n = n.substr(1, n.length()); + } + highlighter->add_keyword_color(n, type_color); + } + + /* User types. */ + const Color usertype_color = EDITOR_GET("text_editor/highlighting/user_type_color"); + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { + highlighter->add_keyword_color(E->get(), usertype_color); + } + + /* Autoloads. */ + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->value(); + if (info.is_singleton) { + highlighter->add_keyword_color(info.name, usertype_color); + } + } + + const Ref<Script> script = _get_edited_resource(); + if (script.is_valid()) { + /* Core types. */ + const Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); + List<String> core_types; + script->get_language()->get_core_type_words(&core_types); + for (List<String>::Element *E = core_types.front(); E; E = E->next()) { + highlighter->add_keyword_color(E->get(), basetype_color); + } + + /* Reserved words. */ + const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + List<String> keywords; + script->get_language()->get_reserved_words(&keywords); + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + highlighter->add_keyword_color(E->get(), keyword_color); + } + + /* Member types. */ + const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + StringName instance_base = script->get_instance_base_type(); + if (instance_base != StringName()) { + List<PropertyInfo> plist; + ClassDB::get_property_list(instance_base, &plist); + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + String name = E->get().name; + if (E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_SUBGROUP) { + continue; + } + if (name.find("/") != -1) { + continue; + } + highlighter->add_member_keyword_color(name, member_variable_color); + } + + List<String> clist; + ClassDB::get_integer_constant_list(instance_base, &clist); + for (List<String>::Element *E = clist.front(); E; E = E->next()) { + highlighter->add_member_keyword_color(E->get(), member_variable_color); + } + } + + /* Comments */ + const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + List<String> comments; + script->get_language()->get_comment_delimiters(&comments); + for (List<String>::Element *E = comments.front(); E; E = E->next()) { + String comment = E->get(); + String beg = comment.get_slice(" ", 0); + String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); + highlighter->add_color_region(beg, end, comment_color, end == ""); + } + + /* Strings */ + const Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); + List<String> strings; + script->get_language()->get_string_delimiters(&strings); + for (List<String>::Element *E = strings.front(); E; E = E->next()) { + String string = E->get(); + String beg = string.get_slice(" ", 0); + String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); + highlighter->add_color_region(beg, end, string_color, end == ""); + } + } +} + +Ref<EditorSyntaxHighlighter> EditorStandardSyntaxHighlighter::_create() const { + Ref<EditorStandardSyntaxHighlighter> syntax_highlighter; + syntax_highlighter.instance(); + return syntax_highlighter; +} + +//// + +Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const { + Ref<EditorPlainTextSyntaxHighlighter> syntax_highlighter; + syntax_highlighter.instance(); + return syntax_highlighter; +} + +//////////////////////////////////////////////////////////////////////////////// + /*** SCRIPT EDITOR ****/ void ScriptEditorBase::_bind_methods() { - ADD_SIGNAL(MethodInfo("name_changed")); ADD_SIGNAL(MethodInfo("edited_script_changed")); ADD_SIGNAL(MethodInfo("request_help", PropertyInfo(Variant::STRING, "topic"))); @@ -62,6 +221,9 @@ void ScriptEditorBase::_bind_methods() { ADD_SIGNAL(MethodInfo("go_to_help", PropertyInfo(Variant::STRING, "what"))); // TODO: This signal is no use for VisualScript. ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text"))); + ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text"))); + + BIND_VMETHOD(MethodInfo("add_syntax_highlighter", PropertyInfo(Variant::OBJECT, "highlighter"))); } static bool _is_built_in_script(Script *p_script) { @@ -71,7 +233,6 @@ static bool _is_built_in_script(Script *p_script) { } class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { - struct Cache { uint64_t time_loaded; RES cache; @@ -84,7 +245,6 @@ public: int max_cache_size; void cleanup() { - List<Map<String, Cache>::Element *> to_clean; Map<String, Cache>::Element *I = cached.front(); @@ -102,10 +262,8 @@ public: } virtual RES get_cached_resource(const String &p_path) { - Map<String, Cache>::Element *E = cached.find(p_path); if (!E) { - Cache c; c.cache = ResourceLoader::load(p_path); E = cached.insert(p_path, c); @@ -135,7 +293,6 @@ public: } EditorScriptCodeCompletionCache() { - max_cache_size = 128; max_time_cache = 5 * 60 * 1000; //minutes, five } @@ -144,61 +301,56 @@ public: }; void ScriptEditorQuickOpen::popup_dialog(const Vector<String> &p_functions, bool p_dontclear) { - popup_centered_ratio(0.6); - if (p_dontclear) + if (p_dontclear) { search_box->select_all(); - else + } else { search_box->clear(); + } search_box->grab_focus(); functions = p_functions; _update_search(); } void ScriptEditorQuickOpen::_text_changed(const String &p_newtext) { - _update_search(); } void ScriptEditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) { - Ref<InputEventKey> k = p_ie; - if (k.is_valid() && (k->get_scancode() == KEY_UP || - k->get_scancode() == KEY_DOWN || - k->get_scancode() == KEY_PAGEUP || - k->get_scancode() == KEY_PAGEDOWN)) { - + if (k.is_valid() && (k->get_keycode() == KEY_UP || + k->get_keycode() == KEY_DOWN || + k->get_keycode() == KEY_PAGEUP || + k->get_keycode() == KEY_PAGEDOWN)) { search_options->call("_gui_input", k); search_box->accept_event(); } } void ScriptEditorQuickOpen::_update_search() { - search_options->clear(); TreeItem *root = search_options->create_item(); for (int i = 0; i < functions.size(); i++) { - String file = functions[i]; if ((search_box->get_text() == "" || file.findn(search_box->get_text()) != -1)) { - TreeItem *ti = search_options->create_item(root); ti->set_text(0, file); - if (root->get_children() == ti) + if (root->get_children() == ti) { ti->select(0); + } } } - get_ok()->set_disabled(root->get_children() == NULL); + get_ok()->set_disabled(root->get_children() == nullptr); } void ScriptEditorQuickOpen::_confirmed() { - TreeItem *ti = search_options->get_selected(); - if (!ti) + if (!ti) { return; + } int line = ti->get_text(0).get_slice(":", 1).to_int(); emit_signal("goto_line", line - 1); @@ -206,82 +358,66 @@ void ScriptEditorQuickOpen::_confirmed() { } void ScriptEditorQuickOpen::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_ENTER_TREE: { - connect("confirmed", this, "_confirmed"); + connect("confirmed", callable_mp(this, &ScriptEditorQuickOpen::_confirmed)); search_box->set_clear_button_enabled(true); - FALLTHROUGH; + [[fallthrough]]; } - case NOTIFICATION_THEME_CHANGED: { - search_box->set_right_icon(get_icon("Search", "EditorIcons")); + case NOTIFICATION_VISIBILITY_CHANGED: { + search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons")); } break; case NOTIFICATION_EXIT_TREE: { - disconnect("confirmed", this, "_confirmed"); + disconnect("confirmed", callable_mp(this, &ScriptEditorQuickOpen::_confirmed)); } break; } } void ScriptEditorQuickOpen::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_text_changed"), &ScriptEditorQuickOpen::_text_changed); - ClassDB::bind_method(D_METHOD("_confirmed"), &ScriptEditorQuickOpen::_confirmed); - ClassDB::bind_method(D_METHOD("_sbox_input"), &ScriptEditorQuickOpen::_sbox_input); - ADD_SIGNAL(MethodInfo("goto_line", PropertyInfo(Variant::INT, "line"))); } ScriptEditorQuickOpen::ScriptEditorQuickOpen() { - VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); search_box = memnew(LineEdit); vbc->add_margin_child(TTR("Search:"), search_box); - search_box->connect("text_changed", this, "_text_changed"); - search_box->connect("gui_input", this, "_sbox_input"); + search_box->connect("text_changed", callable_mp(this, &ScriptEditorQuickOpen::_text_changed)); + search_box->connect("gui_input", callable_mp(this, &ScriptEditorQuickOpen::_sbox_input)); search_options = memnew(Tree); vbc->add_margin_child(TTR("Matches:"), search_options, true); get_ok()->set_text(TTR("Open")); get_ok()->set_disabled(true); register_text_enter(search_box); set_hide_on_ok(false); - search_options->connect("item_activated", this, "_confirmed"); + search_options->connect("item_activated", callable_mp(this, &ScriptEditorQuickOpen::_confirmed)); search_options->set_hide_root(true); search_options->set_hide_folding(true); - search_options->add_constant_override("draw_guides", 1); + search_options->add_theme_constant_override("draw_guides", 1); } ///////////////////////////////// -ScriptEditor *ScriptEditor::script_editor = NULL; +ScriptEditor *ScriptEditor::script_editor = nullptr; /*** SCRIPT EDITOR ******/ String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) { - - String val = debugger->get_var_value(p_text); + String val = EditorDebuggerNode::get_singleton()->get_var_value(p_text); if (val != String()) { return p_text + ": " + val; } else { - return String(); } } void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) { - if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { return; } - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), !(p_breaked && p_can_debug)); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_STEP), !(p_breaked && p_can_debug)); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_BREAK), p_breaked); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), !p_breaked); - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { continue; @@ -291,24 +427,18 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) { } } -void ScriptEditor::_show_debugger(bool p_show) { - - //debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), p_show); -} - void ScriptEditor::_script_created(Ref<Script> p_script) { editor->push_item(p_script.operator->()); } void ScriptEditor::_goto_script_line2(int p_line) { - ScriptEditorBase *current = _get_current_editor(); - if (current) + if (current) { current->goto_line(p_line); + } } void ScriptEditor::_goto_script_line(REF p_script, int p_line) { - Ref<Script> script = Object::cast_to<Script>(*p_script); if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { if (edit(p_script, p_line, 0)) { @@ -328,12 +458,12 @@ void ScriptEditor::_set_execution(REF p_script, int p_line) { Ref<Script> script = Object::cast_to<Script>(*p_script); if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } - if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { se->set_executing_line(p_line); } } @@ -344,12 +474,12 @@ void ScriptEditor::_clear_execution(REF p_script) { Ref<Script> script = Object::cast_to<Script>(*p_script); if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) { for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } - if ((script != NULL && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { + if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) { se->clear_executing_line(); } } @@ -357,32 +487,27 @@ void ScriptEditor::_clear_execution(REF p_script) { } ScriptEditorBase *ScriptEditor::_get_current_editor() const { - int selected = tab_container->get_current_tab(); - if (selected < 0 || selected >= tab_container->get_child_count()) - return NULL; + if (selected < 0 || selected >= tab_container->get_child_count()) { + return nullptr; + } return Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); } void ScriptEditor::_update_history_arrows() { - script_back->set_disabled(history_pos <= 0); script_forward->set_disabled(history_pos >= history.size() - 1); } void ScriptEditor::_save_history() { - if (history_pos >= 0 && history_pos < history.size() && history[history_pos].control == tab_container->get_current_tab_control()) { - Node *n = tab_container->get_current_tab_control(); if (Object::cast_to<ScriptEditorBase>(n)) { - history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } } @@ -399,29 +524,25 @@ void ScriptEditor::_save_history() { } void ScriptEditor::_go_to_tab(int p_idx) { - ScriptEditorBase *current = _get_current_editor(); if (current) { if (current->is_unsaved()) { - current->apply_code(); } } Control *c = Object::cast_to<Control>(tab_container->get_child(p_idx)); - if (!c) + if (!c) { return; + } if (history_pos >= 0 && history_pos < history.size() && history[history_pos].control == tab_container->get_current_tab_control()) { - Node *n = tab_container->get_current_tab_control(); if (Object::cast_to<ScriptEditorBase>(n)) { - history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } } @@ -439,25 +560,25 @@ void ScriptEditor::_go_to_tab(int p_idx) { c = tab_container->get_current_tab_control(); if (Object::cast_to<ScriptEditorBase>(c)) { - script_name_label->set_text(Object::cast_to<ScriptEditorBase>(c)->get_name()); - script_icon->set_texture(Object::cast_to<ScriptEditorBase>(c)->get_icon()); - if (is_visible_in_tree()) + script_icon->set_texture(Object::cast_to<ScriptEditorBase>(c)->get_theme_icon()); + if (is_visible_in_tree()) { Object::cast_to<ScriptEditorBase>(c)->ensure_focus(); + } Ref<Script> script = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource(); - if (script != NULL) { + if (script != nullptr) { notify_script_changed(script); } Object::cast_to<ScriptEditorBase>(c)->validate(); } if (Object::cast_to<EditorHelp>(c)) { - script_name_label->set_text(Object::cast_to<EditorHelp>(c)->get_class()); - script_icon->set_texture(get_icon("Help", "EditorIcons")); - if (is_visible_in_tree()) + script_icon->set_texture(get_theme_icon("Help", "EditorIcons")); + if (is_visible_in_tree()) { Object::cast_to<EditorHelp>(c)->set_focused(); + } } c->set_meta("__editor_pass", ++edit_pass); @@ -471,7 +592,6 @@ void ScriptEditor::_go_to_tab(int p_idx) { } void ScriptEditor::_add_recent_script(String p_path) { - if (p_path.empty()) { return; } @@ -490,13 +610,11 @@ void ScriptEditor::_add_recent_script(String p_path) { } void ScriptEditor::_update_recent_scripts() { - Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); recent_scripts->clear(); String path; for (int i = 0; i < rc.size(); i++) { - path = rc[i]; recent_scripts->add_item(path.replace("res://", "")); } @@ -508,7 +626,6 @@ void ScriptEditor::_update_recent_scripts() { } void ScriptEditor::_open_recent_script(int p_idx) { - // clear button if (p_idx == recent_scripts->get_item_count() - 1) { EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", Array()); @@ -567,28 +684,33 @@ void ScriptEditor::_open_recent_script(int p_idx) { } void ScriptEditor::_show_error_dialog(String p_path) { - error_dialog->set_text(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_path)); - error_dialog->popup_centered_minsize(); + error_dialog->popup_centered(); } void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { - int selected = p_idx; - if (selected < 0 || selected >= tab_container->get_child_count()) + if (selected < 0 || selected >= tab_container->get_child_count()) { return; + } Node *tselected = tab_container->get_child(selected); - ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); + ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected); if (current) { - if (p_save) { - apply_scripts(); - } - Ref<Script> script = current->get_edited_resource(); - if (script != NULL) { - previous_scripts.push_back(script->get_path()); + if (p_save && script.is_valid()) { + // Do not try to save internal scripts, but prompt to save in-memory + // scripts which are not saved to disk yet (have empty path). + if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { + _menu_option(FILE_SAVE); + } + } + if (script.is_valid()) { + if (!script->get_path().empty()) { + // Only saved scripts can be restored. + previous_scripts.push_back(script->get_path()); + } notify_script_close(script); } } @@ -618,10 +740,10 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { current->clear_edit_menu(); } memdelete(tselected); - if (idx >= tab_container->get_child_count()) + if (idx >= tab_container->get_child_count()) { idx = tab_container->get_child_count() - 1; + } if (idx >= 0) { - if (history_pos >= 0) { idx = history[history_pos].control->get_index(); } @@ -639,7 +761,6 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { } void ScriptEditor::_close_current_tab() { - _close_tab(tab_container->get_current_tab()); } @@ -649,10 +770,8 @@ void ScriptEditor::_close_discard_current_tab(const String &p_str) { } void ScriptEditor::_close_docs_tab() { - int child_count = tab_container->get_child_count(); for (int i = child_count - 1; i >= 0; i--) { - EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (se) { @@ -663,16 +782,16 @@ void ScriptEditor::_close_docs_tab() { void ScriptEditor::_copy_script_path() { ScriptEditorBase *se = _get_current_editor(); - RES script = se->get_edited_resource(); - OS::get_singleton()->set_clipboard(script->get_path()); + if (se) { + RES script = se->get_edited_resource(); + DisplayServer::get_singleton()->clipboard_set(script->get_path()); + } } void ScriptEditor::_close_other_tabs() { - int child_count = tab_container->get_child_count(); int current_idx = tab_container->get_current_tab(); for (int i = child_count - 1; i >= 0; i--) { - if (i == current_idx) { continue; } @@ -681,7 +800,6 @@ void ScriptEditor::_close_other_tabs() { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - // Maybe there are unsaved changes if (se->is_unsaved()) { _ask_close_current_unsaved_tab(se); @@ -694,15 +812,12 @@ void ScriptEditor::_close_other_tabs() { } void ScriptEditor::_close_all_tabs() { - int child_count = tab_container->get_child_count(); for (int i = child_count - 1; i >= 0; i--) { - tab_container->set_current_tab(i); ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - // Maybe there are unsaved changes if (se->is_unsaved()) { _ask_close_current_unsaved_tab(se); @@ -716,23 +831,23 @@ void ScriptEditor::_close_all_tabs() { void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) { erase_tab_confirm->set_text(TTR("Close and save changes?") + "\n\"" + current->get_name() + "\""); - erase_tab_confirm->popup_centered_minsize(); + erase_tab_confirm->popup_centered(); } void ScriptEditor::_resave_scripts(const String &p_str) { - apply_scripts(); for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } RES script = se->get_edited_resource(); - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) + if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { continue; //internal script, who cares + } if (trim_trailing_whitespace_on_save) { se->trim_trailing_whitespace(); @@ -749,7 +864,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) { } Ref<TextFile> text_file = script; - if (text_file != NULL) { + if (text_file != nullptr) { se->apply_code(); _save_text_file(text_file, text_file->get_path()); break; @@ -763,19 +878,15 @@ void ScriptEditor::_resave_scripts(const String &p_str) { } void ScriptEditor::_reload_scripts() { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { - continue; } RES edited_res = se->get_edited_resource(); if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { - continue; //internal script, who cares } @@ -787,7 +898,7 @@ void ScriptEditor::_reload_scripts() { } Ref<Script> script = edited_res; - if (script != NULL) { + if (script != nullptr) { Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); ERR_CONTINUE(!rel_script.is_valid()); script->set_source_code(rel_script->get_source_code()); @@ -796,7 +907,7 @@ void ScriptEditor::_reload_scripts() { } Ref<TextFile> text_file = edited_res; - if (text_file != NULL) { + if (text_file != nullptr) { Error err; Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); ERR_CONTINUE(!rel_text_file.is_valid()); @@ -811,12 +922,9 @@ void ScriptEditor::_reload_scripts() { } void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { - continue; } @@ -827,7 +935,6 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { } if (script == p_res) { - se->tag_saved_version(); } } @@ -842,11 +949,10 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { void ScriptEditor::_live_auto_reload_running_scripts() { pending_auto_reload = false; - debugger->reload_scripts(); + EditorDebuggerNode::get_singleton()->reload_scripts(); } bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { - disk_changed_list->clear(); TreeItem *r = disk_changed_list->create_item(); disk_changed_list->set_hide_root(true); @@ -856,22 +962,21 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { bool use_autoreload = bool(EDITOR_DEF("text_editor/files/auto_reload_scripts_on_external_change", false)); for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - RES edited_res = se->get_edited_resource(); - if (p_for_script.is_valid() && edited_res.is_valid() && p_for_script != edited_res) + if (p_for_script.is_valid() && edited_res.is_valid() && p_for_script != edited_res) { continue; + } - if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) + if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { continue; //internal script, who cares + } uint64_t last_date = edited_res->get_last_modified_time(); uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); if (last_date != date) { - TreeItem *ti = disk_changed_list->create_item(r); ti->set_text(0, edited_res->get_path().get_file()); @@ -896,22 +1001,19 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { } void ScriptEditor::_file_dialog_action(String p_file) { - switch (file_dialog_option) { case FILE_NEW_TEXTFILE: { Error err; FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err) { - memdelete(file); editor->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!")); break; } file->close(); memdelete(file); - FALLTHROUGH; + [[fallthrough]]; } case FILE_OPEN: { - List<String> extensions; ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); if (extensions.find(p_file.get_extension())) { @@ -941,17 +1043,19 @@ void ScriptEditor::_file_dialog_action(String p_file) { } break; case FILE_SAVE_AS: { ScriptEditorBase *current = _get_current_editor(); + if (current) { + RES resource = current->get_edited_resource(); + String path = ProjectSettings::get_singleton()->localize_path(p_file); + Error err = _save_text_file(resource, path); - String path = ProjectSettings::get_singleton()->localize_path(p_file); - Error err = _save_text_file(current->get_edited_resource(), path); + if (err != OK) { + editor->show_accept(TTR("Error saving file!"), TTR("OK")); + return; + } - if (err != OK) { - editor->show_accept(TTR("Error saving file!"), TTR("OK")); - return; + resource->set_path(path); + _update_script_names(); } - - ((Resource *)current->get_edited_resource().ptr())->set_path(path); - _update_script_names(); } break; case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { @@ -968,21 +1072,19 @@ void ScriptEditor::_file_dialog_action(String p_file) { } Ref<Script> ScriptEditor::_get_current_script() { - ScriptEditorBase *current = _get_current_editor(); if (current) { Ref<Script> script = current->get_edited_resource(); - return script != NULL ? script : NULL; + return script != nullptr ? script : nullptr; } else { - return NULL; + return nullptr; } } Array ScriptEditor::_get_open_scripts() const { - Array ret; - Vector<Ref<Script> > scripts = get_open_scripts(); + Vector<Ref<Script>> scripts = get_open_scripts(); int scrits_amount = scripts.size(); for (int idx_script = 0; idx_script < scrits_amount; idx_script++) { ret.push_back(scripts[idx_script]); @@ -1000,7 +1102,6 @@ bool ScriptEditor::is_scripts_panel_toggled() { } void ScriptEditor::_menu_option(int p_option) { - ScriptEditorBase *current = _get_current_editor(); switch (p_option) { case FILE_NEW: { @@ -1008,16 +1109,16 @@ void ScriptEditor::_menu_option(int p_option) { script_create_dialog->popup_centered(); } break; case FILE_NEW_TEXTFILE: { - file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_option = FILE_NEW_TEXTFILE; file_dialog->clear_filters(); - file_dialog->popup_centered_ratio(); + file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("New Text File...")); } break; case FILE_OPEN: { - file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_option = FILE_OPEN; @@ -1028,14 +1129,14 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } - file_dialog->popup_centered_ratio(); + file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("Open File")); return; } break; case FILE_REOPEN_CLOSED: { - - if (previous_scripts.empty()) + if (previous_scripts.empty()) { return; + } String path = previous_scripts.back()->get(); previous_scripts.pop_back(); @@ -1072,8 +1173,9 @@ void ScriptEditor::_menu_option(int p_option) { } else { Error error; Ref<TextFile> text_file = _load_text_file(path, &error); - if (error != OK) + if (error != OK) { editor->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!")); + } if (text_file.is_valid()) { edit(text_file); @@ -1083,62 +1185,34 @@ void ScriptEditor::_menu_option(int p_option) { } } break; case FILE_SAVE_ALL: { - - if (_test_script_times_on_disk()) + if (_test_script_times_on_disk()) { return; + } save_all_scripts(); } break; case SEARCH_IN_FILES: { - _on_find_in_files_requested(""); } break; + case REPLACE_IN_FILES: { + _on_replace_in_files_requested(""); + } break; case SEARCH_HELP: { - help_search_dialog->popup_dialog(); } break; case SEARCH_WEBSITE: { - 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: { - _history_forward(); } break; case WINDOW_PREV: { - _history_back(); } break; case WINDOW_SORT: { _sort_list_on_update = true; _update_script_names(); } break; - case DEBUG_SHOW: { - if (debugger) { - bool visible = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW)); - debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW), !visible); - if (visible) - debugger->hide(); - else - debugger->show(); - } - } break; - case DEBUG_SHOW_KEEP_OPEN: { - bool visible = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN)); - if (debugger) - debugger->set_hide_on_stop(visible); - debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN), !visible); - } break; - case DEBUG_WITH_EXTERNAL_EDITOR: { - bool debug_with_external_editor = !debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_WITH_EXTERNAL_EDITOR)); - debugger->set_debug_with_external_editor(debug_with_external_editor); - debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_WITH_EXTERNAL_EDITOR), debug_with_external_editor); - } break; case TOGGLE_SCRIPTS_PANEL: { if (current) { ScriptTextEditor *editor = Object::cast_to<ScriptTextEditor>(current); @@ -1153,15 +1227,15 @@ void ScriptEditor::_menu_option(int p_option) { } if (current) { - switch (p_option) { case FILE_SAVE: { - - if (_test_script_times_on_disk()) + if (_test_script_times_on_disk()) { return; + } - if (trim_trailing_whitespace_on_save) + if (trim_trailing_whitespace_on_save) { current->trim_trailing_whitespace(); + } current->insert_final_newline(); @@ -1173,19 +1247,20 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); - if (text_file != NULL) { + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; + if (text_file != nullptr) { current->apply_code(); _save_text_file(text_file, text_file->get_path()); break; } - editor->save_resource(current->get_edited_resource()); + editor->save_resource(resource); } break; case FILE_SAVE_AS: { - - if (trim_trailing_whitespace_on_save) + if (trim_trailing_whitespace_on_save) { current->trim_trailing_whitespace(); + } current->insert_final_newline(); @@ -1197,9 +1272,10 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); - if (text_file != NULL) { - file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; + if (text_file != nullptr) { + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_option = FILE_SAVE_AS; @@ -1208,26 +1284,24 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->clear_filters(); file_dialog->set_current_dir(text_file->get_path().get_base_dir()); file_dialog->set_current_file(text_file->get_path().get_file()); - file_dialog->popup_centered_ratio(); + file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("Save File As...")); break; } - editor->push_item(Object::cast_to<Object>(current->get_edited_resource().ptr())); - editor->save_resource_as(current->get_edited_resource()); + editor->push_item(resource.ptr()); + editor->save_resource_as(resource); } break; case FILE_TOOL_RELOAD: case FILE_TOOL_RELOAD_SOFT: { - current->reload(p_option == FILE_TOOL_RELOAD_SOFT); } break; case FILE_RUN: { - Ref<Script> scr = current->get_edited_resource(); - if (scr == NULL || scr.is_null()) { + if (scr == nullptr || scr.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Can't obtain the script for running.")); break; } @@ -1240,19 +1314,17 @@ void ScriptEditor::_menu_option(int p_option) { return; } if (!scr->is_tool()) { - EditorNode::get_singleton()->show_warning(TTR("Script is not in tool mode, will not be able to run.")); return; } if (!ClassDB::is_parent_class(scr->get_instance_base_type(), "EditorScript")) { - EditorNode::get_singleton()->show_warning(TTR("To run this script, it must inherit EditorScript and be set to tool mode.")); return; } Ref<EditorScript> es = memnew(EditorScript); - es->set_script(scr.get_ref_ptr()); + es->set_script(scr); es->set_editor(EditorNode::get_singleton()); es->_run(); @@ -1277,7 +1349,7 @@ void ScriptEditor::_menu_option(int p_option) { file_system_dock->navigate_to_path(path); // Ensure that the FileSystem dock is visible. TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control(); - tab_container->set_current_tab(file_system_dock->get_position_in_parent()); + tab_container->set_current_tab(file_system_dock->get_index()); } } break; case CLOSE_DOCS: { @@ -1289,31 +1361,7 @@ void ScriptEditor::_menu_option(int p_option) { case CLOSE_ALL: { _close_all_tabs(); } break; - case DEBUG_NEXT: { - - if (debugger) - debugger->debug_next(); - } break; - case DEBUG_STEP: { - - if (debugger) - debugger->debug_step(); - - } break; - case DEBUG_BREAK: { - - if (debugger) - debugger->debug_break(); - - } break; - case DEBUG_CONTINUE: { - - if (debugger) - debugger->debug_continue(); - - } break; case WINDOW_MOVE_UP: { - if (tab_container->get_current_tab() > 0) { tab_container->move_child(current, tab_container->get_current_tab() - 1); tab_container->set_current_tab(tab_container->get_current_tab() - 1); @@ -1321,7 +1369,6 @@ void ScriptEditor::_menu_option(int p_option) { } } break; case WINDOW_MOVE_DOWN: { - if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) { tab_container->move_child(current, tab_container->get_current_tab() + 1); tab_container->set_current_tab(tab_container->get_current_tab() + 1); @@ -1329,19 +1376,15 @@ void ScriptEditor::_menu_option(int p_option) { } } break; default: { - if (p_option >= WINDOW_SELECT_BASE) { - tab_container->set_current_tab(p_option - WINDOW_SELECT_BASE); _update_script_names(); } } } } else { - EditorHelp *help = Object::cast_to<EditorHelp>(tab_container->get_current_tab_control()); if (help) { - switch (p_option) { case HELP_SEARCH_FIND: { help->popup_search(); @@ -1365,7 +1408,6 @@ void ScriptEditor::_menu_option(int p_option) { _close_all_tabs(); } break; case WINDOW_MOVE_UP: { - if (tab_container->get_current_tab() > 0) { tab_container->move_child(help, tab_container->get_current_tab() - 1); tab_container->set_current_tab(tab_container->get_current_tab() - 1); @@ -1373,7 +1415,6 @@ void ScriptEditor::_menu_option(int p_option) { } } break; case WINDOW_MOVE_DOWN: { - if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) { tab_container->move_child(help, tab_container->get_current_tab() + 1); tab_container->set_current_tab(tab_container->get_current_tab() + 1); @@ -1388,12 +1429,12 @@ void ScriptEditor::_menu_option(int p_option) { void ScriptEditor::_theme_option(int p_option) { switch (p_option) { case THEME_IMPORT: { - file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_option = THEME_IMPORT; file_dialog->clear_filters(); file_dialog->add_filter("*.tet"); - file_dialog->popup_centered_ratio(); + file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("Import Theme")); } break; case THEME_RELOAD: { @@ -1413,82 +1454,70 @@ void ScriptEditor::_theme_option(int p_option) { } void ScriptEditor::_show_save_theme_as_dialog() { - file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_option = THEME_SAVE_AS; file_dialog->clear_filters(); file_dialog->add_filter("*.tet"); file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); - file_dialog->popup_centered_ratio(); + file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("Save Theme As...")); } void ScriptEditor::_tab_changed(int p_which) { - ensure_select_current(); } void ScriptEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { + editor->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop)); + editor->connect("script_add_function_request", callable_mp(this, &ScriptEditor::_add_callback)); + editor->connect("resource_saved", callable_mp(this, &ScriptEditor::_res_saved_callback)); + editor->get_filesystem_dock()->connect("file_removed", callable_mp(this, &ScriptEditor::_file_removed)); + script_list->connect("item_selected", callable_mp(this, &ScriptEditor::_script_selected)); - editor->connect("play_pressed", this, "_editor_play"); - editor->connect("pause_pressed", this, "_editor_pause"); - editor->connect("stop_pressed", this, "_editor_stop"); - editor->connect("script_add_function_request", this, "_add_callback"); - editor->connect("resource_saved", this, "_res_saved_callback"); - script_list->connect("item_selected", this, "_script_selected"); - - members_overview->connect("item_selected", this, "_members_overview_selected"); - help_overview->connect("item_selected", this, "_help_overview_selected"); - script_split->connect("dragged", this, "_script_split_dragged"); + members_overview->connect("item_selected", callable_mp(this, &ScriptEditor::_members_overview_selected)); + help_overview->connect("item_selected", callable_mp(this, &ScriptEditor::_help_overview_selected)); + script_split->connect("dragged", callable_mp(this, &ScriptEditor::_script_split_dragged)); - EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); - FALLTHROUGH; + EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ScriptEditor::_editor_settings_changed)); + EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &ScriptEditor::_filesystem_changed)); + [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { + help_search->set_icon(get_theme_icon("HelpSearch", "EditorIcons")); + site_search->set_icon(get_theme_icon("Instance", "EditorIcons")); - 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")); + script_forward->set_icon(get_theme_icon("Forward", "EditorIcons")); + script_back->set_icon(get_theme_icon("Back", "EditorIcons")); - members_overview_alphabeta_sort_button->set_icon(get_icon("Sort", "EditorIcons")); + members_overview_alphabeta_sort_button->set_icon(get_theme_icon("Sort", "EditorIcons")); - filter_scripts->set_right_icon(get_icon("Search", "EditorIcons")); - filter_methods->set_right_icon(get_icon("Search", "EditorIcons")); + filter_scripts->set_right_icon(get_theme_icon("Search", "EditorIcons")); + filter_methods->set_right_icon(get_theme_icon("Search", "EditorIcons")); - filename->add_style_override("normal", editor->get_gui_base()->get_stylebox("normal", "LineEdit")); + filename->add_theme_style_override("normal", editor->get_gui_base()->get_theme_stylebox("normal", "LineEdit")); recent_scripts->set_as_minsize(); } break; case NOTIFICATION_READY: { - - get_tree()->connect("tree_changed", this, "_tree_changed"); - editor->get_inspector_dock()->connect("request_help", this, "_request_help"); - editor->connect("request_help_search", this, "_help_search"); + get_tree()->connect("tree_changed", callable_mp(this, &ScriptEditor::_tree_changed)); + editor->get_inspector_dock()->connect("request_help", callable_mp(this, &ScriptEditor::_help_class_open)); + editor->connect("request_help_search", callable_mp(this, &ScriptEditor::_help_search)); } break; case NOTIFICATION_EXIT_TREE: { - - editor->disconnect("play_pressed", this, "_editor_play"); - editor->disconnect("pause_pressed", this, "_editor_pause"); - editor->disconnect("stop_pressed", this, "_editor_stop"); + editor->disconnect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop)); } break; - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { - + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { _test_script_times_on_disk(); _update_modified_scripts_for_external_editor(); } break; case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: { - if (is_visible()) { find_in_files_button->show(); } else { @@ -1506,25 +1535,23 @@ void ScriptEditor::_notification(int p_what) { } bool ScriptEditor::can_take_away_focus() const { - ScriptEditorBase *current = _get_current_editor(); - if (current) + if (current) { return current->can_lose_focus_on_node_selection(); - else + } else { return true; + } } void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - Ref<Script> script = se->get_edited_resource(); - if (script == NULL || !script.is_valid()) + if (script == nullptr || !script.is_valid()) { continue; + } if (script->get_path().find("::") != -1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed _close_tab(i); @@ -1535,7 +1562,6 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) { } void ScriptEditor::edited_scene_changed() { - _update_modified_scripts_for_external_editor(); } @@ -1548,38 +1574,38 @@ void ScriptEditor::notify_script_changed(const Ref<Script> &p_script) { } void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } Ref<Script> script = se->get_edited_resource(); - if (script == NULL) { + if (script == nullptr) { continue; } - List<int> bpoints; - se->get_breakpoints(&bpoints); String base = script->get_path(); - ERR_CONTINUE(base.begins_with("local://") || base == ""); - - for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { + if (base.begins_with("local://") || base == "") { + continue; + } - p_breakpoints->push_back(base + ":" + itos(E->get() + 1)); + Array bpoints = se->get_breakpoints(); + for (int j = 0; j < bpoints.size(); j++) { + p_breakpoints->push_back(base + ":" + itos((int)bpoints[j] + 1)); } } } void ScriptEditor::ensure_focus_current() { - - if (!is_inside_tree()) + if (!is_inside_tree()) { return; + } ScriptEditorBase *current = _get_current_editor(); - if (current) + if (current) { current->ensure_focus(); + } } void ScriptEditor::_members_overview_selected(int p_idx) { @@ -1606,7 +1632,6 @@ void ScriptEditor::_help_overview_selected(int p_idx) { } void ScriptEditor::_script_selected(int p_idx) { - grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing _go_to_tab(script_list->get_item_metadata(p_idx)); @@ -1614,28 +1639,30 @@ void ScriptEditor::_script_selected(int p_idx) { } void ScriptEditor::ensure_select_current() { - if (tab_container->get_child_count() && tab_container->get_current_tab() >= 0) { - ScriptEditorBase *se = _get_current_editor(); if (se) { + se->enable_editor(); - if (!grab_focus_block && is_visible_in_tree()) + if (!grab_focus_block && is_visible_in_tree()) { se->ensure_focus(); + } } } _update_selected_editor_menu(); } -void ScriptEditor::_find_scripts(Node *p_base, Node *p_current, Set<Ref<Script> > &used) { - if (p_current != p_base && p_current->get_owner() != p_base) +void ScriptEditor::_find_scripts(Node *p_base, Node *p_current, Set<Ref<Script>> &used) { + if (p_current != p_base && p_current->get_owner() != p_base) { return; + } if (p_current->get_script_instance()) { Ref<Script> scr = p_current->get_script(); - if (scr.is_valid()) + if (scr.is_valid()) { used.insert(scr); + } } for (int i = 0; i < p_current->get_child_count(); i++) { @@ -1644,10 +1671,9 @@ void ScriptEditor::_find_scripts(Node *p_base, Node *p_current, Set<Ref<Script> } struct _ScriptEditorItemData { - String name; String sort_key; - Ref<Texture> icon; + Ref<Texture2D> icon; int index; String tooltip; bool used; @@ -1655,7 +1681,6 @@ struct _ScriptEditorItemData { Node *ref; bool operator<(const _ScriptEditorItemData &id) const { - if (category == id.category) { if (sort_key == id.sort_key) { return index < id.index; @@ -1669,7 +1694,6 @@ struct _ScriptEditorItemData { }; void ScriptEditor::_update_members_overview_visibility() { - ScriptEditorBase *se = _get_current_editor(); if (!se) { members_overview_alphabeta_sort_button->set_visible(false); @@ -1723,7 +1747,6 @@ void ScriptEditor::_update_members_overview() { } void ScriptEditor::_update_help_overview_visibility() { - int selected = tab_container->get_current_tab(); if (selected < 0 || selected >= tab_container->get_child_count()) { help_overview->set_visible(false); @@ -1752,8 +1775,9 @@ void ScriptEditor::_update_help_overview() { help_overview->clear(); int selected = tab_container->get_current_tab(); - if (selected < 0 || selected >= tab_container->get_child_count()) + if (selected < 0 || selected >= tab_container->get_child_count()) { return; + } Node *current = tab_container->get_child(tab_container->get_current_tab()); EditorHelp *se = Object::cast_to<EditorHelp>(current); @@ -1761,7 +1785,7 @@ void ScriptEditor::_update_help_overview() { return; } - Vector<Pair<String, int> > sections = se->get_sections(); + Vector<Pair<String, int>> sections = se->get_sections(); for (int i = 0; i < sections.size(); i++) { help_overview->add_item(sections[i].first); help_overview->set_item_metadata(i, sections[i].second); @@ -1769,20 +1793,19 @@ void ScriptEditor::_update_help_overview() { } void ScriptEditor::_update_script_colors() { - bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_enabled"); bool highlight_current = EditorSettings::get_singleton()->get("text_editor/script_list/highlight_current_script"); int hist_size = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_history_size"); - Color hot_color = get_color("accent_color", "Editor"); - Color cold_color = get_color("font_color", "Editor"); + Color hot_color = get_theme_color("accent_color", "Editor"); + Color cold_color = get_theme_color("font_color", "Editor"); for (int i = 0; i < script_list->get_item_count(); i++) { - int c = script_list->get_item_metadata(i); Node *n = tab_container->get_child(c); - if (!n) + if (!n) { continue; + } script_list->set_item_custom_bg_color(i, Color(0, 0, 0, 0)); @@ -1791,7 +1814,6 @@ void ScriptEditor::_update_script_colors() { script_list->set_item_custom_bg_color(i, EditorSettings::get_singleton()->get("text_editor/script_list/current_script_background_color")); } else if (script_temperature_enabled) { - if (!n->has_meta("__editor_pass")) { continue; } @@ -1804,17 +1826,17 @@ void ScriptEditor::_update_script_colors() { int non_zero_hist_size = (hist_size == 0) ? 1 : hist_size; float v = Math::ease((edit_pass - pass) / float(non_zero_hist_size), 0.4); - script_list->set_item_custom_fg_color(i, hot_color.linear_interpolate(cold_color, v)); + script_list->set_item_custom_fg_color(i, hot_color.lerp(cold_color, v)); } } } void ScriptEditor::_update_script_names() { - - if (restoring_layout) + if (restoring_layout) { return; + } - Set<Ref<Script> > used; + Set<Ref<Script>> used; Node *edited = EditorNode::get_singleton()->get_edited_scene(); if (edited) { _find_scripts(edited, edited, used); @@ -1828,31 +1850,35 @@ void ScriptEditor::_update_script_names() { Vector<_ScriptEditorItemData> sedata; for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - - Ref<Texture> icon = se->get_icon(); + Ref<Texture2D> icon = se->get_theme_icon(); String path = se->get_edited_resource()->get_path(); + bool saved = !path.empty(); + if (saved) { + // The script might be deleted, moved, or renamed, so make sure + // to update original path to previously edited resource. + se->set_meta("_edit_res_path", path); + } bool built_in = !path.is_resource_file(); String name; if (built_in) { - name = path.get_file(); - String resource_name = se->get_edited_resource()->get_name(); + const String &resource_name = se->get_edited_resource()->get_name(); if (resource_name != "") { - name = name.substr(0, name.find("::", 0) + 2) + resource_name; + // If the built-in script has a custom resource name defined, + // display the built-in script name as follows: `ResourceName (scene_file.tscn)` + name = vformat("%s (%s)", resource_name, name.substr(0, name.find("::", 0))); } } else { - name = se->get_name(); } _ScriptEditorItemData sd; sd.icon = icon; sd.name = name; - sd.tooltip = path; + sd.tooltip = saved ? path : TTR("Unsaved file."); sd.index = i; sd.used = used.has(se->get_edited_resource()); sd.category = 0; @@ -1885,15 +1911,34 @@ void ScriptEditor::_update_script_names() { sd.name = path; } break; } + if (!saved) { + sd.name = se->get_name(); + } sedata.push_back(sd); } + Vector<String> disambiguated_script_names; + Vector<String> full_script_paths; + for (int j = 0; j < sedata.size(); j++) { + disambiguated_script_names.append(sedata[j].name.replace("(*)", "")); + full_script_paths.append(sedata[j].tooltip); + } + + EditorNode::disambiguate_filenames(full_script_paths, disambiguated_script_names); + + for (int j = 0; j < sedata.size(); j++) { + if (sedata[j].name.ends_with("(*)")) { + sedata.write[j].name = disambiguated_script_names[j] + "(*)"; + } else { + sedata.write[j].name = disambiguated_script_names[j]; + } + } + EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (eh) { - String name = eh->get_class(); - Ref<Texture> icon = get_icon("Help", "EditorIcons"); + Ref<Texture2D> icon = get_theme_icon("Help", "EditorIcons"); String tooltip = vformat(TTR("%s Class Reference"), name); _ScriptEditorItemData sd; @@ -1926,6 +1971,10 @@ void ScriptEditor::_update_script_names() { if (new_cur_tab == -1 && sedata[i].index == cur_tab) { new_cur_tab = i; } + // Update index of sd entries for sorted order + _ScriptEditorItemData sd = sedata[i]; + sd.index = i; + sedata.set(i, sd); } tab_container->set_current_tab(new_prev_tab); tab_container->set_current_tab(new_cur_tab); @@ -1952,6 +2001,11 @@ void ScriptEditor::_update_script_names() { script_list->select(index); script_name_label->set_text(sedata_filtered[i].name); script_icon->set_texture(sedata_filtered[i].icon); + ScriptEditorBase *se = _get_current_editor(); + if (se) { + se->enable_editor(); + _update_selected_editor_menu(); + } } } @@ -2034,34 +2088,34 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p } bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus) { - - if (p_resource.is_null()) + if (p_resource.is_null()) { return false; + } Ref<Script> script = p_resource; - // refuse to open built-in if scene is not loaded - - // see if already has it - - bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); + // Don't open dominant script if using an external editor. + const bool use_external_editor = + EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || + (script.is_valid() && script->get_language()->overrides_external_editor()); + const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); - const bool should_open = open_dominant || !EditorNode::get_singleton()->is_changing_scene(); + const bool should_open = (open_dominant && !use_external_editor) || !EditorNode::get_singleton()->is_changing_scene(); - if (script != NULL && script->get_language()->overrides_external_editor()) { + if (script.is_valid() && script->get_language()->overrides_external_editor()) { if (should_open) { Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col); - if (err != OK) + if (err != OK) { ERR_PRINT("Couldn't open script in the overridden external text editor"); + } } return false; } - if ((debugger->get_dump_stack_script() != p_resource || debugger->get_debug_with_external_editor()) && + if (use_external_editor && + (EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) && p_resource->get_path().is_resource_file() && - p_resource->get_class_name() != StringName("VisualScript") && - bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { - + p_resource->get_class_name() != StringName("VisualScript")) { String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags"); @@ -2081,16 +2135,13 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra bool inside_quotes = false; for (int i = 0; i < flags.size(); i++) { - if (flags[i] == '"' && (!i || flags[i - 1] != '\\')) { - if (!inside_quotes) { from++; } inside_quotes = !inside_quotes; } else if (flags[i] == '\0' || (!inside_quotes && flags[i] == ' ')) { - String arg = flags.substr(from, num_chars); if (arg.find("{file}") != -1) { has_file_flag = true; @@ -2115,26 +2166,29 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } Error err = OS::get_singleton()->execute(path, args, false); - if (err == OK) + if (err == OK) { return false; + } WARN_PRINT("Couldn't open external text editor, using internal"); } for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } - if ((script != NULL && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) { - + if ((script != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) { if (should_open) { + se->enable_editor(); + if (tab_container->get_current_tab() != i) { _go_to_tab(i); _update_script_names(); } - if (is_visible_in_tree()) + if (is_visible_in_tree()) { se->ensure_focus(); + } if (p_line > 0) { se->goto_line(p_line - 1); @@ -2148,24 +2202,30 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra // doesn't have it, make a new one - ScriptEditorBase *se = NULL; + ScriptEditorBase *se = nullptr; for (int i = script_editor_func_count - 1; i >= 0; i--) { se = script_editor_funcs[i](p_resource); - if (se) + if (se) { break; + } } ERR_FAIL_COND_V(!se, false); + se->set_edited_resource(p_resource); + if (p_resource->get_class_name() != StringName("VisualScript")) { bool highlighter_set = false; - for (int i = 0; i < syntax_highlighters_func_count; i++) { - SyntaxHighlighter *highlighter = syntax_highlighters_funcs[i](); + for (int i = 0; i < syntax_highlighters.size(); i++) { + Ref<EditorSyntaxHighlighter> highlighter = syntax_highlighters[i]->_create(); + if (highlighter.is_null()) { + continue; + } se->add_syntax_highlighter(highlighter); - if (script != NULL && !highlighter_set) { - List<String> languages = highlighter->get_supported_languages(); - if (languages.find(script->get_language()->get_name())) { + if (script != nullptr && !highlighter_set) { + Array languages = highlighter->_get_supported_languages(); + if (languages.find(script->get_language()->get_name()) > -1) { se->set_syntax_highlighter(highlighter); highlighter_set = true; } @@ -2174,7 +2234,14 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } tab_container->add_child(se); - se->set_edited_resource(p_resource); + + if (p_grab_focus) { + se->enable_editor(); + } + + // If we delete a script within the filesystem, the original resource path + // is lost, so keep it as metadata to figure out the exact tab to delete. + se->set_meta("_edit_res_path", p_resource->get_path()); se->set_tooltip_request_func("_get_debug_tooltip", this); if (se->get_edit_menu()) { se->get_edit_menu()->hide(); @@ -2184,18 +2251,20 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if (p_grab_focus) { _go_to_tab(tab_container->get_tab_count() - 1); + _add_recent_script(p_resource->get_path()); } _sort_list_on_update = true; _update_script_names(); _save_layout(); - se->connect("name_changed", this, "_update_script_names"); - se->connect("edited_script_changed", this, "_script_changed"); - se->connect("request_help", this, "_help_search"); - se->connect("request_open_script_at_line", this, "_goto_script_line"); - se->connect("go_to_help", this, "_help_class_goto"); - se->connect("request_save_history", this, "_save_history"); - se->connect("search_in_files_requested", this, "_on_find_in_files_requested"); + se->connect("name_changed", callable_mp(this, &ScriptEditor::_update_script_names)); + se->connect("edited_script_changed", callable_mp(this, &ScriptEditor::_script_changed)); + se->connect("request_help", callable_mp(this, &ScriptEditor::_help_search)); + se->connect("request_open_script_at_line", callable_mp(this, &ScriptEditor::_goto_script_line)); + se->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto)); + se->connect("request_save_history", callable_mp(this, &ScriptEditor::_save_history)); + se->connect("search_in_files_requested", callable_mp(this, &ScriptEditor::_on_find_in_files_requested)); + se->connect("replace_in_files_requested", callable_mp(this, &ScriptEditor::_on_replace_in_files_requested)); //test for modification, maybe the script was not edited but was loaded @@ -2207,17 +2276,15 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } notify_script_changed(p_resource); - _add_recent_script(p_resource->get_path()); return true; } void ScriptEditor::save_all_scripts() { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } if (convert_indent_on_save) { if (use_space_indentation) { @@ -2233,8 +2300,9 @@ void ScriptEditor::save_all_scripts() { se->insert_final_newline(); - if (!se->is_unsaved()) + if (!se->is_unsaved()) { continue; + } RES edited_res = se->get_edited_resource(); if (edited_res.is_valid()) { @@ -2243,7 +2311,7 @@ void ScriptEditor::save_all_scripts() { if (edited_res->get_path() != "" && edited_res->get_path().find("local://") == -1 && edited_res->get_path().find("::") == -1) { Ref<TextFile> text_file = edited_res; - if (text_file != NULL) { + if (text_file != nullptr) { _save_text_file(text_file, text_file->get_path()); continue; } @@ -2256,12 +2324,11 @@ void ScriptEditor::save_all_scripts() { } void ScriptEditor::apply_scripts() const { - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } se->apply_code(); } } @@ -2271,31 +2338,10 @@ void ScriptEditor::open_script_create_dialog(const String &p_base_name, const St script_create_dialog->config(p_base_name, p_base_path); } -void ScriptEditor::_editor_play() { - - debugger->start(); - debug_menu->get_popup()->grab_focus(); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_STEP), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_BREAK), false); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true); -} - -void ScriptEditor::_editor_pause() { -} void ScriptEditor::_editor_stop() { - - debugger->stop(); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_STEP), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true); - for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { - continue; } @@ -2303,8 +2349,7 @@ void ScriptEditor::_editor_stop() { } } -void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PoolStringArray &p_args) { - +void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args) { ERR_FAIL_COND(!p_obj); Ref<Script> script = p_obj->get_script(); ERR_FAIL_COND(!script.is_valid()); @@ -2312,12 +2357,13 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const editor->push_item(script.ptr()); for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; - if (se->get_edited_resource() != script) + } + if (se->get_edited_resource() != script) { continue; + } se->add_callback(p_function, p_args); @@ -2330,7 +2376,6 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const } void ScriptEditor::_save_layout() { - if (restoring_layout) { return; } @@ -2339,7 +2384,6 @@ void ScriptEditor::_save_layout() { } void ScriptEditor::_editor_settings_changed() { - trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/files/trim_trailing_whitespace_on_save"); convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/indent/convert_indent_on_save"); use_space_indentation = EditorSettings::get_singleton()->get("text_editor/indent/type"); @@ -2359,10 +2403,10 @@ void ScriptEditor::_editor_settings_changed() { } for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } se->update_settings(); } @@ -2372,13 +2416,28 @@ void ScriptEditor::_editor_settings_changed() { ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/files/auto_reload_and_parse_scripts_on_save", true)); } -void ScriptEditor::_autosave_scripts() { +void ScriptEditor::_filesystem_changed() { + _update_script_names(); +} + +void ScriptEditor::_file_removed(const String &p_removed_file) { + for (int i = 0; i < tab_container->get_child_count(); i++) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) { + continue; + } + if (se->get_meta("_edit_res_path") == p_removed_file) { + // The script is deleted with no undo, so just close the tab. + _close_tab(i, false, false); + } + } +} +void ScriptEditor::_autosave_scripts() { save_all_scripts(); } void ScriptEditor::_update_autosave_timer() { - if (!autosave_timer->is_inside_tree()) { return; } @@ -2393,9 +2452,9 @@ void ScriptEditor::_update_autosave_timer() { } void ScriptEditor::_tree_changed() { - - if (waiting_update_names) + if (waiting_update_names) { return; + } waiting_update_names = true; call_deferred("_update_script_names"); @@ -2403,30 +2462,29 @@ void ScriptEditor::_tree_changed() { } void ScriptEditor::_script_split_dragged(float) { - _save_layout(); } Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - - if (tab_container->get_child_count() == 0) + 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); String preview_name = ""; - Ref<Texture> preview_icon; + Ref<Texture2D> preview_icon; ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(cur_node); if (se) { preview_name = se->get_name(); - preview_icon = se->get_icon(); + preview_icon = se->get_theme_icon(); } EditorHelp *eh = Object::cast_to<EditorHelp>(cur_node); if (eh) { preview_name = eh->get_class(); - preview_icon = get_icon("Help", "EditorIcons"); + preview_icon = get_theme_icon("Help", "EditorIcons"); } if (!preview_icon.is_null()) { @@ -2446,13 +2504,12 @@ Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { } bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return false; + } if (String(d["type"]) == "script_list_element") { - Node *node = d["script_list_element"]; ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); @@ -2466,10 +2523,10 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data } if (String(d["type"]) == "nodes") { - Array nodes = d["nodes"]; - if (nodes.size() == 0) + if (nodes.size() == 0) { return false; + } Node *node = get_node((nodes[0])); ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); @@ -2483,16 +2540,17 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; - if (files.size() == 0) + if (files.size() == 0) { return false; //weird + } for (int i = 0; i < files.size(); i++) { String file = files[i]; - if (file == "" || !FileAccess::exists(file)) + if (file == "" || !FileAccess::exists(file)) { continue; + } Ref<Script> scr = ResourceLoader::load(file); if (scr.is_valid()) { return true; @@ -2505,16 +2563,16 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data } void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - - if (!can_drop_data_fw(p_point, p_data, p_from)) + if (!can_drop_data_fw(p_point, p_data, p_from)) { return; + } Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return; + } if (String(d["type"]) == "script_list_element") { - Node *node = d["script_list_element"]; ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); @@ -2531,10 +2589,10 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } if (String(d["type"]) == "nodes") { - Array nodes = d["nodes"]; - if (nodes.size() == 0) + if (nodes.size() == 0) { return; + } Node *node = get_node(nodes[0]); ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node); @@ -2551,7 +2609,6 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; int new_index = 0; @@ -2561,8 +2618,9 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co int num_tabs_before = tab_container->get_child_count(); for (int i = 0; i < files.size(); i++) { String file = files[i]; - if (file == "" || !FileAccess::exists(file)) + if (file == "" || !FileAccess::exists(file)) { continue; + } Ref<Script> scr = ResourceLoader::load(file); if (scr.is_valid()) { edit(scr); @@ -2580,8 +2638,9 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) { - if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) + if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) { return; + } if (ED_IS_SHORTCUT("script_editor/next_script", p_event)) { if (script_list->get_item_count() > 1) { int next_tab = script_list->get_current() + 1; @@ -2607,11 +2666,9 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) { } void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) { - Ref<InputEventMouseButton> mb = ev; if (mb.is_valid() && mb->is_pressed()) { switch (mb->get_button_index()) { - case BUTTON_MIDDLE: { // Right-click selects automatically; middle-click does not. int idx = script_list->get_item_at_position(mb->get_position(), true); @@ -2630,12 +2687,12 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) { } void ScriptEditor::_make_script_list_context_menu() { - context_menu->clear(); int selected = tab_container->get_current_tab(); - if (selected < 0 || selected >= tab_container->get_child_count()) + if (selected < 0 || selected >= tab_container->get_child_count()) { return; + } ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); if (se) { @@ -2648,7 +2705,7 @@ void ScriptEditor::_make_script_list_context_menu() { context_menu->add_separator(); if (se) { Ref<Script> scr = se->get_edited_resource(); - if (scr != NULL) { + if (scr != nullptr) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); if (!scr.is_null() && scr->is_tool()) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); @@ -2671,18 +2728,19 @@ void ScriptEditor::_make_script_list_context_menu() { } void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { - if (!bool(EDITOR_DEF("text_editor/files/restore_scripts_on_load", true))) { return; } - if (!p_layout->has_section_key("ScriptEditor", "open_scripts") && !p_layout->has_section_key("ScriptEditor", "open_help")) + if (!p_layout->has_section_key("ScriptEditor", "open_scripts") && !p_layout->has_section_key("ScriptEditor", "open_help")) { return; + } Array scripts = p_layout->get_value("ScriptEditor", "open_scripts"); Array helps; - if (p_layout->has_section_key("ScriptEditor", "open_help")) + if (p_layout->has_section_key("ScriptEditor", "open_help")) { helps = p_layout->get_value("ScriptEditor", "open_help"); + } restoring_layout = true; @@ -2690,7 +2748,6 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); for (int i = 0; i < scripts.size(); i++) { - String path = scripts[i]; Dictionary script_info = scripts[i]; @@ -2698,15 +2755,16 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { path = script_info["path"]; } - if (!FileAccess::exists(path)) + if (!FileAccess::exists(path)) { continue; + } if (extensions.find(path.get_extension())) { Ref<Script> scr = ResourceLoader::load(path); if (!scr.is_valid()) { continue; } - if (!edit(scr)) { + if (!edit(scr, false)) { continue; } } else { @@ -2715,7 +2773,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { if (error != OK || !text_file.is_valid()) { continue; } - if (!edit(text_file)) { + if (!edit(text_file, false)) { continue; } } @@ -2729,7 +2787,6 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { } for (int i = 0; i < helps.size(); i++) { - String path = helps[i]; if (path == "") { // invalid, skip continue; @@ -2751,18 +2808,16 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { } void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { - Array scripts; Array helps; for (int i = 0; i < tab_container->get_child_count(); i++) { - ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - String path = se->get_edited_resource()->get_path(); - if (!path.is_resource_file()) + if (!path.is_resource_file()) { continue; + } Dictionary script_info; script_info["path"] = path; @@ -2774,7 +2829,6 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (eh) { - helps.push_back(eh->get_class()); } } @@ -2785,16 +2839,14 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { } void ScriptEditor::_help_class_open(const String &p_class) { - - if (p_class == "") + if (p_class == "") { return; + } for (int i = 0; i < tab_container->get_child_count(); i++) { - EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (eh && eh->get_class() == p_class) { - _go_to_tab(i); _update_script_names(); return; @@ -2807,7 +2859,7 @@ void ScriptEditor::_help_class_open(const String &p_class) { tab_container->add_child(eh); _go_to_tab(tab_container->get_tab_count() - 1); eh->go_to_class(p_class, 0); - eh->connect("go_to_help", this, "_help_class_goto"); + eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto)); _add_recent_script(p_class); _sort_list_on_update = true; _update_script_names(); @@ -2815,15 +2867,12 @@ void ScriptEditor::_help_class_open(const String &p_class) { } void ScriptEditor::_help_class_goto(const String &p_desc) { - String cname = p_desc.get_slice(":", 1); for (int i = 0; i < tab_container->get_child_count(); i++) { - EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i)); if (eh && eh->get_class() == cname) { - _go_to_tab(i); eh->go_to_help(p_desc); _update_script_names(); @@ -2837,7 +2886,7 @@ void ScriptEditor::_help_class_goto(const String &p_desc) { tab_container->add_child(eh); _go_to_tab(tab_container->get_tab_count() - 1); eh->go_to_help(p_desc); - eh->connect("go_to_help", this, "_help_class_goto"); + eh->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto)); _add_recent_script(eh->get_class()); _sort_list_on_update = true; _update_script_names(); @@ -2845,25 +2894,22 @@ void ScriptEditor::_help_class_goto(const String &p_desc) { } void ScriptEditor::_update_selected_editor_menu() { - for (int i = 0; i < tab_container->get_child_count(); i++) { - bool current = tab_container->get_current_tab() == i; ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se && se->get_edit_menu()) { - - if (current) + if (current) { se->get_edit_menu()->show(); - else + } else { se->get_edit_menu()->hide(); + } } } EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_current_tab_control()); script_search_menu->get_popup()->clear(); if (eh) { - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3), HELP_SEARCH_FIND_PREVIOUS); @@ -2871,7 +2917,6 @@ void ScriptEditor::_update_selected_editor_menu() { script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES); script_search_menu->show(); } else { - if (tab_container->get_child_count() == 0) { script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F), SEARCH_IN_FILES); script_search_menu->show(); @@ -2882,15 +2927,12 @@ void ScriptEditor::_update_selected_editor_menu() { } void ScriptEditor::_update_history_pos(int p_new_pos) { - Node *n = tab_container->get_current_tab_control(); if (Object::cast_to<ScriptEditorBase>(n)) { - history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } @@ -2900,18 +2942,16 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { n = history[history_pos].control; if (Object::cast_to<ScriptEditorBase>(n)) { - Object::cast_to<ScriptEditorBase>(n)->set_edit_state(history[history_pos].state); Object::cast_to<ScriptEditorBase>(n)->ensure_focus(); Ref<Script> script = Object::cast_to<ScriptEditorBase>(n)->get_edited_resource(); - if (script != NULL) { + if (script != nullptr) { notify_script_changed(script); } } if (Object::cast_to<EditorHelp>(n)) { - Object::cast_to<EditorHelp>(n)->set_scroll(history[history_pos].state); Object::cast_to<EditorHelp>(n)->set_focused(); } @@ -2923,30 +2963,28 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { } void ScriptEditor::_history_forward() { - if (history_pos < history.size() - 1) { _update_history_pos(history_pos + 1); } } void ScriptEditor::_history_back() { - if (history_pos > 0) { _update_history_pos(history_pos - 1); } } -Vector<Ref<Script> > ScriptEditor::get_open_scripts() const { - - Vector<Ref<Script> > out_scripts = Vector<Ref<Script> >(); +Vector<Ref<Script>> ScriptEditor::get_open_scripts() const { + Vector<Ref<Script>> out_scripts = Vector<Ref<Script>>(); for (int i = 0; i < tab_container->get_child_count(); i++) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); - if (!se) + if (!se) { continue; + } Ref<Script> script = se->get_edited_resource(); - if (script != NULL) { + if (script != nullptr) { out_scripts.push_back(script); } } @@ -2954,30 +2992,41 @@ Vector<Ref<Script> > ScriptEditor::get_open_scripts() const { return out_scripts; } -void ScriptEditor::set_scene_root_script(Ref<Script> p_script) { - - bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); +Array ScriptEditor::_get_open_script_editors() const { + Array script_editors; + for (int i = 0; i < tab_container->get_child_count(); i++) { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); + if (!se) { + continue; + } + script_editors.push_back(se); + } + return script_editors; +} - if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) - return; +void ScriptEditor::set_scene_root_script(Ref<Script> p_script) { + // Don't open dominant script if using an external editor. + const bool use_external_editor = + EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || + (p_script.is_valid() && p_script->get_language()->overrides_external_editor()); + const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change"); - if (open_dominant && p_script.is_valid()) { + if (open_dominant && !use_external_editor && p_script.is_valid()) { edit(p_script); } } bool ScriptEditor::script_goto_method(Ref<Script> p_script, const String &p_method) { - int line = p_script->get_member_line(p_method); - if (line == -1) + if (line == -1) { return false; + } return edit(p_script, line, 0); } void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) { - auto_reload_running_scripts = p_enabled; } @@ -2986,7 +3035,6 @@ void ScriptEditor::_help_search(String p_text) { } void ScriptEditor::_open_script_request(const String &p_path) { - Ref<Script> script = ResourceLoader::load(p_path); if (script.is_valid()) { script_editor->edit(script, false); @@ -3001,36 +3049,46 @@ void ScriptEditor::_open_script_request(const String &p_path) { } } -int ScriptEditor::syntax_highlighters_func_count = 0; -CreateSyntaxHighlighterFunc ScriptEditor::syntax_highlighters_funcs[ScriptEditor::SYNTAX_HIGHLIGHTER_FUNC_MAX]; +void ScriptEditor::register_syntax_highlighter(const Ref<EditorSyntaxHighlighter> &p_syntax_highlighter) { + ERR_FAIL_COND(p_syntax_highlighter.is_null()); -void ScriptEditor::register_create_syntax_highlighter_function(CreateSyntaxHighlighterFunc p_func) { - ERR_FAIL_COND(syntax_highlighters_func_count == SYNTAX_HIGHLIGHTER_FUNC_MAX); - syntax_highlighters_funcs[syntax_highlighters_func_count++] = p_func; + if (syntax_highlighters.find(p_syntax_highlighter) == -1) { + syntax_highlighters.push_back(p_syntax_highlighter); + } +} + +void ScriptEditor::unregister_syntax_highlighter(const Ref<EditorSyntaxHighlighter> &p_syntax_highlighter) { + ERR_FAIL_COND(p_syntax_highlighter.is_null()); + + syntax_highlighters.erase(p_syntax_highlighter); } int ScriptEditor::script_editor_func_count = 0; CreateScriptEditorFunc ScriptEditor::script_editor_funcs[ScriptEditor::SCRIPT_EDITOR_FUNC_MAX]; void ScriptEditor::register_create_script_editor_function(CreateScriptEditorFunc p_func) { - ERR_FAIL_COND(script_editor_func_count == SCRIPT_EDITOR_FUNC_MAX); script_editor_funcs[script_editor_func_count++] = p_func; } void ScriptEditor::_script_changed() { - NodeDock::singleton->update_lists(); } void ScriptEditor::_on_find_in_files_requested(String text) { + find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::SEARCH_MODE); + find_in_files_dialog->set_search_text(text); + find_in_files_dialog->popup_centered(); +} +void ScriptEditor::_on_replace_in_files_requested(String text) { + find_in_files_dialog->set_find_in_files_mode(FindInFilesDialog::REPLACE_MODE); find_in_files_dialog->set_search_text(text); - find_in_files_dialog->popup_centered_minsize(); + find_in_files_dialog->set_replace_text(""); + find_in_files_dialog->popup_centered(); } void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) { - if (ResourceLoader::exists(fpath)) { RES res = ResourceLoader::load(fpath); @@ -3068,7 +3126,6 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb } void ScriptEditor::_start_find_in_files(bool with_replace) { - FindInFiles *f = find_in_files->get_finder(); f->set_search_text(find_in_files_dialog->get_search_text()); @@ -3078,13 +3135,13 @@ void ScriptEditor::_start_find_in_files(bool with_replace) { f->set_filter(find_in_files_dialog->get_filter()); find_in_files->set_with_replace(with_replace); + find_in_files->set_replace_text(find_in_files_dialog->get_replace_text()); find_in_files->start_search(); editor->make_bottom_panel_item_visible(find_in_files); } -void ScriptEditor::_on_find_in_files_modified_files(PoolStringArray paths) { - +void ScriptEditor::_on_find_in_files_modified_files(PackedStringArray paths) { _test_script_times_on_disk(); _update_modified_scripts_for_external_editor(); } @@ -3098,64 +3155,25 @@ void ScriptEditor::_filter_methods_text_changed(const String &p_newtext) { } void ScriptEditor::_bind_methods() { - - ClassDB::bind_method("_file_dialog_action", &ScriptEditor::_file_dialog_action); - ClassDB::bind_method("_tab_changed", &ScriptEditor::_tab_changed); - ClassDB::bind_method("_menu_option", &ScriptEditor::_menu_option); - ClassDB::bind_method("_close_current_tab", &ScriptEditor::_close_current_tab); - ClassDB::bind_method("_close_discard_current_tab", &ScriptEditor::_close_discard_current_tab); ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab); ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs); ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs); - ClassDB::bind_method("_open_recent_script", &ScriptEditor::_open_recent_script); - ClassDB::bind_method("_theme_option", &ScriptEditor::_theme_option); - ClassDB::bind_method("_editor_play", &ScriptEditor::_editor_play); - ClassDB::bind_method("_editor_pause", &ScriptEditor::_editor_pause); - ClassDB::bind_method("_editor_stop", &ScriptEditor::_editor_stop); - ClassDB::bind_method("_add_callback", &ScriptEditor::_add_callback); - ClassDB::bind_method("_reload_scripts", &ScriptEditor::_reload_scripts); - ClassDB::bind_method("_resave_scripts", &ScriptEditor::_resave_scripts); - ClassDB::bind_method("_res_saved_callback", &ScriptEditor::_res_saved_callback); - ClassDB::bind_method("_goto_script_line", &ScriptEditor::_goto_script_line); ClassDB::bind_method("_goto_script_line2", &ScriptEditor::_goto_script_line2); - ClassDB::bind_method("_set_execution", &ScriptEditor::_set_execution); - ClassDB::bind_method("_clear_execution", &ScriptEditor::_clear_execution); - ClassDB::bind_method("_help_search", &ScriptEditor::_help_search); - ClassDB::bind_method("_save_history", &ScriptEditor::_save_history); ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); - ClassDB::bind_method("_breaked", &ScriptEditor::_breaked); - ClassDB::bind_method("_show_debugger", &ScriptEditor::_show_debugger); ClassDB::bind_method("_get_debug_tooltip", &ScriptEditor::_get_debug_tooltip); - ClassDB::bind_method("_autosave_scripts", &ScriptEditor::_autosave_scripts); - ClassDB::bind_method("_update_autosave_timer", &ScriptEditor::_update_autosave_timer); - ClassDB::bind_method("_editor_settings_changed", &ScriptEditor::_editor_settings_changed); - ClassDB::bind_method("_update_script_names", &ScriptEditor::_update_script_names); ClassDB::bind_method("_update_script_connections", &ScriptEditor::_update_script_connections); - ClassDB::bind_method("_tree_changed", &ScriptEditor::_tree_changed); - ClassDB::bind_method("_members_overview_selected", &ScriptEditor::_members_overview_selected); - ClassDB::bind_method("_help_overview_selected", &ScriptEditor::_help_overview_selected); - ClassDB::bind_method("_script_selected", &ScriptEditor::_script_selected); - ClassDB::bind_method("_script_created", &ScriptEditor::_script_created); - ClassDB::bind_method("_script_split_dragged", &ScriptEditor::_script_split_dragged); ClassDB::bind_method("_help_class_open", &ScriptEditor::_help_class_open); - ClassDB::bind_method("_help_class_goto", &ScriptEditor::_help_class_goto); - ClassDB::bind_method("_request_help", &ScriptEditor::_help_class_open); - ClassDB::bind_method("_history_forward", &ScriptEditor::_history_forward); - ClassDB::bind_method("_history_back", &ScriptEditor::_history_back); ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts); ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input); - ClassDB::bind_method("_script_list_gui_input", &ScriptEditor::_script_list_gui_input); - ClassDB::bind_method("_toggle_members_overview_alpha_sort", &ScriptEditor::_toggle_members_overview_alpha_sort); ClassDB::bind_method("_update_members_overview", &ScriptEditor::_update_members_overview); - ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed); - ClassDB::bind_method("_filter_scripts_text_changed", &ScriptEditor::_filter_scripts_text_changed); - ClassDB::bind_method("_filter_methods_text_changed", &ScriptEditor::_filter_methods_text_changed); ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts); - ClassDB::bind_method("_on_find_in_files_requested", &ScriptEditor::_on_find_in_files_requested); - ClassDB::bind_method("_start_find_in_files", &ScriptEditor::_start_find_in_files); - ClassDB::bind_method("_on_find_in_files_result_selected", &ScriptEditor::_on_find_in_files_result_selected); - ClassDB::bind_method("_on_find_in_files_modified_files", &ScriptEditor::_on_find_in_files_modified_files); + + ClassDB::bind_method("get_current_editor", &ScriptEditor::_get_current_editor); + ClassDB::bind_method("get_open_script_editors", &ScriptEditor::_get_open_script_editors); + + ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter); + ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter); ClassDB::bind_method(D_METHOD("get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); @@ -3171,7 +3189,6 @@ void ScriptEditor::_bind_methods() { } ScriptEditor::ScriptEditor(EditorNode *p_editor) { - current_theme = ""; completion_cache = memnew(EditorScriptCodeCompletionCache); @@ -3204,23 +3221,22 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { filter_scripts = memnew(LineEdit); filter_scripts->set_placeholder(TTR("Filter scripts")); filter_scripts->set_clear_button_enabled(true); - filter_scripts->connect("text_changed", this, "_filter_scripts_text_changed"); + filter_scripts->connect("text_changed", callable_mp(this, &ScriptEditor::_filter_scripts_text_changed)); scripts_vbox->add_child(filter_scripts); script_list = memnew(ItemList); scripts_vbox->add_child(script_list); - script_list->set_custom_minimum_size(Size2(150, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing + script_list->set_custom_minimum_size(Size2(150, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing script_list->set_v_size_flags(SIZE_EXPAND_FILL); - script_split->set_split_offset(140); + script_split->set_split_offset(70 * EDSCALE); _sort_list_on_update = true; - script_list->connect("gui_input", this, "_script_list_gui_input", varray(), CONNECT_DEFERRED); + script_list->connect("gui_input", callable_mp(this, &ScriptEditor::_script_list_gui_input), varray(), CONNECT_DEFERRED); script_list->set_allow_rmb_select(true); script_list->set_drag_forwarding(this); context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", this, "_menu_option"); - context_menu->set_hide_on_window_lose_focus(true); + context_menu->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); overview_vbox = memnew(VBoxContainer); overview_vbox->set_custom_minimum_size(Size2(0, 90)); @@ -3233,35 +3249,36 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { filename = memnew(Label); filename->set_clip_text(true); filename->set_h_size_flags(SIZE_EXPAND_FILL); - filename->add_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_stylebox("normal", "LineEdit")); + filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("normal", "LineEdit")); buttons_hbox->add_child(filename); - members_overview_alphabeta_sort_button = memnew(ToolButton); + members_overview_alphabeta_sort_button = memnew(Button); + members_overview_alphabeta_sort_button->set_flat(true); members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list.")); members_overview_alphabeta_sort_button->set_toggle_mode(true); members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")); - members_overview_alphabeta_sort_button->connect("toggled", this, "_toggle_members_overview_alpha_sort"); + members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort)); buttons_hbox->add_child(members_overview_alphabeta_sort_button); filter_methods = memnew(LineEdit); filter_methods->set_placeholder(TTR("Filter methods")); filter_methods->set_clear_button_enabled(true); - filter_methods->connect("text_changed", this, "_filter_methods_text_changed"); + filter_methods->connect("text_changed", callable_mp(this, &ScriptEditor::_filter_methods_text_changed)); overview_vbox->add_child(filter_methods); members_overview = memnew(ItemList); overview_vbox->add_child(members_overview); members_overview->set_allow_reselect(true); - members_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing + members_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing members_overview->set_v_size_flags(SIZE_EXPAND_FILL); members_overview->set_allow_rmb_select(true); help_overview = memnew(ItemList); overview_vbox->add_child(help_overview); help_overview->set_allow_reselect(true); - help_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing + help_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing help_overview->set_v_size_flags(SIZE_EXPAND_FILL); tab_container = memnew(TabContainer); @@ -3281,7 +3298,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { menu_hb->add_child(file_menu); file_menu->set_text(TTR("File")); file_menu->set_switch_on_hover(true); - file_menu->get_popup()->set_hide_on_window_lose_focus(true); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script...")), FILE_NEW); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File...")), FILE_NEW_TEXTFILE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN); @@ -3291,15 +3308,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { recent_scripts = memnew(PopupMenu); recent_scripts->set_name("RecentScripts"); file_menu->get_popup()->add_child(recent_scripts); - recent_scripts->connect("id_pressed", this, "_open_recent_script"); + recent_scripts->connect("id_pressed", callable_mp(this, &ScriptEditor::_open_recent_script)); _update_recent_scripts(); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_R), FILE_TOOL_RELOAD_SOFT); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/show_in_file_system", TTR("Show in FileSystem")), SHOW_IN_FILE_SYSTEM); file_menu->get_popup()->add_separator(); @@ -3313,7 +3330,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { theme_submenu = memnew(PopupMenu); theme_submenu->set_name("Theme"); file_menu->get_popup()->add_child(theme_submenu); - theme_submenu->connect("id_pressed", this, "_theme_option"); + theme_submenu->connect("id_pressed", callable_mp(this, &ScriptEditor::_theme_option)); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme...")), THEME_IMPORT); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD); @@ -3332,35 +3349,24 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KEY_MASK_CMD | KEY_BACKSLASH), TOGGLE_SCRIPTS_PANEL); - file_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + file_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); script_search_menu = memnew(MenuButton); menu_hb->add_child(script_search_menu); script_search_menu->set_text(TTR("Search")); script_search_menu->set_switch_on_hover(true); - script_search_menu->get_popup()->set_hide_on_window_lose_focus(true); - script_search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + script_search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option)); - debug_menu = memnew(MenuButton); + MenuButton *debug_menu = memnew(MenuButton); menu_hb->add_child(debug_menu); - debug_menu->set_text(TTR("Debug")); - debug_menu->set_switch_on_hover(true); - debug_menu->get_popup()->set_hide_on_window_lose_focus(true); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11), DEBUG_STEP); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10), DEBUG_NEXT); - debug_menu->get_popup()->add_separator(); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/break", TTR("Break")), DEBUG_BREAK); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/continue", TTR("Continue"), KEY_F12), DEBUG_CONTINUE); - debug_menu->get_popup()->add_separator(); - //debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW); - debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")), DEBUG_SHOW_KEEP_OPEN); - debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor")), DEBUG_WITH_EXTERNAL_EDITOR); - debug_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_STEP), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true); - debug_menu->get_popup()->set_item_disabled(debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true); + debug_menu->hide(); // Handled by EditorDebuggerNode below. + + EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton(); + debugger->set_script_debug_button(debug_menu); + debugger->connect("goto_script_line", callable_mp(this, &ScriptEditor::_goto_script_line)); + debugger->connect("set_execution", callable_mp(this, &ScriptEditor::_set_execution)); + debugger->connect("clear_execution", callable_mp(this, &ScriptEditor::_clear_execution)); + debugger->connect("breaked", callable_mp(this, &ScriptEditor::_breaked)); menu_hb->add_spacer(); @@ -3374,66 +3380,58 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { menu_hb->add_spacer(); - site_search = memnew(ToolButton); + site_search = memnew(Button); + site_search->set_flat(true); site_search->set_text(TTR("Online Docs")); - site_search->connect("pressed", this, "_menu_option", varray(SEARCH_WEBSITE)); + site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(SEARCH_WEBSITE)); menu_hb->add_child(site_search); 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 = memnew(Button); + help_search->set_flat(true); help_search->set_text(TTR("Search Help")); - help_search->connect("pressed", this, "_menu_option", varray(SEARCH_HELP)); + help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option), varray(SEARCH_HELP)); menu_hb->add_child(help_search); help_search->set_tooltip(TTR("Search the reference documentation.")); menu_hb->add_child(memnew(VSeparator)); - script_back = memnew(ToolButton); - script_back->connect("pressed", this, "_history_back"); + script_back = memnew(Button); + script_back->set_flat(true); + script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back)); menu_hb->add_child(script_back); script_back->set_disabled(true); script_back->set_tooltip(TTR("Go to previous edited document.")); - script_forward = memnew(ToolButton); - script_forward->connect("pressed", this, "_history_forward"); + script_forward = memnew(Button); + script_forward->set_flat(true); + script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward)); menu_hb->add_child(script_forward); script_forward->set_disabled(true); script_forward->set_tooltip(TTR("Go to next edited document.")); - tab_container->connect("tab_changed", this, "_tab_changed"); + tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed)); erase_tab_confirm = memnew(ConfirmationDialog); erase_tab_confirm->get_ok()->set_text(TTR("Save")); - erase_tab_confirm->add_button(TTR("Discard"), OS::get_singleton()->get_swap_ok_cancel(), "discard"); - erase_tab_confirm->connect("confirmed", this, "_close_current_tab"); - erase_tab_confirm->connect("custom_action", this, "_close_discard_current_tab"); + erase_tab_confirm->add_button(TTR("Discard"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard"); + erase_tab_confirm->connect("confirmed", callable_mp(this, &ScriptEditor::_close_current_tab)); + erase_tab_confirm->connect("custom_action", callable_mp(this, &ScriptEditor::_close_discard_current_tab)); add_child(erase_tab_confirm); script_create_dialog = memnew(ScriptCreateDialog); script_create_dialog->set_title(TTR("Create Script")); add_child(script_create_dialog); - script_create_dialog->connect("script_created", this, "_script_created"); + script_create_dialog->connect("script_created", callable_mp(this, &ScriptEditor::_script_created)); file_dialog_option = -1; file_dialog = memnew(EditorFileDialog); add_child(file_dialog); - file_dialog->connect("file_selected", this, "_file_dialog_action"); + file_dialog->connect("file_selected", callable_mp(this, &ScriptEditor::_file_dialog_action)); error_dialog = memnew(AcceptDialog); add_child(error_dialog); - debugger = memnew(ScriptEditorDebugger(editor)); - debugger->connect("goto_script_line", this, "_goto_script_line"); - debugger->connect("set_execution", this, "_set_execution"); - debugger->connect("clear_execution", this, "_clear_execution"); - debugger->connect("show_debugger", this, "_show_debugger"); - disk_changed = memnew(ConfirmationDialog); { VBoxContainer *vbc = memnew(VBoxContainer); @@ -3447,48 +3445,42 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { vbc->add_child(disk_changed_list); disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL); - disk_changed->connect("confirmed", this, "_reload_scripts"); + disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::_reload_scripts)); disk_changed->get_ok()->set_text(TTR("Reload")); - disk_changed->add_button(TTR("Resave"), !OS::get_singleton()->get_swap_ok_cancel(), "resave"); - disk_changed->connect("custom_action", this, "_resave_scripts"); + disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); + disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts)); } add_child(disk_changed); script_editor = this; - Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"), debugger); - debugger->set_tool_button(db); - - debugger->connect("breaked", this, "_breaked"); - autosave_timer = memnew(Timer); autosave_timer->set_one_shot(false); - autosave_timer->connect(SceneStringNames::get_singleton()->tree_entered, this, "_update_autosave_timer"); - autosave_timer->connect("timeout", this, "_autosave_scripts"); + autosave_timer->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &ScriptEditor::_update_autosave_timer)); + autosave_timer->connect("timeout", callable_mp(this, &ScriptEditor::_autosave_scripts)); add_child(autosave_timer); grab_focus_block = false; help_search_dialog = memnew(EditorHelpSearch); add_child(help_search_dialog); - help_search_dialog->connect("go_to_help", this, "_help_class_goto"); + help_search_dialog->connect("go_to_help", callable_mp(this, &ScriptEditor::_help_class_goto)); find_in_files_dialog = memnew(FindInFilesDialog); - find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_FIND_REQUESTED, this, "_start_find_in_files", varray(false)); - find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, this, "_start_find_in_files", varray(true)); + find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_FIND_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files), varray(false)); + find_in_files_dialog->connect(FindInFilesDialog::SIGNAL_REPLACE_REQUESTED, callable_mp(this, &ScriptEditor::_start_find_in_files), varray(true)); add_child(find_in_files_dialog); find_in_files = memnew(FindInFilesPanel); find_in_files_button = editor->add_bottom_panel_item(TTR("Search Results"), find_in_files); find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE); - find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, this, "_on_find_in_files_result_selected"); - find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, this, "_on_find_in_files_modified_files"); + find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected)); + find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files)); find_in_files->hide(); find_in_files_button->hide(); history_pos = -1; - //debugger_gui->hide(); edit_pass = 0; trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/files/trim_trailing_whitespace_on_save"); @@ -3497,19 +3489,16 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { ScriptServer::edit_request_func = _open_script_request; - add_style_override("panel", editor->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles")); - tab_container->add_style_override("panel", editor->get_gui_base()->get_stylebox("ScriptEditor", "EditorStyles")); + add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("ScriptEditorPanel", "EditorStyles")); + tab_container->add_theme_style_override("panel", editor->get_gui_base()->get_theme_stylebox("ScriptEditor", "EditorStyles")); } ScriptEditor::~ScriptEditor() { - memdelete(completion_cache); } void ScriptEditorPlugin::edit(Object *p_object) { - if (Object::cast_to<Script>(p_object)) { - Script *p_script = Object::cast_to<Script>(p_object); String res_path = p_script->get_path().get_slice("::", 0); @@ -3529,7 +3518,6 @@ void ScriptEditorPlugin::edit(Object *p_object) { } bool ScriptEditorPlugin::handles(Object *p_object) const { - if (Object::cast_to<TextFile>(p_object)) { return true; } @@ -3542,30 +3530,25 @@ bool ScriptEditorPlugin::handles(Object *p_object) const { } void ScriptEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { script_editor->show(); script_editor->set_process(true); script_editor->ensure_select_current(); } else { - script_editor->hide(); script_editor->set_process(false); } } void ScriptEditorPlugin::selected_notify() { - script_editor->ensure_select_current(); } void ScriptEditorPlugin::save_external_data() { - script_editor->save_all_scripts(); } void ScriptEditorPlugin::apply_changes() { - script_editor->apply_scripts(); } @@ -3576,27 +3559,22 @@ void ScriptEditorPlugin::save_global_state() { } void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { - script_editor->set_window_layout(p_layout); } void ScriptEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { - script_editor->get_window_layout(p_layout); } void ScriptEditorPlugin::get_breakpoints(List<String> *p_breakpoints) { - script_editor->get_breakpoints(p_breakpoints); } void ScriptEditorPlugin::edited_scene_changed() { - script_editor->edited_scene_changed(); } ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) { - editor = p_node; script_editor = memnew(ScriptEditor(p_node)); editor->get_viewport()->add_child(script_editor); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index a41480c80d..c2b0b458eb 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -43,13 +43,58 @@ #include "scene/gui/split_container.h" #include "scene/gui/tab_container.h" #include "scene/gui/text_edit.h" -#include "scene/gui/tool_button.h" #include "scene/gui/tree.h" #include "scene/main/timer.h" #include "scene/resources/text_file.h" -class ScriptEditorQuickOpen : public ConfirmationDialog { +class EditorSyntaxHighlighter : public SyntaxHighlighter { + GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter) + +private: + REF edited_resourse; + +protected: + static void _bind_methods(); + +public: + virtual String _get_name() const; + virtual Array _get_supported_languages() const; + + void _set_edited_resource(const RES &p_res) { edited_resourse = p_res; } + REF _get_edited_resource() { return edited_resourse; } + + virtual Ref<EditorSyntaxHighlighter> _create() const; +}; + +class EditorStandardSyntaxHighlighter : public EditorSyntaxHighlighter { + GDCLASS(EditorStandardSyntaxHighlighter, EditorSyntaxHighlighter) + +private: + Ref<CodeHighlighter> highlighter; + +public: + virtual void _update_cache() override; + virtual Dictionary _get_line_syntax_highlighting(int p_line) override { return highlighter->get_line_syntax_highlighting(p_line); } + + virtual String _get_name() const override { return TTR("Standard"); } + + virtual Ref<EditorSyntaxHighlighter> _create() const override; + EditorStandardSyntaxHighlighter() { highlighter.instance(); } +}; + +class EditorPlainTextSyntaxHighlighter : public EditorSyntaxHighlighter { + GDCLASS(EditorPlainTextSyntaxHighlighter, EditorSyntaxHighlighter) + +public: + virtual String _get_name() const override { return TTR("Plain Text"); } + + virtual Ref<EditorSyntaxHighlighter> _create() const override; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class ScriptEditorQuickOpen : public ConfirmationDialog { GDCLASS(ScriptEditorQuickOpen, ConfirmationDialog); LineEdit *search_box; @@ -73,26 +118,26 @@ public: ScriptEditorQuickOpen(); }; -class ScriptEditorDebugger; +class EditorDebuggerNode; class ScriptEditorBase : public VBoxContainer { - GDCLASS(ScriptEditorBase, VBoxContainer); protected: static void _bind_methods(); public: - virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0; - virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0; + virtual void add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) = 0; + virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) = 0; virtual void apply_code() = 0; virtual RES get_edited_resource() const = 0; virtual Vector<String> get_functions() = 0; virtual void set_edited_resource(const RES &p_res) = 0; + virtual void enable_editor() = 0; virtual void reload_text() = 0; virtual String get_name() = 0; - virtual Ref<Texture> get_icon() = 0; + virtual Ref<Texture2D> get_theme_icon() = 0; virtual bool is_unsaved() = 0; virtual Variant get_edit_state() = 0; virtual void set_edit_state(const Variant &p_state) = 0; @@ -106,8 +151,8 @@ public: virtual void ensure_focus() = 0; virtual void tag_saved_version() = 0; virtual void reload(bool p_soft) {} - virtual void get_breakpoints(List<int> *p_breakpoints) = 0; - virtual void add_callback(const String &p_function, PoolStringArray p_args) = 0; + virtual Array get_breakpoints() = 0; + virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0; virtual void update_settings() = 0; virtual void set_debugger_active(bool p_active) = 0; virtual bool can_lose_focus_on_node_selection() { return true; } @@ -123,7 +168,6 @@ public: ScriptEditorBase() {} }; -typedef SyntaxHighlighter *(*CreateSyntaxHighlighterFunc)(); typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const RES &p_resource); class EditorScriptCodeCompletionCache; @@ -131,7 +175,6 @@ class FindInFilesDialog; class FindInFilesPanel; class ScriptEditor : public PanelContainer { - GDCLASS(ScriptEditor, PanelContainer); EditorNode *editor; @@ -155,17 +198,10 @@ class ScriptEditor : public PanelContainer { FILE_COPY_PATH, FILE_TOOL_RELOAD, FILE_TOOL_RELOAD_SOFT, - DEBUG_NEXT, - DEBUG_STEP, - DEBUG_BREAK, - DEBUG_CONTINUE, - DEBUG_SHOW, - DEBUG_SHOW_KEEP_OPEN, - DEBUG_WITH_EXTERNAL_EDITOR, SEARCH_IN_FILES, + REPLACE_IN_FILES, SEARCH_HELP, SEARCH_WEBSITE, - REQUEST_DOCS, HELP_SEARCH_FIND, HELP_SEARCH_FIND_NEXT, HELP_SEARCH_FIND_PREVIOUS, @@ -210,7 +246,6 @@ class ScriptEditor : public PanelContainer { Button *help_search; Button *site_search; - Button *request_docs; EditorHelpSearch *help_search_dialog; ItemList *script_list; @@ -222,7 +257,7 @@ class ScriptEditor : public PanelContainer { VBoxContainer *overview_vbox; HBoxContainer *buttons_hbox; Label *filename; - ToolButton *members_overview_alphabeta_sort_button; + Button *members_overview_alphabeta_sort_button; bool members_overview_enabled; ItemList *help_overview; bool help_overview_enabled; @@ -232,16 +267,15 @@ class ScriptEditor : public PanelContainer { AcceptDialog *error_dialog; ConfirmationDialog *erase_tab_confirm; ScriptCreateDialog *script_create_dialog; - ScriptEditorDebugger *debugger; - ToolButton *scripts_visible; + Button *scripts_visible; String current_theme; TextureRect *script_icon; Label *script_name_label; - ToolButton *script_back; - ToolButton *script_forward; + Button *script_back; + Button *script_forward; FindInFilesDialog *find_in_files_dialog; FindInFilesPanel *find_in_files; @@ -249,17 +283,14 @@ class ScriptEditor : public PanelContainer { enum { SCRIPT_EDITOR_FUNC_MAX = 32, - SYNTAX_HIGHLIGHTER_FUNC_MAX = 32 }; static int script_editor_func_count; static CreateScriptEditorFunc script_editor_funcs[SCRIPT_EDITOR_FUNC_MAX]; - static int syntax_highlighters_func_count; - static CreateSyntaxHighlighterFunc syntax_highlighters_funcs[SYNTAX_HIGHLIGHTER_FUNC_MAX]; + Vector<Ref<EditorSyntaxHighlighter>> syntax_highlighters; struct ScriptHistory { - Control *control; Variant state; }; @@ -314,13 +345,11 @@ class ScriptEditor : public PanelContainer { EditorScriptCodeCompletionCache *completion_cache; - void _editor_play(); - void _editor_pause(); void _editor_stop(); int edit_pass; - void _add_callback(Object *p_obj, const String &p_function, const PoolStringArray &p_args); + void _add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args); void _res_saved_callback(const Ref<Resource> &p_res); bool trim_trailing_whitespace_on_save; @@ -334,14 +363,16 @@ class ScriptEditor : public PanelContainer { void _set_execution(REF p_script, int p_line); void _clear_execution(REF p_script); void _breaked(bool p_breaked, bool p_can_debug); - void _show_debugger(bool p_show); void _update_window_menu(); void _script_created(Ref<Script> p_script); ScriptEditorBase *_get_current_editor() const; + Array _get_open_script_editors() const; void _save_layout(); void _editor_settings_changed(); + void _filesystem_changed(); + void _file_removed(const String &p_file); void _autosave_scripts(); void _update_autosave_timer(); @@ -361,7 +392,7 @@ class ScriptEditor : public PanelContainer { void _update_help_overview(); void _help_overview_selected(int p_idx); - void _find_scripts(Node *p_base, Node *p_current, Set<Ref<Script> > &used); + void _find_scripts(Node *p_base, Node *p_current, Set<Ref<Script>> &used); void _tree_changed(); @@ -404,9 +435,10 @@ class ScriptEditor : public PanelContainer { Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path); void _on_find_in_files_requested(String text); + void _on_replace_in_files_requested(String text); void _on_find_in_files_result_selected(String fpath, int line_number, int begin, int end); void _start_find_in_files(bool with_replace); - void _on_find_in_files_modified_files(PoolStringArray paths); + void _on_find_in_files_modified_files(PackedStringArray paths); static void _open_script_request(const String &p_path); @@ -438,7 +470,7 @@ public: void get_window_layout(Ref<ConfigFile> p_layout); void set_scene_root_script(Ref<Script> p_script); - Vector<Ref<Script> > get_open_scripts() const; + Vector<Ref<Script>> get_open_scripts() const; bool script_goto_method(Ref<Script> p_script, const String &p_method); @@ -455,10 +487,11 @@ public: VSplitContainer *get_left_list_split() { return list_split; } - ScriptEditorDebugger *get_debugger() { return debugger; } void set_live_auto_reload_running_scripts(bool p_enabled); - static void register_create_syntax_highlighter_function(CreateSyntaxHighlighterFunc p_func); + void register_syntax_highlighter(const Ref<EditorSyntaxHighlighter> &p_syntax_highlighter); + void unregister_syntax_highlighter(const Ref<EditorSyntaxHighlighter> &p_syntax_highlighter); + static void register_create_script_editor_function(CreateScriptEditorFunc p_func); ScriptEditor(EditorNode *p_editor); @@ -466,32 +499,31 @@ public: }; class ScriptEditorPlugin : public EditorPlugin { - GDCLASS(ScriptEditorPlugin, EditorPlugin); ScriptEditor *script_editor; EditorNode *editor; public: - virtual String get_name() const { return "Script"; } - bool has_main_screen() const { return true; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); - virtual void selected_notify(); + virtual String get_name() const override { return "Script"; } + bool has_main_screen() const override { return true; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + virtual void selected_notify() override; - virtual void save_external_data(); - virtual void apply_changes(); + virtual void save_external_data() override; + virtual void apply_changes() override; - virtual void restore_global_state(); - virtual void save_global_state(); + virtual void restore_global_state() override; + virtual void save_global_state() override; - virtual void set_window_layout(Ref<ConfigFile> p_layout); - virtual void get_window_layout(Ref<ConfigFile> p_layout); + virtual void set_window_layout(Ref<ConfigFile> p_layout) override; + virtual void get_window_layout(Ref<ConfigFile> p_layout) override; - virtual void get_breakpoints(List<String> *p_breakpoints); + virtual void get_breakpoints(List<String> *p_breakpoints) override; - virtual void edited_scene_changed(); + virtual void edited_scene_changed() override; ScriptEditorPlugin(EditorNode *p_node); ~ScriptEditorPlugin(); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 1432c3fc63..7feb7cb3d3 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -32,10 +32,10 @@ #include "core/math/expression.h" #include "core/os/keyboard.h" +#include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "editor/script_editor_debugger.h" void ConnectionInfoDialog::ok_pressed() { } @@ -53,40 +53,41 @@ void ConnectionInfoDialog::popup_connections(String p_method, Vector<Node *> p_n for (List<Connection>::Element *E = all_connections.front(); E; E = E->next()) { Connection connection = E->get(); - if (connection.method != p_method) { + if (connection.callable.get_method() != p_method) { continue; } TreeItem *node_item = tree->create_item(root); - node_item->set_text(0, Object::cast_to<Node>(connection.source)->get_name()); - node_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(connection.source, "Node")); + node_item->set_text(0, Object::cast_to<Node>(connection.signal.get_object())->get_name()); + node_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(connection.signal.get_object(), "Node")); node_item->set_selectable(0, false); node_item->set_editable(0, false); - node_item->set_text(1, connection.signal); - node_item->set_icon(1, get_parent_control()->get_icon("Slot", "EditorIcons")); + node_item->set_text(1, connection.signal.get_name()); + Control *p = Object::cast_to<Control>(get_parent()); + node_item->set_icon(1, p->get_theme_icon("Slot", "EditorIcons")); node_item->set_selectable(1, false); node_item->set_editable(1, false); - node_item->set_text(2, Object::cast_to<Node>(connection.target)->get_name()); - node_item->set_icon(2, EditorNode::get_singleton()->get_object_icon(connection.target, "Node")); + node_item->set_text(2, Object::cast_to<Node>(connection.callable.get_object())->get_name()); + node_item->set_icon(2, EditorNode::get_singleton()->get_object_icon(connection.callable.get_object(), "Node")); node_item->set_selectable(2, false); node_item->set_editable(2, false); } } - popup_centered(Size2(400, 300) * EDSCALE); + popup_centered(Size2(600, 300) * EDSCALE); } ConnectionInfoDialog::ConnectionInfoDialog() { set_title(TTR("Connections to method:")); VBoxContainer *vbc = memnew(VBoxContainer); - vbc->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -8 * EDSCALE); - vbc->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, 8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -8 * EDSCALE); + vbc->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -8 * EDSCALE); add_child(vbc); method = memnew(Label); @@ -101,26 +102,23 @@ ConnectionInfoDialog::ConnectionInfoDialog() { tree->set_column_title(1, TTR("Signal")); tree->set_column_title(2, TTR("Target")); vbc->add_child(tree); - tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->set_allow_rmb_select(true); } //////////////////////////////////////////////////////////////////////////////// Vector<String> ScriptTextEditor::get_functions() { - String errortxt; int line = -1, col; - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); String text = te->get_text(); List<String> fnc; if (script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc)) { - //if valid rewrite functions to latest functions.clear(); for (List<String>::Element *E = fnc.front(); E; E = E->next()) { - functions.push_back(E->get()); } } @@ -129,12 +127,12 @@ Vector<String> ScriptTextEditor::get_functions() { } void ScriptTextEditor::apply_code() { - - if (script.is_null()) + if (script.is_null()) { return; - script->set_source_code(code_editor->get_text_edit()->get_text()); + } + script->set_source_code(code_editor->get_text_editor()->get_text()); script->update_exports(); - _update_member_keywords(); + code_editor->get_text_editor()->get_syntax_highlighter()->update_cache(); } RES ScriptTextEditor::get_edited_resource() const { @@ -142,57 +140,45 @@ RES ScriptTextEditor::get_edited_resource() const { } void ScriptTextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!script.is_null()); + ERR_FAIL_COND(script.is_valid()); + ERR_FAIL_COND(p_res.is_null()); script = p_res; - _set_theme_for_script(); - code_editor->get_text_edit()->set_text(script->get_source_code()); - code_editor->get_text_edit()->clear_undo_history(); - code_editor->get_text_edit()->tag_saved_version(); + code_editor->get_text_editor()->set_text(script->get_source_code()); + code_editor->get_text_editor()->clear_undo_history(); + code_editor->get_text_editor()->tag_saved_version(); emit_signal("name_changed"); code_editor->update_line_and_column(); - - _validate_script(); } -void ScriptTextEditor::_update_member_keywords() { - member_keywords.clear(); - code_editor->get_text_edit()->clear_member_keywords(); - Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); - - StringName instance_base = script->get_instance_base_type(); - - if (instance_base == StringName()) +void ScriptTextEditor::enable_editor() { + if (editor_enabled) { return; - List<PropertyInfo> plist; - ClassDB::get_property_list(instance_base, &plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - String name = E->get().name; - if (E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_GROUP) - continue; - if (name.find("/") != -1) - continue; - - code_editor->get_text_edit()->add_member_keyword(name, member_variable_color); } - List<String> clist; - ClassDB::get_integer_constant_list(instance_base, &clist); + editor_enabled = true; - for (List<String>::Element *E = clist.front(); E; E = E->next()) { + _enable_code_editor(); + _set_theme_for_script(); - code_editor->get_text_edit()->add_member_keyword(E->get(), member_variable_color); - } + _validate_script(); } void ScriptTextEditor::_load_theme_settings() { - - TextEdit *text_edit = code_editor->get_text_edit(); - - text_edit->clear_colors(); + CodeEdit *text_edit = code_editor->get_text_editor(); + text_edit->clear_keywords(); + + Color updated_safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color"); + if (updated_safe_line_number_color != safe_line_number_color) { + safe_line_number_color = updated_safe_line_number_color; + for (int i = 0; i < text_edit->get_line_count(); i++) { + if (text_edit->get_line_gutter_item_color(i, line_number_gutter) != default_line_number_color) { + text_edit->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); + } + } + } Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color"); @@ -202,7 +188,6 @@ void ScriptTextEditor::_load_theme_settings() { Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color"); Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color"); - Color safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color"); Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color"); Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color"); Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color"); @@ -211,9 +196,6 @@ void ScriptTextEditor::_load_theme_settings() { Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color"); Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color"); Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color"); - Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); - Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); - Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); @@ -221,158 +203,86 @@ void ScriptTextEditor::_load_theme_settings() { Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); - Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); - Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); - Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); - Color usertype_color = EDITOR_GET("text_editor/highlighting/user_type_color"); - Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); - Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); - - text_edit->add_color_override("background_color", background_color); - text_edit->add_color_override("completion_background_color", completion_background_color); - text_edit->add_color_override("completion_selected_color", completion_selected_color); - text_edit->add_color_override("completion_existing_color", completion_existing_color); - text_edit->add_color_override("completion_scroll_color", completion_scroll_color); - text_edit->add_color_override("completion_font_color", completion_font_color); - text_edit->add_color_override("font_color", text_color); - text_edit->add_color_override("line_number_color", line_number_color); - text_edit->add_color_override("safe_line_number_color", safe_line_number_color); - text_edit->add_color_override("caret_color", caret_color); - text_edit->add_color_override("caret_background_color", caret_background_color); - text_edit->add_color_override("font_color_selected", text_selected_color); - text_edit->add_color_override("selection_color", selection_color); - text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); - text_edit->add_color_override("current_line_color", current_line_color); - text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color); - text_edit->add_color_override("word_highlighted_color", word_highlighted_color); - text_edit->add_color_override("number_color", number_color); - text_edit->add_color_override("function_color", function_color); - text_edit->add_color_override("member_variable_color", member_variable_color); - text_edit->add_color_override("bookmark_color", bookmark_color); - text_edit->add_color_override("breakpoint_color", breakpoint_color); - text_edit->add_color_override("executing_line_color", executing_line_color); - text_edit->add_color_override("mark_color", mark_color); - text_edit->add_color_override("code_folding_color", code_folding_color); - text_edit->add_color_override("search_result_color", search_result_color); - text_edit->add_color_override("search_result_border_color", search_result_border_color); - text_edit->add_color_override("symbol_color", symbol_color); - - text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6)); - - colors_cache.symbol_color = symbol_color; - colors_cache.keyword_color = keyword_color; - colors_cache.basetype_color = basetype_color; - colors_cache.type_color = type_color; - colors_cache.usertype_color = usertype_color; - colors_cache.comment_color = comment_color; - colors_cache.string_color = string_color; + + text_edit->add_theme_color_override("background_color", background_color); + text_edit->add_theme_color_override("completion_background_color", completion_background_color); + text_edit->add_theme_color_override("completion_selected_color", completion_selected_color); + text_edit->add_theme_color_override("completion_existing_color", completion_existing_color); + text_edit->add_theme_color_override("completion_scroll_color", completion_scroll_color); + text_edit->add_theme_color_override("completion_font_color", completion_font_color); + text_edit->add_theme_color_override("font_color", text_color); + text_edit->add_theme_color_override("line_number_color", line_number_color); + text_edit->add_theme_color_override("caret_color", caret_color); + text_edit->add_theme_color_override("caret_background_color", caret_background_color); + text_edit->add_theme_color_override("font_color_selected", text_selected_color); + text_edit->add_theme_color_override("selection_color", selection_color); + text_edit->add_theme_color_override("brace_mismatch_color", brace_mismatch_color); + text_edit->add_theme_color_override("current_line_color", current_line_color); + text_edit->add_theme_color_override("line_length_guideline_color", line_length_guideline_color); + text_edit->add_theme_color_override("word_highlighted_color", word_highlighted_color); + text_edit->add_theme_color_override("bookmark_color", bookmark_color); + text_edit->add_theme_color_override("breakpoint_color", breakpoint_color); + text_edit->add_theme_color_override("executing_line_color", executing_line_color); + text_edit->add_theme_color_override("mark_color", mark_color); + text_edit->add_theme_color_override("code_folding_color", code_folding_color); + text_edit->add_theme_color_override("search_result_color", search_result_color); + text_edit->add_theme_color_override("search_result_border_color", search_result_border_color); + + text_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6)); theme_loaded = true; - if (!script.is_null()) + if (!script.is_null()) { _set_theme_for_script(); + } } void ScriptTextEditor::_set_theme_for_script() { - - if (!theme_loaded) + if (!theme_loaded) { return; + } - TextEdit *text_edit = code_editor->get_text_edit(); - - List<String> keywords; - script->get_language()->get_reserved_words(&keywords); + CodeEdit *text_edit = code_editor->get_text_editor(); + text_edit->get_syntax_highlighter()->update_cache(); - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + /* add keywords for auto completion */ + // singleton autoloads (as types, just as engine singletons are) + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->value(); + if (info.is_singleton) { + text_edit->add_keyword(info.name); + } + } - text_edit->add_keyword_color(E->get(), colors_cache.keyword_color); - } - - //colorize core types - const Color basetype_color = colors_cache.basetype_color; - text_edit->add_keyword_color("String", basetype_color); - text_edit->add_keyword_color("Vector2", basetype_color); - text_edit->add_keyword_color("Rect2", basetype_color); - text_edit->add_keyword_color("Transform2D", basetype_color); - text_edit->add_keyword_color("Vector3", basetype_color); - text_edit->add_keyword_color("AABB", basetype_color); - text_edit->add_keyword_color("Basis", basetype_color); - text_edit->add_keyword_color("Plane", basetype_color); - text_edit->add_keyword_color("Transform", basetype_color); - text_edit->add_keyword_color("Quat", basetype_color); - text_edit->add_keyword_color("Color", basetype_color); - text_edit->add_keyword_color("Object", basetype_color); - text_edit->add_keyword_color("NodePath", basetype_color); - text_edit->add_keyword_color("RID", basetype_color); - text_edit->add_keyword_color("Dictionary", basetype_color); - text_edit->add_keyword_color("Array", basetype_color); - text_edit->add_keyword_color("PoolByteArray", basetype_color); - text_edit->add_keyword_color("PoolIntArray", basetype_color); - text_edit->add_keyword_color("PoolRealArray", basetype_color); - text_edit->add_keyword_color("PoolStringArray", basetype_color); - text_edit->add_keyword_color("PoolVector2Array", basetype_color); - text_edit->add_keyword_color("PoolVector3Array", basetype_color); - text_edit->add_keyword_color("PoolColorArray", basetype_color); - - //colorize engine types + // engine types List<StringName> types; ClassDB::get_class_list(&types); - for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - String n = E->get(); - if (n.begins_with("_")) + if (n.begins_with("_")) { n = n.substr(1, n.length()); - - text_edit->add_keyword_color(n, colors_cache.type_color); + } + text_edit->add_keyword(n); } - _update_member_keywords(); - //colorize user types + // user types List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); - for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { - - text_edit->add_keyword_color(E->get(), colors_cache.usertype_color); + text_edit->add_keyword(E->get()); } - //colorize singleton autoloads (as types, just as engine singletons are) - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) { - continue; - } - String path = ProjectSettings::get_singleton()->get(s); - if (path.begins_with("*")) { - text_edit->add_keyword_color(s.get_slice("/", 1), colors_cache.usertype_color); - } - } - - //colorize comments - List<String> comments; - script->get_language()->get_comment_delimiters(&comments); - - for (List<String>::Element *E = comments.front(); E; E = E->next()) { - - String comment = E->get(); - String beg = comment.get_slice(" ", 0); - String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); - - text_edit->add_color_region(beg, end, colors_cache.comment_color, end == ""); + List<String> keywords; + script->get_language()->get_reserved_words(&keywords); + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + text_edit->add_keyword(E->get()); } - //colorize strings - List<String> strings; - script->get_language()->get_string_delimiters(&strings); - for (List<String>::Element *E = strings.front(); E; E = E->next()) { - - String string = E->get(); - String beg = string.get_slice(" ", 0); - String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String(); - text_edit->add_color_region(beg, end, colors_cache.string_color, end == ""); + // core types + List<String> core_types; + script->get_language()->get_core_type_words(&core_types); + for (List<String>::Element *E = core_types.front(); E; E = E->next()) { + text_edit->add_keyword(E->get()); } } @@ -380,25 +290,20 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) { warnings_panel->set_visible(p_show); } -void ScriptTextEditor::_error_pressed() { - code_editor->goto_error(); -} - void ScriptTextEditor::_warning_clicked(Variant p_line) { if (p_line.get_type() == Variant::INT) { - code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t()); + code_editor->get_text_editor()->cursor_set_line(p_line.operator int64_t()); } else if (p_line.get_type() == Variant::DICTIONARY) { Dictionary meta = p_line.operator Dictionary(); - code_editor->get_text_edit()->insert_at("# warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); + code_editor->get_text_editor()->insert_at("# warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); _validate_script(); } } void ScriptTextEditor::reload_text() { - ERR_FAIL_COND(script.is_null()); - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); int column = te->cursor_get_column(); int row = te->cursor_get_line(); int h = te->get_h_scroll(); @@ -415,31 +320,21 @@ void ScriptTextEditor::reload_text() { code_editor->update_line_and_column(); } -void ScriptTextEditor::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - -void ScriptTextEditor::add_callback(const String &p_function, PoolStringArray p_args) { - - String code = code_editor->get_text_edit()->get_text(); +void ScriptTextEditor::add_callback(const String &p_function, PackedStringArray p_args) { + String code = code_editor->get_text_editor()->get_text(); int pos = script->get_language()->find_function(p_function, code); if (pos == -1) { //does not exist - code_editor->get_text_edit()->deselect(); - pos = code_editor->get_text_edit()->get_line_count() + 2; + code_editor->get_text_editor()->deselect(); + pos = code_editor->get_text_editor()->get_line_count() + 2; String func = script->get_language()->make_function("", p_function, p_args); //code=code+func; - code_editor->get_text_edit()->cursor_set_line(pos + 1); - code_editor->get_text_edit()->cursor_set_column(1000000); //none shall be that big - code_editor->get_text_edit()->insert_text_at_cursor("\n\n" + func); + code_editor->get_text_editor()->cursor_set_line(pos + 1); + code_editor->get_text_editor()->cursor_set_column(1000000); //none shall be that big + code_editor->get_text_editor()->insert_text_at_cursor("\n\n" + func); } - code_editor->get_text_edit()->cursor_set_line(pos); - code_editor->get_text_edit()->cursor_set_column(1); + code_editor->get_text_editor()->cursor_set_line(pos); + code_editor->get_text_editor()->cursor_set_column(1); } bool ScriptTextEditor::show_members_overview() { @@ -447,22 +342,22 @@ bool ScriptTextEditor::show_members_overview() { } void ScriptTextEditor::update_settings() { - + code_editor->get_text_editor()->set_gutter_draw(connection_gutter, EditorSettings::get_singleton()->get("text_editor/appearance/show_info_gutter")); code_editor->update_editor_settings(); } bool ScriptTextEditor::is_unsaved() { - - return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); + const bool unsaved = + code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() || + script->get_path().empty(); // In memory. + return unsaved; } Variant ScriptTextEditor::get_edit_state() { - return code_editor->get_edit_state(); } void ScriptTextEditor::set_edit_state(const Variant &p_state) { - code_editor->set_edit_state(p_state); Dictionary state = p_state; @@ -472,50 +367,45 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + if (editor_enabled) { + ensure_focus(); + } } void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { - code_editor->convert_case(p_case); } void ScriptTextEditor::trim_trailing_whitespace() { - code_editor->trim_trailing_whitespace(); } void ScriptTextEditor::insert_final_newline() { - code_editor->insert_final_newline(); } void ScriptTextEditor::convert_indent_to_spaces() { - code_editor->convert_indent_to_spaces(); } void ScriptTextEditor::convert_indent_to_tabs() { - code_editor->convert_indent_to_tabs(); } void ScriptTextEditor::tag_saved_version() { - - code_editor->get_text_edit()->tag_saved_version(); + code_editor->get_text_editor()->tag_saved_version(); } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->goto_line(p_line); } void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - code_editor->goto_line_selection(p_line, p_begin, p_end); } void ScriptTextEditor::goto_line_centered(int p_line) { - code_editor->goto_line_centered(p_line); } @@ -528,8 +418,7 @@ void ScriptTextEditor::clear_executing_line() { } void ScriptTextEditor::ensure_focus() { - - code_editor->get_text_edit()->grab_focus(); + code_editor->get_text_editor()->grab_focus(); } String ScriptTextEditor::get_name() { @@ -538,30 +427,32 @@ String ScriptTextEditor::get_name() { if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { name = script->get_path().get_file(); if (is_unsaved()) { + if (script->get_path().empty()) { + name = TTR("[unsaved]"); + } name += "(*)"; } - } else if (script->get_name() != "") + } else if (script->get_name() != "") { name = script->get_name(); - else + } else { name = script->get_class() + "(" + itos(script->get_instance_id()) + ")"; + } return name; } -Ref<Texture> ScriptTextEditor::get_icon() { - - if (get_parent_control() && get_parent_control()->has_icon(script->get_class(), "EditorIcons")) { - return get_parent_control()->get_icon(script->get_class(), "EditorIcons"); +Ref<Texture2D> ScriptTextEditor::get_theme_icon() { + if (get_parent_control() && get_parent_control()->has_theme_icon(script->get_class(), "EditorIcons")) { + return get_parent_control()->get_theme_icon(script->get_class(), "EditorIcons"); } - return Ref<Texture>(); + return Ref<Texture2D>(); } void ScriptTextEditor::_validate_script() { - String errortxt; int line = -1, col; - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); String text = te->get_text(); List<String> fnc; @@ -579,12 +470,11 @@ void ScriptTextEditor::_validate_script() { if (!script->is_tool()) { script->set_source_code(text); script->update_exports(); - _update_member_keywords(); + te->get_syntax_highlighter()->update_cache(); } functions.clear(); for (List<String>::Element *E = fnc.front(); E; E = E->next()) { - functions.push_back(E->get()); } script_is_valid = true; @@ -603,12 +493,12 @@ void ScriptTextEditor::_validate_script() { Connection connection = E->get(); String base_path = base->get_name(); - String source_path = base == connection.source ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.source)); - String target_path = base == connection.target ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.target)); + String source_path = base == connection.signal.get_object() ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.signal.get_object())); + String target_path = base == connection.callable.get_object() ? base_path : base_path + "/" + base->get_path_to(Object::cast_to<Node>(connection.callable.get_object())); warnings_panel->push_cell(); - warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); - warnings_panel->add_text(vformat(TTR("Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."), connection.method, connection.signal, source_path, target_path)); + warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor")); + warnings_panel->add_text(vformat(TTR("Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."), connection.callable.get_method(), connection.signal.get_name(), source_path, target_path)); warnings_panel->pop(); // Color. warnings_panel->pop(); // Cell. } @@ -625,26 +515,29 @@ void ScriptTextEditor::_validate_script() { for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { ScriptLanguage::Warning w = E->get(); + Dictionary ignore_meta; + ignore_meta["line"] = w.start_line; + ignore_meta["code"] = w.string_code.to_lower(); warnings_panel->push_cell(); - warnings_panel->push_meta(w.line - 1); - warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); - warnings_panel->add_text(TTR("Line") + " " + itos(w.line)); - warnings_panel->add_text(" (" + w.string_code + "):"); + warnings_panel->push_meta(ignore_meta); + warnings_panel->push_color( + warnings_panel->get_theme_color("accent_color", "Editor").lerp(warnings_panel->get_theme_color("mono_color", "Editor"), 0.5)); + warnings_panel->add_text(TTR("[Ignore]")); warnings_panel->pop(); // Color. - warnings_panel->pop(); // Meta goto. + warnings_panel->pop(); // Meta ignore. warnings_panel->pop(); // Cell. warnings_panel->push_cell(); - warnings_panel->add_text(w.message); + warnings_panel->push_meta(w.start_line - 1); + warnings_panel->push_color(warnings_panel->get_theme_color("warning_color", "Editor")); + warnings_panel->add_text(TTR("Line") + " " + itos(w.start_line)); + warnings_panel->add_text(" (" + w.string_code + "):"); + warnings_panel->pop(); // Color. + warnings_panel->pop(); // Meta goto. warnings_panel->pop(); // Cell. - Dictionary ignore_meta; - ignore_meta["line"] = w.line; - ignore_meta["code"] = w.string_code.to_lower(); warnings_panel->push_cell(); - warnings_panel->push_meta(ignore_meta); - warnings_panel->add_text(TTR("(ignore)")); - warnings_panel->pop(); // Meta ignore. + warnings_panel->add_text(w.message); warnings_panel->pop(); // Cell. } warnings_panel->pop(); // Table. @@ -656,16 +549,16 @@ void ScriptTextEditor::_validate_script() { te->set_line_as_marked(i, line == i); if (highlight_safe) { if (safe_lines.has(i + 1)) { - te->set_line_as_safe(i, true); + te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); last_is_safe = true; } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().empty())) { - te->set_line_as_safe(i, true); + te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); } else { - te->set_line_as_safe(i, false); + te->set_line_gutter_item_color(i, line_number_gutter, default_line_number_color); last_is_safe = false; } } else { - te->set_line_as_safe(i, false); + te->set_line_gutter_item_color(line, 1, default_line_number_color); } } @@ -674,7 +567,6 @@ void ScriptTextEditor::_validate_script() { } void ScriptTextEditor::_update_bookmark_list() { - bookmarks_menu->clear(); bookmarks_menu->set_size(Size2(1, 1)); @@ -683,7 +575,7 @@ void ScriptTextEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = code_editor->get_text_edit()->get_bookmarks_array(); + Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -693,7 +585,7 @@ void ScriptTextEditor::_update_bookmark_list() { for (int i = 0; i < bookmark_list.size(); i++) { // Strip edges to remove spaces or tabs. // Also replace any tabs by spaces, since we can't print tabs in the menu. - String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).replace("\t", " ").strip_edges(); + String line = code_editor->get_text_editor()->get_line(bookmark_list[i]).replace("\t", " ").strip_edges(); // Limit the size of the line if too big. if (line.length() > 50) { @@ -706,17 +598,15 @@ void ScriptTextEditor::_update_bookmark_list() { } void ScriptTextEditor::_bookmark_item_pressed(int p_idx) { - if (p_idx < 4) { // Any item before the separator. _edit_option(bookmarks_menu->get_item_id(p_idx)); } else { code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx)); - code_editor->get_text_edit()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred(). + code_editor->get_text_editor()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred(). } } static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { - Vector<Node *> nodes; if (p_current->get_owner() != p_base && p_base != p_current) { @@ -737,29 +627,32 @@ static Vector<Node *> _find_all_node_for_script(Node *p_base, Node *p_current, c } static Node *_find_node_for_script(Node *p_base, Node *p_current, const Ref<Script> &p_script) { - - if (p_current->get_owner() != p_base && p_base != p_current) - return NULL; + if (p_current->get_owner() != p_base && p_base != p_current) { + return nullptr; + } Ref<Script> c = p_current->get_script(); - if (c == p_script) + if (c == p_script) { return p_current; + } for (int i = 0; i < p_current->get_child_count(); i++) { Node *found = _find_node_for_script(p_base, p_current->get_child(i), p_script); - if (found) + if (found) { return found; + } } - return NULL; + return nullptr; } -static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_current, Set<Ref<Script> > &r_scripts) { - - if (p_current->get_owner() != p_base && p_base != p_current) +static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_current, Set<Ref<Script>> &r_scripts) { + if (p_current->get_owner() != p_base && p_base != p_current) { return; + } Ref<Script> c = p_current->get_script(); - if (c.is_valid()) + if (c.is_valid()) { r_scripts.insert(c); + } for (int i = 0; i < p_current->get_child_count(); i++) { _find_changed_scripts_for_external_editor(p_base, p_current->get_child(i), r_scripts); @@ -767,28 +660,27 @@ static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_curr } void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) { - - if (!bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) + if (!bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { return; + } ERR_FAIL_COND(!get_tree()); - Set<Ref<Script> > scripts; + Set<Ref<Script>> scripts; Node *base = get_tree()->get_edited_scene_root(); if (base) { _find_changed_scripts_for_external_editor(base, base, scripts); } - for (Set<Ref<Script> >::Element *E = scripts.front(); E; E = E->next()) { - + for (Set<Ref<Script>>::Element *E = scripts.front(); E; E = E->next()) { Ref<Script> script = E->get(); - if (p_for_script.is_valid() && p_for_script != script) + if (p_for_script.is_valid() && p_for_script != script) { continue; + } if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { - continue; //internal script, who cares, though weird } @@ -796,7 +688,6 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo uint64_t date = FileAccess::get_modified_time(script->get_path()); if (last_date != date) { - Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); ERR_CONTINUE(!rel_script.is_valid()); script->set_source_code(rel_script->get_source_code()); @@ -807,14 +698,14 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo } void ScriptTextEditor::_code_complete_scripts(void *p_ud, const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) { - ScriptTextEditor *ste = (ScriptTextEditor *)p_ud; ste->_code_complete_script(p_code, r_options, r_force); } void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options, bool &r_force) { - - if (color_panel->is_visible_in_tree()) return; + if (color_panel->is_visible()) { + return; + } Node *base = get_tree()->get_edited_scene_root(); if (base) { base = _find_node_for_script(base, base, script); @@ -822,12 +713,11 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCo String hint; Error err = script->get_language()->complete_code(p_code, script->get_path(), base, r_options, r_force, hint); if (err == OK) { - code_editor->get_text_edit()->set_code_hint(hint); + code_editor->get_text_editor()->set_code_hint(hint); } } void ScriptTextEditor::_update_breakpoint_list() { - breakpoints_menu->clear(); breakpoints_menu->set_size(Size2(1, 1)); @@ -836,7 +726,7 @@ void ScriptTextEditor::_update_breakpoint_list() { breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT); breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT); - Array breakpoint_list = code_editor->get_text_edit()->get_breakpoints_array(); + Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines(); if (breakpoint_list.size() == 0) { return; } @@ -846,7 +736,7 @@ void ScriptTextEditor::_update_breakpoint_list() { for (int i = 0; i < breakpoint_list.size(); i++) { // Strip edges to remove spaces or tabs. // Also replace any tabs by spaces, since we can't print tabs in the menu. - String line = code_editor->get_text_edit()->get_line(breakpoint_list[i]).replace("\t", " ").strip_edges(); + String line = code_editor->get_text_editor()->get_line(breakpoint_list[i]).replace("\t", " ").strip_edges(); // Limit the size of the line if too big. if (line.length() > 50) { @@ -859,22 +749,19 @@ void ScriptTextEditor::_update_breakpoint_list() { } void ScriptTextEditor::_breakpoint_item_pressed(int p_idx) { - if (p_idx < 4) { // Any item before the separator. _edit_option(breakpoints_menu->get_item_id(p_idx)); } else { code_editor->goto_line(breakpoints_menu->get_item_metadata(p_idx)); - code_editor->get_text_edit()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred(). + code_editor->get_text_editor()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred(). } } void ScriptTextEditor::_breakpoint_toggled(int p_row) { - - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), p_row + 1, code_editor->get_text_edit()->is_line_set_as_breakpoint(p_row)); + EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), p_row + 1, code_editor->get_text_editor()->is_line_breakpointed(p_row)); } void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_column) { - Node *base = get_tree()->get_edited_scene_root(); if (base) { base = _find_node_for_script(base, base, script); @@ -893,15 +780,13 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c EditorNode::get_singleton()->load_resource(p_symbol); } - } else if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK) { - + } else if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK) { _goto_line(p_row); result.class_name = result.class_name.trim_prefix("_"); switch (result.type) { case ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION: { - if (result.script.is_valid()) { emit_signal("request_open_script_at_line", result.script, result.location - 1); } else { @@ -913,7 +798,6 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c emit_signal("go_to_help", "class_name:" + result.class_name); } break; case ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT: { - StringName cname = result.class_name; bool success; while (true) { @@ -934,7 +818,6 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c } break; case ScriptLanguage::LookupResult::RESULT_CLASS_METHOD: { - StringName cname = result.class_name; while (true) { @@ -950,7 +833,6 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c } break; case ScriptLanguage::LookupResult::RESULT_CLASS_ENUM: { - StringName cname = result.class_name; StringName success; while (true) { @@ -970,18 +852,74 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c emit_signal("go_to_help", "class_global:" + result.class_name + ":" + result.class_member); } break; } + } else if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) { + // Check for Autoload scenes. + const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(p_symbol); + if (info.is_singleton) { + EditorNode::get_singleton()->load_scene(info.path); + } + } else if (p_symbol.is_rel_path()) { + // Every symbol other than absolute path is relative path so keep this condition at last. + String path = _get_absolute_path(p_symbol); + if (FileAccess::exists(path)) { + List<String> scene_extensions; + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions); + + if (scene_extensions.find(path.get_extension())) { + EditorNode::get_singleton()->load_scene(path); + } else { + EditorNode::get_singleton()->load_resource(path); + } + } } } +void ScriptTextEditor::_validate_symbol(const String &p_symbol) { + CodeEdit *text_edit = code_editor->get_text_editor(); + + Node *base = get_tree()->get_edited_scene_root(); + if (base) { + base = _find_node_for_script(base, base, script); + } + + ScriptLanguage::LookupResult result; + if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) { + text_edit->set_highlighted_word(p_symbol); + } else if (p_symbol.is_rel_path()) { + String path = _get_absolute_path(p_symbol); + if (FileAccess::exists(path)) { + text_edit->set_highlighted_word(p_symbol); + } else { + text_edit->set_highlighted_word(String()); + } + + } else { + text_edit->set_highlighted_word(String()); + } +} + +String ScriptTextEditor::_get_absolute_path(const String &rel_path) { + String base_path = script->get_path().get_base_dir(); + String path = base_path.plus_file(rel_path); + return path.replace("///", "//").simplify_path(); +} + void ScriptTextEditor::update_toggle_scripts_button() { - if (code_editor != NULL) { + if (code_editor != nullptr) { code_editor->update_toggle_scripts_button(); } } void ScriptTextEditor::_update_connected_methods() { - TextEdit *text_edit = code_editor->get_text_edit(); - text_edit->clear_info_icons(); + CodeEdit *text_edit = code_editor->get_text_editor(); + for (int i = 0; i < text_edit->get_line_count(); i++) { + if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") { + continue; + } + text_edit->set_line_gutter_metadata(i, connection_gutter, ""); + text_edit->set_line_gutter_icon(i, connection_gutter, nullptr); + text_edit->set_line_gutter_clickable(i, connection_gutter, false); + } missing_connections.clear(); if (!script_is_valid) { @@ -1006,24 +944,26 @@ void ScriptTextEditor::_update_connected_methods() { } // As deleted nodes are still accessible via the undo/redo system, check if they're still on the tree. - Node *source = Object::cast_to<Node>(connection.source); + Node *source = Object::cast_to<Node>(connection.signal.get_object()); if (source && !source->is_inside_tree()) { continue; } - if (methods_found.has(connection.method)) { + if (methods_found.has(connection.callable.get_method())) { continue; } - if (!ClassDB::has_method(script->get_instance_base_type(), connection.method)) { + if (!ClassDB::has_method(script->get_instance_base_type(), connection.callable.get_method())) { int line = -1; for (int j = 0; j < functions.size(); j++) { String name = functions[j].get_slice(":", 0); - if (name == connection.method) { - line = functions[j].get_slice(":", 1).to_int(); - text_edit->set_line_info_icon(line - 1, get_parent_control()->get_icon("Slot", "EditorIcons"), connection.method); - methods_found.insert(connection.method); + if (name == connection.callable.get_method()) { + line = functions[j].get_slice(":", 1).to_int() - 1; + text_edit->set_line_gutter_metadata(line, connection_gutter, connection.callable.get_method()); + text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_theme_icon("Slot", "EditorIcons")); + text_edit->set_line_gutter_clickable(line, connection_gutter, true); + methods_found.insert(connection.callable.get_method()); break; } } @@ -1036,7 +976,7 @@ void ScriptTextEditor::_update_connected_methods() { bool found_inherited_function = false; Ref<Script> inherited_script = script->get_base_script(); while (!inherited_script.is_null()) { - if (inherited_script->has_method(connection.method)) { + if (inherited_script->has_method(connection.callable.get_method())) { found_inherited_function = true; break; } @@ -1052,112 +992,119 @@ void ScriptTextEditor::_update_connected_methods() { } } -void ScriptTextEditor::_lookup_connections(int p_row, String p_method) { +void ScriptTextEditor::_update_gutter_indexes() { + for (int i = 0; i < code_editor->get_text_editor()->get_gutter_count(); i++) { + if (code_editor->get_text_editor()->get_gutter_name(i) == "connection_gutter") { + connection_gutter = i; + continue; + } + + if (code_editor->get_text_editor()->get_gutter_name(i) == "line_numbers") { + line_number_gutter = i; + continue; + } + } +} + +void ScriptTextEditor::_gutter_clicked(int p_line, int p_gutter) { + if (p_gutter != connection_gutter) { + return; + } + + String method = code_editor->get_text_editor()->get_line_gutter_metadata(p_line, p_gutter); + if (method == "") { + return; + } + Node *base = get_tree()->get_edited_scene_root(); if (!base) { return; } Vector<Node *> nodes = _find_all_node_for_script(base, base, script); - connection_info_dialog->popup_connections(p_method, nodes); + connection_info_dialog->popup_connections(method, nodes); } void ScriptTextEditor::_edit_option(int p_op) { - - TextEdit *tx = code_editor->get_text_edit(); + CodeEdit *tx = code_editor->get_text_editor(); switch (p_op) { case EDIT_UNDO: { - tx->undo(); tx->call_deferred("grab_focus"); } break; case EDIT_REDO: { - tx->redo(); tx->call_deferred("grab_focus"); } break; case EDIT_CUT: { - tx->cut(); tx->call_deferred("grab_focus"); } break; case EDIT_COPY: { - tx->copy(); tx->call_deferred("grab_focus"); } break; case EDIT_PASTE: { - tx->paste(); tx->call_deferred("grab_focus"); } break; case EDIT_SELECT_ALL: { - tx->select_all(); tx->call_deferred("grab_focus"); } break; case EDIT_MOVE_LINE_UP: { - code_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - code_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - Ref<Script> scr = script; - if (scr.is_null()) + if (scr.is_null()) { return; + } tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { - Ref<Script> scr = script; - if (scr.is_null()) + if (scr.is_null()) { return; + } tx->indent_right(); } break; case EDIT_DELETE_LINE: { - code_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - code_editor->clone_lines_down(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { - tx->fold_all_lines(); tx->update(); } break; case EDIT_UNFOLD_ALL_LINES: { - tx->unhide_all_lines(); tx->update(); } break; case EDIT_TOGGLE_COMMENT: { - _edit_option_toggle_inline_comment(); } break; case EDIT_COMPLETE: { - tx->query_code_comple(); } break; case EDIT_AUTO_INDENT: { - String text = tx->get_text(); Ref<Script> scr = script; - if (scr.is_null()) + if (scr.is_null()) { return; + } tx->begin_complex_operation(); int begin, end; @@ -1181,38 +1128,30 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { - trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { - convert_indent_to_spaces(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { - convert_indent_to_tabs(); } break; case EDIT_PICK_COLOR: { - color_panel->popup(); } break; case EDIT_TO_UPPERCASE: { - _convert_case(CodeTextEditor::UPPER); } break; case EDIT_TO_LOWERCASE: { - _convert_case(CodeTextEditor::LOWER); } break; case EDIT_CAPITALIZE: { - _convert_case(CodeTextEditor::CAPITALIZE); } break; case EDIT_EVALUATE: { - Expression expression; - Vector<String> lines = code_editor->get_text_edit()->get_selection_text().split("\n"); - PoolStringArray results; + Vector<String> lines = code_editor->get_text_editor()->get_selection_text().split("\n"); + PackedStringArray results; for (int i = 0; i < lines.size(); i++) { String line = lines[i]; @@ -1221,91 +1160,80 @@ void ScriptTextEditor::_edit_option(int p_op) { if (expression.parse(line) == OK) { Variant result = expression.execute(Array(), Variant(), false); if (expression.get_error_text() == "") { - results.append(whitespace + result.get_construct_string()); + results.push_back(whitespace + result.get_construct_string()); } else { - results.append(line); + results.push_back(line); } } else { - results.append(line); + results.push_back(line); } } - code_editor->get_text_edit()->begin_complex_operation(); //prevents creating a two-step undo - code_editor->get_text_edit()->insert_text_at_cursor(results.join("\n")); - code_editor->get_text_edit()->end_complex_operation(); + code_editor->get_text_editor()->begin_complex_operation(); //prevents creating a two-step undo + code_editor->get_text_editor()->insert_text_at_cursor(String("\n").join(results)); + code_editor->get_text_editor()->end_complex_operation(); } break; case SEARCH_FIND: { - code_editor->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - code_editor->get_find_replace_bar()->search_next(); } break; case SEARCH_FIND_PREV: { - code_editor->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - code_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_IN_FILES: { - - String selected_text = code_editor->get_text_edit()->get_selection_text(); + String selected_text = code_editor->get_text_editor()->get_selection_text(); // Yep, because it doesn't make sense to instance this dialog for every single script open... // So this will be delegated to the ScriptEditor. emit_signal("search_in_files_requested", selected_text); } break; - case SEARCH_LOCATE_FUNCTION: { + case REPLACE_IN_FILES: { + String selected_text = code_editor->get_text_editor()->get_selection_text(); + emit_signal("replace_in_files_requested", selected_text); + } break; + case SEARCH_LOCATE_FUNCTION: { quick_open->popup_dialog(get_functions()); quick_open->set_title(TTR("Go to Function")); } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(tx); } break; case BOOKMARK_TOGGLE: { - code_editor->toggle_bookmark(); } break; case BOOKMARK_GOTO_NEXT: { - code_editor->goto_next_bookmark(); } break; case BOOKMARK_GOTO_PREV: { - code_editor->goto_prev_bookmark(); } break; case BOOKMARK_REMOVE_ALL: { - code_editor->remove_all_bookmarks(); } break; case DEBUG_TOGGLE_BREAKPOINT: { - int line = tx->cursor_get_line(); - bool dobreak = !tx->is_line_set_as_breakpoint(line); + bool dobreak = !tx->is_line_breakpointed(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); + EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { + Array bpoints = tx->get_breakpointed_lines(); - List<int> bpoints; - tx->get_breakpoints(&bpoints); - - for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { - int line = E->get(); - bool dobreak = !tx->is_line_set_as_breakpoint(line); + for (int i = 0; i < bpoints.size(); i++) { + int line = bpoints[i]; + bool dobreak = !tx->is_line_breakpointed(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); + EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak); } } break; case DEBUG_GOTO_NEXT_BREAKPOINT: { - - List<int> bpoints; - tx->get_breakpoints(&bpoints); + Array bpoints = tx->get_breakpointed_lines(); if (bpoints.size() <= 0) { return; } @@ -1313,13 +1241,13 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); // wrap around - if (line >= bpoints[bpoints.size() - 1]) { + if (line >= (int)bpoints[bpoints.size() - 1]) { tx->unfold_line(bpoints[0]); tx->cursor_set_line(bpoints[0]); tx->center_viewport_to_cursor(); } else { - for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { - int bline = E->get(); + for (int i = 0; i < bpoints.size(); i++) { + int bline = bpoints[i]; if (bline > line) { tx->unfold_line(bline); tx->cursor_set_line(bline); @@ -1331,22 +1259,20 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case DEBUG_GOTO_PREV_BREAKPOINT: { - - List<int> bpoints; - tx->get_breakpoints(&bpoints); + Array bpoints = tx->get_breakpointed_lines(); if (bpoints.size() <= 0) { return; } int line = tx->cursor_get_line(); // wrap around - if (line <= bpoints[0]) { + if (line <= (int)bpoints[0]) { tx->unfold_line(bpoints[bpoints.size() - 1]); tx->cursor_set_line(bpoints[bpoints.size() - 1]); tx->center_viewport_to_cursor(); } else { - for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) { - int bline = E->get(); + for (int i = bpoints.size(); i >= 0; i--) { + int bline = bpoints[i]; if (bline < line) { tx->unfold_line(bline); tx->cursor_set_line(bline); @@ -1358,19 +1284,19 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case HELP_CONTEXTUAL: { - String text = tx->get_selection_text(); - if (text == "") + if (text == "") { text = tx->get_word_under_cursor(); + } if (text != "") { emit_signal("request_help", text); } } break; case LOOKUP_SYMBOL: { - String text = tx->get_word_under_cursor(); - if (text == "") + if (text == "") { text = tx->get_selection_text(); + } if (text != "") { _lookup_symbol(text, tx->cursor_get_line(), tx->cursor_get_column()); } @@ -1379,8 +1305,9 @@ void ScriptTextEditor::_edit_option(int p_op) { } void ScriptTextEditor::_edit_option_toggle_inline_comment() { - if (script.is_null()) + if (script.is_null()) { return; + } String delimiter = "#"; List<String> comment_delimiters; @@ -1397,58 +1324,53 @@ void ScriptTextEditor::_edit_option_toggle_inline_comment() { 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()); -} +void ScriptTextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); -void ScriptTextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) { - TextEdit *te = code_editor->get_text_edit(); - te->_set_syntax_highlighting(p_highlighter); - if (p_highlighter != NULL) - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true); - else - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(TTR("Standard")), true); + highlighters[p_highlighter->_get_name()] = p_highlighter; + highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } -void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { - Map<String, SyntaxHighlighter *>::Element *el = highlighters.front(); - while (el != NULL) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); +void ScriptTextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + + Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); + while (el != nullptr) { + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); el = el->next(); } - // highlighter_menu->set_item_checked(p_idx, true); + + CodeEdit *te = code_editor->get_text_editor(); + p_highlighter->_set_edited_resource(script); + te->set_syntax_highlighter(p_highlighter); +} + +void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } -void ScriptTextEditor::_bind_methods() { +void ScriptTextEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + code_editor->get_text_editor()->set_gutter_width(connection_gutter, code_editor->get_text_editor()->get_row_height()); + } break; + default: + break; + } +} - ClassDB::bind_method("_validate_script", &ScriptTextEditor::_validate_script); - ClassDB::bind_method("_update_bookmark_list", &ScriptTextEditor::_update_bookmark_list); - ClassDB::bind_method("_bookmark_item_pressed", &ScriptTextEditor::_bookmark_item_pressed); - ClassDB::bind_method("_load_theme_settings", &ScriptTextEditor::_load_theme_settings); - ClassDB::bind_method("_update_breakpoint_list", &ScriptTextEditor::_update_breakpoint_list); - ClassDB::bind_method("_breakpoint_item_pressed", &ScriptTextEditor::_breakpoint_item_pressed); - ClassDB::bind_method("_breakpoint_toggled", &ScriptTextEditor::_breakpoint_toggled); - ClassDB::bind_method("_lookup_connections", &ScriptTextEditor::_lookup_connections); +void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods); - ClassDB::bind_method("_change_syntax_highlighter", &ScriptTextEditor::_change_syntax_highlighter); - ClassDB::bind_method("_edit_option", &ScriptTextEditor::_edit_option); - 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("_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); ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); ClassDB::bind_method("can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw); ClassDB::bind_method("drop_data_fw", &ScriptTextEditor::drop_data_fw); + + ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &ScriptTextEditor::add_syntax_highlighter); } Control *ScriptTextEditor::get_edit_menu() { - return edit_hb; } @@ -1457,43 +1379,38 @@ void ScriptTextEditor::clear_edit_menu() { } void ScriptTextEditor::reload(bool p_soft) { - - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); Ref<Script> scr = script; - if (scr.is_null()) + if (scr.is_null()) { return; + } scr->set_source_code(te->get_text()); bool soft = p_soft || scr->get_instance_base_type() == "EditorPlugin"; //always soft-reload editor plugins scr->get_language()->reload_tool_script(scr, soft); } -void ScriptTextEditor::get_breakpoints(List<int> *p_breakpoints) { - - code_editor->get_text_edit()->get_breakpoints(p_breakpoints); +Array ScriptTextEditor::get_breakpoints() { + return code_editor->get_text_editor()->get_breakpointed_lines(); } void ScriptTextEditor::set_tooltip_request_func(String p_method, Object *p_obj) { - - code_editor->get_text_edit()->set_tooltip_request_func(p_obj, p_method, this); + code_editor->get_text_editor()->set_tooltip_request_func(p_obj, p_method, this); } void ScriptTextEditor::set_debugger_active(bool p_active) { } Variant ScriptTextEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - return Variant(); } bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; if (d.has("type") && (String(d["type"]) == "resource" || String(d["type"]) == "files" || String(d["type"]) == "nodes" || String(d["type"]) == "files_and_dirs")) { - return true; } @@ -1501,34 +1418,34 @@ bool ScriptTextEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_ } static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) { - - if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) - return NULL; + if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) { + return nullptr; + } Ref<Script> scr = p_current_node->get_script(); - if (scr.is_valid() && scr == script) + if (scr.is_valid() && scr == script) { return p_current_node; + } for (int i = 0; i < p_current_node->get_child_count(); i++) { Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script); - if (n) + if (n) { return n; + } } - return NULL; + return nullptr; } void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - Dictionary d = p_data; - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); int row, col; te->_get_mouse_pos(p_point, row, col); if (d.has("type") && String(d["type"]) == "resource") { - Ref<Resource> res = d["resource"]; if (!res.is_valid()) { return; @@ -1545,14 +1462,13 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) { - Array files = d["files"]; String text_to_drop; for (int i = 0; i < files.size(); i++) { - - if (i > 0) + if (i > 0) { text_to_drop += ","; + } text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } @@ -1562,7 +1478,6 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } if (d.has("type") && String(d["type"]) == "nodes") { - Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script); if (!sn) { @@ -1573,9 +1488,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data Array nodes = d["nodes"]; String text_to_drop; for (int i = 0; i < nodes.size(); i++) { - - if (i > 0) + if (i > 0) { text_to_drop += ","; + } NodePath np = nodes[i]; Node *node = get_node(np); @@ -1594,17 +1509,16 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { - Ref<InputEventMouseButton> mb = ev; Ref<InputEventKey> k = ev; Point2 local_pos; bool create_menu = false; - TextEdit *tx = code_editor->get_text_edit(); + CodeEdit *tx = code_editor->get_text_editor(); if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { local_pos = mb->get_global_position() - tx->get_global_position(); create_menu = true; - } else if (k.is_valid() && k->get_scancode() == KEY_MENU) { + } else if (k.is_valid() && k->get_keycode() == KEY_MENU) { local_pos = tx->_get_cursor_pixel_pos(); create_menu = true; } @@ -1633,10 +1547,12 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } String word_at_pos = tx->get_word_at_pos(local_pos); - if (word_at_pos == "") + if (word_at_pos == "") { word_at_pos = tx->get_word_under_cursor(); - if (word_at_pos == "") + } + if (word_at_pos == "") { word_at_pos = tx->get_selection_text(); + } bool has_color = (word_at_pos == "Color"); bool foldable = tx->can_fold(row) || tx->is_folded(row); @@ -1651,7 +1567,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { base = _find_node_for_script(base, base, script); } ScriptLanguage::LookupResult result; - if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), word_at_pos, script->get_path(), base, result) == OK) { + if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_lookup_completion(), word_at_pos, script->get_path(), base, result) == OK) { open_docs = true; } } @@ -1699,21 +1615,20 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { new_args = String("(" + rtos(p_color.r) + ", " + rtos(p_color.g) + ", " + rtos(p_color.b) + ", " + rtos(p_color.a) + ")"); } - String line = code_editor->get_text_edit()->get_line(color_position.x); + String line = code_editor->get_text_editor()->get_line(color_position.x); int color_args_pos = line.find(color_args, color_position.y); String line_with_replaced_args = line; line_with_replaced_args.erase(color_args_pos, color_args.length()); line_with_replaced_args = line_with_replaced_args.insert(color_args_pos, new_args); color_args = new_args; - code_editor->get_text_edit()->begin_complex_operation(); - code_editor->get_text_edit()->set_line(color_position.x, line_with_replaced_args); - code_editor->get_text_edit()->end_complex_operation(); - code_editor->get_text_edit()->update(); + code_editor->get_text_editor()->begin_complex_operation(); + code_editor->get_text_editor()->set_line(color_position.x, line_with_replaced_args); + code_editor->get_text_editor()->end_complex_operation(); + code_editor->get_text_editor()->update(); } void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition, Vector2 p_pos) { - context_menu->clear(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); @@ -1738,15 +1653,18 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE); } - if (p_foldable) + if (p_foldable) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + } if (p_color || p_open_docs || p_goto_definition) { context_menu->add_separator(); - if (p_open_docs) + if (p_open_docs) { context_menu->add_item(TTR("Lookup Symbol"), LOOKUP_SYMBOL); - if (p_color) + } + if (p_color) { context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); + } } context_menu->set_position(get_global_transform().xform(p_pos)); @@ -1754,77 +1672,73 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->popup(); } -ScriptTextEditor::ScriptTextEditor() { - - theme_loaded = false; - script_is_valid = false; +void ScriptTextEditor::_enable_code_editor() { + ERR_FAIL_COND(code_editor->get_parent()); VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); - code_editor = memnew(CodeTextEditor); editor_box->add_child(code_editor); - 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"); - code_editor->set_code_complete_func(_code_complete_scripts, this); - code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); - code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol"); - code_editor->get_text_edit()->connect("info_clicked", this, "_lookup_connections"); - code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); + code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script)); + code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings)); + code_editor->get_text_editor()->connect("breakpoint_toggled", callable_mp(this, &ScriptTextEditor::_breakpoint_toggled)); + code_editor->get_text_editor()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol)); + code_editor->get_text_editor()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol)); + code_editor->get_text_editor()->connect("gutter_added", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes)); + code_editor->get_text_editor()->connect("gutter_removed", callable_mp(this, &ScriptTextEditor::_update_gutter_indexes)); + code_editor->get_text_editor()->connect("gutter_clicked", callable_mp(this, &ScriptTextEditor::_gutter_clicked)); + code_editor->get_text_editor()->connect("gui_input", callable_mp(this, &ScriptTextEditor::_text_edit_gui_input)); code_editor->show_toggle_scripts_button(); + _update_gutter_indexes(); - warnings_panel = memnew(RichTextLabel); editor_box->add_child(warnings_panel); - warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); - warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); - warnings_panel->set_meta_underline(true); - warnings_panel->set_selection_enabled(true); - warnings_panel->set_focus_mode(FOCUS_CLICK); - warnings_panel->hide(); - - 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(); - - code_editor->get_text_edit()->set_callhint_settings( - EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), - EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); - - code_editor->get_text_edit()->set_select_identifiers_on_hover(true); - code_editor->get_text_edit()->set_context_menu_enabled(false); - code_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + warnings_panel->add_theme_font_override( + "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); + warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked)); - context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", this, "_edit_option"); - context_menu->set_hide_on_window_lose_focus(true); + context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - color_panel = memnew(PopupPanel); add_child(color_panel); + color_picker = memnew(ColorPicker); color_picker->set_deferred_mode(true); + color_picker->connect("color_changed", callable_mp(this, &ScriptTextEditor::_color_changed)); + color_panel->add_child(color_picker); - color_picker->connect("color_changed", this, "_color_changed"); // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); - if (default_color_mode == 1) + if (default_color_mode == 1) { color_picker->set_hsv_mode(true); - else if (default_color_mode == 2) + } else if (default_color_mode == 2) { color_picker->set_raw_mode(true); + } - edit_hb = memnew(HBoxContainer); + quick_open = memnew(ScriptEditorQuickOpen); + quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line)); + add_child(quick_open); - edit_menu = memnew(MenuButton); - edit_menu->set_text(TTR("Edit")); - edit_menu->set_switch_on_hover(true); - edit_menu->get_popup()->set_hide_on_window_lose_focus(true); + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); + + add_child(connection_info_dialog); + + edit_hb->add_child(search_menu); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); + search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); + + edit_hb->add_child(edit_menu); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -1851,101 +1765,149 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT); - edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_separator(); - PopupMenu *convert_case = memnew(PopupMenu); - convert_case->set_name("convert_case"); edit_menu->get_popup()->add_child(convert_case); edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KEY_MASK_SHIFT | KEY_F4), EDIT_TO_UPPERCASE); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KEY_MASK_SHIFT | KEY_F5), EDIT_TO_LOWERCASE); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F6), EDIT_CAPITALIZE); - convert_case->connect("id_pressed", this, "_edit_option"); + convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - highlighters[TTR("Standard")] = NULL; - highlighter_menu = memnew(PopupMenu); - highlighter_menu->set_name("highlighter_menu"); edit_menu->get_popup()->add_child(highlighter_menu); edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); - highlighter_menu->add_radio_check_item(TTR("Standard")); - highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); - - search_menu = memnew(MenuButton); - edit_hb->add_child(search_menu); - search_menu->set_text(TTR("Search")); - search_menu->set_switch_on_hover(true); - search_menu->get_popup()->set_hide_on_window_lose_focus(true); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); - search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter)); - edit_hb->add_child(edit_menu); + _load_theme_settings(); - MenuButton *goto_menu = memnew(MenuButton); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); edit_hb->add_child(goto_menu); - goto_menu->set_text(TTR("Go To")); - goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", this, "_edit_option"); - goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); goto_menu->get_popup()->add_separator(); - bookmarks_menu = memnew(PopupMenu); - bookmarks_menu->set_name("Bookmarks"); goto_menu->get_popup()->add_child(bookmarks_menu); goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); _update_bookmark_list(); - bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); - bookmarks_menu->connect("index_pressed", this, "_bookmark_item_pressed"); + bookmarks_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list)); + bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed)); - breakpoints_menu = memnew(PopupMenu); - breakpoints_menu->set_name("Breakpoints"); goto_menu->get_popup()->add_child(breakpoints_menu); goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints"); _update_breakpoint_list(); - breakpoints_menu->connect("about_to_show", this, "_update_breakpoint_list"); - breakpoints_menu->connect("index_pressed", this, "_breakpoint_item_pressed"); + breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); + breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); - quick_open = memnew(ScriptEditorQuickOpen); - add_child(quick_open); - quick_open->connect("goto_line", this, "_goto_line"); + goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); +} - goto_line_dialog = memnew(GotoLineDialog); - add_child(goto_line_dialog); +ScriptTextEditor::ScriptTextEditor() { + code_editor = memnew(CodeTextEditor); + code_editor->add_theme_constant_override("separation", 2); + code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_code_complete_func(_code_complete_scripts, this); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + code_editor->get_text_editor()->set_draw_breakpoints_gutter(true); + code_editor->get_text_editor()->set_draw_executing_lines_gutter(true); + + connection_gutter = 1; + code_editor->get_text_editor()->add_gutter(connection_gutter); + code_editor->get_text_editor()->set_gutter_name(connection_gutter, "connection_gutter"); + code_editor->get_text_editor()->set_gutter_draw(connection_gutter, false); + code_editor->get_text_editor()->set_gutter_overwritable(connection_gutter, true); + code_editor->get_text_editor()->set_gutter_type(connection_gutter, TextEdit::GUTTER_TPYE_ICON); + + warnings_panel = memnew(RichTextLabel); + warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); + warnings_panel->set_meta_underline(true); + warnings_panel->set_selection_enabled(true); + warnings_panel->set_focus_mode(FOCUS_CLICK); + warnings_panel->hide(); + + update_settings(); + + code_editor->get_text_editor()->set_callhint_settings( + EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), + EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); + + code_editor->get_text_editor()->set_select_identifiers_on_hover(true); + code_editor->get_text_editor()->set_context_menu_enabled(false); + + context_menu = memnew(PopupMenu); + + color_panel = memnew(PopupPanel); + + edit_hb = memnew(HBoxContainer); + + edit_menu = memnew(MenuButton); + edit_menu->set_text(TTR("Edit")); + edit_menu->set_switch_on_hover(true); + + convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + + highlighter_menu = memnew(PopupMenu); + highlighter_menu->set_name("highlighter_menu"); + + Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; + plain_highlighter.instance(); + add_syntax_highlighter(plain_highlighter); + + Ref<EditorStandardSyntaxHighlighter> highlighter; + highlighter.instance(); + add_syntax_highlighter(highlighter); + set_syntax_highlighter(highlighter); + + search_menu = memnew(MenuButton); + search_menu->set_text(TTR("Search")); + search_menu->set_switch_on_hover(true); + + goto_menu = memnew(MenuButton); + goto_menu->set_text(TTR("Go To")); + goto_menu->set_switch_on_hover(true); + + bookmarks_menu = memnew(PopupMenu); + bookmarks_menu->set_name("Bookmarks"); + + breakpoints_menu = memnew(PopupMenu); + breakpoints_menu->set_name("Breakpoints"); connection_info_dialog = memnew(ConnectionInfoDialog); - add_child(connection_info_dialog); - code_editor->get_text_edit()->set_drag_forwarding(this); + code_editor->get_text_editor()->set_drag_forwarding(this); } ScriptTextEditor::~ScriptTextEditor() { - for (const Map<String, SyntaxHighlighter *>::Element *E = highlighters.front(); E; E = E->next()) { - if (E->get() != NULL) { - memdelete(E->get()); - } - } highlighters.clear(); + + if (!editor_enabled) { + memdelete(code_editor); + memdelete(warnings_panel); + memdelete(context_menu); + memdelete(color_panel); + memdelete(edit_hb); + memdelete(edit_menu); + memdelete(convert_case); + memdelete(highlighter_menu); + memdelete(search_menu); + memdelete(goto_menu); + memdelete(bookmarks_menu); + memdelete(breakpoints_menu); + memdelete(connection_info_dialog); + } } static ScriptEditorBase *create_editor(const RES &p_resource) { - if (Object::cast_to<Script>(*p_resource)) { return memnew(ScriptTextEditor); } - return NULL; + return nullptr; } void ScriptTextEditor::register_editor() { - ED_SHORTCUT("script_text_editor/undo", TTR("Undo"), KEY_MASK_CMD | KEY_Z); ED_SHORTCUT("script_text_editor/redo", TTR("Redo"), KEY_MASK_CMD | KEY_Y); ED_SHORTCUT("script_text_editor/cut", TTR("Cut"), KEY_MASK_CMD | KEY_X); @@ -1990,6 +1952,7 @@ void ScriptTextEditor::register_editor() { #endif ED_SHORTCUT("script_text_editor/find_in_files", TTR("Find in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F); + ED_SHORTCUT("script_text_editor/replace_in_files", TTR("Replace in Files..."), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R); #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 9018e9d3c2..1e436fbe65 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -37,13 +37,12 @@ #include "script_editor_plugin.h" class ConnectionInfoDialog : public AcceptDialog { - GDCLASS(ConnectionInfoDialog, AcceptDialog); - Label *method; - Tree *tree; + Label *method = nullptr; + Tree *tree = nullptr; - virtual void ok_pressed(); + virtual void ok_pressed() override; public: void popup_connections(String p_method, Vector<Node *> p_nodes); @@ -52,14 +51,14 @@ public: }; class ScriptTextEditor : public ScriptEditorBase { - GDCLASS(ScriptTextEditor, ScriptEditorBase); - CodeTextEditor *code_editor; - RichTextLabel *warnings_panel; + CodeTextEditor *code_editor = nullptr; + RichTextLabel *warnings_panel = nullptr; Ref<Script> script; - bool script_is_valid; + bool script_is_valid = false; + bool editor_enabled = false; Vector<String> functions; @@ -67,37 +66,35 @@ class ScriptTextEditor : public ScriptEditorBase { Vector<String> member_keywords; - HBoxContainer *edit_hb; + HBoxContainer *edit_hb = nullptr; - MenuButton *edit_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *breakpoints_menu; - PopupMenu *highlighter_menu; - PopupMenu *context_menu; + MenuButton *edit_menu = nullptr; + MenuButton *search_menu = nullptr; + MenuButton *goto_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *breakpoints_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + PopupMenu *context_menu = nullptr; + PopupMenu *convert_case = nullptr; - GotoLineDialog *goto_line_dialog; - ScriptEditorQuickOpen *quick_open; - ConnectionInfoDialog *connection_info_dialog; + GotoLineDialog *goto_line_dialog = nullptr; + ScriptEditorQuickOpen *quick_open = nullptr; + ConnectionInfoDialog *connection_info_dialog = nullptr; - PopupPanel *color_panel; - ColorPicker *color_picker; - Vector2 color_position; - String color_args; + int connection_gutter = -1; + void _gutter_clicked(int p_line, int p_gutter); + void _update_gutter_indexes(); - void _update_member_keywords(); + int line_number_gutter = -1; + Color default_line_number_color = Color(1, 1, 1); + Color safe_line_number_color = Color(1, 1, 1); - struct ColorsCache { - Color symbol_color; - Color keyword_color; - Color basetype_color; - Color type_color; - Color usertype_color; - Color comment_color; - Color string_color; - } colors_cache; + PopupPanel *color_panel = nullptr; + ColorPicker *color_picker = nullptr; + Vector2 color_position; + String color_args; - bool theme_loaded; + bool theme_loaded = false; enum { EDIT_UNDO, @@ -133,6 +130,7 @@ class ScriptTextEditor : public ScriptEditorBase { SEARCH_LOCATE_FUNCTION, SEARCH_GOTO_LINE, SEARCH_IN_FILES, + REPLACE_IN_FILES, BOOKMARK_TOGGLE, BOOKMARK_GOTO_NEXT, BOOKMARK_GOTO_PREV, @@ -145,6 +143,8 @@ class ScriptTextEditor : public ScriptEditorBase { LOOKUP_SYMBOL, }; + void _enable_code_editor(); + protected: void _update_breakpoint_list(); void _breakpoint_item_pressed(int p_idx); @@ -160,13 +160,12 @@ protected: void _load_theme_settings(); void _set_theme_for_script(); void _show_warnings_panel(bool p_show); - void _error_pressed(); void _warning_clicked(Variant p_line); void _notification(int p_what); static void _bind_methods(); - Map<String, SyntaxHighlighter *> highlighters; + Map<String, Ref<EditorSyntaxHighlighter>> highlighters; void _change_syntax_highlighter(int p_idx); void _edit_option(int p_op); @@ -177,8 +176,7 @@ protected: void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); - - void _lookup_connections(int p_row, String p_method); + void _validate_symbol(const String &p_symbol); void _convert_case(CodeTextEditor::CaseStyle p_case); @@ -186,53 +184,56 @@ protected: bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + String _get_absolute_path(const String &rel_path); + public: void _update_connected_methods(); - virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); - virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); + virtual void add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; + virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; void update_toggle_scripts_button(); - virtual void apply_code(); - virtual RES get_edited_resource() const; - virtual void set_edited_resource(const RES &p_res); - virtual Vector<String> get_functions(); - virtual void reload_text(); - virtual String get_name(); - virtual Ref<Texture> get_icon(); - virtual bool is_unsaved(); - virtual Variant get_edit_state(); - virtual void set_edit_state(const Variant &p_state); - virtual void ensure_focus(); - virtual void trim_trailing_whitespace(); - virtual void insert_final_newline(); - virtual void convert_indent_to_spaces(); - virtual void convert_indent_to_tabs(); - virtual void tag_saved_version(); - - virtual void goto_line(int p_line, bool p_with_error = false); + virtual void apply_code() override; + virtual RES get_edited_resource() const override; + virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; + virtual Vector<String> get_functions() override; + virtual void reload_text() override; + virtual String get_name() override; + virtual Ref<Texture2D> get_theme_icon() override; + virtual bool is_unsaved() override; + virtual Variant get_edit_state() override; + virtual void set_edit_state(const Variant &p_state) override; + virtual void ensure_focus() override; + virtual void trim_trailing_whitespace() override; + virtual void insert_final_newline() override; + virtual void convert_indent_to_spaces() override; + virtual void convert_indent_to_tabs() override; + virtual void tag_saved_version() override; + + virtual void goto_line(int p_line, bool p_with_error = false) override; void goto_line_selection(int p_line, int p_begin, int p_end); void goto_line_centered(int p_line); - virtual void set_executing_line(int p_line); - virtual void clear_executing_line(); + virtual void set_executing_line(int p_line) override; + virtual void clear_executing_line() override; - virtual void reload(bool p_soft); - virtual void get_breakpoints(List<int> *p_breakpoints); + virtual void reload(bool p_soft) override; + virtual Array get_breakpoints() override; - virtual void add_callback(const String &p_function, PoolStringArray p_args); - virtual void update_settings(); + virtual void add_callback(const String &p_function, PackedStringArray p_args) override; + virtual void update_settings() override; - virtual bool show_members_overview(); + virtual bool show_members_overview() override; - virtual void set_tooltip_request_func(String p_method, Object *p_obj); + virtual void set_tooltip_request_func(String p_method, Object *p_obj) override; - virtual void set_debugger_active(bool p_active); + virtual void set_debugger_active(bool p_active) override; - Control *get_edit_menu(); - virtual void clear_edit_menu(); + Control *get_edit_menu() override; + virtual void clear_edit_menu() override; static void register_editor(); - virtual void validate(); + virtual void validate() override; ScriptTextEditor(); ~ScriptTextEditor(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index c24a666c55..29db284b44 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -38,16 +38,16 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/property_editor.h" -#include "servers/visual/shader_types.h" +#include "servers/display_server.h" +#include "servers/rendering/shader_types.h" /*** SHADER SCRIPT EDITOR ****/ Ref<Shader> ShaderTextEditor::get_edited_shader() const { - return shader; } -void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) { +void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) { if (shader == p_shader) { return; } @@ -55,8 +55,8 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) { _load_theme_settings(); - get_text_edit()->set_text(p_shader->get_code()); - get_text_edit()->clear_undo_history(); + get_text_editor()->set_text(p_shader->get_code()); + get_text_editor()->clear_undo_history(); _validate_script(); _line_col_changed(); @@ -65,7 +65,7 @@ void ShaderTextEditor::set_edited_shader(const Ref<Shader> &p_shader) { void ShaderTextEditor::reload_text() { ERR_FAIL_COND(shader.is_null()); - TextEdit *te = get_text_edit(); + CodeEdit *te = get_text_editor(); int column = te->cursor_get_column(); int row = te->cursor_get_line(); int h = te->get_h_scroll(); @@ -83,9 +83,6 @@ void ShaderTextEditor::reload_text() { } void ShaderTextEditor::_load_theme_settings() { - - get_text_edit()->clear_colors(); - Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color"); Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color"); @@ -102,9 +99,6 @@ void ShaderTextEditor::_load_theme_settings() { Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color"); Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color"); Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color"); - Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); - Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); - Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); @@ -112,69 +106,77 @@ void ShaderTextEditor::_load_theme_settings() { Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); - Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); - Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); - - get_text_edit()->add_color_override("background_color", background_color); - get_text_edit()->add_color_override("completion_background_color", completion_background_color); - get_text_edit()->add_color_override("completion_selected_color", completion_selected_color); - get_text_edit()->add_color_override("completion_existing_color", completion_existing_color); - get_text_edit()->add_color_override("completion_scroll_color", completion_scroll_color); - get_text_edit()->add_color_override("completion_font_color", completion_font_color); - get_text_edit()->add_color_override("font_color", text_color); - get_text_edit()->add_color_override("line_number_color", line_number_color); - get_text_edit()->add_color_override("caret_color", caret_color); - get_text_edit()->add_color_override("caret_background_color", caret_background_color); - get_text_edit()->add_color_override("font_color_selected", text_selected_color); - get_text_edit()->add_color_override("selection_color", selection_color); - get_text_edit()->add_color_override("brace_mismatch_color", brace_mismatch_color); - get_text_edit()->add_color_override("current_line_color", current_line_color); - get_text_edit()->add_color_override("line_length_guideline_color", line_length_guideline_color); - get_text_edit()->add_color_override("word_highlighted_color", word_highlighted_color); - get_text_edit()->add_color_override("number_color", number_color); - get_text_edit()->add_color_override("function_color", function_color); - get_text_edit()->add_color_override("member_variable_color", member_variable_color); - get_text_edit()->add_color_override("mark_color", mark_color); - get_text_edit()->add_color_override("bookmark_color", bookmark_color); - get_text_edit()->add_color_override("breakpoint_color", breakpoint_color); - get_text_edit()->add_color_override("executing_line_color", executing_line_color); - get_text_edit()->add_color_override("code_folding_color", code_folding_color); - get_text_edit()->add_color_override("search_result_color", search_result_color); - get_text_edit()->add_color_override("search_result_border_color", search_result_border_color); - get_text_edit()->add_color_override("symbol_color", symbol_color); + + get_text_editor()->add_theme_color_override("background_color", background_color); + get_text_editor()->add_theme_color_override("completion_background_color", completion_background_color); + get_text_editor()->add_theme_color_override("completion_selected_color", completion_selected_color); + get_text_editor()->add_theme_color_override("completion_existing_color", completion_existing_color); + get_text_editor()->add_theme_color_override("completion_scroll_color", completion_scroll_color); + get_text_editor()->add_theme_color_override("completion_font_color", completion_font_color); + get_text_editor()->add_theme_color_override("font_color", text_color); + get_text_editor()->add_theme_color_override("line_number_color", line_number_color); + get_text_editor()->add_theme_color_override("caret_color", caret_color); + get_text_editor()->add_theme_color_override("caret_background_color", caret_background_color); + get_text_editor()->add_theme_color_override("font_color_selected", text_selected_color); + get_text_editor()->add_theme_color_override("selection_color", selection_color); + get_text_editor()->add_theme_color_override("brace_mismatch_color", brace_mismatch_color); + get_text_editor()->add_theme_color_override("current_line_color", current_line_color); + get_text_editor()->add_theme_color_override("line_length_guideline_color", line_length_guideline_color); + get_text_editor()->add_theme_color_override("word_highlighted_color", word_highlighted_color); + get_text_editor()->add_theme_color_override("mark_color", mark_color); + get_text_editor()->add_theme_color_override("bookmark_color", bookmark_color); + get_text_editor()->add_theme_color_override("breakpoint_color", breakpoint_color); + get_text_editor()->add_theme_color_override("executing_line_color", executing_line_color); + get_text_editor()->add_theme_color_override("code_folding_color", code_folding_color); + get_text_editor()->add_theme_color_override("search_result_color", search_result_color); + get_text_editor()->add_theme_color_override("search_result_border_color", search_result_border_color); + + syntax_highlighter->set_number_color(EDITOR_GET("text_editor/highlighting/number_color")); + syntax_highlighter->set_symbol_color(EDITOR_GET("text_editor/highlighting/symbol_color")); + syntax_highlighter->set_function_color(EDITOR_GET("text_editor/highlighting/function_color")); + syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/highlighting/member_variable_color")); + + syntax_highlighter->clear_keyword_colors(); List<String> keywords; ShaderLanguage::get_keyword_list(&keywords); + const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - if (shader.is_valid()) { + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), keyword_color); + } - for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { + // Colorize built-ins like `COLOR` differently to make them easier + // to distinguish from keywords at a quick glance. + List<String> built_ins; + if (shader.is_valid()) { + for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) { - keywords.push_back(F->key()); + built_ins.push_back(F->key()); } } - for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())).size(); i++) { - - keywords.push_back(ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode()))[i]); + for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) { + built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); } } - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); - get_text_edit()->add_keyword_color(E->get(), keyword_color); + for (List<String>::Element *E = built_ins.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), member_variable_color); } - //colorize comments - get_text_edit()->add_color_region("/*", "*/", comment_color, false); - get_text_edit()->add_color_region("//", "", comment_color, false); + // Colorize comments. + const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + syntax_highlighter->clear_color_regions(); + syntax_highlighter->add_color_region("/*", "*/", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); } void ShaderTextEditor::_check_shader_mode() { - - String type = ShaderLanguage::get_shader_type(get_text_edit()->get_text()); + String type = ShaderLanguage::get_shader_type(get_text_editor()->get_text()); Shader::Mode mode; @@ -187,46 +189,51 @@ void ShaderTextEditor::_check_shader_mode() { } if (shader->get_mode() != mode) { - shader->set_code(get_text_edit()->get_text()); + shader->set_code(get_text_editor()->get_text()); _load_theme_settings(); } } -void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) { +static ShaderLanguage::DataType _get_global_variable_type(const StringName &p_variable) { + RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(p_variable); + return RS::global_variable_type_get_shader_datatype(gvt); +} +void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) { _check_shader_mode(); ShaderLanguage sl; String calltip; - sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), r_options, calltip); + sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip); - get_text_edit()->set_code_hint(calltip); + get_text_editor()->set_code_hint(calltip); } void ShaderTextEditor::_validate_script() { - _check_shader_mode(); - String code = get_text_edit()->get_text(); + String code = get_text_editor()->get_text(); //List<StringName> params; //shader->get_param_list(¶ms); ShaderLanguage sl; - Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types()); + Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type); if (err != OK) { String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); set_error(error_text); set_error_pos(sl.get_error_line() - 1, 0); - for (int i = 0; i < get_text_edit()->get_line_count(); i++) - get_text_edit()->set_line_as_marked(i, false); - get_text_edit()->set_line_as_marked(sl.get_error_line() - 1, true); + for (int i = 0; i < get_text_editor()->get_line_count(); i++) { + get_text_editor()->set_line_as_marked(i, false); + } + get_text_editor()->set_line_as_marked(sl.get_error_line() - 1, true); } else { - for (int i = 0; i < get_text_edit()->get_line_count(); i++) - get_text_edit()->set_line_as_marked(i, false); + for (int i = 0; i < get_text_editor()->get_line_count(); i++) { + get_text_editor()->set_line_as_marked(i, false); + } set_error(""); } @@ -237,30 +244,31 @@ void ShaderTextEditor::_bind_methods() { } ShaderTextEditor::ShaderTextEditor() { + syntax_highlighter.instance(); + get_text_editor()->set_syntax_highlighter(syntax_highlighter); } /*** SCRIPT EDITOR ******/ void ShaderEditor::_menu_option(int p_option) { - switch (p_option) { case EDIT_UNDO: { - shader_editor->get_text_edit()->undo(); + shader_editor->get_text_editor()->undo(); } break; case EDIT_REDO: { - shader_editor->get_text_edit()->redo(); + shader_editor->get_text_editor()->redo(); } break; case EDIT_CUT: { - shader_editor->get_text_edit()->cut(); + shader_editor->get_text_editor()->cut(); } break; case EDIT_COPY: { - shader_editor->get_text_edit()->copy(); + shader_editor->get_text_editor()->copy(); } break; case EDIT_PASTE: { - shader_editor->get_text_edit()->paste(); + shader_editor->get_text_editor()->paste(); } break; case EDIT_SELECT_ALL: { - shader_editor->get_text_edit()->select_all(); + shader_editor->get_text_editor()->select_all(); } break; case EDIT_MOVE_LINE_UP: { shader_editor->move_lines_up(); @@ -269,20 +277,20 @@ void ShaderEditor::_menu_option(int p_option) { shader_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - - if (shader.is_null()) + if (shader.is_null()) { return; + } - TextEdit *tx = shader_editor->get_text_edit(); + CodeEdit *tx = shader_editor->get_text_editor(); tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { - - if (shader.is_null()) + if (shader.is_null()) { return; + } - TextEdit *tx = shader_editor->get_text_edit(); + CodeEdit *tx = shader_editor->get_text_editor(); tx->indent_right(); } break; @@ -293,51 +301,41 @@ void ShaderEditor::_menu_option(int p_option) { shader_editor->clone_lines_down(); } break; case EDIT_TOGGLE_COMMENT: { - - if (shader.is_null()) + if (shader.is_null()) { return; + } shader_editor->toggle_inline_comment("//"); } break; case EDIT_COMPLETE: { - - shader_editor->get_text_edit()->query_code_comple(); + shader_editor->get_text_editor()->query_code_comple(); } break; case SEARCH_FIND: { - shader_editor->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - shader_editor->get_find_replace_bar()->search_next(); } break; case SEARCH_FIND_PREV: { - shader_editor->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - shader_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_GOTO_LINE: { - - goto_line_dialog->popup_find_line(shader_editor->get_text_edit()); + goto_line_dialog->popup_find_line(shader_editor->get_text_editor()); } break; case BOOKMARK_TOGGLE: { - shader_editor->toggle_bookmark(); } break; case BOOKMARK_GOTO_NEXT: { - shader_editor->goto_next_bookmark(); } break; case BOOKMARK_GOTO_PREV: { - shader_editor->goto_prev_bookmark(); } break; case BOOKMARK_REMOVE_ALL: { - shader_editor->remove_all_bookmarks(); } break; case HELP_DOCS: { @@ -345,61 +343,33 @@ void ShaderEditor::_menu_option(int p_option) { } break; } if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { - shader_editor->get_text_edit()->call_deferred("grab_focus"); + shader_editor->get_text_editor()->call_deferred("grab_focus"); } } void ShaderEditor::_notification(int p_what) { - - if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) { + if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) { _check_for_external_edit(); } } void ShaderEditor::_params_changed() { - shader_editor->_validate_script(); } void ShaderEditor::_editor_settings_changed() { + shader_editor->update_editor_settings(); - shader_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete")); - shader_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file")); - shader_editor->get_text_edit()->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size")); - shader_editor->get_text_edit()->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type")); - shader_editor->get_text_edit()->set_auto_indent(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent")); - shader_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs")); - shader_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_numbers")); - shader_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting")); - shader_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_all_occurrences")); - shader_editor->get_text_edit()->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line")); - shader_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); - shader_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); - shader_editor->get_text_edit()->add_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing")); - shader_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); - shader_editor->get_text_edit()->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/navigation/smooth_scrolling")); - shader_editor->get_text_edit()->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/navigation/v_scroll_speed")); - shader_editor->get_text_edit()->set_draw_minimap(EditorSettings::get_singleton()->get("text_editor/navigation/show_minimap")); - shader_editor->get_text_edit()->set_minimap_width((int)EditorSettings::get_singleton()->get("text_editor/navigation/minimap_width") * EDSCALE); + shader_editor->get_text_editor()->add_theme_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/theme/line_spacing")); + shader_editor->get_text_editor()->set_draw_breakpoints_gutter(false); + shader_editor->get_text_editor()->set_draw_executing_lines_gutter(false); } void ShaderEditor::_bind_methods() { - - ClassDB::bind_method("_reload_shader_from_disk", &ShaderEditor::_reload_shader_from_disk); - ClassDB::bind_method("_editor_settings_changed", &ShaderEditor::_editor_settings_changed); - ClassDB::bind_method("_text_edit_gui_input", &ShaderEditor::_text_edit_gui_input); - - ClassDB::bind_method("_update_bookmark_list", &ShaderEditor::_update_bookmark_list); - ClassDB::bind_method("_bookmark_item_pressed", &ShaderEditor::_bookmark_item_pressed); - - ClassDB::bind_method("_menu_option", &ShaderEditor::_menu_option); ClassDB::bind_method("_params_changed", &ShaderEditor::_params_changed); - ClassDB::bind_method("apply_shaders", &ShaderEditor::apply_shaders); - ClassDB::bind_method("save_external_data", &ShaderEditor::save_external_data); } void ShaderEditor::ensure_select_current() { - /* if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) { @@ -412,12 +382,10 @@ void ShaderEditor::ensure_select_current() { } void ShaderEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - shader_editor->goto_line_selection(p_line, p_begin, p_end); } void ShaderEditor::_check_for_external_edit() { - if (shader.is_null() || !shader.is_valid()) { return; } @@ -438,7 +406,6 @@ void ShaderEditor::_check_for_external_edit() { } void ShaderEditor::_reload_shader_from_disk() { - Ref<Shader> rel_shader = ResourceLoader::load(shader->get_path(), shader->get_class(), true); ERR_FAIL_COND(!rel_shader.is_valid()); @@ -448,12 +415,13 @@ void ShaderEditor::_reload_shader_from_disk() { } void ShaderEditor::edit(const Ref<Shader> &p_shader) { - - if (p_shader.is_null() || !p_shader->is_text_shader()) + if (p_shader.is_null() || !p_shader->is_text_shader()) { return; + } - if (shader == p_shader) + if (shader == p_shader) { return; + } shader = p_shader; @@ -464,7 +432,6 @@ void ShaderEditor::edit(const Ref<Shader> &p_shader) { } void ShaderEditor::save_external_data(const String &p_str) { - if (shader.is_null()) { disk_changed->hide(); return; @@ -480,10 +447,9 @@ void ShaderEditor::save_external_data(const String &p_str) { } void ShaderEditor::apply_shaders() { - if (shader.is_valid()) { String shader_code = shader->get_code(); - String editor_code = shader_editor->get_text_edit()->get_text(); + String editor_code = shader_editor->get_text_editor()->get_text(); if (shader_code != editor_code) { shader->set_code(editor_code); shader->set_edited(true); @@ -492,21 +458,17 @@ void ShaderEditor::apply_shaders() { } void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { - Ref<InputEventMouseButton> mb = ev; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { - int col, row; - TextEdit *tx = shader_editor->get_text_edit(); + CodeEdit *tx = shader_editor->get_text_editor(); tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); if (tx->is_right_click_moving_caret()) { if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); int to_line = tx->get_selection_to_line(); int from_column = tx->get_selection_from_column(); @@ -527,15 +489,14 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } Ref<InputEventKey> k = ev; - if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_MENU) { - TextEdit *tx = shader_editor->get_text_edit(); + if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_MENU) { + CodeEdit *tx = shader_editor->get_text_editor(); _make_context_menu(tx->is_selection_active(), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos())); context_menu->grab_focus(); } } void ShaderEditor::_update_bookmark_list() { - bookmarks_menu->clear(); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); @@ -543,7 +504,7 @@ void ShaderEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = shader_editor->get_text_edit()->get_bookmarks_array(); + Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -551,7 +512,7 @@ void ShaderEditor::_update_bookmark_list() { bookmarks_menu->add_separator(); for (int i = 0; i < bookmark_list.size(); i++) { - String line = shader_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + String line = shader_editor->get_text_editor()->get_line(bookmark_list[i]).strip_edges(); // Limit the size of the line if too big. if (line.length() > 50) { line = line.substr(0, 50); @@ -563,7 +524,6 @@ void ShaderEditor::_update_bookmark_list() { } void ShaderEditor::_bookmark_item_pressed(int p_idx) { - if (p_idx < 4) { // Any item before the separator. _menu_option(bookmarks_menu->get_item_id(p_idx)); } else { @@ -572,7 +532,6 @@ void ShaderEditor::_bookmark_item_pressed(int p_idx) { } void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) { - context_menu->clear(); if (p_selection) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); @@ -597,29 +556,27 @@ void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) { } ShaderEditor::ShaderEditor(EditorNode *p_node) { - shader_editor = memnew(ShaderTextEditor); shader_editor->set_v_size_flags(SIZE_EXPAND_FILL); - shader_editor->add_constant_override("separation", 0); + shader_editor->add_theme_constant_override("separation", 0); shader_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); - shader_editor->connect("script_changed", this, "apply_shaders"); - EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed"); + shader_editor->connect("script_changed", callable_mp(this, &ShaderEditor::apply_shaders)); + EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ShaderEditor::_editor_settings_changed)); - shader_editor->get_text_edit()->set_callhint_settings( + shader_editor->get_text_editor()->set_callhint_settings( EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); - shader_editor->get_text_edit()->set_select_identifiers_on_hover(true); - shader_editor->get_text_edit()->set_context_menu_enabled(false); - shader_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + shader_editor->get_text_editor()->set_select_identifiers_on_hover(true); + shader_editor->get_text_editor()->set_context_menu_enabled(false); + shader_editor->get_text_editor()->connect("gui_input", callable_mp(this, &ShaderEditor::_text_edit_gui_input)); shader_editor->update_editor_settings(); context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", this, "_menu_option"); - context_menu->set_hide_on_window_lose_focus(true); + context_menu->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); VBoxContainer *main_container = memnew(VBoxContainer); HBoxContainer *hbc = memnew(HBoxContainer); @@ -627,7 +584,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { edit_menu = memnew(MenuButton); edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); - edit_menu->get_popup()->set_hide_on_window_lose_focus(true); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -646,22 +603,22 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); - edit_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); search_menu = memnew(MenuButton); search_menu->set_text(TTR("Search")); search_menu->set_switch_on_hover(true); - search_menu->get_popup()->set_hide_on_window_lose_focus(true); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); - search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); MenuButton *goto_menu = memnew(MenuButton); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); goto_menu->get_popup()->add_separator(); @@ -671,14 +628,14 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { goto_menu->get_popup()->add_child(bookmarks_menu); goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); _update_bookmark_list(); - bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); - bookmarks_menu->connect("index_pressed", this, "_bookmark_item_pressed"); + bookmarks_menu->connect("about_to_popup", callable_mp(this, &ShaderEditor::_update_bookmark_list)); + bookmarks_menu->connect("index_pressed", callable_mp(this, &ShaderEditor::_bookmark_item_pressed)); help_menu = memnew(MenuButton); help_menu->set_text(TTR("Help")); help_menu->set_switch_on_hover(true); - help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); - help_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + help_menu->get_popup()->add_icon_item(p_node->get_gui_base()->get_theme_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); + help_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); add_child(main_container); main_container->add_child(hbc); @@ -686,7 +643,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { hbc->add_child(edit_menu); hbc->add_child(goto_menu); hbc->add_child(help_menu); - hbc->add_style_override("panel", p_node->get_gui_base()->get_stylebox("ScriptEditorPanel", "EditorStyles")); + hbc->add_theme_style_override("panel", p_node->get_gui_base()->get_theme_stylebox("ScriptEditorPanel", "EditorStyles")); main_container->add_child(shader_editor); goto_line_dialog = memnew(GotoLineDialog); @@ -701,11 +658,11 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { dl->set_text(TTR("This shader has been modified on on disk.\nWhat action should be taken?")); vbc->add_child(dl); - disk_changed->connect("confirmed", this, "_reload_shader_from_disk"); + disk_changed->connect("confirmed", callable_mp(this, &ShaderEditor::_reload_shader_from_disk)); disk_changed->get_ok()->set_text(TTR("Reload")); - disk_changed->add_button(TTR("Resave"), !OS::get_singleton()->get_swap_ok_cancel(), "resave"); - disk_changed->connect("custom_action", this, "save_external_data"); + disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave"); + disk_changed->connect("custom_action", callable_mp(this, &ShaderEditor::save_external_data)); add_child(disk_changed); @@ -713,49 +670,42 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { } void ShaderEditorPlugin::edit(Object *p_object) { - Shader *s = Object::cast_to<Shader>(p_object); shader_editor->edit(s); } bool ShaderEditorPlugin::handles(Object *p_object) const { - Shader *shader = Object::cast_to<Shader>(p_object); - return shader != NULL && shader->is_text_shader(); + return shader != nullptr && shader->is_text_shader(); } void ShaderEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { button->show(); editor->make_bottom_panel_item_visible(shader_editor); } else { - button->hide(); - if (shader_editor->is_visible_in_tree()) + if (shader_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } shader_editor->apply_shaders(); } } void ShaderEditorPlugin::selected_notify() { - shader_editor->ensure_select_current(); } void ShaderEditorPlugin::save_external_data() { - shader_editor->save_external_data(); } void ShaderEditorPlugin::apply_changes() { - shader_editor->apply_shaders(); } ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) { - editor = p_node; shader_editor = memnew(ShaderEditor(p_node)); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 900b40bd7a..904aed186a 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -39,24 +39,24 @@ #include "scene/gui/text_edit.h" #include "scene/main/timer.h" #include "scene/resources/shader.h" -#include "servers/visual/shader_language.h" +#include "servers/rendering/shader_language.h" class ShaderTextEditor : public CodeTextEditor { - GDCLASS(ShaderTextEditor, CodeTextEditor); + Ref<CodeHighlighter> syntax_highlighter; Ref<Shader> shader; void _check_shader_mode(); protected: static void _bind_methods(); - virtual void _load_theme_settings(); + virtual void _load_theme_settings() override; - virtual void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options); + virtual void _code_complete_script(const String &p_code, List<ScriptCodeCompletionOption> *r_options) override; public: - virtual void _validate_script(); + virtual void _validate_script() override; void reload_text(); @@ -66,7 +66,6 @@ public: }; class ShaderEditor : public PanelContainer { - GDCLASS(ShaderEditor, PanelContainer); enum { @@ -136,14 +135,13 @@ public: void goto_line_selection(int p_line, int p_begin, int p_end); - virtual Size2 get_minimum_size() const { return Size2(0, 200); } + virtual Size2 get_minimum_size() const override { return Size2(0, 200); } void save_external_data(const String &p_str = ""); ShaderEditor(EditorNode *p_node); }; class ShaderEditorPlugin : public EditorPlugin { - GDCLASS(ShaderEditorPlugin, EditorPlugin); bool _2d; @@ -152,17 +150,17 @@ class ShaderEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "Shader"; } - 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); - virtual void selected_notify(); + virtual String get_name() const override { return "Shader"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + virtual void selected_notify() override; ShaderEditor *get_shader_editor() const { return shader_editor; } - virtual void save_external_data(); - virtual void apply_changes(); + virtual void save_external_data() override; + virtual void apply_changes() override; ShaderEditorPlugin(EditorNode *p_node); ~ShaderEditorPlugin(); diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp new file mode 100644 index 0000000000..f15a801530 --- /dev/null +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -0,0 +1,324 @@ +/*************************************************************************/ +/* shader_file_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "shader_file_editor_plugin.h" + +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "core/os/keyboard.h" +#include "core/os/os.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "editor/property_editor.h" +#include "servers/display_server.h" +#include "servers/rendering/shader_types.h" + +/*** SHADER SCRIPT EDITOR ****/ + +/*** SCRIPT EDITOR ******/ + +void ShaderFileEditor::_update_version(const StringName &p_version_txt, const RD::ShaderStage p_stage) { +} + +void ShaderFileEditor::_version_selected(int p_option) { + int c = versions->get_current(); + StringName version_txt = versions->get_item_metadata(c); + + RD::ShaderStage stage = RD::SHADER_STAGE_MAX; + int first_found = -1; + + Ref<RDShaderBytecode> bytecode = shader_file->get_bytecode(version_txt); + ERR_FAIL_COND(bytecode.is_null()); + + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + if (bytecode->get_stage_bytecode(RD::ShaderStage(i)).empty() && bytecode->get_stage_compile_error(RD::ShaderStage(i)) == String()) { + stages[i]->set_icon(Ref<Texture2D>()); + continue; + } + + Ref<Texture2D> icon; + if (bytecode->get_stage_compile_error(RD::ShaderStage(i)) != String()) { + icon = get_theme_icon("ImportFail", "EditorIcons"); + } else { + icon = get_theme_icon("ImportCheck", "EditorIcons"); + } + stages[i]->set_icon(icon); + + if (first_found == -1) { + first_found = i; + } + + if (stages[i]->is_pressed()) { + stage = RD::ShaderStage(i); + break; + } + } + + error_text->clear(); + + if (stage == RD::SHADER_STAGE_MAX) { //need to change stage, does not have it + if (first_found == -1) { + error_text->add_text(TTR("No valid shader stages found.")); + return; //well you did not put any stage I guess? + } + stages[first_found]->set_pressed(true); + stage = RD::ShaderStage(first_found); + } + + String error = bytecode->get_stage_compile_error(stage); + + error_text->push_font(get_theme_font("source", "EditorFonts")); + + if (error == String()) { + error_text->add_text(TTR("Shader stage compiled without errors.")); + } else { + error_text->add_text(error); + } +} + +void ShaderFileEditor::_update_options() { + ERR_FAIL_COND(shader_file.is_null()); + + if (shader_file->get_base_error() != String()) { + stage_hb->hide(); + versions->hide(); + error_text->clear(); + error_text->push_font(get_theme_font("source", "EditorFonts")); + error_text->add_text(vformat(TTR("File structure for '%s' contains unrecoverable errors:\n\n"), shader_file->get_path().get_file())); + error_text->add_text(shader_file->get_base_error()); + return; + } + + stage_hb->show(); + versions->show(); + + int c = versions->get_current(); + //remember current + versions->clear(); + Vector<StringName> version_list = shader_file->get_version_list(); + + if (c >= version_list.size()) { + c = version_list.size() - 1; + } + if (c < 0) { + c = 0; + } + + StringName current_version; + + for (int i = 0; i < version_list.size(); i++) { + String title = version_list[i]; + if (title == "") { + title = "default"; + } + + Ref<Texture2D> icon; + + Ref<RDShaderBytecode> bytecode = shader_file->get_bytecode(version_list[i]); + ERR_FAIL_COND(bytecode.is_null()); + + bool failed = false; + for (int j = 0; j < RD::SHADER_STAGE_MAX; j++) { + String error = bytecode->get_stage_compile_error(RD::ShaderStage(j)); + if (error != String()) { + failed = true; + } + } + + if (failed) { + icon = get_theme_icon("ImportFail", "EditorIcons"); + } else { + icon = get_theme_icon("ImportCheck", "EditorIcons"); + } + + versions->add_item(title, icon); + versions->set_item_metadata(i, version_list[i]); + + if (i == c) { + versions->select(i); + current_version = version_list[i]; + } + } + + if (version_list.size() == 0) { + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + stages[i]->set_disabled(true); + } + return; + } + + Ref<RDShaderBytecode> bytecode = shader_file->get_bytecode(current_version); + ERR_FAIL_COND(bytecode.is_null()); + int first_valid = -1; + int current = -1; + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + Vector<uint8_t> bc = bytecode->get_stage_bytecode(RD::ShaderStage(i)); + String error = bytecode->get_stage_compile_error(RD::ShaderStage(i)); + bool disable = error == String() && bc.empty(); + stages[i]->set_disabled(disable); + if (!disable) { + if (stages[i]->is_pressed()) { + current = i; + } + first_valid = i; + } + } + + if (current == -1 && first_valid != -1) { + stages[first_valid]->set_pressed(true); + } + + _version_selected(0); +} + +void ShaderFileEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) { + if (is_visible_in_tree() && shader_file.is_valid()) { + _update_options(); + } + } +} + +void ShaderFileEditor::_editor_settings_changed() { + if (is_visible_in_tree() && shader_file.is_valid()) { + _update_options(); + } +} + +void ShaderFileEditor::_bind_methods() { +} + +void ShaderFileEditor::edit(const Ref<RDShaderFile> &p_shader) { + if (p_shader.is_null()) { + if (shader_file.is_valid()) { + shader_file->disconnect("changed", callable_mp(this, &ShaderFileEditor::_shader_changed)); + } + return; + } + + if (shader_file == p_shader) { + return; + } + + shader_file = p_shader; + + if (shader_file.is_valid()) { + shader_file->connect("changed", callable_mp(this, &ShaderFileEditor::_shader_changed)); + } + + _update_options(); +} + +void ShaderFileEditor::_shader_changed() { + if (is_visible_in_tree()) { + _update_options(); + } +} + +ShaderFileEditor *ShaderFileEditor::singleton = nullptr; + +ShaderFileEditor::ShaderFileEditor(EditorNode *p_node) { + singleton = this; + HSplitContainer *main_hs = memnew(HSplitContainer); + + add_child(main_hs); + + versions = memnew(ItemList); + versions->connect("item_selected", callable_mp(this, &ShaderFileEditor::_version_selected)); + versions->set_custom_minimum_size(Size2i(200 * EDSCALE, 0)); + main_hs->add_child(versions); + + VBoxContainer *main_vb = memnew(VBoxContainer); + main_vb->set_h_size_flags(SIZE_EXPAND_FILL); + main_hs->add_child(main_vb); + + static const char *stage_str[RD::SHADER_STAGE_MAX] = { + "Vertex", + "Fragment", + "TessControl", + "TessEval", + "Compute" + }; + + stage_hb = memnew(HBoxContainer); + main_vb->add_child(stage_hb); + + Ref<ButtonGroup> bg; + bg.instance(); + for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { + Button *button = memnew(Button(stage_str[i])); + button->set_toggle_mode(true); + button->set_focus_mode(FOCUS_NONE); + stage_hb->add_child(button); + stages[i] = button; + button->set_button_group(bg); + button->connect("pressed", callable_mp(this, &ShaderFileEditor::_version_selected), varray(i)); + } + + error_text = memnew(RichTextLabel); + error_text->set_v_size_flags(SIZE_EXPAND_FILL); + main_vb->add_child(error_text); +} + +void ShaderFileEditorPlugin::edit(Object *p_object) { + RDShaderFile *s = Object::cast_to<RDShaderFile>(p_object); + shader_editor->edit(s); +} + +bool ShaderFileEditorPlugin::handles(Object *p_object) const { + RDShaderFile *shader = Object::cast_to<RDShaderFile>(p_object); + return shader != nullptr; +} + +void ShaderFileEditorPlugin::make_visible(bool p_visible) { + if (p_visible) { + button->show(); + editor->make_bottom_panel_item_visible(shader_editor); + + } else { + button->hide(); + if (shader_editor->is_visible_in_tree()) { + editor->hide_bottom_panel(); + } + } +} + +ShaderFileEditorPlugin::ShaderFileEditorPlugin(EditorNode *p_node) { + editor = p_node; + shader_editor = memnew(ShaderFileEditor(p_node)); + + shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); + button = editor->add_bottom_panel_item(TTR("ShaderFile"), shader_editor); + button->hide(); +} + +ShaderFileEditorPlugin::~ShaderFileEditorPlugin() { +} diff --git a/editor/plugins/shader_file_editor_plugin.h b/editor/plugins/shader_file_editor_plugin.h new file mode 100644 index 0000000000..6858f7d933 --- /dev/null +++ b/editor/plugins/shader_file_editor_plugin.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* shader_file_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 SHADER_FILE_EDITOR_PLUGIN_H +#define SHADER_FILE_EDITOR_PLUGIN_H + +#include "editor/code_editor.h" +#include "editor/editor_plugin.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/rich_text_label.h" +#include "scene/gui/tab_container.h" +#include "scene/gui/text_edit.h" +#include "scene/main/timer.h" +#include "servers/rendering/rendering_device_binds.h" + +class ShaderFileEditor : public PanelContainer { + GDCLASS(ShaderFileEditor, PanelContainer); + + Ref<RDShaderFile> shader_file; + + HBoxContainer *stage_hb; + ItemList *versions; + Button *stages[RD::SHADER_STAGE_MAX]; + RichTextLabel *error_text; + + void _update_version(const StringName &p_version_txt, const RenderingDevice::ShaderStage p_stage); + void _version_selected(int p_stage); + void _editor_settings_changed(); + + void _update_options(); + void _shader_changed(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + static ShaderFileEditor *singleton; + void edit(const Ref<RDShaderFile> &p_shader); + + ShaderFileEditor(EditorNode *p_node); +}; + +class ShaderFileEditorPlugin : public EditorPlugin { + GDCLASS(ShaderFileEditorPlugin, EditorPlugin); + + ShaderFileEditor *shader_editor; + EditorNode *editor; + Button *button; + +public: + virtual String get_name() const override { return "ShaderFile"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + ShaderFileEditor *get_shader_editor() const { return shader_editor; } + + ShaderFileEditorPlugin(EditorNode *p_node); + ~ShaderFileEditorPlugin(); +}; + +#endif // SHADER_FILE_EDITOR_PLUGIN_H diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index dbe64f202d..a198e4ff8f 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -36,30 +36,26 @@ #include "thirdparty/misc/clipper.hpp" void Skeleton2DEditor::_node_removed(Node *p_node) { - if (p_node == node) { - node = NULL; + node = nullptr; options->hide(); } } void Skeleton2DEditor::edit(Skeleton2D *p_sprite) { - node = p_sprite; } void Skeleton2DEditor::_menu_option(int p_option) { - if (!node) { return; } switch (p_option) { case MENU_OPTION_MAKE_REST: { - if (node->get_bone_count() == 0) { err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); @@ -75,7 +71,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { case MENU_OPTION_SET_REST: { if (node->get_bone_count() == 0) { err_dialog->set_text(TTR("This skeleton has no bones, create some children Bone2D nodes.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); @@ -92,53 +88,45 @@ void Skeleton2DEditor::_menu_option(int p_option) { } void Skeleton2DEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &Skeleton2DEditor::_menu_option); } Skeleton2DEditor::Skeleton2DEditor() { - options = memnew(MenuButton); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text(TTR("Skeleton2D")); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton2D", "EditorIcons")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Skeleton2D", "EditorIcons")); options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Set Bones to Rest Pose"), MENU_OPTION_SET_REST); options->set_switch_on_hover(true); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton2DEditor::_menu_option)); err_dialog = memnew(AcceptDialog); add_child(err_dialog); } void Skeleton2DEditorPlugin::edit(Object *p_object) { - sprite_editor->edit(Object::cast_to<Skeleton2D>(p_object)); } bool Skeleton2DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("Skeleton2D"); } void Skeleton2DEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { sprite_editor->options->show(); } else { - sprite_editor->options->hide(); - sprite_editor->edit(NULL); + sprite_editor->edit(nullptr); } } Skeleton2DEditorPlugin::Skeleton2DEditorPlugin(EditorNode *p_node) { - editor = p_node; sprite_editor = memnew(Skeleton2DEditor); editor->get_viewport()->add_child(sprite_editor); diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h index ebc6746b81..b8377fc914 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.h +++ b/editor/plugins/skeleton_2d_editor_plugin.h @@ -37,7 +37,6 @@ #include "scene/gui/spin_box.h" class Skeleton2DEditor : public Control { - GDCLASS(Skeleton2DEditor, Control); enum Menu { @@ -65,18 +64,17 @@ public: }; class Skeleton2DEditorPlugin : public EditorPlugin { - GDCLASS(Skeleton2DEditorPlugin, EditorPlugin); Skeleton2DEditor *sprite_editor; EditorNode *editor; public: - virtual String get_name() const { return "Skeleton2D"; } - 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); + virtual String get_name() const override { return "Skeleton2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; Skeleton2DEditorPlugin(EditorNode *p_node); ~Skeleton2DEditorPlugin(); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp new file mode 100644 index 0000000000..52da8dea19 --- /dev/null +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -0,0 +1,686 @@ +/*************************************************************************/ +/* skeleton_3d_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "skeleton_3d_editor_plugin.h" + +#include "core/io/resource_saver.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_properties.h" +#include "editor/editor_scale.h" +#include "editor/plugins/animation_player_editor_plugin.h" +#include "node_3d_editor_plugin.h" +#include "scene/3d/collision_shape_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/3d/physics_body_3d.h" +#include "scene/3d/physics_joint_3d.h" +#include "scene/resources/capsule_shape_3d.h" +#include "scene/resources/sphere_shape_3d.h" + +void BoneTransformEditor::create_editors() { + const Color section_color = get_theme_color("prop_subsection", "Editor"); + + section = memnew(EditorInspectorSection); + section->setup("trf_properties", label, this, section_color, true); + add_child(section); + + key_button = memnew(Button); + key_button->set_text(TTR("Key Transform")); + key_button->set_visible(keyable); + key_button->set_icon(get_theme_icon("Key", "EditorIcons")); + key_button->set_flat(true); + section->get_vbox()->add_child(key_button); + + enabled_checkbox = memnew(CheckBox(TTR("Pose Enabled"))); + enabled_checkbox->set_flat(true); + enabled_checkbox->set_visible(toggle_enabled); + section->get_vbox()->add_child(enabled_checkbox); + + // Translation property + translation_property = memnew(EditorPropertyVector3()); + translation_property->setup(-10000, 10000, 0.001f, true); + translation_property->set_label("Translation"); + translation_property->set_use_folding(true); + translation_property->set_read_only(false); + translation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3)); + section->get_vbox()->add_child(translation_property); + + // Rotation property + rotation_property = memnew(EditorPropertyVector3()); + rotation_property->setup(-10000, 10000, 0.001f, true); + rotation_property->set_label("Rotation Degrees"); + rotation_property->set_use_folding(true); + rotation_property->set_read_only(false); + rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3)); + section->get_vbox()->add_child(rotation_property); + + // Scale property + scale_property = memnew(EditorPropertyVector3()); + scale_property->setup(-10000, 10000, 0.001f, true); + scale_property->set_label("Scale"); + scale_property->set_use_folding(true); + scale_property->set_read_only(false); + scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_vector3)); + section->get_vbox()->add_child(scale_property); + + // Transform/Matrix section + transform_section = memnew(EditorInspectorSection); + transform_section->setup("trf_properties_transform", "Matrix", this, section_color, true); + section->get_vbox()->add_child(transform_section); + + // Transform/Matrix property + transform_property = memnew(EditorPropertyTransform()); + transform_property->setup(-10000, 10000, 0.001f, true); + transform_property->set_label("Transform"); + transform_property->set_use_folding(true); + transform_property->set_read_only(false); + transform_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed_transform)); + transform_section->get_vbox()->add_child(transform_property); +} + +void BoneTransformEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + create_editors(); + key_button->connect("pressed", callable_mp(this, &BoneTransformEditor::_key_button_pressed)); + enabled_checkbox->connect("toggled", callable_mp(this, &BoneTransformEditor::_checkbox_toggled)); + [[fallthrough]]; + } + case NOTIFICATION_SORT_CHILDREN: { + const Ref<Font> font = get_theme_font("font", "Tree"); + + Point2 buffer; + buffer.x += get_theme_constant("inspector_margin", "Editor"); + buffer.y += font->get_height(); + buffer.y += get_theme_constant("vseparation", "Tree"); + + const float vector_height = translation_property->get_size().y; + const float transform_height = transform_property->get_size().y; + const float button_height = key_button->get_size().y; + + const float width = get_size().x - get_theme_constant("inspector_margin", "Editor"); + Vector<Rect2> input_rects; + if (keyable && section->get_vbox()->is_visible()) { + input_rects.push_back(Rect2(key_button->get_position() + buffer, Size2(width, button_height))); + } else { + input_rects.push_back(Rect2(0, 0, 0, 0)); + } + + if (section->get_vbox()->is_visible()) { + input_rects.push_back(Rect2(translation_property->get_position() + buffer, Size2(width, vector_height))); + input_rects.push_back(Rect2(rotation_property->get_position() + buffer, Size2(width, vector_height))); + input_rects.push_back(Rect2(scale_property->get_position() + buffer, Size2(width, vector_height))); + input_rects.push_back(Rect2(transform_property->get_position() + buffer, Size2(width, transform_height))); + } else { + const int32_t start = input_rects.size(); + const int32_t empty_input_rect_elements = 4; + const int32_t end = start + empty_input_rect_elements; + for (int i = start; i < end; ++i) { + input_rects.push_back(Rect2(0, 0, 0, 0)); + } + } + + for (int32_t i = 0; i < input_rects.size(); i++) { + background_rects[i] = input_rects[i]; + } + + update(); + break; + } + case NOTIFICATION_DRAW: { + const Color dark_color = get_theme_color("dark_color_2", "Editor"); + + for (int i = 0; i < 5; ++i) { + draw_rect(background_rects[i], dark_color); + } + + break; + } + } +} + +void BoneTransformEditor::_value_changed(const double p_value) { + if (updating) + return; + + Transform tform = compute_transform_from_vector3s(); + _change_transform(tform); +} + +void BoneTransformEditor::_value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean) { + if (updating) + return; + Transform tform = compute_transform_from_vector3s(); + _change_transform(tform); +} + +Transform BoneTransformEditor::compute_transform_from_vector3s() const { + // Convert rotation from degrees to radians. + Vector3 prop_rotation = rotation_property->get_vector(); + prop_rotation.x = Math::deg2rad(prop_rotation.x); + prop_rotation.y = Math::deg2rad(prop_rotation.y); + prop_rotation.z = Math::deg2rad(prop_rotation.z); + + return Transform( + Basis(prop_rotation, scale_property->get_vector()), + translation_property->get_vector()); +} + +void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) { + if (updating) + return; + _change_transform(p_transform); +} + +void BoneTransformEditor::_change_transform(Transform p_new_transform) { + if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") { + undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS); + undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int())); + undo_redo->add_do_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), p_new_transform); + undo_redo->commit_action(); + } else if (property.get_slicec('/', 0) == "bones") { + undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); + undo_redo->add_undo_property(skeleton, property, skeleton->get(property)); + undo_redo->add_do_property(skeleton, property, p_new_transform); + undo_redo->commit_action(); + } +} + +void BoneTransformEditor::update_enabled_checkbox() { + if (enabled_checkbox) { + const String path = "bones/" + property.get_slicec('/', 1) + "/enabled"; + const bool is_enabled = skeleton->get(path); + enabled_checkbox->set_pressed(is_enabled); + } +} + +void BoneTransformEditor::_update_properties() { + if (updating) + return; + + if (skeleton == nullptr) + return; + + updating = true; + + Transform tform = skeleton->get(property); + _update_transform_properties(tform); +} + +void BoneTransformEditor::_update_custom_pose_properties() { + if (updating) + return; + + if (skeleton == nullptr) + return; + + updating = true; + + Transform tform = skeleton->get_bone_custom_pose(property.to_int()); + _update_transform_properties(tform); +} + +void BoneTransformEditor::_update_transform_properties(Transform tform) { + Basis rotation_basis = tform.get_basis(); + Vector3 rotation_radians = rotation_basis.get_rotation_euler(); + Vector3 rotation_degrees = Vector3(Math::rad2deg(rotation_radians.x), Math::rad2deg(rotation_radians.y), Math::rad2deg(rotation_radians.z)); + Vector3 translation = tform.get_origin(); + Vector3 scale = tform.basis.get_scale(); + + translation_property->update_using_vector(translation); + rotation_property->update_using_vector(rotation_degrees); + scale_property->update_using_vector(scale); + transform_property->update_using_transform(tform); + + update_enabled_checkbox(); + updating = false; +} + +BoneTransformEditor::BoneTransformEditor(Skeleton3D *p_skeleton) : + skeleton(p_skeleton), + key_button(nullptr), + enabled_checkbox(nullptr), + keyable(false), + toggle_enabled(false), + updating(false) { + undo_redo = EditorNode::get_undo_redo(); +} + +void BoneTransformEditor::set_target(const String &p_prop) { + property = p_prop; +} + +void BoneTransformEditor::set_keyable(const bool p_keyable) { + keyable = p_keyable; + if (key_button) { + key_button->set_visible(p_keyable); + } +} + +void BoneTransformEditor::set_toggle_enabled(const bool p_enabled) { + toggle_enabled = p_enabled; + if (enabled_checkbox) { + enabled_checkbox->set_visible(p_enabled); + } +} + +void BoneTransformEditor::_key_button_pressed() { + if (skeleton == nullptr) + return; + + const BoneId bone_id = property.get_slicec('/', 1).to_int(); + const String name = skeleton->get_bone_name(bone_id); + + if (name.empty()) + return; + + // Need to normalize the basis before you key it + Transform tform = compute_transform_from_vector3s(); + tform.orthonormalize(); + AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform); +} + +void BoneTransformEditor::_checkbox_toggled(const bool p_toggled) { + if (enabled_checkbox) { + const String path = "bones/" + property.get_slicec('/', 1) + "/enabled"; + skeleton->set(path, p_toggled); + } +} + +void Skeleton3DEditor::_on_click_option(int p_option) { + if (!skeleton) { + return; + } + + switch (p_option) { + case MENU_OPTION_CREATE_PHYSICAL_SKELETON: { + create_physical_skeleton(); + break; + } + } +} + +void Skeleton3DEditor::create_physical_skeleton() { + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ERR_FAIL_COND(!get_tree()); + Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner(); + + const int bc = skeleton->get_bone_count(); + + if (!bc) { + return; + } + + Vector<BoneInfo> bones_infos; + bones_infos.resize(bc); + + for (int bone_id = 0; bc > bone_id; ++bone_id) { + const int parent = skeleton->get_bone_parent(bone_id); + + if (parent < 0) { + bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id); + + } else { + const int parent_parent = skeleton->get_bone_parent(parent); + + bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id); + + /// create physical bone on parent + if (!bones_infos[parent].physical_bone) { + bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); + + ur->create_action(TTR("Create physical bones")); + ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); + ur->add_do_reference(bones_infos[parent].physical_bone); + ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone); + ur->commit_action(); + + bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent)); + bones_infos[parent].physical_bone->set_owner(owner); + bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner + + /// Create joint between parent of parent + if (-1 != parent_parent) { + bones_infos[parent].physical_bone->set_joint_type(PhysicalBone3D::JOINT_TYPE_PIN); + } + } + } + } +} + +PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) { + const Transform child_rest = skeleton->get_bone_rest(bone_child_id); + + const real_t half_height(child_rest.origin.length() * 0.5); + const real_t radius(half_height * 0.2); + + CapsuleShape3D *bone_shape_capsule = memnew(CapsuleShape3D); + bone_shape_capsule->set_height((half_height - radius) * 2); + bone_shape_capsule->set_radius(radius); + + CollisionShape3D *bone_shape = memnew(CollisionShape3D); + bone_shape->set_shape(bone_shape_capsule); + + Transform body_transform; + body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0)); + body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height)); + + Transform joint_transform; + joint_transform.origin = Vector3(0, 0, half_height); + + PhysicalBone3D *physical_bone = memnew(PhysicalBone3D); + physical_bone->add_child(bone_shape); + physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id)); + physical_bone->set_body_offset(body_transform); + physical_bone->set_joint_offset(joint_transform); + return physical_bone; +} + +Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + TreeItem *selected = joint_tree->get_selected(); + + if (!selected) + return Variant(); + + Ref<Texture> icon = selected->get_icon(0); + + VBoxContainer *vb = memnew(VBoxContainer); + HBoxContainer *hb = memnew(HBoxContainer); + TextureRect *tf = memnew(TextureRect); + tf->set_texture(icon); + tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + hb->add_child(tf); + Label *label = memnew(Label(selected->get_text(0))); + hb->add_child(label); + vb->add_child(hb); + hb->set_modulate(Color(1, 1, 1, 1)); + + set_drag_preview(vb); + Dictionary drag_data; + drag_data["type"] = "nodes"; + drag_data["node"] = selected; + + return drag_data; +} + +bool Skeleton3DEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + TreeItem *target = joint_tree->get_item_at_position(p_point); + if (!target) + return false; + + const String path = target->get_metadata(0); + if (!path.begins_with("bones/")) + return false; + + TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]); + if (target == selected) + return false; + + const String path2 = target->get_metadata(0); + if (!path2.begins_with("bones/")) + return false; + + return true; +} + +void Skeleton3DEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + if (!can_drop_data_fw(p_point, p_data, p_from)) + return; + + TreeItem *target = joint_tree->get_item_at_position(p_point); + TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]); + + const BoneId target_boneidx = String(target->get_metadata(0)).get_slicec('/', 1).to_int(); + const BoneId selected_boneidx = String(selected->get_metadata(0)).get_slicec('/', 1).to_int(); + + move_skeleton_bone(skeleton->get_path(), selected_boneidx, target_boneidx); +} + +void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx) { + Node *node = get_node_or_null(p_skeleton_path); + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); + ERR_FAIL_NULL(skeleton); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Set Bone Parentage")); + // If the target is a child of ourselves, we move only *us* and not our children + if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) { + const BoneId parent_idx = skeleton->get_bone_parent(p_selected_boneidx); + const int bone_count = skeleton->get_bone_count(); + for (BoneId i = 0; i < bone_count; ++i) { + if (skeleton->get_bone_parent(i) == p_selected_boneidx) { + ur->add_undo_method(skeleton, "set_bone_parent", i, skeleton->get_bone_parent(i)); + ur->add_do_method(skeleton, "set_bone_parent", i, parent_idx); + skeleton->set_bone_parent(i, parent_idx); + } + } + } + ur->add_undo_method(skeleton, "set_bone_parent", p_selected_boneidx, skeleton->get_bone_parent(p_selected_boneidx)); + ur->add_do_method(skeleton, "set_bone_parent", p_selected_boneidx, p_target_boneidx); + skeleton->set_bone_parent(p_selected_boneidx, p_target_boneidx); + + update_joint_tree(); + ur->commit_action(); +} + +void Skeleton3DEditor::_joint_tree_selection_changed() { + TreeItem *selected = joint_tree->get_selected(); + const String path = selected->get_metadata(0); + + if (path.begins_with("bones/")) { + const int b_idx = path.get_slicec('/', 1).to_int(); + const String bone_path = "bones/" + itos(b_idx) + "/"; + + pose_editor->set_target(bone_path + "pose"); + rest_editor->set_target(bone_path + "rest"); + custom_pose_editor->set_target(bone_path + "custom_pose"); + + pose_editor->set_visible(true); + rest_editor->set_visible(true); + custom_pose_editor->set_visible(true); + } +} + +void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos) { +} + +void Skeleton3DEditor::_update_properties() { + if (rest_editor) + rest_editor->_update_properties(); + if (pose_editor) + pose_editor->_update_properties(); + if (custom_pose_editor) + custom_pose_editor->_update_custom_pose_properties(); +} + +void Skeleton3DEditor::update_joint_tree() { + joint_tree->clear(); + + if (skeleton == nullptr) + return; + + TreeItem *root = joint_tree->create_item(); + + Map<int, TreeItem *> items; + + items.insert(-1, root); + + const Vector<int> &joint_porder = skeleton->get_bone_process_orders(); + Ref<Texture> bone_icon = get_theme_icon("BoneAttachment3D", "EditorIcons"); + + for (int i = 0; i < joint_porder.size(); ++i) { + const int b_idx = joint_porder[i]; + + const int p_idx = skeleton->get_bone_parent(b_idx); + TreeItem *p_item = items.find(p_idx)->get(); + + TreeItem *joint_item = joint_tree->create_item(p_item); + items.insert(b_idx, joint_item); + + joint_item->set_text(0, skeleton->get_bone_name(b_idx)); + joint_item->set_icon(0, bone_icon); + joint_item->set_selectable(0, true); + joint_item->set_metadata(0, "bones/" + itos(b_idx)); + } +} + +void Skeleton3DEditor::update_editors() { +} + +void Skeleton3DEditor::create_editors() { + set_h_size_flags(SIZE_EXPAND_FILL); + add_theme_constant_override("separation", 0); + + set_focus_mode(FOCUS_ALL); + + // Create Top Menu Bar + options = memnew(MenuButton); + Node3DEditor::get_singleton()->add_control_to_menu_panel(options); + + options->set_text(TTR("Skeleton3D")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Skeleton3D", "EditorIcons")); + + options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON); + + options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_option)); + + const Color section_color = get_theme_color("prop_subsection", "Editor"); + + EditorInspectorSection *bones_section = memnew(EditorInspectorSection); + bones_section->setup("bones", "Bones", skeleton, section_color, true); + add_child(bones_section); + bones_section->unfold(); + + ScrollContainer *s_con = memnew(ScrollContainer); + s_con->set_h_size_flags(SIZE_EXPAND_FILL); + s_con->set_custom_minimum_size(Size2(1, 350) * EDSCALE); + bones_section->get_vbox()->add_child(s_con); + + joint_tree = memnew(Tree); + joint_tree->set_columns(1); + joint_tree->set_focus_mode(Control::FocusMode::FOCUS_NONE); + joint_tree->set_select_mode(Tree::SELECT_SINGLE); + joint_tree->set_hide_root(true); + joint_tree->set_v_size_flags(SIZE_EXPAND_FILL); + joint_tree->set_h_size_flags(SIZE_EXPAND_FILL); + joint_tree->set_allow_rmb_select(true); + joint_tree->set_drag_forwarding(this); + s_con->add_child(joint_tree); + + pose_editor = memnew(BoneTransformEditor(skeleton)); + pose_editor->set_label(TTR("Bone Pose")); + pose_editor->set_keyable(AnimationPlayerEditor::singleton->get_track_editor()->has_keying()); + pose_editor->set_toggle_enabled(true); + pose_editor->set_visible(false); + add_child(pose_editor); + + rest_editor = memnew(BoneTransformEditor(skeleton)); + rest_editor->set_label(TTR("Bone Rest")); + rest_editor->set_visible(false); + add_child(rest_editor); + + custom_pose_editor = memnew(BoneTransformEditor(skeleton)); + custom_pose_editor->set_label(TTR("Bone Custom Pose")); + custom_pose_editor->set_visible(false); + add_child(custom_pose_editor); +} + +void Skeleton3DEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + create_editors(); + update_joint_tree(); + update_editors(); + + get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Vector<Variant>(), Object::CONNECT_ONESHOT); + joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); + joint_tree->connect("item_rmb_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); +#ifdef TOOLS_ENABLED + skeleton->connect("pose_updated", callable_mp(this, &Skeleton3DEditor::_update_properties)); +#endif // TOOLS_ENABLED + + break; + } + } +} + +void Skeleton3DEditor::_node_removed(Node *p_node) { + if (skeleton && p_node == skeleton) { + skeleton = nullptr; + options->hide(); + } + + _update_properties(); +} + +void Skeleton3DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_node_removed"), &Skeleton3DEditor::_node_removed); + ClassDB::bind_method(D_METHOD("_joint_tree_selection_changed"), &Skeleton3DEditor::_joint_tree_selection_changed); + ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &Skeleton3DEditor::_joint_tree_rmb_select); + ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties); + ClassDB::bind_method(D_METHOD("_on_click_option"), &Skeleton3DEditor::_on_click_option); + + ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone); +} + +Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *p_skeleton) : + editor(p_editor), + editor_plugin(e_plugin), + skeleton(p_skeleton) { +} + +Skeleton3DEditor::~Skeleton3DEditor() { + if (options) { + Node3DEditor::get_singleton()->remove_control_from_menu_panel(options); + } +} + +bool EditorInspectorPluginSkeleton::can_handle(Object *p_object) { + return Object::cast_to<Skeleton3D>(p_object) != nullptr; +} + +void EditorInspectorPluginSkeleton::parse_begin(Object *p_object) { + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_object); + ERR_FAIL_COND(!skeleton); + + Skeleton3DEditor *skel_editor = memnew(Skeleton3DEditor(this, editor, skeleton)); + add_custom_control(skel_editor); +} + +Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) { + editor = p_node; + + Ref<EditorInspectorPluginSkeleton> skeleton_plugin; + skeleton_plugin.instance(); + skeleton_plugin->editor = editor; + + EditorInspector::add_inspector_plugin(skeleton_plugin); +} diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h new file mode 100644 index 0000000000..7843fc1754 --- /dev/null +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -0,0 +1,208 @@ +/*************************************************************************/ +/* skeleton_3d_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 SKELETON_3D_EDITOR_PLUGIN_H +#define SKELETON_3D_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/3d/skeleton_3d.h" + +class EditorInspectorPluginSkeleton; +class Joint; +class PhysicalBone3D; +class Skeleton3DEditorPlugin; +class Button; +class CheckBox; +class EditorPropertyTransform; +class EditorPropertyVector3; + +class BoneTransformEditor : public VBoxContainer { + GDCLASS(BoneTransformEditor, VBoxContainer); + + EditorInspectorSection *section; + + EditorPropertyVector3 *translation_property; + EditorPropertyVector3 *rotation_property; + EditorPropertyVector3 *scale_property; + EditorInspectorSection *transform_section; + EditorPropertyTransform *transform_property; + + Rect2 background_rects[5]; + + Skeleton3D *skeleton; + String property; + + UndoRedo *undo_redo; + + Button *key_button; + CheckBox *enabled_checkbox; + + bool keyable; + bool toggle_enabled; + bool updating; + + String label; + + void create_editors(); + + // Called when one of the EditorSpinSliders are changed. + void _value_changed(const double p_value); + // Called when the one of the EditorPropertyVector3 are updated. + void _value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean); + // Called when the transform_property is updated. + void _value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean); + // Changes the transform to the given transform and updates the UI accordingly. + void _change_transform(Transform p_new_transform); + // Creates a Transform using the EditorPropertyVector3 properties. + Transform compute_transform_from_vector3s() const; + + void update_enabled_checkbox(); + +protected: + void _notification(int p_what); + +public: + BoneTransformEditor(Skeleton3D *p_skeleton); + + // Which transform target to modify + void set_target(const String &p_prop); + void set_label(const String &p_label) { label = p_label; } + + void _update_properties(); + void _update_custom_pose_properties(); + void _update_transform_properties(Transform p_transform); + + // Can/cannot modify the spinner values for the Transform + void set_read_only(const bool p_read_only); + + // Transform can be keyed, whether or not to show the button + void set_keyable(const bool p_keyable); + + // Bone can be toggled enabled or disabled, whether or not to show the checkbox + void set_toggle_enabled(const bool p_enabled); + + // Key Transform Button pressed + void _key_button_pressed(); + + // Bone Enabled Checkbox toggled + void _checkbox_toggled(const bool p_toggled); +}; + +class Skeleton3DEditor : public VBoxContainer { + GDCLASS(Skeleton3DEditor, VBoxContainer); + + friend class Skeleton3DEditorPlugin; + + enum Menu { + MENU_OPTION_CREATE_PHYSICAL_SKELETON + }; + + struct BoneInfo { + PhysicalBone3D *physical_bone = nullptr; + Transform relative_rest; // Relative to skeleton node + BoneInfo() {} + }; + + EditorNode *editor; + EditorInspectorPluginSkeleton *editor_plugin; + + Skeleton3D *skeleton; + + Tree *joint_tree; + BoneTransformEditor *rest_editor; + BoneTransformEditor *pose_editor; + BoneTransformEditor *custom_pose_editor; + + MenuButton *options; + EditorFileDialog *file_dialog; + + UndoRedo *undo_redo; + + void _on_click_option(int p_option); + void _file_selected(const String &p_file); + + EditorFileDialog *file_export_lib; + + void update_joint_tree(); + void update_editors(); + + void create_editors(); + + void create_physical_skeleton(); + PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos); + + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + +protected: + void _notification(int p_what); + void _node_removed(Node *p_node); + static void _bind_methods(); + +public: + void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx); + + Skeleton3D *get_skeleton() const { return skeleton; }; + + void _joint_tree_selection_changed(); + void _joint_tree_rmb_select(const Vector2 &p_pos); + + void _update_properties(); + + Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *skeleton); + ~Skeleton3DEditor(); +}; + +class EditorInspectorPluginSkeleton : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginSkeleton, EditorInspectorPlugin); + + friend class Skeleton3DEditorPlugin; + + EditorNode *editor; + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; + +class Skeleton3DEditorPlugin : public EditorPlugin { + GDCLASS(Skeleton3DEditorPlugin, EditorPlugin); + + EditorNode *editor; + +public: + Skeleton3DEditorPlugin(EditorNode *p_node); + + virtual String get_name() const override { return "Skeleton3D"; } +}; + +#endif // SKELETON_3D_EDITOR_PLUGIN_H diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp deleted file mode 100644 index 8b5fe7d2c5..0000000000 --- a/editor/plugins/skeleton_editor_plugin.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/*************************************************************************/ -/* skeleton_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "skeleton_editor_plugin.h" - -#include "scene/3d/collision_shape.h" -#include "scene/3d/physics_body.h" -#include "scene/3d/physics_joint.h" -#include "scene/resources/capsule_shape.h" -#include "scene/resources/sphere_shape.h" -#include "spatial_editor_plugin.h" - -void SkeletonEditor::_on_click_option(int p_option) { - if (!skeleton) { - return; - } - - switch (p_option) { - case MENU_OPTION_CREATE_PHYSICAL_SKELETON: { - create_physical_skeleton(); - } break; - } -} - -void SkeletonEditor::create_physical_skeleton() { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner(); - - const int bc = skeleton->get_bone_count(); - - if (!bc) { - return; - } - - Vector<BoneInfo> bones_infos; - bones_infos.resize(bc); - - for (int bone_id = 0; bc > bone_id; ++bone_id) { - - const int parent = skeleton->get_bone_parent(bone_id); - - if (parent < 0) { - - bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id); - - } else { - - const int parent_parent = skeleton->get_bone_parent(parent); - - bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id); - - /// create physical bone on parent - if (!bones_infos[parent].physical_bone) { - - bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); - - ur->create_action(TTR("Create physical bones")); - ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); - ur->add_do_reference(bones_infos[parent].physical_bone); - ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone); - ur->commit_action(); - - bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent)); - bones_infos[parent].physical_bone->set_owner(owner); - bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner - - /// Create joint between parent of parent - if (-1 != parent_parent) { - - bones_infos[parent].physical_bone->set_joint_type(PhysicalBone::JOINT_TYPE_PIN); - } - } - } - } -} - -PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) { - - real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5); - real_t radius(half_height * 0.2); - - CapsuleShape *bone_shape_capsule = memnew(CapsuleShape); - bone_shape_capsule->set_height((half_height - radius) * 2); - bone_shape_capsule->set_radius(radius); - - CollisionShape *bone_shape = memnew(CollisionShape); - bone_shape->set_shape(bone_shape_capsule); - - Transform body_transform; - body_transform.origin = Vector3(0, 0, -half_height); - - Transform joint_transform; - joint_transform.origin = Vector3(0, 0, half_height); - - PhysicalBone *physical_bone = memnew(PhysicalBone); - physical_bone->add_child(bone_shape); - physical_bone->set_name("Physical Bone " + skeleton->get_bone_name(bone_id)); - physical_bone->set_body_offset(body_transform); - physical_bone->set_joint_offset(joint_transform); - return physical_bone; -} - -void SkeletonEditor::edit(Skeleton *p_node) { - - skeleton = p_node; -} - -void SkeletonEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - get_tree()->connect("node_removed", this, "_node_removed"); - } -} - -void SkeletonEditor::_node_removed(Node *p_node) { - - if (p_node == skeleton) { - skeleton = NULL; - options->hide(); - } -} - -void SkeletonEditor::_bind_methods() { - ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option); - ClassDB::bind_method("_node_removed", &SkeletonEditor::_node_removed); -} - -SkeletonEditor::SkeletonEditor() { - skeleton = NULL; - options = memnew(MenuButton); - SpatialEditor::get_singleton()->add_control_to_menu_panel(options); - - options->set_text(TTR("Skeleton")); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons")); - - options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON); - - options->get_popup()->connect("id_pressed", this, "_on_click_option"); - options->hide(); -} - -SkeletonEditor::~SkeletonEditor() {} - -void SkeletonEditorPlugin::edit(Object *p_object) { - skeleton_editor->edit(Object::cast_to<Skeleton>(p_object)); -} - -bool SkeletonEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("Skeleton"); -} - -void SkeletonEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - skeleton_editor->options->show(); - } else { - - skeleton_editor->options->hide(); - skeleton_editor->edit(NULL); - } -} - -SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) { - editor = p_node; - skeleton_editor = memnew(SkeletonEditor); - editor->get_viewport()->add_child(skeleton_editor); -} - -SkeletonEditorPlugin::~SkeletonEditorPlugin() {} diff --git a/editor/plugins/skeleton_ik_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp index 43dc13b270..8fc789b94a 100644 --- a/editor/plugins/skeleton_ik_editor_plugin.cpp +++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* skeleton_ik_editor_plugin.cpp */ +/* skeleton_ik_3d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,40 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "skeleton_ik_editor_plugin.h" +#include "skeleton_ik_3d_editor_plugin.h" -#include "scene/animation/skeleton_ik.h" +#include "scene/3d/skeleton_ik_3d.h" -void SkeletonIKEditorPlugin::_play() { - - if (!skeleton_ik) +void SkeletonIK3DEditorPlugin::_play() { + if (!skeleton_ik) { return; + } - if (!skeleton_ik->get_parent_skeleton()) + if (!skeleton_ik->get_parent_skeleton()) { return; + } if (play_btn->is_pressed()) { - - initial_bone_poses.resize(skeleton_ik->get_parent_skeleton()->get_bone_count()); - for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { - initial_bone_poses.write[i] = skeleton_ik->get_parent_skeleton()->get_bone_pose(i); - } - skeleton_ik->start(); } else { skeleton_ik->stop(); - - if (initial_bone_poses.size() != skeleton_ik->get_parent_skeleton()->get_bone_count()) - return; - - for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { - skeleton_ik->get_parent_skeleton()->set_bone_pose(i, initial_bone_poses[i]); - } + skeleton_ik->get_parent_skeleton()->clear_bones_global_pose_override(); } } -void SkeletonIKEditorPlugin::edit(Object *p_object) { - +void SkeletonIK3DEditorPlugin::edit(Object *p_object) { if (p_object != skeleton_ik) { if (skeleton_ik) { play_btn->set_pressed(false); @@ -69,42 +57,39 @@ void SkeletonIKEditorPlugin::edit(Object *p_object) { } } - SkeletonIK *s = Object::cast_to<SkeletonIK>(p_object); - if (!s) + SkeletonIK3D *s = Object::cast_to<SkeletonIK3D>(p_object); + if (!s) { return; + } skeleton_ik = s; } -bool SkeletonIKEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("SkeletonIK"); +bool SkeletonIK3DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("SkeletonIK3D"); } -void SkeletonIKEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) +void SkeletonIK3DEditorPlugin::make_visible(bool p_visible) { + if (p_visible) { play_btn->show(); - else + } else { play_btn->hide(); + } } -void SkeletonIKEditorPlugin::_bind_methods() { - - ClassDB::bind_method("_play", &SkeletonIKEditorPlugin::_play); +void SkeletonIK3DEditorPlugin::_bind_methods() { } -SkeletonIKEditorPlugin::SkeletonIKEditorPlugin(EditorNode *p_node) { - +SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin(EditorNode *p_node) { editor = p_node; play_btn = memnew(Button); - play_btn->set_icon(editor->get_gui_base()->get_icon("Play", "EditorIcons")); + play_btn->set_icon(editor->get_gui_base()->get_theme_icon("Play", "EditorIcons")); play_btn->set_text(TTR("Play IK")); play_btn->set_toggle_mode(true); play_btn->hide(); - play_btn->connect("pressed", this, "_play"); + play_btn->connect("pressed", callable_mp(this, &SkeletonIK3DEditorPlugin::_play)); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, play_btn); - skeleton_ik = NULL; + skeleton_ik = nullptr; } -SkeletonIKEditorPlugin::~SkeletonIKEditorPlugin() {} +SkeletonIK3DEditorPlugin::~SkeletonIK3DEditorPlugin() {} diff --git a/editor/plugins/skeleton_ik_editor_plugin.h b/editor/plugins/skeleton_ik_3d_editor_plugin.h index 06c07031f6..c1585ea670 100644 --- a/editor/plugins/skeleton_ik_editor_plugin.h +++ b/editor/plugins/skeleton_ik_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* skeleton_ik_editor_plugin.h */ +/* skeleton_ik_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SKELETON_IK_EDITOR_PLUGIN_H -#define SKELETON_IK_EDITOR_PLUGIN_H +#ifndef SKELETON_IK_3D_EDITOR_PLUGIN_H +#define SKELETON_IK_3D_EDITOR_PLUGIN_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" -class SkeletonIK; +class SkeletonIK3D; -class SkeletonIKEditorPlugin : public EditorPlugin { +class SkeletonIK3DEditorPlugin : public EditorPlugin { + GDCLASS(SkeletonIK3DEditorPlugin, EditorPlugin); - GDCLASS(SkeletonIKEditorPlugin, EditorPlugin); - - SkeletonIK *skeleton_ik; + SkeletonIK3D *skeleton_ik; Button *play_btn; EditorNode *editor; - Vector<Transform> initial_bone_poses; void _play(); @@ -52,14 +50,14 @@ protected: static void _bind_methods(); public: - virtual String get_name() const { return "SkeletonIK"; } - 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); - - SkeletonIKEditorPlugin(EditorNode *p_node); - ~SkeletonIKEditorPlugin(); + virtual String get_name() const override { return "SkeletonIK3D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + SkeletonIK3DEditorPlugin(EditorNode *p_node); + ~SkeletonIK3DEditorPlugin(); }; -#endif // SKELETON_IK_EDITOR_PLUGIN_H +#endif // SKELETON_IK_3D_EDITOR_PLUGIN_H diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 6757b180a3..f5fafb68a5 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* sprite_editor_plugin.cpp */ +/* sprite_2d_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "sprite_editor_plugin.h" +#include "sprite_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "core/math/geometry_2d.h" #include "editor/editor_scale.h" #include "scene/2d/collision_polygon_2d.h" #include "scene/2d/light_occluder_2d.h" @@ -39,16 +40,14 @@ #include "scene/gui/box_container.h" #include "thirdparty/misc/clipper.hpp" -void SpriteEditor::_node_removed(Node *p_node) { - +void Sprite2DEditor::_node_removed(Node *p_node) { if (p_node == node) { - node = NULL; + node = nullptr; options->hide(); } } -void SpriteEditor::edit(Sprite *p_sprite) { - +void Sprite2DEditor::edit(Sprite2D *p_sprite) { node = p_sprite; } @@ -63,7 +62,6 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float ClipperLib::PolyTree out; for (int i = 0; i < points.size(); i++) { - subj << ClipperLib::IntPoint(points[i].x * PRECISION, points[i].y * PRECISION); } ClipperLib::ClipperOffset co; @@ -104,7 +102,6 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float int lasti = p2->Contour.size() - 1; Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION); for (uint64_t i = 0; i < p2->Contour.size(); i++) { - Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION); if (cur.distance_to(prev) > 0.5) { outPoints.push_back(cur); @@ -114,8 +111,7 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float return outPoints; } -void SpriteEditor::_menu_option(int p_option) { - +void Sprite2DEditor::_menu_option(int p_option) { if (!node) { return; } @@ -124,7 +120,6 @@ void SpriteEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_CONVERT_TO_MESH_2D: { - debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D")); debug_uv_dialog->set_title(TTR("Mesh2D Preview")); @@ -134,7 +129,6 @@ void SpriteEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CONVERT_TO_POLYGON_2D: { - debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D")); debug_uv_dialog->set_title(TTR("Polygon2D Preview")); @@ -143,7 +137,6 @@ void SpriteEditor::_menu_option(int p_option) { debug_uv->update(); } break; case MENU_OPTION_CREATE_COLLISION_POLY_2D: { - debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D")); debug_uv_dialog->set_title(TTR("CollisionPolygon2D Preview")); @@ -153,7 +146,6 @@ void SpriteEditor::_menu_option(int p_option) { } break; case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: { - debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D")); debug_uv_dialog->set_title(TTR("LightOccluder2D Preview")); @@ -165,28 +157,28 @@ void SpriteEditor::_menu_option(int p_option) { } } -void SpriteEditor::_update_mesh_data() { - - Ref<Texture> texture = node->get_texture(); +void Sprite2DEditor::_update_mesh_data() { + Ref<Texture2D> texture = node->get_texture(); if (texture.is_null()) { - err_dialog->set_text(TTR("Sprite is empty!")); - err_dialog->popup_centered_minsize(); + err_dialog->set_text(TTR("Sprite2D is empty!")); + err_dialog->popup_centered(); return; } if (node->get_hframes() > 1 || node->get_vframes() > 1) { err_dialog->set_text(TTR("Can't convert a sprite using animation frames to mesh.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } Ref<Image> image = texture->get_data(); ERR_FAIL_COND(image.is_null()); Rect2 rect; - if (node->is_region()) + if (node->is_region()) { rect = node->get_region_rect(); - else + } else { rect.size = Size2(image->get_width(), image->get_height()); + } Ref<BitMap> bm; bm.instance(); @@ -204,7 +196,7 @@ void SpriteEditor::_update_mesh_data() { float epsilon = simplification->get_value(); - Vector<Vector<Vector2> > lines = bm->clip_opaque_to_polygons(rect, epsilon); + Vector<Vector<Vector2>> lines = bm->clip_opaque_to_polygons(rect, epsilon); uv_lines.clear(); @@ -218,7 +210,6 @@ void SpriteEditor::_update_mesh_data() { } if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D) { - for (int j = 0; j < lines.size(); j++) { int index_ofs = computed_vertices.size(); @@ -229,18 +220,21 @@ void SpriteEditor::_update_mesh_data() { vtx -= rect.position; //offset by rect position //flip if flipped - if (node->is_flipped_h()) + if (node->is_flipped_h()) { vtx.x = rect.size.x - vtx.x - 1.0; - if (node->is_flipped_v()) + } + if (node->is_flipped_v()) { vtx.y = rect.size.y - vtx.y - 1.0; + } - if (node->is_centered()) + if (node->is_centered()) { vtx -= rect.size / 2.0; + } computed_vertices.push_back(vtx); } - Vector<int> poly = Geometry::triangulate_polygon(lines[j]); + Vector<int> poly = Geometry2D::triangulate_polygon(lines[j]); for (int i = 0; i < poly.size(); i += 3) { for (int k = 0; k < 3; k++) { @@ -262,7 +256,6 @@ void SpriteEditor::_update_mesh_data() { outline_lines.resize(lines.size()); computed_outline_lines.resize(lines.size()); for (int pi = 0; pi < lines.size(); pi++) { - Vector<Vector2> ol; Vector<Vector2> col; @@ -277,13 +270,16 @@ void SpriteEditor::_update_mesh_data() { vtx -= rect.position; //offset by rect position //flip if flipped - if (node->is_flipped_h()) + if (node->is_flipped_h()) { vtx.x = rect.size.x - vtx.x - 1.0; - if (node->is_flipped_v()) + } + if (node->is_flipped_v()) { vtx.y = rect.size.y - vtx.y - 1.0; + } - if (node->is_centered()) + if (node->is_centered()) { vtx -= rect.size / 2.0; + } col.write[i] = vtx; } @@ -296,7 +292,7 @@ void SpriteEditor::_update_mesh_data() { debug_uv->update(); } -void SpriteEditor::_create_node() { +void Sprite2DEditor::_create_node() { switch (selected_menu_item) { case MENU_OPTION_CONVERT_TO_MESH_2D: { _convert_to_mesh_2d_node(); @@ -313,11 +309,10 @@ void SpriteEditor::_create_node() { } } -void SpriteEditor::_convert_to_mesh_2d_node() { - +void Sprite2DEditor::_convert_to_mesh_2d_node() { if (computed_vertices.size() < 3) { err_dialog->set_text(TTR("Invalid geometry, can't replace by mesh.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } @@ -330,7 +325,7 @@ void SpriteEditor::_convert_to_mesh_2d_node() { a[Mesh::ARRAY_TEX_UV] = computed_uv; a[Mesh::ARRAY_INDEX] = computed_indices; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); @@ -344,27 +339,27 @@ void SpriteEditor::_convert_to_mesh_2d_node() { ur->commit_action(); } -void SpriteEditor::_convert_to_polygon_2d_node() { - +void Sprite2DEditor::_convert_to_polygon_2d_node() { if (computed_outline_lines.empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create polygon.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } Polygon2D *polygon_2d_instance = memnew(Polygon2D); int total_point_count = 0; - for (int i = 0; i < computed_outline_lines.size(); i++) + for (int i = 0; i < computed_outline_lines.size(); i++) { total_point_count += computed_outline_lines[i].size(); + } - PoolVector2Array polygon; + PackedVector2Array polygon; polygon.resize(total_point_count); - PoolVector2Array::Write polygon_write = polygon.write(); + Vector2 *polygon_write = polygon.ptrw(); - PoolVector2Array uvs; + PackedVector2Array uvs; uvs.resize(total_point_count); - PoolVector2Array::Write uvs_write = uvs.write(); + Vector2 *uvs_write = uvs.ptrw(); int current_point_index = 0; @@ -372,13 +367,12 @@ void SpriteEditor::_convert_to_polygon_2d_node() { polys.resize(computed_outline_lines.size()); for (int i = 0; i < computed_outline_lines.size(); i++) { - Vector<Vector2> outline = computed_outline_lines[i]; Vector<Vector2> uv_outline = outline_lines[i]; - PoolIntArray pia; + PackedInt32Array pia; pia.resize(outline.size()); - PoolIntArray::Write pia_write = pia.write(); + int *pia_write = pia.ptrw(); for (int pi = 0; pi < outline.size(); pi++) { polygon_write[current_point_index] = outline[pi]; @@ -403,16 +397,14 @@ void SpriteEditor::_convert_to_polygon_2d_node() { ur->commit_action(); } -void SpriteEditor::_create_collision_polygon_2d_node() { - +void Sprite2DEditor::_create_collision_polygon_2d_node() { if (computed_outline_lines.empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } for (int i = 0; i < computed_outline_lines.size(); i++) { - Vector<Vector2> outline = computed_outline_lines[i]; CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); @@ -427,24 +419,22 @@ void SpriteEditor::_create_collision_polygon_2d_node() { } } -void SpriteEditor::_create_light_occluder_2d_node() { - +void Sprite2DEditor::_create_light_occluder_2d_node() { if (computed_outline_lines.empty()) { err_dialog->set_text(TTR("Invalid geometry, can't create light occluder.")); - err_dialog->popup_centered_minsize(); + err_dialog->popup_centered(); return; } for (int i = 0; i < computed_outline_lines.size(); i++) { - Vector<Vector2> outline = computed_outline_lines[i]; Ref<OccluderPolygon2D> polygon; polygon.instance(); - PoolVector2Array a; + PackedVector2Array a; a.resize(outline.size()); - PoolVector2Array::Write aw = a.write(); + Vector2 *aw = a.ptrw(); for (int io = 0; io < outline.size(); io++) { aw[io] = outline[io]; } @@ -462,7 +452,7 @@ void SpriteEditor::_create_light_occluder_2d_node() { } } -void SpriteEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) { +void Sprite2DEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) { // Can't make sibling if own node is scene root if (p_own_node != this->get_tree()->get_edited_scene_root()) { p_own_node->get_parent()->add_child(p_new_node, true); @@ -474,9 +464,8 @@ void SpriteEditor::_add_as_sibling_or_child(Node *p_own_node, Node *p_new_node) p_new_node->set_owner(this->get_tree()->get_edited_scene_root()); } -void SpriteEditor::_debug_uv_draw() { - - Ref<Texture> tex = node->get_texture(); +void Sprite2DEditor::_debug_uv_draw() { + Ref<Texture2D> tex = node->get_texture(); ERR_FAIL_COND(!tex.is_valid()); Point2 draw_pos_offset = Point2(1.0, 1.0); @@ -502,23 +491,17 @@ void SpriteEditor::_debug_uv_draw() { } } -void SpriteEditor::_bind_methods() { - - ClassDB::bind_method("_menu_option", &SpriteEditor::_menu_option); - ClassDB::bind_method("_debug_uv_draw", &SpriteEditor::_debug_uv_draw); - ClassDB::bind_method("_update_mesh_data", &SpriteEditor::_update_mesh_data); - ClassDB::bind_method("_create_node", &SpriteEditor::_create_node); - ClassDB::bind_method("_add_as_sibling_or_child", &SpriteEditor::_add_as_sibling_or_child); +void Sprite2DEditor::_bind_methods() { + ClassDB::bind_method("_add_as_sibling_or_child", &Sprite2DEditor::_add_as_sibling_or_child); } -SpriteEditor::SpriteEditor() { - +Sprite2DEditor::Sprite2DEditor() { options = memnew(MenuButton); CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options); - options->set_text(TTR("Sprite")); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Sprite", "EditorIcons")); + options->set_text(TTR("Sprite2D")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Sprite2D", "EditorIcons")); options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D); options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D); @@ -526,7 +509,7 @@ SpriteEditor::SpriteEditor() { options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D); options->set_switch_on_hover(true); - options->get_popup()->connect("id_pressed", this, "_menu_option"); + options->get_popup()->connect("id_pressed", callable_mp(this, &Sprite2DEditor::_menu_option)); err_dialog = memnew(AcceptDialog); add_child(err_dialog); @@ -542,9 +525,9 @@ SpriteEditor::SpriteEditor() { scroll->set_enable_v_scroll(true); vb->add_margin_child(TTR("Preview:"), scroll, true); debug_uv = memnew(Control); - debug_uv->connect("draw", this, "_debug_uv_draw"); + debug_uv->connect("draw", callable_mp(this, &Sprite2DEditor::_debug_uv_draw)); scroll->add_child(debug_uv); - debug_uv_dialog->connect("confirmed", this, "_create_node"); + debug_uv_dialog->connect("confirmed", callable_mp(this, &Sprite2DEditor::_create_node)); HBoxContainer *hb = memnew(HBoxContainer); hb->add_child(memnew(Label(TTR("Simplification: ")))); @@ -573,43 +556,38 @@ SpriteEditor::SpriteEditor() { hb->add_spacer(); update_preview = memnew(Button); update_preview->set_text(TTR("Update Preview")); - update_preview->connect("pressed", this, "_update_mesh_data"); + update_preview->connect("pressed", callable_mp(this, &Sprite2DEditor::_update_mesh_data)); hb->add_child(update_preview); vb->add_margin_child(TTR("Settings:"), hb); add_child(debug_uv_dialog); } -void SpriteEditorPlugin::edit(Object *p_object) { - - sprite_editor->edit(Object::cast_to<Sprite>(p_object)); +void Sprite2DEditorPlugin::edit(Object *p_object) { + sprite_editor->edit(Object::cast_to<Sprite2D>(p_object)); } -bool SpriteEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("Sprite"); +bool Sprite2DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("Sprite2D"); } -void SpriteEditorPlugin::make_visible(bool p_visible) { - +void Sprite2DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { sprite_editor->options->show(); } else { - sprite_editor->options->hide(); - sprite_editor->edit(NULL); + sprite_editor->edit(nullptr); } } -SpriteEditorPlugin::SpriteEditorPlugin(EditorNode *p_node) { - +Sprite2DEditorPlugin::Sprite2DEditorPlugin(EditorNode *p_node) { editor = p_node; - sprite_editor = memnew(SpriteEditor); + sprite_editor = memnew(Sprite2DEditor); editor->get_viewport()->add_child(sprite_editor); make_visible(false); //sprite_editor->options->hide(); } -SpriteEditorPlugin::~SpriteEditorPlugin() { +Sprite2DEditorPlugin::~Sprite2DEditorPlugin() { } diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_2d_editor_plugin.h index 13177c9142..8769f19b5c 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_2d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* sprite_editor_plugin.h */ +/* sprite_2d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,12 +33,11 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" #include "scene/gui/spin_box.h" -class SpriteEditor : public Control { - - GDCLASS(SpriteEditor, Control); +class Sprite2DEditor : public Control { + GDCLASS(Sprite2DEditor, Control); enum Menu { MENU_OPTION_CONVERT_TO_MESH_2D, @@ -49,7 +48,7 @@ class SpriteEditor : public Control { Menu selected_menu_item; - Sprite *node; + Sprite2D *node; MenuButton *options; @@ -60,8 +59,8 @@ class SpriteEditor : public Control { ConfirmationDialog *debug_uv_dialog; Control *debug_uv; Vector<Vector2> uv_lines; - Vector<Vector<Vector2> > outline_lines; - Vector<Vector<Vector2> > computed_outline_lines; + Vector<Vector<Vector2>> outline_lines; + Vector<Vector<Vector2>> computed_outline_lines; Vector<Vector2> computed_vertices; Vector<Vector2> computed_uv; Vector<int> computed_indices; @@ -74,7 +73,7 @@ class SpriteEditor : public Control { void _menu_option(int p_option); //void _create_uv_lines(); - friend class SpriteEditorPlugin; + friend class Sprite2DEditorPlugin; void _debug_uv_draw(); void _update_mesh_data(); @@ -92,26 +91,25 @@ protected: static void _bind_methods(); public: - void edit(Sprite *p_sprite); - SpriteEditor(); + void edit(Sprite2D *p_sprite); + Sprite2DEditor(); }; -class SpriteEditorPlugin : public EditorPlugin { - - GDCLASS(SpriteEditorPlugin, EditorPlugin); +class Sprite2DEditorPlugin : public EditorPlugin { + GDCLASS(Sprite2DEditorPlugin, EditorPlugin); - SpriteEditor *sprite_editor; + Sprite2DEditor *sprite_editor; EditorNode *editor; public: - virtual String get_name() const { return "Sprite"; } - 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); - - SpriteEditorPlugin(EditorNode *p_node); - ~SpriteEditorPlugin(); + virtual String get_name() const override { return "Sprite2D"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + Sprite2DEditorPlugin(EditorNode *p_node); + ~Sprite2DEditorPlugin(); }; #endif // SPRITE_EDITOR_PLUGIN_H diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 4101980e29..5007983581 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -36,24 +36,24 @@ #include "editor/editor_settings.h" #include "scene/3d/sprite_3d.h" #include "scene/gui/center_container.h" +#include "scene/gui/margin_container.h" +#include "scene/gui/panel_container.h" void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { } void SpriteFramesEditor::_open_sprite_sheet() { - file_split_sheet->clear_filters(); List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions); for (int i = 0; i < extensions.size(); i++) { file_split_sheet->add_filter("*." + extensions[i]); } - file_split_sheet->popup_centered_ratio(); + file_split_sheet->popup_file_dialog(); } void SpriteFramesEditor::_sheet_preview_draw() { - Size2i size = split_sheet_preview->get_size(); int h = split_sheet_h->get_value(); int v = split_sheet_v->get_value(); @@ -61,13 +61,11 @@ void SpriteFramesEditor::_sheet_preview_draw() { int height = size.height / v; const float a = 0.3; for (int i = 1; i < h; i++) { - int x = i * width; split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a)); split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a)); for (int j = 1; j < v; j++) { - int y = j * height; split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a)); @@ -81,7 +79,7 @@ void SpriteFramesEditor::_sheet_preview_draw() { return; } - Color accent = get_color("accent_color", "Editor"); + Color accent = get_theme_color("accent_color", "Editor"); for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { int idx = E->get(); @@ -102,8 +100,8 @@ void SpriteFramesEditor::_sheet_preview_draw() { split_sheet_dialog->get_ok()->set_disabled(false); split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d Frame(s)"), frames_selected.size())); } -void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { +void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { @@ -144,9 +142,27 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { } } -void SpriteFramesEditor::_sheet_add_frames() { +void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) { + const Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid()) { + // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer + // to allow performing this action anywhere, even if the cursor isn't + // hovering the texture in the workspace. + if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) { + _sheet_zoom_in(); + // Don't scroll up after zooming in. + accept_event(); + } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) { + _sheet_zoom_out(); + // Don't scroll down after zooming out. + accept_event(); + } + } +} - Size2i size = split_sheet_preview->get_size(); +void SpriteFramesEditor::_sheet_add_frames() { + Size2i size = split_sheet_preview->get_texture()->get_size(); int h = split_sheet_h->get_value(); int v = split_sheet_v->get_value(); @@ -154,14 +170,22 @@ void SpriteFramesEditor::_sheet_add_frames() { int fc = frames->get_frame_count(edited_anim); + AtlasTexture *atlas_source = Object::cast_to<AtlasTexture>(*split_sheet_preview->get_texture()); + + Rect2 region_rect = Rect2(); + + if (atlas_source && atlas_source->get_atlas().is_valid()) { + region_rect = atlas_source->get_region(); + } + for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { int idx = E->get(); int width = size.width / h; int height = size.height / v; int xp = idx % h; int yp = (idx - xp) / h; - int x = xp * width; - int y = yp * height; + int x = (xp * width) + region_rect.position.x; + int y = (yp * height) + region_rect.position.y; Ref<AtlasTexture> at; at.instance(); @@ -177,8 +201,29 @@ void SpriteFramesEditor::_sheet_add_frames() { undo_redo->commit_action(); } -void SpriteFramesEditor::_sheet_select_clear_all_frames() { +void SpriteFramesEditor::_sheet_zoom_in() { + if (sheet_zoom < max_sheet_zoom) { + sheet_zoom *= scale_ratio; + Size2 texture_size = split_sheet_preview->get_texture()->get_size(); + split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom); + } +} +void SpriteFramesEditor::_sheet_zoom_out() { + if (sheet_zoom > min_sheet_zoom) { + sheet_zoom /= scale_ratio; + Size2 texture_size = split_sheet_preview->get_texture()->get_size(); + split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom); + } +} + +void SpriteFramesEditor::_sheet_zoom_reset() { + sheet_zoom = 1.f; + Size2 texture_size = split_sheet_preview->get_texture()->get_size(); + split_sheet_preview->set_custom_minimum_size(texture_size * sheet_zoom); +} + +void SpriteFramesEditor::_sheet_select_clear_all_frames() { bool should_clear = true; for (int i = 0; i < split_sheet_h->get_value() * split_sheet_v->get_value(); i++) { if (!frames_selected.has(i)) { @@ -194,66 +239,70 @@ void SpriteFramesEditor::_sheet_select_clear_all_frames() { } void SpriteFramesEditor::_sheet_spin_changed(double) { - frames_selected.clear(); last_frame_selected = -1; split_sheet_preview->update(); } void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { - Ref<Resource> texture = ResourceLoader::load(p_file); if (!texture.is_valid()) { EditorNode::get_singleton()->show_warning(TTR("Unable to load images")); ERR_FAIL_COND(!texture.is_valid()); } - if (texture != split_sheet_preview->get_texture()) { - //different texture, reset to 4x4 - split_sheet_h->set_value(4); - split_sheet_v->set_value(4); - } + bool new_texture = texture != split_sheet_preview->get_texture(); frames_selected.clear(); last_frame_selected = -1; split_sheet_preview->set_texture(texture); + if (new_texture) { + //different texture, reset to 4x4 + split_sheet_h->set_value(4); + split_sheet_v->set_value(4); + //reset zoom + _sheet_zoom_reset(); + } split_sheet_dialog->popup_centered_ratio(0.65); } void SpriteFramesEditor::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_ENTER_TREE: { - load->set_icon(get_icon("Load", "EditorIcons")); - load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons")); - copy->set_icon(get_icon("ActionCopy", "EditorIcons")); - paste->set_icon(get_icon("ActionPaste", "EditorIcons")); - empty->set_icon(get_icon("InsertBefore", "EditorIcons")); - empty2->set_icon(get_icon("InsertAfter", "EditorIcons")); - move_up->set_icon(get_icon("MoveLeft", "EditorIcons")); - move_down->set_icon(get_icon("MoveRight", "EditorIcons")); - _delete->set_icon(get_icon("Remove", "EditorIcons")); - new_anim->set_icon(get_icon("New", "EditorIcons")); - remove_anim->set_icon(get_icon("Remove", "EditorIcons")); - FALLTHROUGH; + load->set_icon(get_theme_icon("Load", "EditorIcons")); + load_sheet->set_icon(get_theme_icon("SpriteSheet", "EditorIcons")); + copy->set_icon(get_theme_icon("ActionCopy", "EditorIcons")); + paste->set_icon(get_theme_icon("ActionPaste", "EditorIcons")); + empty->set_icon(get_theme_icon("InsertBefore", "EditorIcons")); + empty2->set_icon(get_theme_icon("InsertAfter", "EditorIcons")); + move_up->set_icon(get_theme_icon("MoveLeft", "EditorIcons")); + move_down->set_icon(get_theme_icon("MoveRight", "EditorIcons")); + _delete->set_icon(get_theme_icon("Remove", "EditorIcons")); + zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons")); + zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons")); + zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); + new_anim->set_icon(get_theme_icon("New", "EditorIcons")); + remove_anim->set_icon(get_theme_icon("Remove", "EditorIcons")); + split_sheet_zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons")); + split_sheet_zoom_1->set_icon(get_theme_icon("ZoomReset", "EditorIcons")); + split_sheet_zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); + [[fallthrough]]; } case NOTIFICATION_THEME_CHANGED: { - splite_sheet_scroll->add_style_override("bg", get_stylebox("bg", "Tree")); + splite_sheet_scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree")); } break; case NOTIFICATION_READY: { - add_constant_override("autohide", 1); // Fixes the dragger always showing up. + add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up. } break; } } -void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, int p_at_pos) { - +void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_at_pos) { ERR_FAIL_COND(!frames->has_animation(edited_anim)); - List<Ref<Texture> > resources; + List<Ref<Texture2D>> resources; for (int i = 0; i < p_path.size(); i++) { - - Ref<Texture> resource; + Ref<Texture2D> resource; resource = ResourceLoader::load(p_path[i]); if (resource.is_null()) { @@ -262,7 +311,7 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in //dialog->get_cancel()->set_text("Close"); dialog->get_ok()->set_text(TTR("Close")); - dialog->popup_centered_minsize(); + dialog->popup_centered(); return; ///beh should show an error i guess } @@ -278,8 +327,7 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in int count = 0; - for (List<Ref<Texture> >::Element *E = resources.front(); E; E = E->next()) { - + for (List<Ref<Texture2D>>::Element *E = resources.front(); E; E = E->next()) { undo_redo->add_do_method(frames, "add_frame", edited_anim, E->get(), p_at_pos == -1 ? -1 : p_at_pos + count); undo_redo->add_undo_method(frames, "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos); count++; @@ -291,32 +339,30 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in } void SpriteFramesEditor::_load_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); loading_scene = false; file->clear_filters(); List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); - for (int i = 0; i < extensions.size(); i++) + ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions); + for (int i = 0; i < extensions.size(); i++) { file->add_filter("*." + extensions[i]); + } - file->set_mode(EditorFileDialog::MODE_OPEN_FILES); - - file->popup_centered_ratio(); + file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); + file->popup_file_dialog(); } void SpriteFramesEditor::_paste_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); - Ref<Texture> r = EditorSettings::get_singleton()->get_resource_clipboard(); + Ref<Texture2D> r = EditorSettings::get_singleton()->get_resource_clipboard(); if (!r.is_valid()) { dialog->set_text(TTR("Resource clipboard is empty or not a texture!")); dialog->set_title(TTR("Error!")); //dialog->get_cancel()->set_text("Close"); dialog->get_ok()->set_text(TTR("Close")); - dialog->popup_centered_minsize(); + dialog->popup_centered(); return; ///beh should show an error i guess } @@ -331,9 +377,10 @@ void SpriteFramesEditor::_paste_pressed() { void SpriteFramesEditor::_copy_pressed() { ERR_FAIL_COND(!frames->has_animation(edited_anim)); - if (tree->get_current() < 0) + if (tree->get_current() < 0) { return; - Ref<Texture> r = frames->get_frame(edited_anim, tree->get_current()); + } + Ref<Texture2D> r = frames->get_frame(edited_anim, tree->get_current()); if (!r.is_valid()) { return; } @@ -342,13 +389,11 @@ void SpriteFramesEditor::_copy_pressed() { } void SpriteFramesEditor::_empty_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); int from = -1; if (tree->get_current() >= 0) { - from = tree->get_current(); sel = from; @@ -356,7 +401,7 @@ void SpriteFramesEditor::_empty_pressed() { from = frames->get_frame_count(edited_anim); } - Ref<Texture> r; + Ref<Texture2D> r; undo_redo->create_action(TTR("Add Empty")); undo_redo->add_do_method(frames, "add_frame", edited_anim, r, from); @@ -367,13 +412,11 @@ void SpriteFramesEditor::_empty_pressed() { } void SpriteFramesEditor::_empty2_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); int from = -1; if (tree->get_current() >= 0) { - from = tree->get_current(); sel = from; @@ -381,7 +424,7 @@ void SpriteFramesEditor::_empty2_pressed() { from = frames->get_frame_count(edited_anim); } - Ref<Texture> r; + Ref<Texture2D> r; undo_redo->create_action(TTR("Add Empty")); undo_redo->add_do_method(frames, "add_frame", edited_anim, r, from + 1); @@ -392,15 +435,16 @@ void SpriteFramesEditor::_empty2_pressed() { } void SpriteFramesEditor::_up_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); - if (tree->get_current() < 0) + if (tree->get_current() < 0) { return; + } int to_move = tree->get_current(); - if (to_move < 1) + if (to_move < 1) { return; + } sel = to_move; sel -= 1; @@ -416,15 +460,16 @@ void SpriteFramesEditor::_up_pressed() { } void SpriteFramesEditor::_down_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); - if (tree->get_current() < 0) + if (tree->get_current() < 0) { return; + } int to_move = tree->get_current(); - if (to_move < 0 || to_move >= frames->get_frame_count(edited_anim) - 1) + if (to_move < 0 || to_move >= frames->get_frame_count(edited_anim) - 1) { return; + } sel = to_move; sel += 1; @@ -440,11 +485,11 @@ void SpriteFramesEditor::_down_pressed() { } void SpriteFramesEditor::_delete_pressed() { - ERR_FAIL_COND(!frames->has_animation(edited_anim)); - if (tree->get_current() < 0) + if (tree->get_current() < 0) { return; + } int to_delete = tree->get_current(); if (to_delete < 0 || to_delete >= frames->get_frame_count(edited_anim)) { @@ -460,14 +505,15 @@ void SpriteFramesEditor::_delete_pressed() { } void SpriteFramesEditor::_animation_select() { - - if (updating) + if (updating) { return; + } if (frames->has_animation(edited_anim)) { - double value = anim_speed->get_line_edit()->get_text().to_double(); - if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim))) + double value = anim_speed->get_line_edit()->get_text().to_float(); + if (!Math::is_equal_approx(value, frames->get_animation_speed(edited_anim))) { _animation_fps_changed(value); + } } TreeItem *selected = animations->get_selected(); @@ -477,15 +523,16 @@ void SpriteFramesEditor::_animation_select() { } static void _find_anim_sprites(Node *p_node, List<Node *> *r_nodes, Ref<SpriteFrames> p_sfames) { - Node *edited = EditorNode::get_singleton()->get_edited_scene(); - if (!edited) + if (!edited) { return; - if (p_node != edited && p_node->get_owner() != edited) + } + if (p_node != edited && p_node->get_owner() != edited) { return; + } { - AnimatedSprite *as = Object::cast_to<AnimatedSprite>(p_node); + AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node); if (as && as->get_sprite_frames() == p_sfames) { r_nodes->push_back(p_node); } @@ -504,21 +551,24 @@ static void _find_anim_sprites(Node *p_node, List<Node *> *r_nodes, Ref<SpriteFr } void SpriteFramesEditor::_animation_name_edited() { - - if (updating) + if (updating) { return; + } - if (!frames->has_animation(edited_anim)) + if (!frames->has_animation(edited_anim)) { return; + } TreeItem *edited = animations->get_edited(); - if (!edited) + if (!edited) { return; + } String new_name = edited->get_text(0); - if (new_name == String(edited_anim)) + if (new_name == String(edited_anim)) { return; + } new_name = new_name.replace("/", "_").replace(",", " "); @@ -537,7 +587,6 @@ void SpriteFramesEditor::_animation_name_edited() { undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim); for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) { - String current = E->get()->call("get_animation"); undo_redo->add_do_method(E->get(), "set_animation", name); undo_redo->add_undo_method(E->get(), "set_animation", edited_anim); @@ -552,7 +601,6 @@ void SpriteFramesEditor::_animation_name_edited() { } void SpriteFramesEditor::_animation_add() { - String name = "New Anim"; int counter = 0; while (frames->has_animation(name)) { @@ -570,7 +618,6 @@ void SpriteFramesEditor::_animation_add() { undo_redo->add_undo_method(this, "_update_library"); for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) { - String current = E->get()->call("get_animation"); undo_redo->add_do_method(E->get(), "set_animation", name); undo_redo->add_undo_method(E->get(), "set_animation", current); @@ -583,19 +630,19 @@ void SpriteFramesEditor::_animation_add() { } void SpriteFramesEditor::_animation_remove() { - - if (updating) + if (updating) { return; + } - if (!frames->has_animation(edited_anim)) + if (!frames->has_animation(edited_anim)) { return; + } delete_dialog->set_text(TTR("Delete Animation?")); - delete_dialog->popup_centered_minsize(); + delete_dialog->popup_centered(); } void SpriteFramesEditor::_animation_remove_confirmed() { - undo_redo->create_action(TTR("Remove Animation")); undo_redo->add_do_method(frames, "remove_animation", edited_anim); undo_redo->add_undo_method(frames, "add_animation", edited_anim); @@ -603,7 +650,7 @@ void SpriteFramesEditor::_animation_remove_confirmed() { undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim)); int fc = frames->get_frame_count(edited_anim); for (int i = 0; i < fc; i++) { - Ref<Texture> frame = frames->get_frame(edited_anim, i); + Ref<Texture2D> frame = frames->get_frame(edited_anim, i); undo_redo->add_undo_method(frames, "add_frame", edited_anim, frame); } undo_redo->add_do_method(this, "_update_library"); @@ -615,9 +662,9 @@ void SpriteFramesEditor::_animation_remove_confirmed() { } void SpriteFramesEditor::_animation_loop_changed() { - - if (updating) + if (updating) { return; + } undo_redo->create_action(TTR("Change Animation Loop")); undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed()); @@ -628,9 +675,9 @@ void SpriteFramesEditor::_animation_loop_changed() { } void SpriteFramesEditor::_animation_fps_changed(double p_value) { - - if (updating) + if (updating) { return; + } undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value); @@ -641,8 +688,55 @@ void SpriteFramesEditor::_animation_fps_changed(double p_value) { undo_redo->commit_action(); } -void SpriteFramesEditor::_update_library(bool p_skip_selector) { +void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) { + const Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid()) { + if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) { + _zoom_in(); + // Don't scroll up after zooming in. + accept_event(); + } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) { + _zoom_out(); + // Don't scroll down after zooming out. + accept_event(); + } + } +} + +void SpriteFramesEditor::_zoom_in() { + // Do not zoom in or out with no visible frames + if (frames->get_frame_count(edited_anim) <= 0) { + return; + } + if (thumbnail_zoom < max_thumbnail_zoom) { + thumbnail_zoom *= scale_ratio; + int thumbnail_size = (int)(thumbnail_default_size * thumbnail_zoom); + tree->set_fixed_column_width(thumbnail_size * 3 / 2); + tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); + } +} + +void SpriteFramesEditor::_zoom_out() { + // Do not zoom in or out with no visible frames + if (frames->get_frame_count(edited_anim) <= 0) { + return; + } + if (thumbnail_zoom > min_thumbnail_zoom) { + thumbnail_zoom /= scale_ratio; + int thumbnail_size = (int)(thumbnail_default_size * thumbnail_zoom); + tree->set_fixed_column_width(thumbnail_size * 3 / 2); + tree->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); + } +} + +void SpriteFramesEditor::_zoom_reset() { + thumbnail_zoom = 1.0f; + tree->set_fixed_column_width(thumbnail_default_size * 3 / 2); + tree->set_fixed_icon_size(Size2(thumbnail_default_size, thumbnail_default_size)); +} +void SpriteFramesEditor::_update_library(bool p_skip_selector) { updating = true; if (!p_skip_selector) { @@ -657,7 +751,6 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { anim_names.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E = anim_names.front(); E; E = E->next()) { - String name = E->get(); TreeItem *it = animations->create_item(anim_root); @@ -680,18 +773,17 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { return; } - if (sel >= frames->get_frame_count(edited_anim)) + if (sel >= frames->get_frame_count(edited_anim)) { sel = frames->get_frame_count(edited_anim) - 1; - else if (sel < 0 && frames->get_frame_count(edited_anim)) + } else if (sel < 0 && frames->get_frame_count(edited_anim)) { sel = 0; + } for (int i = 0; i < frames->get_frame_count(edited_anim); i++) { - String name; - Ref<Texture> icon; + Ref<Texture2D> icon; if (frames->get_frame(edited_anim, i).is_null()) { - name = itos(i) + ": " + TTR("(empty)"); } else { @@ -700,10 +792,12 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { } tree->add_item(name, icon); - if (frames->get_frame(edited_anim, i).is_valid()) + if (frames->get_frame(edited_anim, i).is_valid()) { tree->set_item_tooltip(tree->get_item_count() - 1, frames->get_frame(edited_anim, i)->get_path()); - if (sel == i) + } + if (sel == i) { tree->select(tree->get_item_count() - 1); + } } anim_speed->set_value(frames->get_animation_speed(edited_anim)); @@ -714,16 +808,14 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) { } void SpriteFramesEditor::edit(SpriteFrames *p_frames) { - - if (frames == p_frames) + if (frames == p_frames) { return; + } frames = p_frames; if (p_frames) { - if (!p_frames->has_animation(edited_anim)) { - List<StringName> anim_names; frames->get_animation_list(&anim_names); anim_names.sort_custom<StringName::AlphCompare>(); @@ -735,26 +827,30 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) { } _update_library(); + // Clear zoom and split sheet texture + split_sheet_preview->set_texture(Ref<Texture2D>()); + _zoom_reset(); } else { - hide(); } } Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - - if (!frames->has_animation(edited_anim)) + if (!frames->has_animation(edited_anim)) { return false; + } int idx = tree->get_item_at_position(p_point, true); - if (idx < 0 || idx >= frames->get_frame_count(edited_anim)) + if (idx < 0 || idx >= frames->get_frame_count(edited_anim)) { return Variant(); + } RES frame = frames->get_frame(edited_anim, idx); - if (frame.is_null()) + if (frame.is_null()) { return Variant(); + } Dictionary drag_data = EditorNode::get_singleton()->drag_resource(frame, p_from); drag_data["frame"] = idx; // store the frame, in case we want to reorder frames inside 'drop_data_fw' @@ -762,39 +858,39 @@ Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f } bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return false; + } // reordering frames - if (d.has("from") && (Object *)(d["from"]) == tree) + if (d.has("from") && (Object *)(d["from"]) == tree) { return true; + } if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; - Ref<Texture> texture = r; + Ref<Texture2D> texture = r; if (texture.is_valid()) { - return true; } } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; - if (files.size() == 0) + if (files.size() == 0) { return false; + } for (int i = 0; i < files.size(); i++) { String file = files[i]; String ftype = EditorFileSystem::get_singleton()->get_file_type(file); - if (!ClassDB::is_parent_class(ftype, "Texture")) { + if (!ClassDB::is_parent_class(ftype, "Texture2D")) { return false; } } @@ -805,31 +901,34 @@ bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant & } void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - - if (!can_drop_data_fw(p_point, p_data, p_from)) + if (!can_drop_data_fw(p_point, p_data, p_from)) { return; + } Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return; + } int at_pos = tree->get_item_at_position(p_point, true); if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; - Ref<Texture> texture = r; + Ref<Texture2D> texture = r; if (texture.is_valid()) { bool reorder = false; - if (d.has("from") && (Object *)(d["from"]) == tree) + if (d.has("from") && (Object *)(d["from"]) == tree) { reorder = true; + } if (reorder) { //drop is from reordering frames int from_frame = -1; - if (d.has("frame")) + if (d.has("frame")) { from_frame = d["frame"]; + } undo_redo->create_action(TTR("Move Frame")); undo_redo->add_do_method(frames, "remove_frame", edited_anim, from_frame == -1 ? frames->get_frame_count(edited_anim) : from_frame); @@ -851,46 +950,20 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "files") { - - PoolVector<String> files = d["files"]; + Vector<String> files = d["files"]; _file_load_request(files, at_pos); } } void SpriteFramesEditor::_bind_methods() { - - 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); - ClassDB::bind_method(D_METHOD("_delete_pressed"), &SpriteFramesEditor::_delete_pressed); - ClassDB::bind_method(D_METHOD("_copy_pressed"), &SpriteFramesEditor::_copy_pressed); - ClassDB::bind_method(D_METHOD("_paste_pressed"), &SpriteFramesEditor::_paste_pressed); - ClassDB::bind_method(D_METHOD("_file_load_request", "files", "at_position"), &SpriteFramesEditor::_file_load_request, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("_up_pressed"), &SpriteFramesEditor::_up_pressed); - ClassDB::bind_method(D_METHOD("_down_pressed"), &SpriteFramesEditor::_down_pressed); - ClassDB::bind_method(D_METHOD("_animation_select"), &SpriteFramesEditor::_animation_select); - ClassDB::bind_method(D_METHOD("_animation_name_edited"), &SpriteFramesEditor::_animation_name_edited); - ClassDB::bind_method(D_METHOD("_animation_add"), &SpriteFramesEditor::_animation_add); - ClassDB::bind_method(D_METHOD("_animation_remove"), &SpriteFramesEditor::_animation_remove); - ClassDB::bind_method(D_METHOD("_animation_remove_confirmed"), &SpriteFramesEditor::_animation_remove_confirmed); - ClassDB::bind_method(D_METHOD("_animation_loop_changed"), &SpriteFramesEditor::_animation_loop_changed); - ClassDB::bind_method(D_METHOD("_animation_fps_changed"), &SpriteFramesEditor::_animation_fps_changed); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw); - ClassDB::bind_method(D_METHOD("_prepare_sprite_sheet"), &SpriteFramesEditor::_prepare_sprite_sheet); - ClassDB::bind_method(D_METHOD("_open_sprite_sheet"), &SpriteFramesEditor::_open_sprite_sheet); - ClassDB::bind_method(D_METHOD("_sheet_preview_draw"), &SpriteFramesEditor::_sheet_preview_draw); - ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input); - ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed); - ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames); - ClassDB::bind_method(D_METHOD("_sheet_select_clear_all_frames"), &SpriteFramesEditor::_sheet_select_clear_all_frames); } SpriteFramesEditor::SpriteFramesEditor() { - VBoxContainer *vbc_animlist = memnew(VBoxContainer); add_child(vbc_animlist); vbc_animlist->set_custom_minimum_size(Size2(150, 0) * EDSCALE); @@ -902,35 +975,42 @@ SpriteFramesEditor::SpriteFramesEditor() { HBoxContainer *hbc_animlist = memnew(HBoxContainer); sub_vb->add_child(hbc_animlist); - new_anim = memnew(ToolButton); + new_anim = memnew(Button); + new_anim->set_flat(true); new_anim->set_tooltip(TTR("New Animation")); hbc_animlist->add_child(new_anim); - new_anim->connect("pressed", this, "_animation_add"); + new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add)); - remove_anim = memnew(ToolButton); + remove_anim = memnew(Button); + remove_anim->set_flat(true); remove_anim->set_tooltip(TTR("Remove Animation")); hbc_animlist->add_child(remove_anim); - remove_anim->connect("pressed", this, "_animation_remove"); + remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove)); animations = memnew(Tree); sub_vb->add_child(animations); animations->set_v_size_flags(SIZE_EXPAND_FILL); animations->set_hide_root(true); - animations->connect("cell_selected", this, "_animation_select"); - animations->connect("item_edited", this, "_animation_name_edited"); + animations->connect("cell_selected", callable_mp(this, &SpriteFramesEditor::_animation_select)); + animations->connect("item_edited", callable_mp(this, &SpriteFramesEditor::_animation_name_edited)); animations->set_allow_reselect(true); + HBoxContainer *hbc_anim_speed = memnew(HBoxContainer); + hbc_anim_speed->add_child(memnew(Label(TTR("Speed:")))); + vbc_animlist->add_child(hbc_anim_speed); anim_speed = memnew(SpinBox); - vbc_animlist->add_margin_child(TTR("Speed (FPS):"), anim_speed); + anim_speed->set_suffix(TTR("FPS")); anim_speed->set_min(0); anim_speed->set_max(100); anim_speed->set_step(0.01); - anim_speed->connect("value_changed", this, "_animation_fps_changed"); + anim_speed->set_h_size_flags(SIZE_EXPAND_FILL); + hbc_anim_speed->add_child(anim_speed); + anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_fps_changed)); anim_loop = memnew(CheckButton); anim_loop->set_text(TTR("Loop")); vbc_animlist->add_child(anim_loop); - anim_loop->connect("pressed", this, "_animation_loop_changed"); + anim_loop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_loop_changed)); VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); @@ -942,48 +1022,75 @@ SpriteFramesEditor::SpriteFramesEditor() { HBoxContainer *hbc = memnew(HBoxContainer); sub_vb->add_child(hbc); - load = memnew(ToolButton); + load = memnew(Button); + load->set_flat(true); load->set_tooltip(TTR("Add a Texture from File")); hbc->add_child(load); - load_sheet = memnew(ToolButton); + load_sheet = memnew(Button); + load_sheet->set_flat(true); load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet")); hbc->add_child(load_sheet); hbc->add_child(memnew(VSeparator)); - copy = memnew(ToolButton); + copy = memnew(Button); + copy->set_flat(true); copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); - paste = memnew(ToolButton); + paste = memnew(Button); + paste->set_flat(true); paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); hbc->add_child(memnew(VSeparator)); - empty = memnew(ToolButton); + empty = memnew(Button); + empty->set_flat(true); empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); - empty2 = memnew(ToolButton); + empty2 = memnew(Button); + empty2->set_flat(true); empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); hbc->add_child(memnew(VSeparator)); - move_up = memnew(ToolButton); + move_up = memnew(Button); + move_up->set_flat(true); move_up->set_tooltip(TTR("Move (Before)")); hbc->add_child(move_up); - move_down = memnew(ToolButton); + move_down = memnew(Button); + move_down->set_flat(true); move_down->set_tooltip(TTR("Move (After)")); hbc->add_child(move_down); - _delete = memnew(ToolButton); + _delete = memnew(Button); + _delete->set_flat(true); _delete->set_tooltip(TTR("Delete")); hbc->add_child(_delete); + hbc->add_spacer(); + + zoom_out = memnew(Button); + zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_out)); + zoom_out->set_flat(true); + zoom_out->set_tooltip(TTR("Zoom Out")); + hbc->add_child(zoom_out); + zoom_1 = memnew(Button); + zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset)); + zoom_1->set_flat(true); + zoom_1->set_tooltip(TTR("Zoom Reset")); + hbc->add_child(zoom_1); + zoom_in = memnew(Button); + zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in)); + zoom_in->set_flat(true); + zoom_in->set_tooltip(TTR("Zoom In")); + hbc->add_child(zoom_in); + file = memnew(EditorFileDialog); add_child(file); @@ -991,29 +1098,27 @@ SpriteFramesEditor::SpriteFramesEditor() { tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->set_icon_mode(ItemList::ICON_MODE_TOP); - int thumbnail_size = 96; tree->set_max_columns(0); tree->set_icon_mode(ItemList::ICON_MODE_TOP); - 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_drag_forwarding(this); + tree->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_tree_input)); sub_vb->add_child(tree); dialog = memnew(AcceptDialog); add_child(dialog); - load->connect("pressed", this, "_load_pressed"); - load_sheet->connect("pressed", this, "_open_sprite_sheet"); - _delete->connect("pressed", this, "_delete_pressed"); - copy->connect("pressed", this, "_copy_pressed"); - paste->connect("pressed", this, "_paste_pressed"); - empty->connect("pressed", this, "_empty_pressed"); - empty2->connect("pressed", this, "_empty2_pressed"); - move_up->connect("pressed", this, "_up_pressed"); - move_down->connect("pressed", this, "_down_pressed"); - file->connect("files_selected", this, "_file_load_request"); + load->connect("pressed", callable_mp(this, &SpriteFramesEditor::_load_pressed)); + load_sheet->connect("pressed", callable_mp(this, &SpriteFramesEditor::_open_sprite_sheet)); + _delete->connect("pressed", callable_mp(this, &SpriteFramesEditor::_delete_pressed)); + copy->connect("pressed", callable_mp(this, &SpriteFramesEditor::_copy_pressed)); + paste->connect("pressed", callable_mp(this, &SpriteFramesEditor::_paste_pressed)); + empty->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty_pressed)); + empty2->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty2_pressed)); + move_up->connect("pressed", callable_mp(this, &SpriteFramesEditor::_up_pressed)); + move_down->connect("pressed", callable_mp(this, &SpriteFramesEditor::_down_pressed)); + file->connect("files_selected", callable_mp(this, &SpriteFramesEditor::_file_load_request), make_binds(-1)); loading_scene = false; sel = -1; @@ -1023,14 +1128,14 @@ SpriteFramesEditor::SpriteFramesEditor() { delete_dialog = memnew(ConfirmationDialog); add_child(delete_dialog); - delete_dialog->connect("confirmed", this, "_animation_remove_confirmed"); + delete_dialog->connect("confirmed", callable_mp(this, &SpriteFramesEditor::_animation_remove_confirmed)); split_sheet_dialog = memnew(ConfirmationDialog); add_child(split_sheet_dialog); VBoxContainer *split_sheet_vb = memnew(VBoxContainer); split_sheet_dialog->add_child(split_sheet_vb); split_sheet_dialog->set_title(TTR("Select Frames")); - split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames"); + split_sheet_dialog->connect("confirmed", callable_mp(this, &SpriteFramesEditor::_sheet_add_frames)); HBoxContainer *split_sheet_hb = memnew(HBoxContainer); @@ -1041,7 +1146,7 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_h->set_max(128); split_sheet_h->set_step(1); split_sheet_hb->add_child(split_sheet_h); - split_sheet_h->connect("value_changed", this, "_sheet_spin_changed"); + split_sheet_h->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed)); ss_label = memnew(Label(TTR("Vertical:"))); split_sheet_hb->add_child(ss_label); @@ -1050,82 +1155,129 @@ SpriteFramesEditor::SpriteFramesEditor() { split_sheet_v->set_max(128); split_sheet_v->set_step(1); split_sheet_hb->add_child(split_sheet_v); - split_sheet_v->connect("value_changed", this, "_sheet_spin_changed"); + split_sheet_v->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_sheet_spin_changed)); split_sheet_hb->add_spacer(); Button *select_clear_all = memnew(Button); select_clear_all->set_text(TTR("Select/Clear All Frames")); - select_clear_all->connect("pressed", this, "_sheet_select_clear_all_frames"); + select_clear_all->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_select_clear_all_frames)); split_sheet_hb->add_child(select_clear_all); split_sheet_vb->add_child(split_sheet_hb); + PanelContainer *split_sheet_panel = memnew(PanelContainer); + split_sheet_panel->set_h_size_flags(SIZE_EXPAND_FILL); + split_sheet_panel->set_v_size_flags(SIZE_EXPAND_FILL); + split_sheet_vb->add_child(split_sheet_panel); + split_sheet_preview = memnew(TextureRect); - split_sheet_preview->set_expand(false); + split_sheet_preview->set_expand(true); split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS); - split_sheet_preview->connect("draw", this, "_sheet_preview_draw"); - split_sheet_preview->connect("gui_input", this, "_sheet_preview_input"); + split_sheet_preview->connect("draw", callable_mp(this, &SpriteFramesEditor::_sheet_preview_draw)); + split_sheet_preview->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_preview_input)); splite_sheet_scroll = memnew(ScrollContainer); splite_sheet_scroll->set_enable_h_scroll(true); splite_sheet_scroll->set_enable_v_scroll(true); - splite_sheet_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + splite_sheet_scroll->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_sheet_scroll_input)); + split_sheet_panel->add_child(splite_sheet_scroll); CenterContainer *cc = memnew(CenterContainer); cc->add_child(split_sheet_preview); cc->set_h_size_flags(SIZE_EXPAND_FILL); cc->set_v_size_flags(SIZE_EXPAND_FILL); splite_sheet_scroll->add_child(cc); - split_sheet_vb->add_child(splite_sheet_scroll); + MarginContainer *split_sheet_zoom_margin = memnew(MarginContainer); + split_sheet_panel->add_child(split_sheet_zoom_margin); + split_sheet_zoom_margin->set_h_size_flags(0); + split_sheet_zoom_margin->set_v_size_flags(0); + split_sheet_zoom_margin->add_theme_constant_override("margin_top", 5); + split_sheet_zoom_margin->add_theme_constant_override("margin_left", 5); + HBoxContainer *split_sheet_zoom_hb = memnew(HBoxContainer); + split_sheet_zoom_margin->add_child(split_sheet_zoom_hb); + + split_sheet_zoom_out = memnew(Button); + split_sheet_zoom_out->set_flat(true); + split_sheet_zoom_out->set_focus_mode(FOCUS_NONE); + split_sheet_zoom_out->set_tooltip(TTR("Zoom Out")); + split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out)); + split_sheet_zoom_hb->add_child(split_sheet_zoom_out); + split_sheet_zoom_1 = memnew(Button); + split_sheet_zoom_1->set_flat(true); + split_sheet_zoom_1->set_focus_mode(FOCUS_NONE); + split_sheet_zoom_1->set_tooltip(TTR("Zoom Reset")); + split_sheet_zoom_1->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset)); + split_sheet_zoom_hb->add_child(split_sheet_zoom_1); + split_sheet_zoom_in = memnew(Button); + split_sheet_zoom_in->set_flat(true); + split_sheet_zoom_in->set_focus_mode(FOCUS_NONE); + split_sheet_zoom_in->set_tooltip(TTR("Zoom In")); + split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in)); + split_sheet_zoom_hb->add_child(split_sheet_zoom_in); file_split_sheet = memnew(EditorFileDialog); file_split_sheet->set_title(TTR("Create Frames from Sprite Sheet")); - file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_split_sheet->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); add_child(file_split_sheet); - file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet"); + file_split_sheet->connect("file_selected", callable_mp(this, &SpriteFramesEditor::_prepare_sprite_sheet)); + + // Config scale. + scale_ratio = 1.2f; + thumbnail_default_size = 96; + thumbnail_zoom = 1.0f; + max_thumbnail_zoom = 8.0f; + min_thumbnail_zoom = 0.1f; + sheet_zoom = 1.0f; + max_sheet_zoom = 16.0f; + min_sheet_zoom = 0.01f; + _zoom_reset(); } void SpriteFramesEditorPlugin::edit(Object *p_object) { - frames_editor->set_undo_redo(&get_undo_redo()); SpriteFrames *s; - AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object); + AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object); if (animated_sprite) { s = *animated_sprite->get_sprite_frames(); } else { - s = Object::cast_to<SpriteFrames>(p_object); + AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object); + if (animated_sprite_3d) { + s = *animated_sprite_3d->get_sprite_frames(); + } else { + s = Object::cast_to<SpriteFrames>(p_object); + } } frames_editor->edit(s); } bool SpriteFramesEditorPlugin::handles(Object *p_object) const { - - AnimatedSprite *animated_sprite = Object::cast_to<AnimatedSprite>(p_object); + AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object); + AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object); if (animated_sprite && *animated_sprite->get_sprite_frames()) { return true; + } else if (animated_sprite_3d && *animated_sprite_3d->get_sprite_frames()) { + return true; } else { return p_object->is_class("SpriteFrames"); } } void SpriteFramesEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { button->show(); editor->make_bottom_panel_item_visible(frames_editor); } else { - button->hide(); - if (frames_editor->is_visible_in_tree()) + if (frames_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } } } SpriteFramesEditorPlugin::SpriteFramesEditorPlugin(EditorNode *p_node) { - editor = p_node; frames_editor = memnew(SpriteFramesEditor); frames_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index aa683605ed..0dce93f55a 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -33,33 +33,36 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/2d/animated_sprite.h" +#include "scene/2d/animated_sprite_2d.h" #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/scroll_container.h" #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" class SpriteFramesEditor : public HSplitContainer { - GDCLASS(SpriteFramesEditor, HSplitContainer); - ToolButton *load; - ToolButton *load_sheet; - ToolButton *_delete; - ToolButton *copy; - ToolButton *paste; - ToolButton *empty; - ToolButton *empty2; - ToolButton *move_up; - ToolButton *move_down; + Button *load; + Button *load_sheet; + Button *_delete; + Button *copy; + Button *paste; + Button *empty; + Button *empty2; + Button *move_up; + Button *move_down; + Button *zoom_out; + Button *zoom_1; + Button *zoom_in; ItemList *tree; bool loading_scene; int sel; HSplitContainer *split; - ToolButton *new_anim; - ToolButton *remove_anim; + Button *new_anim; + Button *remove_anim; Tree *animations; SpinBox *anim_speed; @@ -80,13 +83,25 @@ class SpriteFramesEditor : public HSplitContainer { TextureRect *split_sheet_preview; SpinBox *split_sheet_h; SpinBox *split_sheet_v; + Button *split_sheet_zoom_out; + Button *split_sheet_zoom_1; + Button *split_sheet_zoom_in; EditorFileDialog *file_split_sheet; Set<int> frames_selected; int last_frame_selected; + float scale_ratio; + int thumbnail_default_size; + float thumbnail_zoom; + float max_thumbnail_zoom; + float min_thumbnail_zoom; + float sheet_zoom; + float max_sheet_zoom; + float min_sheet_zoom; + void _load_pressed(); void _load_scene_pressed(); - void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1); + void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1); void _copy_pressed(); void _paste_pressed(); void _empty_pressed(); @@ -104,6 +119,11 @@ class SpriteFramesEditor : public HSplitContainer { void _animation_loop_changed(); void _animation_fps_changed(double p_value); + void _tree_input(const Ref<InputEvent> &p_event); + void _zoom_in(); + void _zoom_out(); + void _zoom_reset(); + bool updating; UndoRedo *undo_redo; @@ -118,7 +138,11 @@ class SpriteFramesEditor : public HSplitContainer { void _sheet_preview_draw(); void _sheet_spin_changed(double); void _sheet_preview_input(const Ref<InputEvent> &p_event); + void _sheet_scroll_input(const Ref<InputEvent> &p_event); void _sheet_add_frames(); + void _sheet_zoom_in(); + void _sheet_zoom_out(); + void _sheet_zoom_reset(); void _sheet_select_clear_all_frames(); protected: @@ -134,7 +158,6 @@ public: }; class SpriteFramesEditorPlugin : public EditorPlugin { - GDCLASS(SpriteFramesEditorPlugin, EditorPlugin); SpriteFramesEditor *frames_editor; @@ -142,11 +165,11 @@ class SpriteFramesEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "SpriteFrames"; } - 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); + virtual String get_name() const override { return "SpriteFrames"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; SpriteFramesEditorPlugin(EditorNode *p_node); ~SpriteFramesEditorPlugin(); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index eebcd567a4..3641052a4e 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -33,38 +33,37 @@ #include "editor/editor_scale.h" bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { - - return Object::cast_to<StyleBox>(p_object) != NULL; + return Object::cast_to<StyleBox>(p_object) != nullptr; } void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) { - Ref<StyleBox> sb = Ref<StyleBox>(Object::cast_to<StyleBox>(p_object)); StyleBoxPreview *preview = memnew(StyleBoxPreview); preview->edit(sb); add_custom_control(preview); } -bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + +bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { return false; //do not want } + void EditorInspectorPluginStyleBox::parse_end() { } void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { - - if (stylebox.is_valid()) - stylebox->disconnect("changed", this, "_sb_changed"); + if (stylebox.is_valid()) { + stylebox->disconnect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed)); + } stylebox = p_stylebox; if (p_stylebox.is_valid()) { - preview->add_style_override("panel", stylebox); - stylebox->connect("changed", this, "_sb_changed"); + preview->add_theme_style_override("panel", stylebox); + stylebox->connect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed)); } _sb_changed(); } void StyleBoxPreview::_sb_changed() { - preview->update(); } @@ -82,21 +81,17 @@ void StyleBoxPreview::_redraw() { } void StyleBoxPreview::_bind_methods() { - - ClassDB::bind_method("_sb_changed", &StyleBoxPreview::_sb_changed); - ClassDB::bind_method("_redraw", &StyleBoxPreview::_redraw); } StyleBoxPreview::StyleBoxPreview() { preview = memnew(Control); preview->set_custom_minimum_size(Size2(0, 150 * EDSCALE)); preview->set_clip_contents(true); - preview->connect("draw", this, "_redraw"); + preview->connect("draw", callable_mp(this, &StyleBoxPreview::_redraw)); add_margin_child(TTR("Preview:"), preview); } StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) { - Ref<EditorInspectorPluginStyleBox> inspector_plugin; inspector_plugin.instance(); add_inspector_plugin(inspector_plugin); diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index f4a72d9d1c..41daa662db 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -38,7 +38,6 @@ #include "scene/resources/style_box.h" class StyleBoxPreview : public VBoxContainer { - GDCLASS(StyleBoxPreview, VBoxContainer); Control *preview; @@ -60,18 +59,17 @@ class EditorInspectorPluginStyleBox : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginStyleBox, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); - virtual void parse_end(); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual void parse_end() override; }; class StyleBoxEditorPlugin : public EditorPlugin { - GDCLASS(StyleBoxEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "StyleBox"; } + virtual String get_name() const override { return "StyleBox"; } StyleBoxEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 57447abf47..8935b698b6 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -33,46 +33,34 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" -void TextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) { - highlighters[p_highlighter->get_name()] = p_highlighter; - highlighter_menu->add_radio_check_item(p_highlighter->get_name()); +void TextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + + highlighters[p_highlighter->_get_name()] = p_highlighter; + highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } -void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) { - TextEdit *te = code_editor->get_text_edit(); - te->_set_syntax_highlighting(p_highlighter); - if (p_highlighter != NULL) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true); - } else { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text("Standard"), true); - } +void TextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); - // little work around. GDScript highlighter goes through text_edit for colours, - // so to remove all colours we need to set and unset them here. - if (p_highlighter == NULL) { // standard - TextEdit *text_edit = code_editor->get_text_edit(); - text_edit->add_color_override("number_color", colors_cache.font_color); - text_edit->add_color_override("function_color", colors_cache.font_color); - text_edit->add_color_override("number_color", colors_cache.font_color); - text_edit->add_color_override("member_variable_color", colors_cache.font_color); - } else { - _load_theme_settings(); + Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); + while (el != nullptr) { + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); + el = el->next(); } + + CodeEdit *te = code_editor->get_text_editor(); + te->set_syntax_highlighter(p_highlighter); } void TextEditor::_change_syntax_highlighter(int p_idx) { - Map<String, SyntaxHighlighter *>::Element *el = highlighters.front(); - while (el != NULL) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); - el = el->next(); - } set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } void TextEditor::_load_theme_settings() { - - TextEdit *text_edit = code_editor->get_text_edit(); - text_edit->clear_colors(); + CodeEdit *text_edit = code_editor->get_text_editor(); + text_edit->get_syntax_highlighter()->update_cache(); Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color"); @@ -90,9 +78,6 @@ void TextEditor::_load_theme_settings() { Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color"); Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color"); Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color"); - Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); - Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); - Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color bookmark_color = EDITOR_GET("text_editor/highlighting/bookmark_color"); Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); @@ -100,50 +85,32 @@ void TextEditor::_load_theme_settings() { Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); - Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); - Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); - Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); - Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); - Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); - - text_edit->add_color_override("background_color", background_color); - text_edit->add_color_override("completion_background_color", completion_background_color); - text_edit->add_color_override("completion_selected_color", completion_selected_color); - text_edit->add_color_override("completion_existing_color", completion_existing_color); - text_edit->add_color_override("completion_scroll_color", completion_scroll_color); - text_edit->add_color_override("completion_font_color", completion_font_color); - text_edit->add_color_override("font_color", text_color); - text_edit->add_color_override("line_number_color", line_number_color); - text_edit->add_color_override("caret_color", caret_color); - text_edit->add_color_override("caret_background_color", caret_background_color); - text_edit->add_color_override("font_color_selected", text_selected_color); - text_edit->add_color_override("selection_color", selection_color); - text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); - text_edit->add_color_override("current_line_color", current_line_color); - text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color); - text_edit->add_color_override("word_highlighted_color", word_highlighted_color); - text_edit->add_color_override("number_color", number_color); - text_edit->add_color_override("function_color", function_color); - text_edit->add_color_override("member_variable_color", member_variable_color); - text_edit->add_color_override("breakpoint_color", breakpoint_color); - text_edit->add_color_override("executing_line_color", executing_line_color); - text_edit->add_color_override("mark_color", mark_color); - text_edit->add_color_override("bookmark_color", bookmark_color); - text_edit->add_color_override("code_folding_color", code_folding_color); - text_edit->add_color_override("search_result_color", search_result_color); - text_edit->add_color_override("search_result_border_color", search_result_border_color); - text_edit->add_color_override("symbol_color", symbol_color); - - text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6)); - - colors_cache.font_color = text_color; - colors_cache.symbol_color = symbol_color; - colors_cache.keyword_color = keyword_color; - colors_cache.basetype_color = basetype_color; - colors_cache.type_color = type_color; - colors_cache.comment_color = comment_color; - colors_cache.string_color = string_color; + + text_edit->add_theme_color_override("background_color", background_color); + text_edit->add_theme_color_override("completion_background_color", completion_background_color); + text_edit->add_theme_color_override("completion_selected_color", completion_selected_color); + text_edit->add_theme_color_override("completion_existing_color", completion_existing_color); + text_edit->add_theme_color_override("completion_scroll_color", completion_scroll_color); + text_edit->add_theme_color_override("completion_font_color", completion_font_color); + text_edit->add_theme_color_override("font_color", text_color); + text_edit->add_theme_color_override("line_number_color", line_number_color); + text_edit->add_theme_color_override("caret_color", caret_color); + text_edit->add_theme_color_override("caret_background_color", caret_background_color); + text_edit->add_theme_color_override("font_color_selected", text_selected_color); + text_edit->add_theme_color_override("selection_color", selection_color); + text_edit->add_theme_color_override("brace_mismatch_color", brace_mismatch_color); + text_edit->add_theme_color_override("current_line_color", current_line_color); + text_edit->add_theme_color_override("line_length_guideline_color", line_length_guideline_color); + text_edit->add_theme_color_override("word_highlighted_color", word_highlighted_color); + text_edit->add_theme_color_override("breakpoint_color", breakpoint_color); + text_edit->add_theme_color_override("executing_line_color", executing_line_color); + text_edit->add_theme_color_override("mark_color", mark_color); + text_edit->add_theme_color_override("bookmark_color", bookmark_color); + text_edit->add_theme_color_override("code_folding_color", code_folding_color); + text_edit->add_theme_color_override("search_result_color", search_result_color); + text_edit->add_theme_color_override("search_result_border_color", search_result_border_color); + + text_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6)); } String TextEditor::get_name() { @@ -152,6 +119,9 @@ String TextEditor::get_name() { if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { name = text_file->get_path().get_file(); if (is_unsaved()) { + if (text_file->get_path().empty()) { + name = TTR("[unsaved]"); + } name += "(*)"; } } else if (text_file->get_name() != "") { @@ -163,9 +133,8 @@ String TextEditor::get_name() { return name; } -Ref<Texture> TextEditor::get_icon() { - - return EditorNode::get_singleton()->get_object_icon(text_file.operator->(), ""); +Ref<Texture2D> TextEditor::get_theme_icon() { + return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), ""); } RES TextEditor::get_edited_resource() const { @@ -173,32 +142,43 @@ RES TextEditor::get_edited_resource() const { } void TextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!text_file.is_null()); + ERR_FAIL_COND(text_file.is_valid()); + ERR_FAIL_COND(p_res.is_null()); text_file = p_res; - code_editor->get_text_edit()->set_text(text_file->get_text()); - code_editor->get_text_edit()->clear_undo_history(); - code_editor->get_text_edit()->tag_saved_version(); + code_editor->get_text_editor()->set_text(text_file->get_text()); + code_editor->get_text_editor()->clear_undo_history(); + code_editor->get_text_editor()->tag_saved_version(); emit_signal("name_changed"); code_editor->update_line_and_column(); } -void TextEditor::add_callback(const String &p_function, PoolStringArray p_args) { +void TextEditor::enable_editor() { + if (editor_enabled) { + return; + } + + editor_enabled = true; + + _load_theme_settings(); +} + +void TextEditor::add_callback(const String &p_function, PackedStringArray p_args) { } void TextEditor::set_debugger_active(bool p_active) { } -void TextEditor::get_breakpoints(List<int> *p_breakpoints) { +Array TextEditor::get_breakpoints() { + return Array(); } void TextEditor::reload_text() { - ERR_FAIL_COND(text_file.is_null()); - TextEdit *te = code_editor->get_text_edit(); + CodeEdit *te = code_editor->get_text_editor(); int column = te->cursor_get_column(); int row = te->cursor_get_line(); int h = te->get_h_scroll(); @@ -221,7 +201,6 @@ void TextEditor::_validate_script() { } void TextEditor::_update_bookmark_list() { - bookmarks_menu->clear(); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); @@ -229,7 +208,7 @@ void TextEditor::_update_bookmark_list() { bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); - Array bookmark_list = code_editor->get_text_edit()->get_bookmarks_array(); + Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines(); if (bookmark_list.size() == 0) { return; } @@ -237,7 +216,7 @@ void TextEditor::_update_bookmark_list() { bookmarks_menu->add_separator(); for (int i = 0; i < bookmark_list.size(); i++) { - String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); + String line = code_editor->get_text_editor()->get_line(bookmark_list[i]).strip_edges(); // Limit the size of the line if too big. if (line.length() > 50) { line = line.substr(0, 50); @@ -249,7 +228,6 @@ void TextEditor::_update_bookmark_list() { } void TextEditor::_bookmark_item_pressed(int p_idx) { - if (p_idx < 4) { // Any item before the separator. _edit_option(bookmarks_menu->get_item_id(p_idx)); } else { @@ -258,21 +236,21 @@ void TextEditor::_bookmark_item_pressed(int p_idx) { } void TextEditor::apply_code() { - text_file->set_text(code_editor->get_text_edit()->get_text()); + text_file->set_text(code_editor->get_text_editor()->get_text()); } bool TextEditor::is_unsaved() { - - return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); + const bool unsaved = + code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() || + text_file->get_path().empty(); // In memory. + return unsaved; } Variant TextEditor::get_edit_state() { - return code_editor->get_edit_state(); } void TextEditor::set_edit_state(const Variant &p_state) { - code_editor->set_edit_state(p_state); Dictionary state = p_state; @@ -282,45 +260,39 @@ void TextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + ensure_focus(); } void TextEditor::trim_trailing_whitespace() { - code_editor->trim_trailing_whitespace(); } void TextEditor::insert_final_newline() { - code_editor->insert_final_newline(); } void TextEditor::convert_indent_to_spaces() { - code_editor->convert_indent_to_spaces(); } void TextEditor::convert_indent_to_tabs() { - code_editor->convert_indent_to_tabs(); } void TextEditor::tag_saved_version() { - - code_editor->get_text_edit()->tag_saved_version(); + code_editor->get_text_editor()->tag_saved_version(); } void TextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->goto_line(p_line); } void TextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - code_editor->goto_line_selection(p_line, p_begin, p_end); } void TextEditor::set_executing_line(int p_line) { - code_editor->set_executing_line(p_line); } @@ -329,12 +301,10 @@ void TextEditor::clear_executing_line() { } void TextEditor::ensure_focus() { - - code_editor->get_text_edit()->grab_focus(); + code_editor->get_text_editor()->grab_focus(); } Vector<String> TextEditor::get_functions() { - return Vector<String>(); } @@ -343,17 +313,14 @@ bool TextEditor::show_members_overview() { } void TextEditor::update_settings() { - code_editor->update_editor_settings(); } void TextEditor::set_tooltip_request_func(String p_method, Object *p_obj) { - - code_editor->get_text_edit()->set_tooltip_request_func(p_obj, p_method, this); + code_editor->get_text_editor()->set_tooltip_request_func(p_obj, p_method, this); } Control *TextEditor::get_edit_menu() { - return edit_hb; } @@ -361,197 +328,150 @@ void TextEditor::clear_edit_menu() { memdelete(edit_hb); } -void TextEditor::_notification(int p_what) { - - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - void TextEditor::_edit_option(int p_op) { - TextEdit *tx = code_editor->get_text_edit(); + CodeEdit *tx = code_editor->get_text_editor(); switch (p_op) { case EDIT_UNDO: { - tx->undo(); tx->call_deferred("grab_focus"); } break; case EDIT_REDO: { - tx->redo(); tx->call_deferred("grab_focus"); } break; case EDIT_CUT: { - tx->cut(); tx->call_deferred("grab_focus"); } break; case EDIT_COPY: { - tx->copy(); tx->call_deferred("grab_focus"); } break; case EDIT_PASTE: { - tx->paste(); tx->call_deferred("grab_focus"); } break; case EDIT_SELECT_ALL: { - tx->select_all(); tx->call_deferred("grab_focus"); } break; case EDIT_MOVE_LINE_UP: { - code_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - code_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - tx->indent_left(); } break; case EDIT_INDENT_RIGHT: { - tx->indent_right(); } break; case EDIT_DELETE_LINE: { - code_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - code_editor->clone_lines_down(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { - tx->fold_all_lines(); tx->update(); } break; case EDIT_UNFOLD_ALL_LINES: { - tx->unhide_all_lines(); tx->update(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { - trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { - convert_indent_to_spaces(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { - convert_indent_to_tabs(); } break; case EDIT_TO_UPPERCASE: { - _convert_case(CodeTextEditor::UPPER); } break; case EDIT_TO_LOWERCASE: { - _convert_case(CodeTextEditor::LOWER); } break; case EDIT_CAPITALIZE: { - _convert_case(CodeTextEditor::CAPITALIZE); } break; case SEARCH_FIND: { - code_editor->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - code_editor->get_find_replace_bar()->search_next(); } break; case SEARCH_FIND_PREV: { - code_editor->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - code_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_IN_FILES: { - - String selected_text = code_editor->get_text_edit()->get_selection_text(); + String selected_text = code_editor->get_text_editor()->get_selection_text(); // Yep, because it doesn't make sense to instance this dialog for every single script open... // So this will be delegated to the ScriptEditor. emit_signal("search_in_files_requested", selected_text); } break; - case SEARCH_GOTO_LINE: { + case REPLACE_IN_FILES: { + String selected_text = code_editor->get_text_editor()->get_selection_text(); + emit_signal("replace_in_files_requested", selected_text); + } break; + case SEARCH_GOTO_LINE: { goto_line_dialog->popup_find_line(tx); } break; case BOOKMARK_TOGGLE: { - code_editor->toggle_bookmark(); } break; case BOOKMARK_GOTO_NEXT: { - code_editor->goto_next_bookmark(); } break; case BOOKMARK_GOTO_PREV: { - code_editor->goto_prev_bookmark(); } break; case BOOKMARK_REMOVE_ALL: { - code_editor->remove_all_bookmarks(); } break; } } void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { - code_editor->convert_case(p_case); } void TextEditor::_bind_methods() { - - ClassDB::bind_method("_validate_script", &TextEditor::_validate_script); - ClassDB::bind_method("_update_bookmark_list", &TextEditor::_update_bookmark_list); - ClassDB::bind_method("_bookmark_item_pressed", &TextEditor::_bookmark_item_pressed); - ClassDB::bind_method("_load_theme_settings", &TextEditor::_load_theme_settings); - ClassDB::bind_method("_edit_option", &TextEditor::_edit_option); - ClassDB::bind_method("_change_syntax_highlighter", &TextEditor::_change_syntax_highlighter); - ClassDB::bind_method("_text_edit_gui_input", &TextEditor::_text_edit_gui_input); + ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &TextEditor::add_syntax_highlighter); } static ScriptEditorBase *create_editor(const RES &p_resource) { - if (Object::cast_to<TextFile>(*p_resource)) { return memnew(TextEditor); } - return NULL; + return nullptr; } void TextEditor::register_editor() { - ScriptEditor::register_create_script_editor_function(create_editor); } void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { - Ref<InputEventMouseButton> mb = ev; if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_RIGHT) { - int col, row; - TextEdit *tx = code_editor->get_text_edit(); + CodeEdit *tx = code_editor->get_text_editor(); tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); @@ -560,7 +480,6 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (tx->is_right_click_moving_caret()) { if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); int to_line = tx->get_selection_to_line(); int from_column = tx->get_selection_from_column(); @@ -584,8 +503,8 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } Ref<InputEventKey> k = ev; - if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_MENU) { - TextEdit *tx = code_editor->get_text_edit(); + if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_MENU) { + CodeEdit *tx = code_editor->get_text_editor(); int line = tx->cursor_get_line(); _make_context_menu(tx->is_selection_active(), tx->can_fold(line), tx->is_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos())); context_menu->grab_focus(); @@ -593,7 +512,6 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position) { - context_menu->clear(); if (p_selection) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); @@ -615,8 +533,9 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); } - if (p_can_fold || p_is_folded) + if (p_can_fold || p_is_folded) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + } context_menu->set_position(get_global_transform().xform(p_position)); context_menu->set_size(Vector2(1, 1)); @@ -626,20 +545,20 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is TextEditor::TextEditor() { code_editor = memnew(CodeTextEditor); add_child(code_editor); - code_editor->add_constant_override("separation", 0); - code_editor->connect("load_theme_settings", this, "_load_theme_settings"); - code_editor->connect("validate_script", this, "_validate_script"); + code_editor->add_theme_constant_override("separation", 0); + code_editor->connect("load_theme_settings", callable_mp(this, &TextEditor::_load_theme_settings)); + code_editor->connect("validate_script", callable_mp(this, &TextEditor::_validate_script)); code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); update_settings(); - code_editor->get_text_edit()->set_context_menu_enabled(false); - code_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + code_editor->get_text_editor()->set_context_menu_enabled(false); + code_editor->get_text_editor()->connect("gui_input", callable_mp(this, &TextEditor::_text_edit_gui_input)); context_menu = memnew(PopupMenu); add_child(context_menu); - context_menu->connect("id_pressed", this, "_edit_option"); + context_menu->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); edit_hb = memnew(HBoxContainer); @@ -647,7 +566,7 @@ TextEditor::TextEditor() { edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); search_menu->set_switch_on_hover(true); - search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + search_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); @@ -655,12 +574,13 @@ TextEditor::TextEditor() { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); search_menu->get_popup()->add_separator(); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); edit_menu = memnew(MenuButton); edit_hb->add_child(edit_menu); edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); - edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); @@ -693,21 +613,28 @@ TextEditor::TextEditor() { convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE); - convert_case->connect("id_pressed", this, "_edit_option"); + convert_case->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); - highlighters["Standard"] = NULL; highlighter_menu = memnew(PopupMenu); highlighter_menu->set_name("highlighter_menu"); edit_menu->get_popup()->add_child(highlighter_menu); edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); - highlighter_menu->add_radio_check_item(TTR("Standard")); - highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); + highlighter_menu->connect("id_pressed", callable_mp(this, &TextEditor::_change_syntax_highlighter)); + + Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; + plain_highlighter.instance(); + add_syntax_highlighter(plain_highlighter); + + Ref<EditorStandardSyntaxHighlighter> highlighter; + highlighter.instance(); + add_syntax_highlighter(highlighter); + set_syntax_highlighter(plain_highlighter); MenuButton *goto_menu = memnew(MenuButton); edit_hb->add_child(goto_menu); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); goto_menu->get_popup()->add_separator(); @@ -717,21 +644,16 @@ TextEditor::TextEditor() { goto_menu->get_popup()->add_child(bookmarks_menu); goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); _update_bookmark_list(); - bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); - bookmarks_menu->connect("index_pressed", this, "_bookmark_item_pressed"); + bookmarks_menu->connect("about_to_popup", callable_mp(this, &TextEditor::_update_bookmark_list)); + bookmarks_menu->connect("index_pressed", callable_mp(this, &TextEditor::_bookmark_item_pressed)); goto_line_dialog = memnew(GotoLineDialog); add_child(goto_line_dialog); - code_editor->get_text_edit()->set_drag_forwarding(this); + code_editor->get_text_editor()->set_drag_forwarding(this); } TextEditor::~TextEditor() { - for (const Map<String, SyntaxHighlighter *>::Element *E = highlighters.front(); E; E = E->next()) { - if (E->get() != NULL) { - memdelete(E->get()); - } - } highlighters.clear(); } diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index fe157a29e6..ea425bd033 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -34,32 +34,22 @@ #include "script_editor_plugin.h" class TextEditor : public ScriptEditorBase { - GDCLASS(TextEditor, ScriptEditorBase); private: - CodeTextEditor *code_editor; + CodeTextEditor *code_editor = nullptr; Ref<TextFile> text_file; + bool editor_enabled = false; + + HBoxContainer *edit_hb = nullptr; + MenuButton *edit_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + MenuButton *search_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *context_menu = nullptr; - HBoxContainer *edit_hb; - MenuButton *edit_menu; - PopupMenu *highlighter_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *context_menu; - - GotoLineDialog *goto_line_dialog; - - struct ColorsCache { - Color font_color; - Color symbol_color; - Color keyword_color; - Color basetype_color; - Color type_color; - Color comment_color; - Color string_color; - } colors_cache; + GotoLineDialog *goto_line_dialog = nullptr; enum { EDIT_UNDO, @@ -88,6 +78,7 @@ private: SEARCH_FIND_PREV, SEARCH_REPLACE, SEARCH_IN_FILES, + REPLACE_IN_FILES, SEARCH_GOTO_LINE, BOOKMARK_TOGGLE, BOOKMARK_GOTO_NEXT, @@ -98,13 +89,11 @@ private: protected: static void _bind_methods(); - void _notification(int p_what); - void _edit_option(int p_op); void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position); void _text_edit_gui_input(const Ref<InputEvent> &ev); - Map<String, SyntaxHighlighter *> highlighters; + Map<String, Ref<EditorSyntaxHighlighter>> highlighters; void _change_syntax_highlighter(int p_idx); void _load_theme_settings(); @@ -116,42 +105,42 @@ protected: void _bookmark_item_pressed(int p_idx); public: - virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); - virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); - - virtual String get_name(); - virtual Ref<Texture> get_icon(); - virtual RES get_edited_resource() const; - virtual void set_edited_resource(const RES &p_res); - void set_edited_file(const Ref<TextFile> &p_file); - virtual void reload_text(); - virtual void apply_code(); - virtual bool is_unsaved(); - virtual Variant get_edit_state(); - virtual void set_edit_state(const Variant &p_state); - virtual Vector<String> get_functions(); - virtual void get_breakpoints(List<int> *p_breakpoints); - virtual void goto_line(int p_line, bool p_with_error = false); + virtual void add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; + virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override; + + virtual String get_name() override; + virtual Ref<Texture2D> get_theme_icon() override; + virtual RES get_edited_resource() const override; + virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; + virtual void reload_text() override; + virtual void apply_code() override; + virtual bool is_unsaved() override; + virtual Variant get_edit_state() override; + virtual void set_edit_state(const Variant &p_state) override; + virtual Vector<String> get_functions() override; + virtual Array get_breakpoints() override; + virtual void goto_line(int p_line, bool p_with_error = false) override; void goto_line_selection(int p_line, int p_begin, int p_end); - virtual void set_executing_line(int p_line); - virtual void clear_executing_line(); - virtual void trim_trailing_whitespace(); - virtual void insert_final_newline(); - virtual void convert_indent_to_spaces(); - virtual void convert_indent_to_tabs(); - virtual void ensure_focus(); - virtual void tag_saved_version(); - virtual void update_settings(); - virtual bool show_members_overview(); - virtual bool can_lose_focus_on_node_selection() { return true; } - virtual void set_debugger_active(bool p_active); - virtual void set_tooltip_request_func(String p_method, Object *p_obj); - virtual void add_callback(const String &p_function, PoolStringArray p_args); - - virtual Control *get_edit_menu(); - virtual void clear_edit_menu(); - - virtual void validate(); + virtual void set_executing_line(int p_line) override; + virtual void clear_executing_line() override; + virtual void trim_trailing_whitespace() override; + virtual void insert_final_newline() override; + virtual void convert_indent_to_spaces() override; + virtual void convert_indent_to_tabs() override; + virtual void ensure_focus() override; + virtual void tag_saved_version() override; + virtual void update_settings() override; + virtual bool show_members_overview() override; + virtual bool can_lose_focus_on_node_selection() override { return true; } + virtual void set_debugger_active(bool p_active) override; + virtual void set_tooltip_request_func(String p_method, Object *p_obj) override; + virtual void add_callback(const String &p_function, PackedStringArray p_args) override; + + virtual Control *get_edit_menu() override; + virtual void clear_edit_menu() override; + + virtual void validate() override; static void register_editor(); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp new file mode 100644 index 0000000000..ba2eef8484 --- /dev/null +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -0,0 +1,213 @@ +/*************************************************************************/ +/* texture_3d_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "texture_3d_editor_plugin.h" + +#include "core/io/resource_loader.h" +#include "core/project_settings.h" +#include "editor/editor_settings.h" + +void Texture3DEditor::_gui_input(Ref<InputEvent> p_event) { +} + +void Texture3DEditor::_texture_rect_draw() { + texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); +} + +void Texture3DEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + //get_scene()->connect("node_removed",this,"_node_removed"); + } + if (p_what == NOTIFICATION_RESIZED) { + _texture_rect_update_area(); + } + + if (p_what == NOTIFICATION_DRAW) { + Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons"); + Size2 size = get_size(); + + draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + } +} + +void Texture3DEditor::_changed_callback(Object *p_changed, const char *p_prop) { + if (!is_visible()) { + return; + } + update(); +} + +void Texture3DEditor::_update_material() { + material->set_shader_param("layer", (layer->get_value() + 0.5) / texture->get_depth()); + material->set_shader_param("tex", texture->get_rid()); + + String format = Image::get_format_name(texture->get_format()); + + String text; + text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + "x" + itos(texture->get_depth()) + " " + format; + + info->set_text(text); +} + +void Texture3DEditor::_make_shaders() { + String shader_3d = "" + "shader_type canvas_item;\n" + "uniform sampler3D tex;\n" + "uniform float layer;\n" + "void fragment() {\n" + " COLOR = textureLod(tex,vec3(UV,layer),0.0);\n" + "}"; + + shader.instance(); + shader->set_code(shader_3d); + material.instance(); + material->set_shader(shader); +} + +void Texture3DEditor::_texture_rect_update_area() { + Size2 size = get_size(); + int tex_width = texture->get_width() * size.height / texture->get_height(); + int tex_height = size.height; + + if (tex_width > size.width) { + tex_width = size.width; + tex_height = texture->get_height() * tex_width / texture->get_width(); + } + + // Prevent the texture from being unpreviewable after the rescale, so that we can still see something + if (tex_height <= 0) { + tex_height = 1; + } + if (tex_width <= 0) { + tex_width = 1; + } + + int ofs_x = (size.width - tex_width) / 2; + int ofs_y = (size.height - tex_height) / 2; + + texture_rect->set_position(Vector2(ofs_x, ofs_y)); + texture_rect->set_size(Vector2(tex_width, tex_height)); +} + +void Texture3DEditor::edit(Ref<Texture3D> p_texture) { + if (!texture.is_null()) { + texture->remove_change_receptor(this); + } + + texture = p_texture; + + if (!texture.is_null()) { + if (shader.is_null()) { + _make_shaders(); + } + + texture->add_change_receptor(this); + update(); + texture_rect->set_material(material); + setting = true; + layer->set_max(texture->get_depth() - 1); + layer->set_value(0); + layer->show(); + _update_material(); + setting = false; + _texture_rect_update_area(); + } else { + hide(); + } +} + +void Texture3DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_gui_input"), &Texture3DEditor::_gui_input); + ClassDB::bind_method(D_METHOD("_layer_changed"), &Texture3DEditor::_layer_changed); +} + +Texture3DEditor::Texture3DEditor() { + set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); + set_custom_minimum_size(Size2(1, 150)); + texture_rect = memnew(Control); + texture_rect->connect("draw", callable_mp(this, &Texture3DEditor::_texture_rect_draw)); + texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE); + add_child(texture_rect); + + layer = memnew(SpinBox); + layer->set_step(1); + layer->set_max(100); + add_child(layer); + layer->set_anchor(MARGIN_RIGHT, 1); + layer->set_anchor(MARGIN_LEFT, 1); + layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); + layer->set_modulate(Color(1, 1, 1, 0.8)); + info = memnew(Label); + add_child(info); + info->set_anchor(MARGIN_RIGHT, 1); + info->set_anchor(MARGIN_LEFT, 1); + info->set_anchor(MARGIN_BOTTOM, 1); + info->set_anchor(MARGIN_TOP, 1); + info->set_h_grow_direction(GROW_DIRECTION_BEGIN); + info->set_v_grow_direction(GROW_DIRECTION_BEGIN); + info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); + info->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 0.5)); + info->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 0.5)); + info->add_theme_constant_override("shadow_as_outline", 1); + info->add_theme_constant_override("shadow_offset_x", 2); + info->add_theme_constant_override("shadow_offset_y", 2); + + setting = false; + layer->connect("value_changed", Callable(this, "_layer_changed")); +} + +Texture3DEditor::~Texture3DEditor() { + if (!texture.is_null()) { + texture->remove_change_receptor(this); + } +} + +// +bool EditorInspectorPlugin3DTexture::can_handle(Object *p_object) { + return Object::cast_to<Texture3D>(p_object) != nullptr; +} + +void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) { + Texture3D *texture = Object::cast_to<Texture3D>(p_object); + if (!texture) { + return; + } + Ref<Texture3D> m(texture); + + Texture3DEditor *editor = memnew(Texture3DEditor); + editor->edit(m); + add_custom_control(editor); +} + +Texture3DEditorPlugin::Texture3DEditorPlugin(EditorNode *p_node) { + Ref<EditorInspectorPlugin3DTexture> plugin; + plugin.instance(); + add_inspector_plugin(plugin); +} diff --git a/editor/plugins/skeleton_editor_plugin.h b/editor/plugins/texture_3d_editor_plugin.h index 1dce6d12ed..4fbf47ecfe 100644 --- a/editor/plugins/skeleton_editor_plugin.h +++ b/editor/plugins/texture_3d_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* skeleton_editor_plugin.h */ +/* texture_3d_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,69 +28,66 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SKELETON_EDITOR_PLUGIN_H -#define SKELETON_EDITOR_PLUGIN_H +#ifndef TEXTURE_3D_EDITOR_PLUGIN_H +#define TEXTURE_3D_EDITOR_PLUGIN_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/skeleton.h" +#include "scene/resources/shader.h" +#include "scene/resources/texture.h" -class PhysicalBone; -class Joint; +class Texture3DEditor : public Control { + GDCLASS(Texture3DEditor, Control); -class SkeletonEditor : public Node { - GDCLASS(SkeletonEditor, Node); + SpinBox *layer; + Label *info; + Ref<Texture3D> texture; - enum Menu { - MENU_OPTION_CREATE_PHYSICAL_SKELETON - }; + Ref<Shader> shader; + Ref<ShaderMaterial> material; - struct BoneInfo { - PhysicalBone *physical_bone; - Transform relative_rest; // Relative to skeleton node - BoneInfo() : - physical_bone(NULL) {} - }; + Control *texture_rect; - Skeleton *skeleton; + void _make_shaders(); - MenuButton *options; + void _update_material(); + bool setting; + void _layer_changed(double) { + if (!setting) { + _update_material(); + } + } - void _on_click_option(int p_option); - - friend class SkeletonEditorPlugin; + void _texture_rect_update_area(); + void _texture_rect_draw(); protected: void _notification(int p_what); - void _node_removed(Node *p_node); + void _gui_input(Ref<InputEvent> p_event); + void _changed_callback(Object *p_changed, const char *p_prop) override; static void _bind_methods(); - void create_physical_skeleton(); - PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos); - public: - void edit(Skeleton *p_node); - - SkeletonEditor(); - ~SkeletonEditor(); + void edit(Ref<Texture3D> p_texture); + Texture3DEditor(); + ~Texture3DEditor(); }; -class SkeletonEditorPlugin : public EditorPlugin { +class EditorInspectorPlugin3DTexture : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPlugin3DTexture, EditorInspectorPlugin); - GDCLASS(SkeletonEditorPlugin, EditorPlugin); +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; - EditorNode *editor; - SkeletonEditor *skeleton_editor; +class Texture3DEditorPlugin : public EditorPlugin { + GDCLASS(Texture3DEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "Skeleton"; } - virtual 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); - - SkeletonEditorPlugin(EditorNode *p_node); - ~SkeletonEditorPlugin(); + virtual String get_name() const override { return "Texture3D"; } + + Texture3DEditorPlugin(EditorNode *p_node); }; -#endif // SKELETON_EDITOR_PLUGIN_H +#endif // TEXTURE_EDITOR_PLUGIN_H diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 9489836984..b728a6700c 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -38,15 +38,12 @@ void TextureEditor::_gui_input(Ref<InputEvent> p_event) { } void TextureEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - //get_scene()->connect("node_removed",this,"_node_removed"); } if (p_what == NOTIFICATION_DRAW) { - - Ref<Texture> checkerboard = get_icon("Checkerboard", "EditorIcons"); + Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons"); Size2 size = get_size(); draw_texture_rect(checkerboard, Rect2(Point2(), size), true); @@ -60,10 +57,12 @@ void TextureEditor::_notification(int p_what) { } // Prevent the texture from being unpreviewable after the rescale, so that we can still see something - if (tex_height <= 0) + if (tex_height <= 0) { tex_height = 1; - if (tex_width <= 0) + } + if (tex_width <= 0) { tex_width = 1; + } int ofs_x = (size.width - tex_width) / 2; int ofs_y = (size.height - tex_height) / 2; @@ -79,13 +78,13 @@ void TextureEditor::_notification(int p_what) { draw_texture_rect(texture, Rect2(ofs_x, ofs_y, tex_width, tex_height)); - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); String format; if (Object::cast_to<ImageTexture>(*texture)) { format = Image::get_format_name(Object::cast_to<ImageTexture>(*texture)->get_format()); - } else if (Object::cast_to<StreamTexture>(*texture)) { - format = Image::get_format_name(Object::cast_to<StreamTexture>(*texture)->get_format()); + } else if (Object::cast_to<StreamTexture2D>(*texture)) { + format = Image::get_format_name(Object::cast_to<StreamTexture2D>(*texture)->get_format()); } else { format = texture->get_class(); } @@ -94,8 +93,9 @@ void TextureEditor::_notification(int p_what) { Size2 rect = font->get_string_size(text); Vector2 draw_from = size - rect + Size2(-2, font->get_ascent() - 2); - if (draw_from.x < 0) + if (draw_from.x < 0) { draw_from.x = 0; + } draw_string(font, draw_from + Vector2(2, 2), text, Color(0, 0, 0, 0.5), size.width); draw_string(font, draw_from - Vector2(2, 2), text, Color(0, 0, 0, 0.5), size.width); @@ -104,16 +104,16 @@ void TextureEditor::_notification(int p_what) { } void TextureEditor::_changed_callback(Object *p_changed, const char *p_prop) { - - if (!is_visible()) + if (!is_visible()) { return; + } update(); } -void TextureEditor::edit(Ref<Texture> p_texture) { - - if (!texture.is_null()) +void TextureEditor::edit(Ref<Texture2D> p_texture) { + if (!texture.is_null()) { texture->remove_change_receptor(this); + } texture = p_texture; @@ -126,12 +126,11 @@ void TextureEditor::edit(Ref<Texture> p_texture) { } void TextureEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &TextureEditor::_gui_input); } TextureEditor::TextureEditor() { - + set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); set_custom_minimum_size(Size2(1, 150)); } @@ -140,19 +139,18 @@ TextureEditor::~TextureEditor() { texture->remove_change_receptor(this); } } + // bool EditorInspectorPluginTexture::can_handle(Object *p_object) { - - 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; + return Object::cast_to<ImageTexture>(p_object) != nullptr || Object::cast_to<AtlasTexture>(p_object) != nullptr || Object::cast_to<StreamTexture2D>(p_object) != nullptr || Object::cast_to<LargeTexture>(p_object) != nullptr || Object::cast_to<AnimatedTexture>(p_object) != nullptr; } void EditorInspectorPluginTexture::parse_begin(Object *p_object) { - - Texture *texture = Object::cast_to<Texture>(p_object); + Texture2D *texture = Object::cast_to<Texture2D>(p_object); if (!texture) { return; } - Ref<Texture> m(texture); + Ref<Texture2D> m(texture); TextureEditor *editor = memnew(TextureEditor); editor->edit(m); @@ -160,7 +158,6 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) { } TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) { - 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 f587579902..0d4452c662 100644 --- a/editor/plugins/texture_editor_plugin.h +++ b/editor/plugins/texture_editor_plugin.h @@ -36,19 +36,18 @@ #include "scene/resources/texture.h" class TextureEditor : public Control { - GDCLASS(TextureEditor, Control); - Ref<Texture> texture; + Ref<Texture2D> texture; protected: void _notification(int p_what); void _gui_input(Ref<InputEvent> p_event); - void _changed_callback(Object *p_changed, const char *p_prop); + void _changed_callback(Object *p_changed, const char *p_prop) override; static void _bind_methods(); public: - void edit(Ref<Texture> p_texture); + void edit(Ref<Texture2D> p_texture); TextureEditor(); ~TextureEditor(); }; @@ -57,16 +56,15 @@ class EditorInspectorPluginTexture : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginTexture, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; }; class TextureEditorPlugin : public EditorPlugin { - GDCLASS(TextureEditorPlugin, EditorPlugin); public: - virtual String get_name() const { return "Texture"; } + virtual String get_name() const override { return "Texture2D"; } TextureEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp new file mode 100644 index 0000000000..59e87fb273 --- /dev/null +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -0,0 +1,278 @@ +/*************************************************************************/ +/* texture_layered_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 "texture_layered_editor_plugin.h" + +#include "core/io/resource_loader.h" +#include "core/project_settings.h" +#include "editor/editor_settings.h" + +void TextureLayeredEditor::_gui_input(Ref<InputEvent> p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { + y_rot += -mm->get_relative().x * 0.01; + x_rot += mm->get_relative().y * 0.01; + _update_material(); + } +} + +void TextureLayeredEditor::_texture_rect_draw() { + texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); +} + +void TextureLayeredEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + //get_scene()->connect("node_removed",this,"_node_removed"); + } + if (p_what == NOTIFICATION_RESIZED) { + _texture_rect_update_area(); + } + + if (p_what == NOTIFICATION_DRAW) { + Ref<Texture2D> checkerboard = get_theme_icon("Checkerboard", "EditorIcons"); + Size2 size = get_size(); + + draw_texture_rect(checkerboard, Rect2(Point2(), size), true); + } +} + +void TextureLayeredEditor::_changed_callback(Object *p_changed, const char *p_prop) { + if (!is_visible()) { + return; + } + update(); +} + +void TextureLayeredEditor::_update_material() { + materials[0]->set_shader_param("layer", layer->get_value()); + materials[2]->set_shader_param("layer", layer->get_value()); + materials[texture->get_layered_type()]->set_shader_param("tex", texture->get_rid()); + + Vector3 v(1, 1, 1); + v.normalize(); + + Basis b; + b.rotate(Vector3(1, 0, 0), x_rot); + b.rotate(Vector3(0, 1, 0), y_rot); + + materials[1]->set_shader_param("normal", v); + materials[1]->set_shader_param("rot", b); + materials[2]->set_shader_param("normal", v); + materials[2]->set_shader_param("rot", b); + + String format = Image::get_format_name(texture->get_format()); + + String text; + if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) { + text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers()) + ")" + format; + } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP) { + text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " " + format; + } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) { + text = itos(texture->get_width()) + "x" + itos(texture->get_height()) + " (x " + itos(texture->get_layers() / 6) + ")" + format; + } + + info->set_text(text); +} + +void TextureLayeredEditor::_make_shaders() { + String shader_2d_array = "" + "shader_type canvas_item;\n" + "uniform sampler2DArray tex;\n" + "uniform float layer;\n" + "void fragment() {\n" + " COLOR = textureLod(tex,vec3(UV,layer),0.0);\n" + "}"; + + shaders[0].instance(); + shaders[0]->set_code(shader_2d_array); + + String shader_cube = "" + "shader_type canvas_item;\n" + "uniform samplerCube tex;\n" + "uniform vec3 normal;\n" + "uniform mat3 rot;\n" + "void fragment() {\n" + " vec3 n = rot * normalize(vec3(normal.xy*(UV * 2.0 - 1.0),normal.z));\n" + " COLOR = textureLod(tex,n,0.0);\n" + "}"; + + shaders[1].instance(); + shaders[1]->set_code(shader_cube); + + String shader_cube_array = "" + "shader_type canvas_item;\n" + "uniform samplerCubeArray tex;\n" + "uniform vec3 normal;\n" + "uniform mat3 rot;\n" + "uniform float layer;\n" + "void fragment() {\n" + " vec3 n = rot * normalize(vec3(normal.xy*(UV * 2.0 - 1.0),normal.z));\n" + " COLOR = textureLod(tex,vec4(n,layer),0.0);\n" + "}"; + + shaders[2].instance(); + shaders[2]->set_code(shader_cube_array); + + for (int i = 0; i < 3; i++) { + materials[i].instance(); + materials[i]->set_shader(shaders[i]); + } +} + +void TextureLayeredEditor::_texture_rect_update_area() { + Size2 size = get_size(); + int tex_width = texture->get_width() * size.height / texture->get_height(); + int tex_height = size.height; + + if (tex_width > size.width) { + tex_width = size.width; + tex_height = texture->get_height() * tex_width / texture->get_width(); + } + + // Prevent the texture from being unpreviewable after the rescale, so that we can still see something + if (tex_height <= 0) { + tex_height = 1; + } + if (tex_width <= 0) { + tex_width = 1; + } + + int ofs_x = (size.width - tex_width) / 2; + int ofs_y = (size.height - tex_height) / 2; + + texture_rect->set_position(Vector2(ofs_x, ofs_y)); + texture_rect->set_size(Vector2(tex_width, tex_height)); +} + +void TextureLayeredEditor::edit(Ref<TextureLayered> p_texture) { + if (!texture.is_null()) { + texture->remove_change_receptor(this); + } + + texture = p_texture; + + if (!texture.is_null()) { + if (shaders[0].is_null()) { + _make_shaders(); + } + + texture->add_change_receptor(this); + update(); + texture_rect->set_material(materials[texture->get_layered_type()]); + setting = true; + if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_2D_ARRAY) { + layer->set_max(texture->get_layers() - 1); + layer->set_value(0); + layer->show(); + } else if (texture->get_layered_type() == TextureLayered::LAYERED_TYPE_CUBEMAP_ARRAY) { + layer->set_max(texture->get_layers() / 6 - 1); + layer->set_value(0); + layer->show(); + } else { + layer->hide(); + } + x_rot = 0; + y_rot = 0; + _update_material(); + setting = false; + _texture_rect_update_area(); + } else { + hide(); + } +} + +void TextureLayeredEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_gui_input"), &TextureLayeredEditor::_gui_input); + ClassDB::bind_method(D_METHOD("_layer_changed"), &TextureLayeredEditor::_layer_changed); +} + +TextureLayeredEditor::TextureLayeredEditor() { + set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); + set_custom_minimum_size(Size2(1, 150)); + texture_rect = memnew(Control); + texture_rect->connect("draw", callable_mp(this, &TextureLayeredEditor::_texture_rect_draw)); + texture_rect->set_mouse_filter(MOUSE_FILTER_IGNORE); + add_child(texture_rect); + + layer = memnew(SpinBox); + layer->set_step(1); + layer->set_max(100); + add_child(layer); + layer->set_anchor(MARGIN_RIGHT, 1); + layer->set_anchor(MARGIN_LEFT, 1); + layer->set_h_grow_direction(GROW_DIRECTION_BEGIN); + layer->set_modulate(Color(1, 1, 1, 0.8)); + info = memnew(Label); + add_child(info); + info->set_anchor(MARGIN_RIGHT, 1); + info->set_anchor(MARGIN_LEFT, 1); + info->set_anchor(MARGIN_BOTTOM, 1); + info->set_anchor(MARGIN_TOP, 1); + info->set_h_grow_direction(GROW_DIRECTION_BEGIN); + info->set_v_grow_direction(GROW_DIRECTION_BEGIN); + info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); + info->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 0.5)); + info->add_theme_color_override("font_color_shadow", Color(0, 0, 0, 0.5)); + info->add_theme_constant_override("shadow_as_outline", 1); + info->add_theme_constant_override("shadow_offset_x", 2); + info->add_theme_constant_override("shadow_offset_y", 2); + + setting = false; + layer->connect("value_changed", Callable(this, "_layer_changed")); +} + +TextureLayeredEditor::~TextureLayeredEditor() { + if (!texture.is_null()) { + texture->remove_change_receptor(this); + } +} + +// +bool EditorInspectorPluginLayeredTexture::can_handle(Object *p_object) { + return Object::cast_to<TextureLayered>(p_object) != nullptr; +} + +void EditorInspectorPluginLayeredTexture::parse_begin(Object *p_object) { + TextureLayered *texture = Object::cast_to<TextureLayered>(p_object); + if (!texture) { + return; + } + Ref<TextureLayered> m(texture); + + TextureLayeredEditor *editor = memnew(TextureLayeredEditor); + editor->edit(m); + add_custom_control(editor); +} + +TextureLayeredEditorPlugin::TextureLayeredEditorPlugin(EditorNode *p_node) { + Ref<EditorInspectorPluginLayeredTexture> plugin; + plugin.instance(); + add_inspector_plugin(plugin); +} diff --git a/editor/plugins/texture_layered_editor_plugin.h b/editor/plugins/texture_layered_editor_plugin.h new file mode 100644 index 0000000000..9a28d2dff8 --- /dev/null +++ b/editor/plugins/texture_layered_editor_plugin.h @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* texture_layered_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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 TEXTURE_LAYERED_EDITOR_PLUGIN_H +#define TEXTURE_LAYERED_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/resources/shader.h" +#include "scene/resources/texture.h" + +class TextureLayeredEditor : public Control { + GDCLASS(TextureLayeredEditor, Control); + + SpinBox *layer; + Label *info; + Ref<TextureLayered> texture; + + Ref<Shader> shaders[3]; + Ref<ShaderMaterial> materials[3]; + + float x_rot = 0; + float y_rot = 0; + Control *texture_rect; + + void _make_shaders(); + + void _update_material(); + bool setting; + void _layer_changed(double) { + if (!setting) { + _update_material(); + } + } + + void _texture_rect_update_area(); + void _texture_rect_draw(); + +protected: + void _notification(int p_what); + void _gui_input(Ref<InputEvent> p_event); + void _changed_callback(Object *p_changed, const char *p_prop) override; + static void _bind_methods(); + +public: + void edit(Ref<TextureLayered> p_texture); + TextureLayeredEditor(); + ~TextureLayeredEditor(); +}; + +class EditorInspectorPluginLayeredTexture : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginLayeredTexture, EditorInspectorPlugin); + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; + +class TextureLayeredEditorPlugin : public EditorPlugin { + GDCLASS(TextureLayeredEditorPlugin, EditorPlugin); + +public: + virtual String get_name() const override { return "TextureLayered"; } + + TextureLayeredEditorPlugin(EditorNode *p_node); +}; + +#endif // TEXTURE_EDITOR_PLUGIN_H diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 507ea0b83d..6e722607f7 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -31,7 +31,7 @@ #include "texture_region_editor_plugin.h" #include "core/core_string_names.h" -#include "core/os/input.h" +#include "core/input/input.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "scene/gui/check_box.h" @@ -43,34 +43,36 @@ void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) { Vector2 line = (to - from).normalized() * 10; while ((to - from).length_squared() > 200) { - edit_draw->draw_line(from, from + line, EditorNode::get_singleton()->get_theme_base()->get_color("mono_color", "Editor"), 2); + edit_draw->draw_line(from, from + line, EditorNode::get_singleton()->get_theme_base()->get_theme_color("mono_color", "Editor"), 2); from += line * 2; } } void TextureRegionEditor::_region_draw() { - Ref<Texture> base_tex = NULL; - if (node_sprite) + Ref<Texture2D> base_tex = nullptr; + if (node_sprite) { base_tex = node_sprite->get_texture(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { base_tex = node_sprite_3d->get_texture(); - else if (node_ninepatch) + } else if (node_ninepatch) { base_tex = node_ninepatch->get_texture(); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { base_tex = obj_styleBox->get_texture(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { base_tex = atlas_tex->get_atlas(); + } - if (base_tex.is_null()) + if (base_tex.is_null()) { return; + } Transform2D mtx; 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); + RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx); edit_draw->draw_texture(base_tex, Point2()); - VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D()); + RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D()); if (snap_mode == SNAP_GRID) { Color grid_color = Color(1.0, 1.0, 1.0, 0.15); @@ -78,45 +80,55 @@ void TextureRegionEditor::_region_draw() { int last_cell = 0; if (snap_step.x != 0) { - if (snap_separation.x == 0) + if (snap_separation.x == 0) { for (int i = 0; i < s.width; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / snap_step.x)); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { edit_draw->draw_line(Point2(i, 0), Point2(i, s.height), grid_color); + } last_cell = cell; } - else + } else { for (int i = 0; i < s.width; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / (snap_step.x + snap_separation.x))); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { edit_draw->draw_rect(Rect2(i - snap_separation.x * draw_zoom, 0, snap_separation.x * draw_zoom, s.height), grid_color); + } last_cell = cell; } + } } if (snap_step.y != 0) { - if (snap_separation.y == 0) + if (snap_separation.y == 0) { for (int i = 0; i < s.height; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / snap_step.y)); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { edit_draw->draw_line(Point2(0, i), Point2(s.width, i), grid_color); + } last_cell = cell; } - else + } else { for (int i = 0; i < s.height; i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / (snap_step.y + snap_separation.y))); - if (i == 0) + if (i == 0) { last_cell = cell; - if (last_cell != cell) + } + if (last_cell != cell) { edit_draw->draw_rect(Rect2(0, i - snap_separation.y * draw_zoom, s.width, snap_separation.y * draw_zoom), grid_color); + } last_cell = cell; } + } } } else if (snap_mode == SNAP_AUTOSLICE) { for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) { @@ -134,7 +146,7 @@ void TextureRegionEditor::_region_draw() { } } - Ref<Texture> select_handle = get_icon("EditorHandle", "EditorIcons"); + Ref<Texture2D> select_handle = get_theme_icon("EditorHandle", "EditorIcons"); Rect2 scroll_rect(Point2(), base_tex->get_size()); @@ -150,9 +162,8 @@ void TextureRegionEditor::_region_draw() { mtx.basis_xform(raw_endpoints[2]), mtx.basis_xform(raw_endpoints[3]) }; - Color color = get_color("mono_color", "Editor"); + Color color = get_theme_color("mono_color", "Editor"); for (int i = 0; i < 4; i++) { - int prev = (i + 3) % 4; int next = (i + 1) % 4; @@ -161,14 +172,16 @@ void TextureRegionEditor::_region_draw() { edit_draw->draw_line(endpoints[i] - draw_ofs * draw_zoom, endpoints[next] - draw_ofs * draw_zoom, color, 2); - if (snap_mode != SNAP_AUTOSLICE) + if (snap_mode != SNAP_AUTOSLICE) { 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) + if (snap_mode != SNAP_AUTOSLICE) { edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs * draw_zoom); + } scroll_rect.expand_to(raw_endpoints[i]); } @@ -259,9 +272,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_LEFT) { - if (mb->is_pressed()) { if (node_ninepatch || obj_styleBox.is_valid()) { edited_margin = -1; @@ -309,16 +320,17 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { rect = E->get(); if (Input::get_singleton()->is_key_pressed(KEY_CONTROL) && !(Input::get_singleton()->is_key_pressed(KEY_SHIFT | KEY_ALT))) { Rect2 r; - if (node_sprite) + if (node_sprite) { r = node_sprite->get_region_rect(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { r = node_sprite_3d->get_region_rect(); - else if (node_ninepatch) + } else if (node_ninepatch) { r = node_ninepatch->get_region_rect(); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { r = obj_styleBox->get_region_rect(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { r = atlas_tex->get_region(); + } rect.expand_to(r.position); rect.expand_to(r.position + r.size); } @@ -349,21 +361,23 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } } else if (edited_margin < 0) { drag_from = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y)); - if (snap_mode == SNAP_PIXEL) + if (snap_mode == SNAP_PIXEL) { drag_from = drag_from.snapped(Vector2(1, 1)); - else if (snap_mode == SNAP_GRID) + } else if (snap_mode == SNAP_GRID) { drag_from = snap_point(drag_from); + } drag = true; - if (node_sprite) + if (node_sprite) { rect_prev = node_sprite->get_region_rect(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { rect_prev = node_sprite_3d->get_region_rect(); - else if (node_ninepatch) + } else if (node_ninepatch) { rect_prev = node_ninepatch->get_region_rect(); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { rect_prev = obj_styleBox->get_region_rect(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { rect_prev = atlas_tex->get_region(); + } for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; @@ -421,15 +435,16 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { - if (drag) { drag = false; if (edited_margin >= 0) { static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT }; - if (node_ninepatch) + if (node_ninepatch) { node_ninepatch->set_patch_margin(m[edited_margin], prev_margin); - if (obj_styleBox.is_valid()) + } + if (obj_styleBox.is_valid()) { obj_styleBox->set_margin_size(m[edited_margin], prev_margin); + } edited_margin = -1; } else { apply_rect(rect_prev); @@ -448,41 +463,43 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseMotion> mm = p_input; if (mm.is_valid()) { - if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) { - Vector2 dragged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom); hscroll->set_value(hscroll->get_value() - dragged.x); vscroll->set_value(vscroll->get_value() - dragged.y); } else if (drag) { - if (edited_margin >= 0) { float new_margin = 0; - if (edited_margin == 0) + if (edited_margin == 0) { new_margin = prev_margin + (mm->get_position().y - drag_from.y) / draw_zoom; - else if (edited_margin == 1) + } else if (edited_margin == 1) { new_margin = prev_margin - (mm->get_position().y - drag_from.y) / draw_zoom; - else if (edited_margin == 2) + } else if (edited_margin == 2) { new_margin = prev_margin + (mm->get_position().x - drag_from.x) / draw_zoom; - else if (edited_margin == 3) + } else if (edited_margin == 3) { new_margin = prev_margin - (mm->get_position().x - drag_from.x) / draw_zoom; - else + } else { ERR_PRINT("Unexpected edited_margin"); + } - if (new_margin < 0) + if (new_margin < 0) { new_margin = 0; + } static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT }; - if (node_ninepatch) + if (node_ninepatch) { node_ninepatch->set_patch_margin(m[edited_margin], new_margin); - if (obj_styleBox.is_valid()) + } + if (obj_styleBox.is_valid()) { obj_styleBox->set_margin_size(m[edited_margin], new_margin); + } } else { Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position()); - if (snap_mode == SNAP_PIXEL) + if (snap_mode == SNAP_PIXEL) { new_pos = new_pos.snapped(Vector2(1, 1)); - else if (snap_mode == SNAP_GRID) + } else if (snap_mode == SNAP_GRID) { new_pos = snap_point(new_pos); + } if (creating) { rect = Rect2(drag_from, Size2()); @@ -546,11 +563,23 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { edit_draw->update(); } } + + Ref<InputEventMagnifyGesture> magnify_gesture = p_input; + if (magnify_gesture.is_valid()) { + _zoom_on_position(draw_zoom * magnify_gesture->get_factor(), magnify_gesture->get_position()); + } + + Ref<InputEventPanGesture> pan_gesture = p_input; + if (pan_gesture.is_valid()) { + hscroll->set_value(hscroll->get_value() + hscroll->get_page() * pan_gesture->get_delta().x / 8); + vscroll->set_value(vscroll->get_value() + vscroll->get_page() * pan_gesture->get_delta().y / 8); + } } void TextureRegionEditor::_scroll_changed(float) { - if (updating_scroll) + if (updating_scroll) { return; + } draw_ofs.x = hscroll->get_value(); draw_ofs.y = vscroll->get_value(); @@ -560,10 +589,11 @@ void TextureRegionEditor::_scroll_changed(float) { void TextureRegionEditor::_set_snap_mode(int p_mode) { snap_mode = p_mode; - if (snap_mode == SNAP_GRID) + if (snap_mode == SNAP_GRID) { hb_grid->show(); - else + } else { hb_grid->hide(); + } if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) { _update_autoslice(); @@ -603,8 +633,9 @@ void TextureRegionEditor::_set_snap_sep_y(float p_val) { } void TextureRegionEditor::_zoom_on_position(float p_zoom, Point2 p_position) { - if (p_zoom < 0.25 || p_zoom > 8) + if (p_zoom < 0.25 || p_zoom > 8) { return; + } float prev_zoom = draw_zoom; draw_zoom = p_zoom; @@ -629,49 +660,52 @@ void TextureRegionEditor::_zoom_out() { } void TextureRegionEditor::apply_rect(const Rect2 &p_rect) { - if (node_sprite) + if (node_sprite) { node_sprite->set_region_rect(p_rect); - else if (node_sprite_3d) + } else if (node_sprite_3d) { node_sprite_3d->set_region_rect(p_rect); - else if (node_ninepatch) + } else if (node_ninepatch) { node_ninepatch->set_region_rect(p_rect); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { obj_styleBox->set_region_rect(p_rect); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { atlas_tex->set_region(p_rect); + } } void TextureRegionEditor::_update_rect() { - if (node_sprite) + if (node_sprite) { rect = node_sprite->get_region_rect(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { rect = node_sprite_3d->get_region_rect(); - else if (node_ninepatch) { + } else if (node_ninepatch) { rect = node_ninepatch->get_region_rect(); if (rect == Rect2()) { rect = Rect2(Vector2(), node_ninepatch->get_texture()->get_size()); } - } else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { rect = obj_styleBox->get_region_rect(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { rect = atlas_tex->get_region(); + } } void TextureRegionEditor::_update_autoslice() { autoslice_is_dirty = false; autoslice_cache.clear(); - Ref<Texture> texture = NULL; - if (node_sprite) + Ref<Texture2D> texture = nullptr; + if (node_sprite) { texture = node_sprite->get_texture(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { texture = node_sprite_3d->get_texture(); - else if (node_ninepatch) + } else if (node_ninepatch) { texture = node_ninepatch->get_texture(); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { texture = obj_styleBox->get_texture(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { texture = atlas_tex->get_atlas(); + } if (texture.is_null()) { return; @@ -696,8 +730,9 @@ void TextureRegionEditor::_update_autoslice() { autoslice_cache.erase(F->prev()); queue_erase = false; } - if (F == E) + if (F == E) { continue; + } if (E->get().grow(1).intersects(F->get())) { E->get().expand_to(F->get().position); E->get().expand_to(F->get().position + F->get().size); @@ -730,12 +765,12 @@ void TextureRegionEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - edit_draw->add_style_override("panel", get_stylebox("bg", "Tree")); + edit_draw->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); } break; case NOTIFICATION_READY: { - zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); - zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); - zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons")); + zoom_out->set_icon(get_theme_icon("ZoomLess", "EditorIcons")); + zoom_reset->set_icon(get_theme_icon("ZoomReset", "EditorIcons")); + zoom_in->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); vscroll->set_anchors_and_margins_preset(PRESET_RIGHT_WIDE); hscroll->set_anchors_and_margins_preset(PRESET_BOTTOM_WIDE); @@ -745,7 +780,7 @@ void TextureRegionEditor::_notification(int p_what) { _update_autoslice(); } } break; - case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { // This happens when the user leaves the Editor and returns, // they could have changed the textures, so the cache is cleared. cache_map.clear(); @@ -756,32 +791,19 @@ void TextureRegionEditor::_notification(int p_what) { void TextureRegionEditor::_node_removed(Object *p_obj) { if (p_obj == node_sprite || p_obj == node_sprite_3d || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) { - node_sprite = NULL; - node_sprite_3d = NULL; - node_ninepatch = NULL; - obj_styleBox = Ref<StyleBox>(NULL); - atlas_tex = Ref<AtlasTexture>(NULL); + node_sprite = nullptr; + node_sprite_3d = nullptr; + node_ninepatch = nullptr; + obj_styleBox = Ref<StyleBox>(nullptr); + atlas_tex = Ref<AtlasTexture>(nullptr); hide(); } } void TextureRegionEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_edit_region"), &TextureRegionEditor::_edit_region); - ClassDB::bind_method(D_METHOD("_region_draw"), &TextureRegionEditor::_region_draw); - ClassDB::bind_method(D_METHOD("_region_input"), &TextureRegionEditor::_region_input); - ClassDB::bind_method(D_METHOD("_scroll_changed"), &TextureRegionEditor::_scroll_changed); ClassDB::bind_method(D_METHOD("_node_removed"), &TextureRegionEditor::_node_removed); - ClassDB::bind_method(D_METHOD("_set_snap_mode"), &TextureRegionEditor::_set_snap_mode); - ClassDB::bind_method(D_METHOD("_set_snap_off_x"), &TextureRegionEditor::_set_snap_off_x); - ClassDB::bind_method(D_METHOD("_set_snap_off_y"), &TextureRegionEditor::_set_snap_off_y); - ClassDB::bind_method(D_METHOD("_set_snap_step_x"), &TextureRegionEditor::_set_snap_step_x); - 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); ClassDB::bind_method(D_METHOD("_update_rect"), &TextureRegionEditor::_update_rect); } @@ -790,49 +812,55 @@ bool TextureRegionEditor::is_stylebox() { } bool TextureRegionEditor::is_atlas_texture() { - return atlas_tex.is_valid(); } bool TextureRegionEditor::is_ninepatch() { - return node_ninepatch != NULL; + return node_ninepatch != nullptr; } Sprite3D *TextureRegionEditor::get_sprite_3d() { return node_sprite_3d; } -Sprite *TextureRegionEditor::get_sprite() { +Sprite2D *TextureRegionEditor::get_sprite() { return node_sprite; } void TextureRegionEditor::edit(Object *p_obj) { - if (node_sprite) + if (node_sprite) { node_sprite->remove_change_receptor(this); - if (node_sprite_3d) + } + if (node_sprite_3d) { node_sprite_3d->remove_change_receptor(this); - if (node_ninepatch) + } + if (node_ninepatch) { node_ninepatch->remove_change_receptor(this); - if (obj_styleBox.is_valid()) + } + if (obj_styleBox.is_valid()) { obj_styleBox->remove_change_receptor(this); - if (atlas_tex.is_valid()) + } + if (atlas_tex.is_valid()) { atlas_tex->remove_change_receptor(this); + } if (p_obj) { - node_sprite = Object::cast_to<Sprite>(p_obj); + node_sprite = Object::cast_to<Sprite2D>(p_obj); node_sprite_3d = Object::cast_to<Sprite3D>(p_obj); node_ninepatch = Object::cast_to<NinePatchRect>(p_obj); - if (Object::cast_to<StyleBoxTexture>(p_obj)) + if (Object::cast_to<StyleBoxTexture>(p_obj)) { obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj)); - if (Object::cast_to<AtlasTexture>(p_obj)) + } + if (Object::cast_to<AtlasTexture>(p_obj)) { atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj)); + } p_obj->add_change_receptor(this); _edit_region(); } else { - node_sprite = NULL; - node_sprite_3d = NULL; - node_ninepatch = NULL; - obj_styleBox = Ref<StyleBoxTexture>(NULL); - atlas_tex = Ref<AtlasTexture>(NULL); + node_sprite = nullptr; + node_sprite_3d = nullptr; + node_ninepatch = nullptr; + obj_styleBox = Ref<StyleBoxTexture>(nullptr); + atlas_tex = Ref<AtlasTexture>(nullptr); } edit_draw->update(); if ((node_sprite && !node_sprite->is_region()) || (node_sprite_3d && !node_sprite_3d->is_region())) { @@ -844,25 +872,27 @@ void TextureRegionEditor::edit(Object *p_obj) { } void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_prop) { - - if (!is_visible()) + if (!is_visible()) { return; - if (p_prop == StringName("atlas") || p_prop == StringName("texture")) + } + if (p_prop == StringName("atlas") || p_prop == StringName("texture") || p_prop == StringName("region")) { _edit_region(); + } } void TextureRegionEditor::_edit_region() { - Ref<Texture> texture = NULL; - if (node_sprite) + Ref<Texture2D> texture = nullptr; + if (node_sprite) { texture = node_sprite->get_texture(); - else if (node_sprite_3d) + } else if (node_sprite_3d) { texture = node_sprite_3d->get_texture(); - else if (node_ninepatch) + } else if (node_ninepatch) { texture = node_ninepatch->get_texture(); - else if (obj_styleBox.is_valid()) + } else if (obj_styleBox.is_valid()) { texture = obj_styleBox->get_texture(); - else if (atlas_tex.is_valid()) + } else if (atlas_tex.is_valid()) { texture = atlas_tex->get_atlas(); + } if (texture.is_null()) { _zoom_reset(); @@ -898,11 +928,11 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const { } TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { - node_sprite = NULL; - node_sprite_3d = NULL; - node_ninepatch = NULL; - obj_styleBox = Ref<StyleBoxTexture>(NULL); - atlas_tex = Ref<AtlasTexture>(NULL); + node_sprite = nullptr; + node_sprite_3d = nullptr; + node_ninepatch = nullptr; + obj_styleBox = Ref<StyleBoxTexture>(nullptr); + atlas_tex = Ref<AtlasTexture>(nullptr); editor = p_editor; undo_redo = editor->get_undo_redo(); @@ -924,7 +954,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { snap_mode_button->add_item(TTR("Grid Snap"), 2); snap_mode_button->add_item(TTR("Auto Slice"), 3); snap_mode_button->select(0); - snap_mode_button->connect("item_selected", this, "_set_snap_mode"); + snap_mode_button->connect("item_selected", callable_mp(this, &TextureRegionEditor::_set_snap_mode)); hb_grid = memnew(HBoxContainer); hb_tools->add_child(hb_grid); @@ -938,7 +968,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_off_x->set_step(1); sb_off_x->set_value(snap_offset.x); sb_off_x->set_suffix("px"); - sb_off_x->connect("value_changed", this, "_set_snap_off_x"); + sb_off_x->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_off_x)); hb_grid->add_child(sb_off_x); sb_off_y = memnew(SpinBox); @@ -947,7 +977,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_off_y->set_step(1); sb_off_y->set_value(snap_offset.y); sb_off_y->set_suffix("px"); - sb_off_y->connect("value_changed", this, "_set_snap_off_y"); + sb_off_y->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_off_y)); hb_grid->add_child(sb_off_y); hb_grid->add_child(memnew(VSeparator)); @@ -959,7 +989,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_step_x->set_step(1); sb_step_x->set_value(snap_step.x); sb_step_x->set_suffix("px"); - sb_step_x->connect("value_changed", this, "_set_snap_step_x"); + sb_step_x->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_step_x)); hb_grid->add_child(sb_step_x); sb_step_y = memnew(SpinBox); @@ -968,7 +998,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_step_y->set_step(1); sb_step_y->set_value(snap_step.y); sb_step_y->set_suffix("px"); - sb_step_y->connect("value_changed", this, "_set_snap_step_y"); + sb_step_y->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_step_y)); hb_grid->add_child(sb_step_y); hb_grid->add_child(memnew(VSeparator)); @@ -980,7 +1010,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_sep_x->set_step(1); sb_sep_x->set_value(snap_separation.x); sb_sep_x->set_suffix("px"); - sb_sep_x->connect("value_changed", this, "_set_snap_sep_x"); + sb_sep_x->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_sep_x)); hb_grid->add_child(sb_sep_x); sb_sep_y = memnew(SpinBox); @@ -989,7 +1019,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { sb_sep_y->set_step(1); sb_sep_y->set_value(snap_separation.y); sb_sep_y->set_suffix("px"); - sb_sep_y->connect("value_changed", this, "_set_snap_sep_y"); + sb_sep_y->connect("value_changed", callable_mp(this, &TextureRegionEditor::_set_snap_sep_y)); hb_grid->add_child(sb_sep_y); hb_grid->hide(); @@ -997,8 +1027,8 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { edit_draw = memnew(Panel); add_child(edit_draw); edit_draw->set_v_size_flags(SIZE_EXPAND_FILL); - edit_draw->connect("draw", this, "_region_draw"); - edit_draw->connect("gui_input", this, "_region_input"); + edit_draw->connect("draw", callable_mp(this, &TextureRegionEditor::_region_draw)); + edit_draw->connect("gui_input", callable_mp(this, &TextureRegionEditor::_region_input)); draw_zoom = 1.0; edit_draw->set_clip_contents(true); @@ -1007,31 +1037,35 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { edit_draw->add_child(zoom_hb); zoom_hb->set_begin(Point2(5, 5)); - zoom_out = memnew(ToolButton); + zoom_out = memnew(Button); + zoom_out->set_flat(true); zoom_out->set_tooltip(TTR("Zoom Out")); - zoom_out->connect("pressed", this, "_zoom_out"); + zoom_out->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_out)); zoom_hb->add_child(zoom_out); - zoom_reset = memnew(ToolButton); + zoom_reset = memnew(Button); + zoom_reset->set_flat(true); zoom_reset->set_tooltip(TTR("Zoom Reset")); - zoom_reset->connect("pressed", this, "_zoom_reset"); + zoom_reset->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_reset)); zoom_hb->add_child(zoom_reset); - zoom_in = memnew(ToolButton); + zoom_in = memnew(Button); + zoom_in->set_flat(true); zoom_in->set_tooltip(TTR("Zoom In")); - zoom_in->connect("pressed", this, "_zoom_in"); + zoom_in->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_in)); zoom_hb->add_child(zoom_in); vscroll = memnew(VScrollBar); vscroll->set_step(0.001); edit_draw->add_child(vscroll); - vscroll->connect("value_changed", this, "_scroll_changed"); + vscroll->connect("value_changed", callable_mp(this, &TextureRegionEditor::_scroll_changed)); hscroll = memnew(HScrollBar); hscroll->set_step(0.001); edit_draw->add_child(hscroll); - hscroll->connect("value_changed", this, "_scroll_changed"); + hscroll->connect("value_changed", callable_mp(this, &TextureRegionEditor::_scroll_changed)); updating_scroll = false; + autoslice_is_dirty = true; } void TextureRegionEditorPlugin::edit(Object *p_object) { @@ -1039,7 +1073,7 @@ void TextureRegionEditorPlugin::edit(Object *p_object) { } bool TextureRegionEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("Sprite") || p_object->is_class("Sprite3D") || p_object->is_class("NinePatchRect") || p_object->is_class("StyleBoxTexture") || p_object->is_class("AtlasTexture"); + return p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D") || p_object->is_class("NinePatchRect") || p_object->is_class("StyleBoxTexture") || p_object->is_class("AtlasTexture"); } void TextureRegionEditorPlugin::_editor_visiblity_changed() { @@ -1059,12 +1093,11 @@ void TextureRegionEditorPlugin::make_visible(bool p_visible) { manually_hidden = false; } texture_region_button->hide(); - region_editor->edit(NULL); + region_editor->edit(nullptr); } } Dictionary TextureRegionEditorPlugin::get_state() const { - Dictionary state; state["snap_offset"] = region_editor->snap_offset; state["snap_step"] = region_editor->snap_step; @@ -1074,7 +1107,6 @@ Dictionary TextureRegionEditorPlugin::get_state() const { } void TextureRegionEditorPlugin::set_state(const Dictionary &p_state) { - Dictionary state = p_state; if (state.has("snap_step")) { Vector2 s = state["snap_step"]; @@ -1104,7 +1136,6 @@ void TextureRegionEditorPlugin::set_state(const Dictionary &p_state) { } void TextureRegionEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("_editor_visiblity_changed"), &TextureRegionEditorPlugin::_editor_visiblity_changed); } TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { @@ -1114,7 +1145,7 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { region_editor = memnew(TextureRegionEditor(p_node)); region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); region_editor->hide(); - region_editor->connect("visibility_changed", this, "_editor_visiblity_changed"); + region_editor->connect("visibility_changed", callable_mp(this, &TextureRegionEditorPlugin::_editor_visiblity_changed)); texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor); texture_region_button->hide(); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index d877cf9436..e9f58006a4 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -34,7 +34,7 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" #include "scene/3d/sprite_3d.h" #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" @@ -45,7 +45,6 @@ */ class TextureRegionEditor : public VBoxContainer { - GDCLASS(TextureRegionEditor, VBoxContainer); enum SnapMode { @@ -57,9 +56,9 @@ class TextureRegionEditor : public VBoxContainer { friend class TextureRegionEditorPlugin; OptionButton *snap_mode_button; - ToolButton *zoom_in; - ToolButton *zoom_reset; - ToolButton *zoom_out; + Button *zoom_in; + Button *zoom_reset; + Button *zoom_out; HBoxContainer *hb_grid; //For showing/hiding the grid controls when changing the SnapMode SpinBox *sb_step_y; SpinBox *sb_step_x; @@ -84,7 +83,7 @@ class TextureRegionEditor : public VBoxContainer { Vector2 snap_step; Vector2 snap_separation; - Sprite *node_sprite; + Sprite2D *node_sprite; Sprite3D *node_sprite_3d; NinePatchRect *node_ninepatch; Ref<StyleBoxTexture> obj_styleBox; @@ -94,7 +93,7 @@ class TextureRegionEditor : public VBoxContainer { Rect2 rect_prev; float prev_margin; int edited_margin; - Map<RID, List<Rect2> > cache_map; + Map<RID, List<Rect2>> cache_map; List<Rect2> autoslice_cache; bool autoslice_is_dirty; @@ -125,7 +124,7 @@ protected: Vector2 snap_point(Vector2 p_target) const; - virtual void _changed_callback(Object *p_changed, const char *p_prop); + virtual void _changed_callback(Object *p_changed, const char *p_prop) override; public: void _edit_region(); @@ -136,7 +135,7 @@ public: bool is_atlas_texture(); bool is_ninepatch(); Sprite3D *get_sprite_3d(); - Sprite *get_sprite(); + Sprite2D *get_sprite(); void edit(Object *p_obj); TextureRegionEditor(EditorNode *p_editor); @@ -156,13 +155,13 @@ protected: void _editor_visiblity_changed(); public: - virtual String get_name() const { return "TextureRegion"; } - 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); - void set_state(const Dictionary &p_state); - Dictionary get_state() const; + virtual String get_name() const override { return "TextureRegion"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + void set_state(const Dictionary &p_state) override; + Dictionary get_state() const override; TextureRegionEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 22105f7ed4..932ded6938 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -36,52 +36,55 @@ #include "scene/gui/progress_bar.h" void ThemeEditor::edit(const Ref<Theme> &p_theme) { - theme = p_theme; main_panel->set_theme(p_theme); main_container->set_theme(p_theme); } void ThemeEditor::_propagate_redraw(Control *p_at) { - p_at->notification(NOTIFICATION_THEME_CHANGED); p_at->minimum_size_changed(); p_at->update(); for (int i = 0; i < p_at->get_child_count(); i++) { Control *a = Object::cast_to<Control>(p_at->get_child(i)); - if (a) + if (a) { _propagate_redraw(a); + } } } void ThemeEditor::_refresh_interval() { - _propagate_redraw(main_panel); _propagate_redraw(main_container); } void ThemeEditor::_type_menu_cbk(int p_option) { - type_edit->set_text(type_menu->get_popup()->get_item_text(p_option)); } void ThemeEditor::_name_menu_about_to_show() { - String fromtype = type_edit->get_text(); List<StringName> names; if (popup_mode == POPUP_ADD) { - switch (type_select->get_selected()) { - - case 0: Theme::get_default()->get_icon_list(fromtype, &names); break; - case 1: Theme::get_default()->get_stylebox_list(fromtype, &names); break; - case 2: Theme::get_default()->get_font_list(fromtype, &names); break; - case 3: Theme::get_default()->get_color_list(fromtype, &names); break; - case 4: Theme::get_default()->get_constant_list(fromtype, &names); break; + case 0: + Theme::get_default()->get_icon_list(fromtype, &names); + break; + case 1: + Theme::get_default()->get_stylebox_list(fromtype, &names); + break; + case 2: + Theme::get_default()->get_font_list(fromtype, &names); + break; + case 3: + Theme::get_default()->get_color_list(fromtype, &names); + break; + case 4: + Theme::get_default()->get_constant_list(fromtype, &names); + break; } } else if (popup_mode == POPUP_REMOVE) { - theme->get_icon_list(fromtype, &names); theme->get_stylebox_list(fromtype, &names); theme->get_font_list(fromtype, &names); @@ -92,21 +95,17 @@ void ThemeEditor::_name_menu_about_to_show() { name_menu->get_popup()->clear(); name_menu->get_popup()->set_size(Size2()); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - name_menu->get_popup()->add_item(E->get()); } } void ThemeEditor::_name_menu_cbk(int p_option) { - name_edit->set_text(name_menu->get_popup()->get_item_text(p_option)); } struct _TECategory { - template <class T> struct RefItem { - Ref<T> item; StringName name; bool operator<(const RefItem<T> &p) const { return item->get_instance_id() < p.item->get_instance_id(); } @@ -114,22 +113,20 @@ struct _TECategory { template <class T> struct Item { - T item; String name; bool operator<(const Item<T> &p) const { return name < p.name; } }; - Set<RefItem<StyleBox> > stylebox_items; - Set<RefItem<Font> > font_items; - Set<RefItem<Texture> > icon_items; + Set<RefItem<StyleBox>> stylebox_items; + Set<RefItem<Font>> font_items; + Set<RefItem<Texture2D>> icon_items; - Set<Item<Color> > color_items; - Set<Item<int> > constant_items; + Set<Item<Color>> color_items; + Set<Item<int>> constant_items; }; void ThemeEditor::_save_template_cbk(String fname) { - String filename = file_dialog->get_current_path(); Map<String, _TECategory> categories; @@ -143,7 +140,6 @@ void ThemeEditor::_save_template_cbk(String fname) { // Fill default theme. for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) { - _TECategory &tc = E->get(); List<StringName> stylebox_list; @@ -167,7 +163,7 @@ void ThemeEditor::_save_template_cbk(String fname) { List<StringName> icon_list; Theme::get_default()->get_icon_list(E->key(), &icon_list); for (List<StringName>::Element *F = icon_list.front(); F; F = F->next()) { - _TECategory::RefItem<Texture> it; + _TECategory::RefItem<Texture2D> it; it.name = F->get(); it.item = Theme::get_default()->get_icon(F->get(), E->key()); tc.icon_items.insert(it); @@ -210,8 +206,8 @@ void ThemeEditor::_save_template_cbk(String fname) { file->store_line("; [value] examples:"); file->store_line("; "); file->store_line("; Type.item = 6 ; numeric constant. "); - file->store_line("; Type.item = #FF00FF ; HTML color "); - file->store_line("; Type.item = #55FF00FF ; HTML color with alpha 55."); + file->store_line("; Type.item = #FF00FF ; HTML color (magenta)."); + file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55)."); file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file)."); file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file)."); file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file)."); @@ -260,55 +256,55 @@ void ThemeEditor::_save_template_cbk(String fname) { // Write default theme. for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) { - _TECategory &tc = E->get(); String underline = "; "; - for (int i = 0; i < E->key().length(); i++) + for (int i = 0; i < E->key().length(); i++) { underline += "*"; + } file->store_line(""); file->store_line(underline); file->store_line("; " + E->key()); file->store_line(underline); - if (tc.stylebox_items.size()) + if (tc.stylebox_items.size()) { file->store_line("\n; StyleBox Items:\n"); + } - for (Set<_TECategory::RefItem<StyleBox> >::Element *F = tc.stylebox_items.front(); F; F = F->next()) { - + for (Set<_TECategory::RefItem<StyleBox>>::Element *F = tc.stylebox_items.front(); F; F = F->next()) { file->store_line(E->key() + "." + F->get().name + " = default"); } - if (tc.font_items.size()) + if (tc.font_items.size()) { file->store_line("\n; Font Items:\n"); + } - for (Set<_TECategory::RefItem<Font> >::Element *F = tc.font_items.front(); F; F = F->next()) { - + for (Set<_TECategory::RefItem<Font>>::Element *F = tc.font_items.front(); F; F = F->next()) { file->store_line(E->key() + "." + F->get().name + " = default"); } - if (tc.icon_items.size()) + if (tc.icon_items.size()) { file->store_line("\n; Icon Items:\n"); + } - for (Set<_TECategory::RefItem<Texture> >::Element *F = tc.icon_items.front(); F; F = F->next()) { - + for (Set<_TECategory::RefItem<Texture2D>>::Element *F = tc.icon_items.front(); F; F = F->next()) { file->store_line(E->key() + "." + F->get().name + " = default"); } - if (tc.color_items.size()) + if (tc.color_items.size()) { file->store_line("\n; Color Items:\n"); + } - for (Set<_TECategory::Item<Color> >::Element *F = tc.color_items.front(); F; F = F->next()) { - + for (Set<_TECategory::Item<Color>>::Element *F = tc.color_items.front(); F; F = F->next()) { file->store_line(E->key() + "." + F->get().name + " = default"); } - if (tc.constant_items.size()) + if (tc.constant_items.size()) { file->store_line("\n; Constant Items:\n"); + } - for (Set<_TECategory::Item<int> >::Element *F = tc.constant_items.front(); F; F = F->next()) { - + for (Set<_TECategory::Item<int>>::Element *F = tc.constant_items.front(); F; F = F->next()) { file->store_line(E->key() + "." + F->get().name + " = default"); } } @@ -318,22 +314,28 @@ void ThemeEditor::_save_template_cbk(String fname) { } void ThemeEditor::_dialog_cbk() { - switch (popup_mode) { case POPUP_ADD: { - switch (type_select->get_selected()) { - - case 0: theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture>()); break; - case 1: theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>()); break; - case 2: theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>()); break; - case 3: theme->set_color(name_edit->get_text(), type_edit->get_text(), Color()); break; - case 4: theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0); break; + case 0: + theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture2D>()); + break; + case 1: + theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>()); + break; + case 2: + theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>()); + break; + case 3: + theme->set_color(name_edit->get_text(), type_edit->get_text(), Color()); + break; + case 4: + theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0); + break; } } break; case POPUP_CLASS_ADD: { - StringName fromtype = type_edit->get_text(); List<StringName> names; @@ -341,7 +343,7 @@ void ThemeEditor::_dialog_cbk() { names.clear(); Theme::get_default()->get_icon_list(fromtype, &names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - theme->set_icon(E->get(), fromtype, Ref<Texture>()); + theme->set_icon(E->get(), fromtype, Ref<Texture2D>()); } } { @@ -375,12 +377,21 @@ void ThemeEditor::_dialog_cbk() { } break; case POPUP_REMOVE: { switch (type_select->get_selected()) { - - case 0: theme->clear_icon(name_edit->get_text(), type_edit->get_text()); break; - case 1: theme->clear_stylebox(name_edit->get_text(), type_edit->get_text()); break; - case 2: theme->clear_font(name_edit->get_text(), type_edit->get_text()); break; - case 3: theme->clear_color(name_edit->get_text(), type_edit->get_text()); break; - case 4: theme->clear_constant(name_edit->get_text(), type_edit->get_text()); break; + case 0: + theme->clear_icon(name_edit->get_text(), type_edit->get_text()); + break; + case 1: + theme->clear_stylebox(name_edit->get_text(), type_edit->get_text()); + break; + case 2: + theme->clear_font(name_edit->get_text(), type_edit->get_text()); + break; + case 3: + theme->clear_color(name_edit->get_text(), type_edit->get_text()); + break; + case 4: + theme->clear_constant(name_edit->get_text(), type_edit->get_text()); + break; } } break; @@ -429,9 +440,7 @@ void ThemeEditor::_dialog_cbk() { } void ThemeEditor::_theme_menu_cbk(int p_option) { - if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) { - bool import = (p_option == POPUP_IMPORT_EDITOR_THEME); Ref<Theme> base_theme; @@ -443,7 +452,6 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { } { - List<StringName> types; base_theme->get_type_list(&types); @@ -454,7 +462,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { base_theme->get_icon_list(type, &icons); for (List<StringName>::Element *E = icons.front(); E; E = E->next()) { - theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture>()); + theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>()); } List<StringName> shaders; @@ -525,7 +533,6 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { type_select->hide(); } else if (p_option == POPUP_REMOVE) { - add_del_dialog->set_title(TTR("Remove Item")); add_del_dialog->get_ok()->set_text(TTR("Remove")); add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE); @@ -533,7 +540,6 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { base_theme = theme; } else if (p_option == POPUP_CLASS_REMOVE) { - add_del_dialog->set_title(TTR("Remove All Items")); add_del_dialog->get_ok()->set_text(TTR("Remove All")); add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE); @@ -559,30 +565,27 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { List<StringName> new_types; theme->get_type_list(&new_types); for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) { - bool found = false; for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - if (E->get() == F->get()) { found = true; break; } } - if (!found) + if (!found) { types.push_back(F->get()); + } } } types.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - type_menu->get_popup()->add_item(E->get()); } } void ThemeEditor::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_PROCESS: { time_left -= get_process_delta_time(); @@ -592,23 +595,15 @@ void ThemeEditor::_notification(int p_what) { } } break; case NOTIFICATION_THEME_CHANGED: { - theme_menu->set_icon(get_icon("Theme", "EditorIcons")); + theme_menu->set_icon(get_theme_icon("Theme", "EditorIcons")); } break; } } void ThemeEditor::_bind_methods() { - - ClassDB::bind_method("_type_menu_cbk", &ThemeEditor::_type_menu_cbk); - ClassDB::bind_method("_name_menu_about_to_show", &ThemeEditor::_name_menu_about_to_show); - ClassDB::bind_method("_name_menu_cbk", &ThemeEditor::_name_menu_cbk); - ClassDB::bind_method("_theme_menu_cbk", &ThemeEditor::_theme_menu_cbk); - ClassDB::bind_method("_dialog_cbk", &ThemeEditor::_dialog_cbk); - ClassDB::bind_method("_save_template_cbk", &ThemeEditor::_save_template_cbk); } ThemeEditor::ThemeEditor() { - time_left = 0; HBoxContainer *top_menu = memnew(HBoxContainer); @@ -629,12 +624,12 @@ ThemeEditor::ThemeEditor() { theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY); theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME); top_menu->add_child(theme_menu); - theme_menu->get_popup()->connect("id_pressed", this, "_theme_menu_cbk"); + theme_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_menu_cbk)); ScrollContainer *scroll = memnew(ScrollContainer); add_child(scroll); scroll->set_enable_v_scroll(true); - scroll->set_enable_h_scroll(false); + scroll->set_enable_h_scroll(true); scroll->set_v_size_flags(SIZE_EXPAND_FILL); MarginContainer *root_container = memnew(MarginContainer); @@ -652,10 +647,10 @@ ThemeEditor::ThemeEditor() { main_container = memnew(MarginContainer); root_container->add_child(main_container); - main_container->add_constant_override("margin_right", 4 * EDSCALE); - main_container->add_constant_override("margin_top", 4 * EDSCALE); - main_container->add_constant_override("margin_left", 4 * EDSCALE); - main_container->add_constant_override("margin_bottom", 4 * EDSCALE); + main_container->add_theme_constant_override("margin_right", 4 * EDSCALE); + main_container->add_theme_constant_override("margin_top", 4 * EDSCALE); + main_container->add_theme_constant_override("margin_left", 4 * EDSCALE); + main_container->add_theme_constant_override("margin_bottom", 4 * EDSCALE); HBoxContainer *main_hb = memnew(HBoxContainer); main_container->add_child(main_hb); @@ -663,7 +658,7 @@ ThemeEditor::ThemeEditor() { VBoxContainer *first_vb = memnew(VBoxContainer); main_hb->add_child(first_vb); first_vb->set_h_size_flags(SIZE_EXPAND_FILL); - first_vb->add_constant_override("separation", 10 * EDSCALE); + first_vb->add_theme_constant_override("separation", 10 * EDSCALE); first_vb->add_child(memnew(Label("Label"))); @@ -677,8 +672,9 @@ ThemeEditor::ThemeEditor() { bt->set_text(TTR("Disabled Button")); bt->set_disabled(true); first_vb->add_child(bt); - ToolButton *tb = memnew(ToolButton); - tb->set_text("ToolButton"); + Button *tb = memnew(Button); + tb->set_flat(true); + tb->set_text("Button"); first_vb->add_child(tb); CheckButton *cb = memnew(CheckButton); @@ -723,7 +719,7 @@ ThemeEditor::ThemeEditor() { VBoxContainer *second_vb = memnew(VBoxContainer); second_vb->set_h_size_flags(SIZE_EXPAND_FILL); main_hb->add_child(second_vb); - second_vb->add_constant_override("separation", 10 * EDSCALE); + second_vb->add_theme_constant_override("separation", 10 * EDSCALE); LineEdit *le = memnew(LineEdit); le->set_text("LineEdit"); second_vb->add_child(le); @@ -763,7 +759,7 @@ ThemeEditor::ThemeEditor() { VBoxContainer *third_vb = memnew(VBoxContainer); third_vb->set_h_size_flags(SIZE_EXPAND_FILL); - third_vb->add_constant_override("separation", 10 * EDSCALE); + third_vb->add_theme_constant_override("separation", 10 * EDSCALE); main_hb->add_child(third_vb); TabContainer *tc = memnew(TabContainer); @@ -783,7 +779,7 @@ ThemeEditor::ThemeEditor() { Tree *test_tree = memnew(Tree); third_vb->add_child(test_tree); test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE); - test_tree->add_constant_override("draw_relationship_lines", 1); + test_tree->add_theme_constant_override("draw_relationship_lines", 1); TreeItem *item = test_tree->create_item(); item->set_text(0, "Tree"); @@ -809,7 +805,7 @@ ThemeEditor::ThemeEditor() { item->set_text(0, TTR("Has,Many,Options")); item->set_range(0, 2); - main_hb->add_constant_override("separation", 20 * EDSCALE); + main_hb->add_theme_constant_override("separation", 20 * EDSCALE); //////// @@ -832,10 +828,10 @@ ThemeEditor::ThemeEditor() { type_hbc->add_child(type_edit); type_menu = memnew(MenuButton); type_menu->set_flat(false); - type_menu->set_text(".."); + type_menu->set_text("..."); type_hbc->add_child(type_menu); - type_menu->get_popup()->connect("id_pressed", this, "_type_menu_cbk"); + type_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_type_menu_cbk)); l = memnew(Label); l->set_text(TTR("Name:")); @@ -850,11 +846,11 @@ ThemeEditor::ThemeEditor() { name_hbc->add_child(name_edit); name_menu = memnew(MenuButton); type_menu->set_flat(false); - name_menu->set_text(".."); + name_menu->set_text("..."); name_hbc->add_child(name_menu); - name_menu->get_popup()->connect("about_to_show", this, "_name_menu_about_to_show"); - name_menu->get_popup()->connect("id_pressed", this, "_name_menu_cbk"); + name_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ThemeEditor::_name_menu_about_to_show)); + name_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_name_menu_cbk)); type_select_label = memnew(Label); type_select_label->set_text(TTR("Data Type:")); @@ -869,16 +865,15 @@ ThemeEditor::ThemeEditor() { dialog_vbc->add_child(type_select); - add_del_dialog->get_ok()->connect("pressed", this, "_dialog_cbk"); + add_del_dialog->get_ok()->connect("pressed", callable_mp(this, &ThemeEditor::_dialog_cbk)); file_dialog = memnew(EditorFileDialog); file_dialog->add_filter("*.theme ; " + TTR("Theme File")); add_child(file_dialog); - file_dialog->connect("file_selected", this, "_save_template_cbk"); + file_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_save_template_cbk)); } void ThemeEditorPlugin::edit(Object *p_node) { - if (Object::cast_to<Theme>(p_node)) { theme_editor->edit(Object::cast_to<Theme>(p_node)); } else { @@ -887,27 +882,25 @@ void ThemeEditorPlugin::edit(Object *p_node) { } bool ThemeEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("Theme"); } void ThemeEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { theme_editor->set_process(true); button->show(); editor->make_bottom_panel_item_visible(theme_editor); } else { theme_editor->set_process(false); - if (theme_editor->is_visible_in_tree()) + if (theme_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } button->hide(); } } ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) { - editor = p_node; theme_editor = memnew(ThemeEditor); theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index c51583593d..e374dd8714 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -42,7 +42,6 @@ #include "editor/editor_node.h" class ThemeEditor : public VBoxContainer { - GDCLASS(ThemeEditor, VBoxContainer); Panel *main_panel; @@ -99,7 +98,6 @@ public: }; class ThemeEditorPlugin : public EditorPlugin { - GDCLASS(ThemeEditorPlugin, EditorPlugin); ThemeEditor *theme_editor; @@ -107,11 +105,11 @@ class ThemeEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "Theme"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); + virtual String get_name() const override { return "Theme"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_node) override; + virtual bool handles(Object *p_node) const override; + virtual void make_visible(bool p_visible) override; ThemeEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index f889228f87..8cd8aaf277 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -31,63 +31,72 @@ #include "tile_map_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "core/input/input.h" #include "core/math/math_funcs.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "scene/gui/split_container.h" -void TileMapEditor::_notification(int p_what) { +void TileMapEditor::_node_removed(Node *p_node) { + if (p_node == node) { + node = nullptr; + } +} +void TileMapEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_PROCESS: { - if (bucket_queue.size()) { CanvasItemEditor::get_singleton()->update_viewport(); } } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + case NOTIFICATION_ENTER_TREE: { + get_tree()->connect("node_removed", callable_mp(this, &TileMapEditor::_node_removed)); + [[fallthrough]]; + } + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (is_visible_in_tree()) { _update_palette(); } - FALLTHROUGH; - } - - case NOTIFICATION_ENTER_TREE: { - paint_button->set_icon(get_icon("Edit", "EditorIcons")); - bucket_fill_button->set_icon(get_icon("Bucket", "EditorIcons")); - picker_button->set_icon(get_icon("ColorPick", "EditorIcons")); - select_button->set_icon(get_icon("ActionCopy", "EditorIcons")); + paint_button->set_icon(get_theme_icon("Edit", "EditorIcons")); + line_button->set_icon(get_theme_icon("CurveLinear", "EditorIcons")); + rectangle_button->set_icon(get_theme_icon("RectangleShape2D", "EditorIcons")); + bucket_fill_button->set_icon(get_theme_icon("Bucket", "EditorIcons")); + picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons")); + select_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons")); - rotate_left_button->set_icon(get_icon("RotateLeft", "EditorIcons")); - rotate_right_button->set_icon(get_icon("RotateRight", "EditorIcons")); - flip_horizontal_button->set_icon(get_icon("MirrorX", "EditorIcons")); - flip_vertical_button->set_icon(get_icon("MirrorY", "EditorIcons")); - clear_transform_button->set_icon(get_icon("Clear", "EditorIcons")); + rotate_left_button->set_icon(get_theme_icon("RotateLeft", "EditorIcons")); + rotate_right_button->set_icon(get_theme_icon("RotateRight", "EditorIcons")); + flip_horizontal_button->set_icon(get_theme_icon("MirrorX", "EditorIcons")); + flip_vertical_button->set_icon(get_theme_icon("MirrorY", "EditorIcons")); + clear_transform_button->set_icon(get_theme_icon("Clear", "EditorIcons")); - search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); search_box->set_clear_button_enabled(true); PopupMenu *p = options->get_popup(); - p->set_item_icon(p->get_item_index(OPTION_CUT), get_icon("ActionCut", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_COPY), get_icon("Duplicate", "EditorIcons")); - p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_CUT), get_theme_icon("ActionCut", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_COPY), get_theme_icon("Duplicate", "EditorIcons")); + p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_theme_icon("Remove", "EditorIcons")); + + } break; + case NOTIFICATION_EXIT_TREE: { + get_tree()->disconnect("node_removed", callable_mp(this, &TileMapEditor::_node_removed)); } break; } } void TileMapEditor::_update_button_tool() { + Button *tb[6] = { paint_button, line_button, rectangle_button, bucket_fill_button, picker_button, select_button }; - ToolButton *tb[4] = { paint_button, bucket_fill_button, picker_button, select_button }; // Unpress all buttons - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 6; i++) { tb[i]->set_pressed(false); } @@ -97,6 +106,12 @@ void TileMapEditor::_update_button_tool() { case TOOL_PAINTING: { paint_button->set_pressed(true); } break; + case TOOL_LINE_PAINT: { + line_button->set_pressed(true); + } break; + case TOOL_RECTANGLE_PAINT: { + rectangle_button->set_pressed(true); + } break; case TOOL_BUCKET: { bucket_fill_button->set_pressed(true); } break; @@ -110,8 +125,9 @@ void TileMapEditor::_update_button_tool() { break; } - if (tool != TOOL_PICKING) + if (tool != TOOL_PICKING) { last_tool = tool; + } } void TileMapEditor::_button_tool_select(int p_tool) { @@ -119,7 +135,6 @@ void TileMapEditor::_button_tool_select(int p_tool) { _update_button_tool(); switch (tool) { case TOOL_SELECTING: { - selection_active = false; } break; default: @@ -129,10 +144,8 @@ void TileMapEditor::_button_tool_select(int p_tool) { } void TileMapEditor::_menu_option(int p_option) { - switch (p_option) { case OPTION_COPY: { - _update_copydata(); if (selection_active) { @@ -142,9 +155,9 @@ void TileMapEditor::_menu_option(int p_option) { } } break; case OPTION_ERASE_SELECTION: { - - if (!selection_active) + if (!selection_active) { return; + } _start_undo(TTR("Erase Selection")); _erase_selection(); @@ -156,7 +169,6 @@ void TileMapEditor::_menu_option(int p_option) { CanvasItemEditor::get_singleton()->update_viewport(); } break; case OPTION_FIX_INVALID: { - undo_redo->create_action(TTR("Fix Invalid Tiles")); undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); node->fix_invalid_tiles(); @@ -165,7 +177,6 @@ void TileMapEditor::_menu_option(int p_option) { } break; case OPTION_CUT: { - if (selection_active) { _update_copydata(); @@ -192,20 +203,32 @@ void TileMapEditor::_palette_multi_selected(int index, bool selected) { _update_palette(); } -void TileMapEditor::_canvas_mouse_enter() { +void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) { + const Ref<InputEventMouseButton> mb = p_event; + + // Zoom in/out using Ctrl + mouse wheel. + if (mb.is_valid() && mb->is_pressed() && mb->get_command()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) { + size_slider->set_value(size_slider->get_value() + 0.2); + } + + if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) { + size_slider->set_value(size_slider->get_value() - 0.2); + } + } +} +void TileMapEditor::_canvas_mouse_enter() { mouse_over = true; CanvasItemEditor::get_singleton()->update_viewport(); } void TileMapEditor::_canvas_mouse_exit() { - mouse_over = false; CanvasItemEditor::get_singleton()->update_viewport(); } Vector<int> TileMapEditor::get_selected_tiles() const { - Vector<int> items = palette->get_selected_items(); if (items.size() == 0) { @@ -220,7 +243,6 @@ Vector<int> TileMapEditor::get_selected_tiles() const { } void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) { - palette->unselect_all(); for (int i = p_tiles.size() - 1; i >= 0; i--) { @@ -235,7 +257,6 @@ void TileMapEditor::set_selected_tiles(Vector<int> p_tiles) { } Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord) { - Dictionary cell; cell["id"] = tile; @@ -248,7 +269,6 @@ Dictionary TileMapEditor::_create_cell_dictionary(int tile, bool flip_x, bool fl } void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellOp &p_cell_old, const CellOp &p_cell_new) { - Dictionary cell_old = _create_cell_dictionary(p_cell_old.idx, p_cell_old.xf, p_cell_old.yf, p_cell_old.tr, p_cell_old.ac); Dictionary cell_new = _create_cell_dictionary(p_cell_new.idx, p_cell_new.xf, p_cell_new.yf, p_cell_new.tr, p_cell_new.ac); @@ -257,13 +277,11 @@ void TileMapEditor::_create_set_cell_undo_redo(const Vector2 &p_vec, const CellO } void TileMapEditor::_start_undo(const String &p_action) { - undo_data.clear(); undo_redo->create_action(p_action); } void TileMapEditor::_finish_undo() { - if (undo_data.size()) { for (Map<Point2i, CellOp>::Element *E = undo_data.front(); E; E = E->next()) { _create_set_cell_undo_redo(E->key(), E->get(), _get_op_from_cell(E->key())); @@ -276,11 +294,11 @@ void TileMapEditor::_finish_undo() { } void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord) { - ERR_FAIL_COND(!node); - if (p_values.size() == 0) + if (p_values.size() == 0) { return; + } int p_value = p_values[Math::rand() % p_values.size()]; int prev_val = node->get_cell(p_pos.x, p_pos.y); @@ -306,8 +324,9 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p position = prev_position; } - if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position) + if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position) { return; // Check that it's actually different. + } for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) { for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) { @@ -320,8 +339,9 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord)); - if (tool == TOOL_PASTING) + if (tool == TOOL_PASTING) { return; + } if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) { if (current != -1) { @@ -347,7 +367,6 @@ void TileMapEditor::_priority_toggled(bool p_enabled) { } void TileMapEditor::_text_entered(const String &p_text) { - canvas_item_editor_viewport->grab_focus(); } @@ -356,14 +375,12 @@ void TileMapEditor::_text_changed(const String &p_text) { } void TileMapEditor::_sbox_input(const Ref<InputEvent> &p_ie) { - Ref<InputEventKey> k = p_ie; - if (k.is_valid() && (k->get_scancode() == KEY_UP || - k->get_scancode() == KEY_DOWN || - k->get_scancode() == KEY_PAGEUP || - k->get_scancode() == KEY_PAGEDOWN)) { - + if (k.is_valid() && (k->get_keycode() == KEY_UP || + k->get_keycode() == KEY_DOWN || + k->get_keycode() == KEY_PAGEUP || + k->get_keycode() == KEY_PAGEDOWN)) { palette->call("_gui_input", k); search_box->accept_event(); } @@ -383,9 +400,9 @@ struct _PaletteEntry { } // namespace void TileMapEditor::_update_palette() { - - if (!node) + if (!node) { return; + } // Update the clear button. clear_transform_button->set_disabled(!flip_h && !flip_v && !transpose); @@ -411,8 +428,9 @@ void TileMapEditor::_update_palette() { List<int> tiles; tileset->get_tile_list(&tiles); - if (tiles.empty()) + if (tiles.empty()) { return; + } float min_size = EDITOR_DEF("editors/tile_map/preview_size", 64); min_size *= EDSCALE; @@ -421,7 +439,7 @@ void TileMapEditor::_update_palette() { bool show_tile_ids = bool(EDITOR_DEF("editors/tile_map/show_tile_ids", false)); bool sort_by_name = bool(EDITOR_DEF("editors/tile_map/sort_tiles_by_name", true)); - palette->add_constant_override("hseparation", hseparation * EDSCALE); + palette->add_theme_constant_override("hseparation", hseparation * EDSCALE); palette->set_fixed_icon_size(Size2(min_size, min_size)); palette->set_fixed_column_width(min_size * MAX(size_slider->get_value(), 1)); @@ -434,7 +452,6 @@ void TileMapEditor::_update_palette() { Vector<_PaletteEntry> entries; for (List<int>::Element *E = tiles.front(); E; E = E->next()) { - String name = tileset->tile_get_name(E->get()); if (name != "") { @@ -449,8 +466,9 @@ void TileMapEditor::_update_palette() { name = "#" + itos(E->get()); } - if (filter != "" && !filter.is_subsequence_ofi(name)) + if (filter != "" && !filter.is_subsequence_ofi(name)) { continue; + } const _PaletteEntry entry = { E->get(), name }; entries.push_back(entry); @@ -461,14 +479,13 @@ void TileMapEditor::_update_palette() { } for (int i = 0; i < entries.size(); i++) { - if (show_tile_names) { palette->add_item(entries[i].name); } else { palette->add_item(String()); } - Ref<Texture> tex = tileset->tile_get_texture(entries[i].id); + Ref<Texture2D> tex = tileset->tile_get_texture(entries[i].id); if (tex.is_valid()) { Rect2 region = tileset->tile_get_region(entries[i].id); @@ -489,8 +506,9 @@ void TileMapEditor::_update_palette() { } // Set region. - if (region.size != Size2()) + if (region.size != Size2()) { palette->set_item_icon_region(palette->get_item_count() - 1, region); + } // Set icon. palette->set_item_icon(palette->get_item_count() - 1, tex); @@ -513,7 +531,6 @@ void TileMapEditor::_update_palette() { } if (sel_tile != TileMap::INVALID_CELL && ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE))) { - const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile); Vector<Vector2> entries2; @@ -528,21 +545,20 @@ void TileMapEditor::_update_palette() { }; entries2.sort_custom<SwapComparator>(); - Ref<Texture> tex = tileset->tile_get_texture(sel_tile); + Ref<Texture2D> tex = tileset->tile_get_texture(sel_tile); for (int i = 0; i < entries2.size(); i++) { - manual_palette->add_item(String()); if (tex.is_valid()) { - 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)) * entries2[i]; - if (!region.has_no_area()) + if (!region.has_no_area()) { manual_palette->set_item_icon_region(manual_palette->get_item_count() - 1, region); + } manual_palette->set_item_icon(manual_palette->get_item_count() - 1, tex); } @@ -553,10 +569,12 @@ void TileMapEditor::_update_palette() { if (manual_palette->get_item_count() > 0) { // Only show the manual palette if at least tile exists in it. - if (selected_manual == -1 || selected_single != palette->get_current()) + if (selected_manual == -1 || selected_single != palette->get_current()) { selected_manual = 0; - if (selected_manual < manual_palette->get_item_count()) + } + if (selected_manual < manual_palette->get_item_count()) { manual_palette->set_current(selected_manual); + } manual_palette->show(); } @@ -570,11 +588,11 @@ void TileMapEditor::_update_palette() { } void TileMapEditor::_pick_tile(const Point2 &p_pos) { - int id = node->get_cell(p_pos.x, p_pos.y); - if (id == TileMap::INVALID_CELL) + if (id == TileMap::INVALID_CELL) { return; + } if (search_box->get_text() != "") { search_box->set_text(""); @@ -598,23 +616,23 @@ void TileMapEditor::_pick_tile(const Point2 &p_pos) { CanvasItemEditor::get_singleton()->update_viewport(); } -PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) { - +Vector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) { int prev_id = node->get_cell(p_start.x, p_start.y); Vector<int> ids; ids.push_back(TileMap::INVALID_CELL); if (!erase) { ids = get_selected_tiles(); - if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL) - return PoolVector<Vector2>(); + if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL) { + return Vector<Vector2>(); + } } else if (prev_id == TileMap::INVALID_CELL) { - return PoolVector<Vector2>(); + return Vector<Vector2>(); } if (ids.size() == 1 && ids[0] == prev_id) { // Same ID, nothing to change - return PoolVector<Vector2>(); + return Vector<Vector2>(); } Rect2i r = node->get_used_rect(); @@ -624,10 +642,11 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era // Test if we can re-use the result from preview bucket fill bool invalidate_cache = false; // Area changed - if (r != bucket_cache_rect) + if (r != bucket_cache_rect) { _clear_bucket_cache(); + } // Cache grid is not initialized - if (bucket_cache_visited == NULL) { + if (bucket_cache_visited == nullptr) { bucket_cache_visited = new bool[area]; invalidate_cache = true; } @@ -638,16 +657,17 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era invalidate_cache = true; } if (invalidate_cache) { - for (int i = 0; i < area; ++i) + for (int i = 0; i < area; ++i) { bucket_cache_visited[i] = false; - bucket_cache = PoolVector<Vector2>(); + } + bucket_cache = Vector<Vector2>(); bucket_cache_tile = prev_id; bucket_cache_rect = r; bucket_queue.clear(); } } - PoolVector<Vector2> points; + Vector<Vector2> points; Vector<Vector2> non_preview_cache; int count = 0; int limit = 0; @@ -661,24 +681,25 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era bucket_queue.push_back(p_start); while (bucket_queue.size()) { - Point2i n = bucket_queue.front()->get(); bucket_queue.pop_front(); - if (!r.has_point(n)) + if (!r.has_point(n)) { continue; + } if (node->get_cell(n.x, n.y) == prev_id) { - if (preview) { int loc = (n.x - r.position.x) + (n.y - r.position.y) * r.get_size().x; - if (bucket_cache_visited[loc]) + if (bucket_cache_visited[loc]) { continue; + } bucket_cache_visited[loc] = true; bucket_cache.push_back(n); } else { - if (non_preview_cache.find(n) >= 0) + if (non_preview_cache.find(n) >= 0) { continue; + } points.push_back(n); non_preview_cache.push_back(n); } @@ -698,10 +719,9 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era return preview ? bucket_cache : points; } -void TileMapEditor::_fill_points(const PoolVector<Vector2> &p_points, const Dictionary &p_op) { - +void TileMapEditor::_fill_points(const Vector<Vector2> &p_points, const Dictionary &p_op) { int len = p_points.size(); - PoolVector<Vector2>::Read pr = p_points.read(); + const Vector2 *pr = p_points.ptr(); Vector<int> ids = p_op["id"]; bool xf = p_op["flip_h"]; @@ -712,32 +732,28 @@ void TileMapEditor::_fill_points(const PoolVector<Vector2> &p_points, const Dict _set_cell(pr[i], ids, xf, yf, tr); node->make_bitmask_area_dirty(pr[i]); } - if (!manual_autotile) + if (!manual_autotile) { node->update_dirty_bitmask(); + } } -void TileMapEditor::_erase_points(const PoolVector<Vector2> &p_points) { - +void TileMapEditor::_erase_points(const Vector<Vector2> &p_points) { int len = p_points.size(); - PoolVector<Vector2>::Read pr = p_points.read(); + const Vector2 *pr = p_points.ptr(); for (int i = 0; i < len; i++) { - _set_cell(pr[i], invalid_cell); } } void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) { - Point2i begin = p_from; Point2i end = p_to; if (begin.x > end.x) { - SWAP(begin.x, end.x); } if (begin.y > end.y) { - SWAP(begin.y, end.y); } @@ -748,23 +764,23 @@ void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) { } void TileMapEditor::_erase_selection() { - if (!selection_active) + if (!selection_active) { return; + } for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), invalid_cell, false, false, false); } } } void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) { + Ref<Texture2D> t = node->get_tileset()->tile_get_texture(p_cell); - Ref<Texture> t = node->get_tileset()->tile_get_texture(p_cell); - - if (t.is_null()) + if (t.is_null()) { return; + } Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell); @@ -786,7 +802,6 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p r.size = node->get_tileset()->autotile_get_size(p_cell); r.position += (r.size + Vector2(spacing, spacing)) * offset; } - Size2 sc = p_xform.get_scale(); Size2 cell_size = node->get_cell_size(); bool centered_texture = node->is_centered_textures_enabled(); bool compatibility_mode_enabled = node->is_compatibility_mode_enabled(); @@ -801,11 +816,13 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p if (compatibility_mode_enabled && !centered_texture) { if (rect.size.y > rect.size.x) { - if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose)) + if ((p_flip_h && (p_flip_v || p_transpose)) || (p_flip_v && !p_transpose)) { tile_ofs.y += rect.size.y - rect.size.x; + } } else if (rect.size.y < rect.size.x) { - if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose)) + if ((p_flip_v && (p_flip_h || p_transpose)) || (p_flip_h && !p_transpose)) { tile_ofs.x += rect.size.x - rect.size.y; + } } } @@ -820,70 +837,70 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p } if (p_flip_h) { - sc.x *= -1.0; + rect.size.x *= -1.0; tile_ofs.x *= -1.0; } if (p_flip_v) { - sc.y *= -1.0; + rect.size.y *= -1.0; tile_ofs.y *= -1.0; } if (compatibility_mode_enabled && !centered_texture) { if (node->get_tile_origin() == TileMap::TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_BOTTOM_LEFT) { - rect.position += tile_ofs; if (p_transpose) { - if (p_flip_h) + if (p_flip_h) { rect.position.x -= cell_size.x; - else + } else { rect.position.x += cell_size.x; + } } else { - if (p_flip_v) + if (p_flip_v) { rect.position.y -= cell_size.y; - else + } else { rect.position.y += cell_size.y; + } } } else if (node->get_tile_origin() == TileMap::TILE_ORIGIN_CENTER) { - rect.position += tile_ofs; - if (p_flip_h) + if (p_flip_h) { rect.position.x -= cell_size.x / 2; - else + } else { rect.position.x += cell_size.x / 2; + } - if (p_flip_v) + if (p_flip_v) { rect.position.y -= cell_size.y / 2; - else + } else { rect.position.y += cell_size.y / 2; + } } } else { rect.position += tile_ofs; } - rect.position = p_xform.xform(rect.position); - rect.size *= sc; - Color modulate = node->get_tileset()->tile_get_modulate(p_cell); modulate.a = 0.5; + Transform2D old_transform = p_viewport->get_viewport_transform(); + p_viewport->draw_set_transform_matrix(p_xform); // Take into account TileMap transformation when displaying cell if (r.has_no_area()) { p_viewport->draw_texture_rect(t, rect, false, modulate, p_transpose); } else { p_viewport->draw_texture_rect_region(t, rect, r, modulate, p_transpose); } + p_viewport->draw_set_transform_matrix(old_transform); } void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i &p_autotile_coord, const Transform2D &p_xform) { - - PoolVector<Vector2> points = _bucket_fill(p_point, false, true); - PoolVector<Vector2>::Read pr = points.read(); + Vector<Vector2> points = _bucket_fill(p_point, false, true); + const Vector2 *pr = points.ptr(); int len = points.size(); for (int i = 0; i < len; ++i) { @@ -894,21 +911,19 @@ void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Po void TileMapEditor::_clear_bucket_cache() { if (bucket_cache_visited) { delete[] bucket_cache_visited; - bucket_cache_visited = NULL; + bucket_cache_visited = nullptr; } } void TileMapEditor::_update_copydata() { - copydata.clear(); - if (!selection_active) + if (!selection_active) { return; + } for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { - for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - TileData tcd; tcd.cell = node->get_cell(j, i); @@ -926,7 +941,6 @@ void TileMapEditor::_update_copydata() { } static inline Vector<Point2i> line(int x0, int x1, int y0, int y1) { - Vector<Point2i> points; float dx = ABS(x1 - x0); @@ -970,9 +984,9 @@ static inline Vector<Point2i> line(int x0, int x1, int y0, int y1) { } bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { - - if (!node || !node->get_tileset().is_valid() || !node->is_visible_in_tree() || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) + if (!node || !node->get_tileset().is_valid() || !node->is_visible_in_tree() || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) { return false; + } Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform(); Transform2D xform_inv = xform.affine_inverse(); @@ -981,27 +995,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_LEFT) { - if (mb->is_pressed()) { - - if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) + if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) { return false; // Drag. + } if (tool == TOOL_NONE) { - - if (mb->get_shift()) { - - if (mb->get_command()) - tool = TOOL_RECTANGLE_PAINT; - else - tool = TOOL_LINE_PAINT; - - selection_active = false; - rectangle_begin = over_tile; - - _update_button_tool(); - return true; - } + tool = TOOL_PAINTING; + _update_button_tool(); if (mb->get_command()) { tool = TOOL_PICKING; @@ -1010,26 +1011,24 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } - - tool = TOOL_PAINTING; - _update_button_tool(); } - if (tool == TOOL_PAINTING) { + if (tool == TOOL_LINE_PAINT || tool == TOOL_RECTANGLE_PAINT) { + selection_active = false; + rectangle_begin = over_tile; + mouse_down = true; + } else if (tool == TOOL_PAINTING) { Vector<int> ids = get_selected_tiles(); if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - tool = TOOL_PAINTING; _start_undo(TTR("Paint TileMap")); } } else if (tool == TOOL_PICKING) { - _pick_tile(over_tile); } else if (tool == TOOL_SELECTING) { - selection_active = true; rectangle_begin = over_tile; } @@ -1040,27 +1039,25 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else { // Mousebutton was released. if (tool != TOOL_NONE) { - if (tool == TOOL_PAINTING) { - Vector<int> ids = get_selected_tiles(); if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _set_cell(over_tile, ids, flip_h, flip_v, transpose); _finish_undo(); paint_undo.clear(); } } else if (tool == TOOL_LINE_PAINT) { + if (!mouse_down) { + return true; + } Vector<int> ids = get_selected_tiles(); if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _start_undo(TTR("Line Draw")); for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - _set_cell(E->key(), ids, flip_h, flip_v, transpose); } _finish_undo(); @@ -1068,33 +1065,42 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { paint_undo.clear(); CanvasItemEditor::get_singleton()->update_viewport(); + + mouse_down = false; + return true; } + + mouse_down = false; } else if (tool == TOOL_RECTANGLE_PAINT) { + if (!mouse_down) { + return true; + } Vector<int> ids = get_selected_tiles(); if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - _start_undo(TTR("Rectangle Paint")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _set_cell(Point2i(j, i), ids, flip_h, flip_v, transpose); } } _finish_undo(); CanvasItemEditor::get_singleton()->update_viewport(); + + mouse_down = false; + return true; } - } else if (tool == TOOL_PASTING) { + mouse_down = false; + } else if (tool == TOOL_PASTING) { Point2 ofs = over_tile - rectangle.position; Vector<int> ids; _start_undo(TTR("Paste")); ids.push_back(0); for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { - ids.write[0] = E->get().cell; _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose, E->get().autotile_coord); } @@ -1104,15 +1110,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; // We want to keep the Pasting tool. } else if (tool == TOOL_SELECTING) { - CanvasItemEditor::get_singleton()->update_viewport(); } else if (tool == TOOL_BUCKET) { + Vector<Vector2> points = _bucket_fill(over_tile); - PoolVector<Vector2> points = _bucket_fill(over_tile); - - if (points.size() == 0) + if (points.size() == 0) { return false; + } _start_undo(TTR("Bucket Fill")); @@ -1140,11 +1145,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } } } else if (mb->get_button_index() == BUTTON_RIGHT) { - if (mb->is_pressed()) { - if (tool == TOOL_SELECTING || selection_active) { - tool = TOOL_NONE; selection_active = false; @@ -1155,8 +1157,29 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_PASTING) { - tool = TOOL_NONE; + + CanvasItemEditor::get_singleton()->update_viewport(); + + _update_button_tool(); + return true; + } + + if (tool == TOOL_LINE_PAINT) { + tool = TOOL_LINE_ERASE; + mouse_down = true; + rectangle_begin = over_tile; + + CanvasItemEditor::get_singleton()->update_viewport(); + + _update_button_tool(); + return true; + } + + if (tool == TOOL_RECTANGLE_PAINT) { + tool = TOOL_RECTANGLE_ERASE; + mouse_down = true; + rectangle_begin = over_tile; copydata.clear(); CanvasItemEditor::get_singleton()->update_viewport(); @@ -1166,48 +1189,80 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_NONE) { - paint_undo.clear(); Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); _start_undo(TTR("Erase TileMap")); + tool = TOOL_ERASING; + _set_cell(local, invalid_cell); + + _update_button_tool(); + return true; + } + + } else { + if (tool == TOOL_LINE_ERASE) { + if (!mouse_down) { + return true; + } + + tool = TOOL_LINE_PAINT; + _update_button_tool(); - if (mb->get_shift()) { - if (mb->get_command()) - tool = TOOL_RECTANGLE_ERASE; - else - tool = TOOL_LINE_ERASE; + Vector<int> ids = get_selected_tiles(); + + if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { + _start_undo(TTR("Line Erase")); + for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { + _set_cell(E->key(), invalid_cell, flip_h, flip_v, transpose); + } + _finish_undo(); + paint_undo.clear(); - selection_active = false; - rectangle_begin = local; - } else { + CanvasItemEditor::get_singleton()->update_viewport(); - tool = TOOL_ERASING; + mouse_down = false; + return true; + } - _set_cell(local, invalid_cell); + mouse_down = false; + } else if (tool == TOOL_RECTANGLE_ERASE) { + if (!mouse_down) { + return true; } + tool = TOOL_RECTANGLE_PAINT; _update_button_tool(); - return true; - } - } else { - if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { + Vector<int> ids = get_selected_tiles(); - _finish_undo(); + if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { + _start_undo(TTR("Rectangle Erase")); + for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { + for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { + _set_cell(Point2i(j, i), invalid_cell, flip_h, flip_v, transpose); + } + } + _finish_undo(); + paint_undo.clear(); - if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { CanvasItemEditor::get_singleton()->update_viewport(); + + mouse_down = false; + return true; } - tool = TOOL_NONE; + mouse_down = false; + tool = TOOL_RECTANGLE_PAINT; + } + if (tool == TOOL_ERASING) { + tool = TOOL_NONE; _update_button_tool(); - return true; + return true; } else if (tool == TOOL_BUCKET) { - Vector<int> ids; ids.push_back(node->get_cell(over_tile.x, over_tile.y)); Dictionary pop; @@ -1216,10 +1271,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { pop["flip_v"] = node->is_cell_y_flipped(over_tile.x, over_tile.y); pop["transpose"] = node->is_cell_transposed(over_tile.x, over_tile.y); - PoolVector<Vector2> points = _bucket_fill(over_tile, true); + Vector<Vector2> points = _bucket_fill(over_tile, true); - if (points.size() == 0) + if (points.size() == 0) { return false; + } undo_redo->create_action(TTR("Bucket Fill")); @@ -1235,12 +1291,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - Point2i new_over_tile = node->world_to_map(xform_inv.xform(mm->get_position())); Point2i old_over_tile = over_tile; if (new_over_tile != over_tile) { - over_tile = new_over_tile; CanvasItemEditor::get_singleton()->update_viewport(); } @@ -1248,20 +1302,19 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { int tile_under = node->get_cell(over_tile.x, over_tile.y); String tile_name = "none"; - if (node->get_tileset()->has_tile(tile_under)) + if (node->get_tileset()->has_tile(tile_under)) { tile_name = node->get_tileset()->tile_get_name(tile_under); + } tile_info->show(); tile_info->set_text(String::num(over_tile.x) + ", " + String::num(over_tile.y) + " [" + tile_name + "]"); if (tool == TOOL_PAINTING) { - // Paint using bresenham line to prevent holes in painting if the user moves fast. Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y); Vector<int> ids = get_selected_tiles(); for (int i = 0; i < points.size(); ++i) { - Point2i pos = points[i]; if (!paint_undo.has(pos)) { @@ -1275,13 +1328,11 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_ERASING) { - // Erase using bresenham line to prevent holes in painting if the user moves fast. Vector<Point2i> points = line(old_over_tile.x, over_tile.x, old_over_tile.y, over_tile.y); for (int i = 0; i < points.size(); ++i) { - Point2i pos = points[i]; _set_cell(pos, invalid_cell); @@ -1291,23 +1342,23 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_SELECTING) { - _select(rectangle_begin, over_tile); return true; } if (tool == TOOL_LINE_PAINT || tool == TOOL_LINE_ERASE) { - Vector<int> ids = get_selected_tiles(); Vector<int> tmp_cell; bool erasing = (tool == TOOL_LINE_ERASE); + if (!mouse_down) { + return true; + } + tmp_cell.push_back(0); if (erasing && paint_undo.size()) { - for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - tmp_cell.write[0] = E->get().idx; _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); } @@ -1316,15 +1367,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { paint_undo.clear(); if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) { - Vector<Point2i> points = line(rectangle_begin.x, over_tile.x, rectangle_begin.y, over_tile.y); for (int i = 0; i < points.size(); i++) { - paint_undo[points[i]] = _get_op_from_cell(points[i]); - if (erasing) + if (erasing) { _set_cell(points[i], invalid_cell); + } } CanvasItemEditor::get_singleton()->update_viewport(); @@ -1333,18 +1383,27 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } if (tool == TOOL_RECTANGLE_PAINT || tool == TOOL_RECTANGLE_ERASE) { - Vector<int> tmp_cell; tmp_cell.push_back(0); - _select(rectangle_begin, over_tile); + Point2i end_tile = over_tile; - if (tool == TOOL_RECTANGLE_ERASE) { + if (!mouse_down) { + return true; + } - if (paint_undo.size()) { + if (mm->get_shift()) { + int size = fmax(ABS(end_tile.x - rectangle_begin.x), ABS(end_tile.y - rectangle_begin.y)); + int xDirection = MAX(MIN(end_tile.x - rectangle_begin.x, 1), -1); + int yDirection = MAX(MIN(end_tile.y - rectangle_begin.y, 1), -1); + end_tile = rectangle_begin + Point2i(xDirection * size, yDirection * size); + } - for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { + _select(rectangle_begin, end_tile); + if (tool == TOOL_RECTANGLE_ERASE) { + if (paint_undo.size()) { + for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { tmp_cell.write[0] = E->get().idx; _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); } @@ -1354,7 +1413,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - Point2i tile = Point2i(j, i); paint_undo[tile] = _get_op_from_cell(tile); @@ -1366,7 +1424,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return true; } if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { - _pick_tile(over_tile); return true; @@ -1376,8 +1433,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid() && k->is_pressed()) { - - if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_scancode() == KEY_SHIFT && k->get_command()) { + if (last_tool == TOOL_NONE && tool == TOOL_PICKING && k->get_keycode() == KEY_SHIFT && k->get_command()) { // trying to draw a rectangle with the painting tool, so change to the correct tool tool = last_tool; @@ -1385,12 +1441,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _update_button_tool(); } - if (k->get_scancode() == KEY_ESCAPE) { - - if (tool == TOOL_PASTING) + if (k->get_keycode() == KEY_ESCAPE) { + if (tool == TOOL_PASTING) { copydata.clear(); - else if (tool == TOOL_SELECTING || selection_active) + } else if (tool == TOOL_SELECTING || selection_active) { selection_active = false; + } tool = TOOL_NONE; @@ -1414,6 +1470,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _update_button_tool(); return true; } + if (ED_IS_SHORTCUT("tile_map_editor/line_fill", p_event)) { + tool = TOOL_LINE_PAINT; + CanvasItemEditor::get_singleton()->update_viewport(); + + _update_button_tool(); + return true; + } + if (ED_IS_SHORTCUT("tile_map_editor/rectangle_fill", p_event)) { + tool = TOOL_RECTANGLE_PAINT; + CanvasItemEditor::get_singleton()->update_viewport(); + + _update_button_tool(); + return true; + } if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) { tool = TOOL_BUCKET; CanvasItemEditor::get_singleton()->update_viewport(); @@ -1505,18 +1575,15 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else if (k.is_valid()) { // Release event. if (tool == TOOL_NONE) { - - if (k->get_scancode() == KEY_SHIFT && k->get_command()) { - + if (k->get_keycode() == KEY_SHIFT && k->get_command()) { tool = TOOL_PICKING; _update_button_tool(); } } else if (tool == TOOL_PICKING) { - #ifdef APPLE_STYLE_KEYS - if (k->get_scancode() == KEY_META) { + if (k->get_keycode() == KEY_META) { #else - if (k->get_scancode() == KEY_CONTROL) { + if (k->get_keycode() == KEY_CONTROL) { #endif // Go back to that last tool if KEY_CONTROL was released. tool = last_tool; @@ -1530,9 +1597,9 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - - if (!node || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) + if (!node || CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) { return; + } Transform2D cell_xf = node->get_cell_transform(); Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform(); @@ -1548,27 +1615,23 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { Rect2i si = aabb.grow(1.0); 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 small for (int i = (si.position.x) - 1; i <= (si.position.x + si.size.x); i++) { - Vector2 from = xform.xform(node->map_to_world(Vector2(i, si.position.y))); Vector2 to = xform.xform(node->map_to_world(Vector2(i, si.position.y + si.size.y + 1))); 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; + } } } else { - 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++) { - for (int j = (si.position.y) - 1; j <= (si.position.y + si.size.y); j++) { - Vector2 ofs; if (ABS(j) & 1) { ofs = cell_xf[0] * (node->get_half_offset() == TileMap::HALF_OFFSET_X ? 0.5 : -0.5); @@ -1580,35 +1643,33 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { 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) + if (max_lines == 0) { break; + } } } int max_lines = 10000; //avoid crash if size too small 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++) { - Vector2 from = xform.xform(node->map_to_world(Vector2(si.position.x, i))); Vector2 to = xform.xform(node->map_to_world(Vector2(si.position.x + si.size.x + 1, i))); 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; + } } } else { - for (int i = (si.position.y) - 1; i <= (si.position.y + si.size.y); i++) { - for (int j = (si.position.x) - 1; j <= (si.position.x + si.size.x); j++) { - Vector2 ofs; if (ABS(j) & 1) { ofs = cell_xf[1] * (node->get_half_offset() == TileMap::HALF_OFFSET_Y ? 0.5 : -0.5); @@ -1620,17 +1681,18 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { 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) + if (max_lines == 0) { break; + } } } } if (selection_active) { - Vector<Vector2> points; points.push_back(xform.xform(node->map_to_world((rectangle.position)))); points.push_back(xform.xform(node->map_to_world((rectangle.position + Point2(rectangle.size.x + 1, 0))))); @@ -1641,7 +1703,6 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } if (mouse_over && node->get_tileset().is_valid()) { - Vector2 endpoints[4] = { node->map_to_world(over_tile, true), node->map_to_world((over_tile + Point2(1, 0)), true), @@ -1650,24 +1711,30 @@ 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) + 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) + } + 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) + } + 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) + } + 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; - if (node->get_cell(over_tile.x, over_tile.y) != TileMap::INVALID_CELL) + if (node->get_cell(over_tile.x, over_tile.y) != TileMap::INVALID_CELL) { col = Color(0.2, 0.8, 1.0, 0.8); - else + } else { col = Color(1.0, 0.4, 0.2, 0.8); + } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { p_overlay->draw_line(endpoints[i], endpoints[(i + 1) % 4], col, 2); + } bool bucket_preview = EditorSettings::get_singleton()->get("editors/tile_map/bucket_fill_preview"); if (tool == TOOL_SELECTING || tool == TOOL_PICKING || !bucket_preview) { @@ -1675,49 +1742,57 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } if (tool == TOOL_LINE_PAINT) { + if (!mouse_down) { + return; + } - if (paint_undo.empty()) + if (paint_undo.empty()) { return; + } Vector<int> ids = get_selected_tiles(); - if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) + if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) { return; + } for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - _draw_cell(p_overlay, ids[0], E->key(), flip_h, flip_v, transpose, autotile_coord, xform); } } else if (tool == TOOL_RECTANGLE_PAINT) { + if (!mouse_down) { + return; + } Vector<int> ids = get_selected_tiles(); - if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) + if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) { return; + } for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { - _draw_cell(p_overlay, ids[0], Point2i(j, i), flip_h, flip_v, transpose, autotile_coord, xform); } } } else if (tool == TOOL_PASTING) { - - if (copydata.empty()) + if (copydata.empty()) { return; + } Ref<TileSet> ts = node->get_tileset(); - if (ts.is_null()) + if (ts.is_null()) { return; + } Point2 ofs = over_tile - rectangle.position; for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { - - if (!ts->has_tile(E->get().cell)) + if (!ts->has_tile(E->get().cell)) { continue; + } TileData tcd = E->get(); @@ -1736,16 +1811,15 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { p_overlay->draw_colored_polygon(points, Color(0.2, 1.0, 0.8, 0.2)); } else if (tool == TOOL_BUCKET) { - Vector<int> tiles = get_selected_tiles(); _draw_fill_preview(p_overlay, tiles[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform); } else { - Vector<int> st = get_selected_tiles(); - if (st.size() == 1 && st[0] == TileMap::INVALID_CELL) + if (st.size() == 1 && st[0] == TileMap::INVALID_CELL) { return; + } _draw_cell(p_overlay, st[0], over_tile, flip_h, flip_v, transpose, autotile_coord, xform); } @@ -1753,44 +1827,47 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } void TileMapEditor::edit(Node *p_tile_map) { - search_box->set_text(""); if (!canvas_item_editor_viewport) { canvas_item_editor_viewport = CanvasItemEditor::get_singleton()->get_viewport_control(); } - if (node) - node->disconnect("settings_changed", this, "_tileset_settings_changed"); + if (node) { + node->disconnect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed)); + } if (p_tile_map) { - node = Object::cast_to<TileMap>(p_tile_map); - if (!canvas_item_editor_viewport->is_connected("mouse_entered", this, "_canvas_mouse_enter")) - canvas_item_editor_viewport->connect("mouse_entered", this, "_canvas_mouse_enter"); - if (!canvas_item_editor_viewport->is_connected("mouse_exited", this, "_canvas_mouse_exit")) - canvas_item_editor_viewport->connect("mouse_exited", this, "_canvas_mouse_exit"); + if (!canvas_item_editor_viewport->is_connected("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter))) { + canvas_item_editor_viewport->connect("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter)); + } + if (!canvas_item_editor_viewport->is_connected("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit))) { + canvas_item_editor_viewport->connect("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit)); + } _update_palette(); } else { - node = NULL; + node = nullptr; - if (canvas_item_editor_viewport->is_connected("mouse_entered", this, "_canvas_mouse_enter")) - canvas_item_editor_viewport->disconnect("mouse_entered", this, "_canvas_mouse_enter"); - if (canvas_item_editor_viewport->is_connected("mouse_exited", this, "_canvas_mouse_exit")) - canvas_item_editor_viewport->disconnect("mouse_exited", this, "_canvas_mouse_exit"); + if (canvas_item_editor_viewport->is_connected("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter))) { + canvas_item_editor_viewport->disconnect("mouse_entered", callable_mp(this, &TileMapEditor::_canvas_mouse_enter)); + } + if (canvas_item_editor_viewport->is_connected("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit))) { + canvas_item_editor_viewport->disconnect("mouse_exited", callable_mp(this, &TileMapEditor::_canvas_mouse_exit)); + } _update_palette(); } - if (node) - node->connect("settings_changed", this, "_tileset_settings_changed"); + if (node) { + node->connect("settings_changed", callable_mp(this, &TileMapEditor::_tileset_settings_changed)); + } _clear_bucket_cache(); } void TileMapEditor::_tileset_settings_changed() { - _update_palette(); CanvasItemEditor::get_singleton()->update_viewport(); } @@ -1804,40 +1881,23 @@ void TileMapEditor::_icon_size_changed(float p_value) { } void TileMapEditor::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_manual_toggled"), &TileMapEditor::_manual_toggled); - ClassDB::bind_method(D_METHOD("_priority_toggled"), &TileMapEditor::_priority_toggled); - ClassDB::bind_method(D_METHOD("_text_entered"), &TileMapEditor::_text_entered); - ClassDB::bind_method(D_METHOD("_text_changed"), &TileMapEditor::_text_changed); - ClassDB::bind_method(D_METHOD("_sbox_input"), &TileMapEditor::_sbox_input); - ClassDB::bind_method(D_METHOD("_button_tool_select"), &TileMapEditor::_button_tool_select); - ClassDB::bind_method(D_METHOD("_menu_option"), &TileMapEditor::_menu_option); - ClassDB::bind_method(D_METHOD("_canvas_mouse_enter"), &TileMapEditor::_canvas_mouse_enter); - ClassDB::bind_method(D_METHOD("_canvas_mouse_exit"), &TileMapEditor::_canvas_mouse_exit); - ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed); - ClassDB::bind_method(D_METHOD("_rotate"), &TileMapEditor::_rotate); - ClassDB::bind_method(D_METHOD("_flip_horizontal"), &TileMapEditor::_flip_horizontal); - ClassDB::bind_method(D_METHOD("_flip_vertical"), &TileMapEditor::_flip_vertical); - ClassDB::bind_method(D_METHOD("_clear_transform"), &TileMapEditor::_clear_transform); - ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected); - ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected); - ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points); ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points); - - ClassDB::bind_method(D_METHOD("_icon_size_changed"), &TileMapEditor::_icon_size_changed); } TileMapEditor::CellOp TileMapEditor::_get_op_from_cell(const Point2i &p_pos) { CellOp op; op.idx = node->get_cell(p_pos.x, p_pos.y); if (op.idx != TileMap::INVALID_CELL) { - if (node->is_cell_x_flipped(p_pos.x, p_pos.y)) + if (node->is_cell_x_flipped(p_pos.x, p_pos.y)) { op.xf = true; - if (node->is_cell_y_flipped(p_pos.x, p_pos.y)) + } + if (node->is_cell_y_flipped(p_pos.x, p_pos.y)) { op.yf = true; - if (node->is_cell_transposed(p_pos.x, p_pos.y)) + } + if (node->is_cell_transposed(p_pos.x, p_pos.y)) { op.tr = true; + } op.ac = node->get_cell_autotile_coord(p_pos.x, p_pos.y); } return op; @@ -1907,25 +1967,25 @@ void TileMapEditor::_clear_transform() { } TileMapEditor::TileMapEditor(EditorNode *p_editor) { - - node = NULL; + node = nullptr; manual_autotile = false; priority_atlastile = false; manual_position = Vector2(0, 0); - canvas_item_editor_viewport = NULL; + canvas_item_editor_viewport = nullptr; editor = p_editor; undo_redo = EditorNode::get_undo_redo(); tool = TOOL_NONE; selection_active = false; mouse_over = false; + mouse_down = false; flip_h = false; flip_v = false; transpose = false; bucket_cache_tile = -1; - bucket_cache_visited = NULL; + bucket_cache_visited = nullptr; invalid_cell.resize(1); invalid_cell.write[0] = TileMap::INVALID_CELL; @@ -1939,20 +1999,20 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { manual_button = memnew(CheckBox); manual_button->set_text(TTR("Disable Autotile")); - manual_button->connect("toggled", this, "_manual_toggled"); + manual_button->connect("toggled", callable_mp(this, &TileMapEditor::_manual_toggled)); add_child(manual_button); priority_button = memnew(CheckBox); priority_button->set_text(TTR("Enable Priority")); - priority_button->connect("toggled", this, "_priority_toggled"); + priority_button->connect("toggled", callable_mp(this, &TileMapEditor::_priority_toggled)); add_child(priority_button); search_box = memnew(LineEdit); search_box->set_placeholder(TTR("Filter tiles")); search_box->set_h_size_flags(SIZE_EXPAND_FILL); - search_box->connect("text_entered", this, "_text_entered"); - search_box->connect("text_changed", this, "_text_changed"); - search_box->connect("gui_input", this, "_sbox_input"); + search_box->connect("text_entered", callable_mp(this, &TileMapEditor::_text_entered)); + search_box->connect("text_changed", callable_mp(this, &TileMapEditor::_text_changed)); + search_box->connect("gui_input", callable_mp(this, &TileMapEditor::_sbox_input)); add_child(search_box); size_slider = memnew(HSlider); @@ -1961,7 +2021,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { size_slider->set_max(4.0f); size_slider->set_step(0.1f); size_slider->set_value(1.0f); - size_slider->connect("value_changed", this, "_icon_size_changed"); + size_slider->connect("value_changed", callable_mp(this, &TileMapEditor::_icon_size_changed)); add_child(size_slider); int mw = EDITOR_DEF("editors/tile_map/palette_min_width", 80); @@ -1979,9 +2039,10 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { palette->set_icon_mode(ItemList::ICON_MODE_TOP); palette->set_max_text_lines(2); palette->set_select_mode(ItemList::SELECT_MULTI); - palette->add_constant_override("vseparation", 8 * EDSCALE); - palette->connect("item_selected", this, "_palette_selected"); - palette->connect("multi_selected", this, "_palette_multi_selected"); + palette->add_theme_constant_override("vseparation", 8 * EDSCALE); + palette->connect("item_selected", callable_mp(this, &TileMapEditor::_palette_selected)); + palette->connect("multi_selected", callable_mp(this, &TileMapEditor::_palette_multi_selected)); + palette->connect("gui_input", callable_mp(this, &TileMapEditor::_palette_input)); palette_container->add_child(palette); // Add message for when no texture is selected. @@ -2012,28 +2073,48 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { toolbar->add_child(memnew(VSeparator)); // Tools. - paint_button = memnew(ToolButton); + paint_button = memnew(Button); + paint_button->set_flat(true); paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); - paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint")); - paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE)); + paint_button->set_tooltip(TTR("RMB: Erase")); + paint_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_NONE)); paint_button->set_toggle_mode(true); toolbar->add_child(paint_button); - bucket_fill_button = memnew(ToolButton); - bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_G)); - bucket_fill_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_BUCKET)); + line_button = memnew(Button); + line_button->set_flat(true); + line_button->set_shortcut(ED_SHORTCUT("tile_map_editor/line_fill", TTR("Line Fill"), KEY_L)); + line_button->set_tooltip(TTR("RMB: Erase")); + line_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_LINE_PAINT)); + line_button->set_toggle_mode(true); + toolbar->add_child(line_button); + + rectangle_button = memnew(Button); + rectangle_button->set_flat(true); + rectangle_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rectangle_fill", TTR("Rectangle Fill"), KEY_O)); + rectangle_button->set_tooltip(TTR("Shift+LMB: Keep 1:1 proporsions\nRMB: Erase")); + rectangle_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_RECTANGLE_PAINT)); + rectangle_button->set_toggle_mode(true); + toolbar->add_child(rectangle_button); + + bucket_fill_button = memnew(Button); + bucket_fill_button->set_flat(true); + bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B)); + bucket_fill_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_BUCKET)); bucket_fill_button->set_toggle_mode(true); toolbar->add_child(bucket_fill_button); - picker_button = memnew(ToolButton); - picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_CONTROL)); - picker_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PICKING)); + picker_button = memnew(Button); + picker_button->set_flat(true); + picker_button->set_shortcut(ED_SHORTCUT("tile_map_editor/pick_tile", TTR("Pick Tile"), KEY_I)); + picker_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_PICKING)); picker_button->set_toggle_mode(true); toolbar->add_child(picker_button); - select_button = memnew(ToolButton); - select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_MASK_CMD + KEY_B)); - select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECTING)); + select_button = memnew(Button); + select_button->set_flat(true); + select_button->set_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_M)); + select_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_SELECTING)); select_button->set_toggle_mode(true); toolbar->add_child(select_button); @@ -2050,7 +2131,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { tile_info = memnew(Label); tile_info->set_modulate(Color(1, 1, 1, 0.8)); tile_info->set_mouse_filter(MOUSE_FILTER_IGNORE); - tile_info->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("main", "EditorFonts")); + tile_info->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); // The tile info is only displayed after a tile has been hovered. tile_info->hide(); CanvasItemEditor::get_singleton()->add_control_to_info_overlay(tile_info); @@ -2058,7 +2139,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { // Menu. options = memnew(MenuButton); options->set_text("TileMap"); - options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("TileMap", "EditorIcons")); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("TileMap", "EditorIcons")); options->set_process_unhandled_key_input(false); toolbar_right->add_child(options); @@ -2068,40 +2149,45 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION); p->add_separator(); p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID); - p->connect("id_pressed", this, "_menu_option"); + p->connect("id_pressed", callable_mp(this, &TileMapEditor::_menu_option)); - rotate_left_button = memnew(ToolButton); + rotate_left_button = memnew(Button); + rotate_left_button->set_flat(true); rotate_left_button->set_tooltip(TTR("Rotate Left")); rotate_left_button->set_focus_mode(FOCUS_NONE); - rotate_left_button->connect("pressed", this, "_rotate", varray(-1)); + rotate_left_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(-1)); rotate_left_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_left", TTR("Rotate Left"), KEY_A)); tool_hb->add_child(rotate_left_button); - rotate_right_button = memnew(ToolButton); + rotate_right_button = memnew(Button); + rotate_right_button->set_flat(true); rotate_right_button->set_tooltip(TTR("Rotate Right")); rotate_right_button->set_focus_mode(FOCUS_NONE); - rotate_right_button->connect("pressed", this, "_rotate", varray(1)); + rotate_right_button->connect("pressed", callable_mp(this, &TileMapEditor::_rotate), varray(1)); rotate_right_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rotate_right", TTR("Rotate Right"), KEY_S)); tool_hb->add_child(rotate_right_button); - flip_horizontal_button = memnew(ToolButton); + flip_horizontal_button = memnew(Button); + flip_horizontal_button->set_flat(true); flip_horizontal_button->set_tooltip(TTR("Flip Horizontally")); flip_horizontal_button->set_focus_mode(FOCUS_NONE); - flip_horizontal_button->connect("pressed", this, "_flip_horizontal"); + flip_horizontal_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_horizontal)); flip_horizontal_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_horizontal", TTR("Flip Horizontally"), KEY_X)); tool_hb->add_child(flip_horizontal_button); - flip_vertical_button = memnew(ToolButton); + flip_vertical_button = memnew(Button); + flip_vertical_button->set_flat(true); flip_vertical_button->set_tooltip(TTR("Flip Vertically")); flip_vertical_button->set_focus_mode(FOCUS_NONE); - flip_vertical_button->connect("pressed", this, "_flip_vertical"); + flip_vertical_button->connect("pressed", callable_mp(this, &TileMapEditor::_flip_vertical)); flip_vertical_button->set_shortcut(ED_SHORTCUT("tile_map_editor/flip_vertical", TTR("Flip Vertically"), KEY_Z)); tool_hb->add_child(flip_vertical_button); - clear_transform_button = memnew(ToolButton); + clear_transform_button = memnew(Button); + clear_transform_button->set_flat(true); clear_transform_button->set_tooltip(TTR("Clear Transform")); clear_transform_button->set_focus_mode(FOCUS_NONE); - clear_transform_button->connect("pressed", this, "_clear_transform"); + clear_transform_button->connect("pressed", callable_mp(this, &TileMapEditor::_clear_transform)); clear_transform_button->set_shortcut(ED_SHORTCUT("tile_map_editor/clear_transform", TTR("Clear Transform"), KEY_W)); tool_hb->add_child(clear_transform_button); @@ -2118,9 +2204,7 @@ TileMapEditor::~TileMapEditor() { /////////////////////////////////////////////////////////////// void TileMapEditorPlugin::_notification(int p_what) { - if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { - switch ((int)EditorSettings::get_singleton()->get("editors/tile_map/editor_side")) { case 0: { // Left. CanvasItemEditor::get_singleton()->get_palette_split()->move_child(tile_map_editor, 0); @@ -2133,19 +2217,15 @@ void TileMapEditorPlugin::_notification(int p_what) { } void TileMapEditorPlugin::edit(Object *p_object) { - tile_map_editor->edit(Object::cast_to<Node>(p_object)); } bool TileMapEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("TileMap"); } void TileMapEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - tile_map_editor->show(); tile_map_editor->get_toolbar()->show(); tile_map_editor->get_toolbar_right()->show(); @@ -2156,17 +2236,15 @@ void TileMapEditorPlugin::make_visible(bool p_visible) { // Change to TOOL_SELECT when TileMap node is selected, to prevent accidental movement. CanvasItemEditor::get_singleton()->set_current_tool(CanvasItemEditor::TOOL_SELECT); } else { - tile_map_editor->hide(); tile_map_editor->get_toolbar()->hide(); tile_map_editor->get_toolbar_right()->hide(); tile_map_editor->get_tile_info()->hide(); - tile_map_editor->edit(NULL); + tile_map_editor->edit(nullptr); } } TileMapEditorPlugin::TileMapEditorPlugin(EditorNode *p_node) { - EDITOR_DEF("editors/tile_map/preview_size", 64); EDITOR_DEF("editors/tile_map/palette_item_hseparation", 8); EDITOR_DEF("editors/tile_map/show_tile_names", true); diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 927f0887bb..996e904853 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -33,16 +33,13 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" - #include "scene/2d/tile_map.h" #include "scene/gui/check_box.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/menu_button.h" -#include "scene/gui/tool_button.h" class TileMapEditor : public VBoxContainer { - GDCLASS(TileMapEditor, VBoxContainer); enum Tool { @@ -90,16 +87,18 @@ class TileMapEditor : public VBoxContainer { Label *tile_info; MenuButton *options; - ToolButton *paint_button; - ToolButton *bucket_fill_button; - ToolButton *picker_button; - ToolButton *select_button; + Button *paint_button; + Button *line_button; + Button *rectangle_button; + Button *bucket_fill_button; + Button *picker_button; + Button *select_button; - ToolButton *flip_horizontal_button; - ToolButton *flip_vertical_button; - ToolButton *rotate_left_button; - ToolButton *rotate_right_button; - ToolButton *clear_transform_button; + Button *flip_horizontal_button; + Button *flip_vertical_button; + Button *rotate_left_button; + Button *rotate_right_button; + Button *clear_transform_button; CheckBox *manual_button; CheckBox *priority_button; @@ -109,6 +108,7 @@ class TileMapEditor : public VBoxContainer { bool selection_active; bool mouse_over; + bool mouse_down; bool flip_h; bool flip_v; @@ -123,38 +123,30 @@ class TileMapEditor : public VBoxContainer { bool *bucket_cache_visited; Rect2i bucket_cache_rect; int bucket_cache_tile; - PoolVector<Vector2> bucket_cache; + Vector<Vector2> bucket_cache; List<Point2i> bucket_queue; struct CellOp { - int idx; - bool xf; - bool yf; - bool tr; + int idx = TileMap::INVALID_CELL; + bool xf = false; + bool yf = false; + bool tr = false; Vector2 ac; - CellOp() : - idx(TileMap::INVALID_CELL), - xf(false), - yf(false), - tr(false) {} + CellOp() {} }; Map<Point2i, CellOp> paint_undo; struct TileData { Point2i pos; - int cell; - bool flip_h; - bool flip_v; - bool transpose; + int cell = TileMap::INVALID_CELL; + bool flip_h = false; + bool flip_v = false; + bool transpose = false; Point2i autotile_coord; - TileData() : - cell(TileMap::INVALID_CELL), - flip_h(false), - flip_v(false), - transpose(false) {} + TileData() {} }; List<TileData> copydata; @@ -164,10 +156,10 @@ class TileMapEditor : public VBoxContainer { void _pick_tile(const Point2 &p_pos); - PoolVector<Vector2> _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false); + Vector<Vector2> _bucket_fill(const Point2i &p_start, bool erase = false, bool preview = false); - void _fill_points(const PoolVector<Vector2> &p_points, const Dictionary &p_op); - void _erase_points(const PoolVector<Vector2> &p_points); + void _fill_points(const Vector<Vector2> &p_points, const Dictionary &p_op); + void _erase_points(const Vector<Vector2> &p_points); void _select(const Point2i &p_from, const Point2i &p_to); void _erase_selection(); @@ -192,6 +184,7 @@ class TileMapEditor : public VBoxContainer { void _menu_option(int p_option); void _palette_selected(int index); void _palette_multi_selected(int index, bool selected); + void _palette_input(const Ref<InputEvent> &p_event); Dictionary _create_cell_dictionary(int tile, bool flip_x, bool flip_y, bool transpose, Vector2 autotile_coord); void _start_undo(const String &p_action); @@ -211,6 +204,7 @@ class TileMapEditor : public VBoxContainer { protected: void _notification(int p_what); + void _node_removed(Node *p_node); static void _bind_methods(); CellOp _get_op_from_cell(const Point2i &p_pos); @@ -229,7 +223,6 @@ public: }; class TileMapEditorPlugin : public EditorPlugin { - GDCLASS(TileMapEditorPlugin, EditorPlugin); TileMapEditor *tile_map_editor; @@ -238,14 +231,14 @@ protected: void _notification(int p_what); public: - virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return tile_map_editor->forward_gui_input(p_event); } - virtual void forward_canvas_draw_over_viewport(Control *p_overlay) { tile_map_editor->forward_canvas_draw_over_viewport(p_overlay); } - - virtual String get_name() const { return "TileMap"; } - 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); + virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return tile_map_editor->forward_gui_input(p_event); } + virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { tile_map_editor->forward_canvas_draw_over_viewport(p_overlay); } + + virtual String get_name() const override { return "TileMap"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; TileMapEditorPlugin(EditorNode *p_node); ~TileMapEditorPlugin(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index b24d5add9f..684d8f0f10 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -30,15 +30,14 @@ #include "tile_set_editor_plugin.h" -#include "core/os/input.h" +#include "core/input/input.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/physics_body_2d.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" void TileSetEditor::edit(const Ref<TileSet> &p_tileset) { - tileset = p_tileset; tileset->add_change_receptor(this); @@ -48,12 +47,10 @@ void TileSetEditor::edit(const Ref<TileSet> &p_tileset) { } void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *child = p_node->get_child(i); - if (!Object::cast_to<Sprite>(child)) { + if (!Object::cast_to<Sprite2D>(child)) { if (child->get_child_count() > 0) { _import_node(child, p_library); } @@ -61,17 +58,17 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { continue; } - Sprite *mi = Object::cast_to<Sprite>(child); - Ref<Texture> texture = mi->get_texture(); - Ref<Texture> normal_map = mi->get_normal_map(); + Sprite2D *mi = Object::cast_to<Sprite2D>(child); + Ref<Texture2D> texture = mi->get_texture(); + Ref<Texture2D> normal_map = mi->get_normal_map(); Ref<ShaderMaterial> material = mi->get_material(); - if (texture.is_null()) + if (texture.is_null()) { continue; + } int id = p_library->find_tile_by_name(mi->get_name()); if (id < 0) { - id = p_library->get_last_unused_tile_id(); p_library->create_tile(id); p_library->tile_set_name(id, mi->get_name()); @@ -106,17 +103,19 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { bool found_collisions = false; for (int j = 0; j < mi->get_child_count(); j++) { - Node *child2 = mi->get_child(j); - if (Object::cast_to<NavigationPolygonInstance>(child2)) - nav_poly = Object::cast_to<NavigationPolygonInstance>(child2)->get_navigation_polygon(); + if (Object::cast_to<NavigationRegion2D>(child2)) { + nav_poly = Object::cast_to<NavigationRegion2D>(child2)->get_navigation_polygon(); + } - if (Object::cast_to<LightOccluder2D>(child2)) + if (Object::cast_to<LightOccluder2D>(child2)) { occluder = Object::cast_to<LightOccluder2D>(child2)->get_occluder_polygon(); + } - if (!Object::cast_to<StaticBody2D>(child2)) + if (!Object::cast_to<StaticBody2D>(child2)) { continue; + } found_collisions = true; @@ -126,7 +125,9 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { sb->get_shape_owners(&shapes); for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) { - if (sb->is_shape_owner_disabled(E->get())) continue; + if (sb->is_shape_owner_disabled(E->get())) { + continue; + } Transform2D shape_transform = sb->get_transform() * sb->shape_owner_get_transform(E->get()); bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); @@ -134,7 +135,6 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { shape_transform[2] -= phys_offset; for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { - Ref<Shape2D> shape = sb->shape_owner_get_shape(E->get(), k); TileSet::ShapeData shape_data; shape_data.shape = shape; @@ -159,56 +159,53 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { } void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge) { - - if (!p_merge) + if (!p_merge) { p_library->clear(); + } _import_node(p_scene, p_library); } void TileSetEditor::_undo_redo_import_scene(Node *p_scene, bool p_merge) { - _import_scene(p_scene, tileset, p_merge); } Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) { - _import_scene(p_base_scene, ml, p_merge); return OK; } Variant TileSetEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { - return false; } bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return false; + } - if (d.has("from") && (Object *)(d["from"]) == texture_list) + if (d.has("from") && (Object *)(d["from"]) == texture_list) { return false; + } if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; - Ref<Texture> texture = r; + Ref<Texture2D> texture = r; if (texture.is_valid()) { - return true; } } if (String(d["type"]) == "files") { - Vector<String> files = d["files"]; - if (files.size() == 0) + if (files.size() == 0) { return false; + } for (int i = 0; i < files.size(); i++) { String file = files[i]; @@ -225,22 +222,24 @@ bool TileSetEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_dat } void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - - if (!can_drop_data_fw(p_point, p_data, p_from)) + if (!can_drop_data_fw(p_point, p_data, p_from)) { return; + } Dictionary d = p_data; - if (!d.has("type")) + if (!d.has("type")) { return; + } if (String(d["type"]) == "resource" && d.has("resource")) { RES r = d["resource"]; - Ref<Texture> texture = r; + Ref<Texture2D> texture = r; - if (texture.is_valid()) + if (texture.is_valid()) { add_texture(texture); + } if (texture_list->get_item_count() > 0) { update_texture_list_icon(); @@ -250,37 +249,19 @@ void TileSetEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, C } if (String(d["type"]) == "files") { - - PoolVector<String> files = d["files"]; + Vector<String> files = d["files"]; _on_textures_added(files); } } void TileSetEditor::_bind_methods() { - ClassDB::bind_method("_undo_redo_import_scene", &TileSetEditor::_undo_redo_import_scene); - ClassDB::bind_method("_on_tileset_toolbar_button_pressed", &TileSetEditor::_on_tileset_toolbar_button_pressed); - ClassDB::bind_method("_on_textures_added", &TileSetEditor::_on_textures_added); - ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm); - ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected); - ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed); - ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed); - ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw); - ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); - ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw); - ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input); - ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked); - ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed); - ClassDB::bind_method("_on_z_index_changed", &TileSetEditor::_on_z_index_changed); - ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled); + ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); // Still used by some connect_compat. ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step); ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off); ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep); ClassDB::bind_method("_validate_current_tile_id", &TileSetEditor::_validate_current_tile_id); - ClassDB::bind_method("_zoom_in", &TileSetEditor::_zoom_in); - 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); @@ -296,57 +277,53 @@ void TileSetEditor::_bind_methods() { } void TileSetEditor::_notification(int p_what) { - switch (p_what) { case NOTIFICATION_READY: { - - add_constant_override("autohide", 1); // Fixes the dragger always showing up. + add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up. } break; case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons")); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons")); - tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons")); - - tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons")); - tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons")); - - tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); - tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); - 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")); - tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); - 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")); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_theme_icon("ToolAddNode", "EditorIcons")); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_theme_icon("Remove", "EditorIcons")); + tileset_toolbar_tools->set_icon(get_theme_icon("Tools", "EditorIcons")); + + tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_theme_icon("Edit", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_theme_icon("AddSingleTile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_theme_icon("AddAutotile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_theme_icon("AddAtlasTile", "EditorIcons")); + + tools[TOOL_SELECT]->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); + tools[BITMASK_COPY]->set_icon(get_theme_icon("Duplicate", "EditorIcons")); + tools[BITMASK_PASTE]->set_icon(get_theme_icon("Override", "EditorIcons")); + tools[BITMASK_CLEAR]->set_icon(get_theme_icon("Clear", "EditorIcons")); + tools[SHAPE_NEW_POLYGON]->set_icon(get_theme_icon("CollisionPolygon2D", "EditorIcons")); + tools[SHAPE_NEW_RECTANGLE]->set_icon(get_theme_icon("CollisionShape2D", "EditorIcons")); + tools[SELECT_PREVIOUS]->set_icon(get_theme_icon("ArrowLeft", "EditorIcons")); + tools[SELECT_NEXT]->set_icon(get_theme_icon("ArrowRight", "EditorIcons")); + tools[SHAPE_DELETE]->set_icon(get_theme_icon("Remove", "EditorIcons")); + tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_theme_icon("Snap", "EditorIcons")); + tools[TOOL_GRID_SNAP]->set_icon(get_theme_icon("SnapGrid", "EditorIcons")); + tools[ZOOM_OUT]->set_icon(get_theme_icon("ZoomLess", "EditorIcons")); + tools[ZOOM_1]->set_icon(get_theme_icon("ZoomReset", "EditorIcons")); + tools[ZOOM_IN]->set_icon(get_theme_icon("ZoomMore", "EditorIcons")); + tools[VISIBLE_INFO]->set_icon(get_theme_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")); - tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons")); - tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons")); - tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons")); - tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons")); - tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons")); - tool_editmode[EDITMODE_Z_INDEX]->set_icon(get_icon("Sort", "EditorIcons")); + tool_editmode[EDITMODE_REGION]->set_icon(get_theme_icon("RegionEdit", "EditorIcons")); + tool_editmode[EDITMODE_COLLISION]->set_icon(get_theme_icon("StaticBody2D", "EditorIcons")); + tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_theme_icon("LightOccluder2D", "EditorIcons")); + tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_theme_icon("Navigation2D", "EditorIcons")); + tool_editmode[EDITMODE_BITMASK]->set_icon(get_theme_icon("PackedDataContainer", "EditorIcons")); + tool_editmode[EDITMODE_PRIORITY]->set_icon(get_theme_icon("MaterialPreviewLight1", "EditorIcons")); + tool_editmode[EDITMODE_ICON]->set_icon(get_theme_icon("LargeTexture", "EditorIcons")); + tool_editmode[EDITMODE_Z_INDEX]->set_icon(get_theme_icon("Sort", "EditorIcons")); - scroll->add_style_override("bg", get_stylebox("bg", "Tree")); + scroll->add_theme_style_override("bg", get_theme_stylebox("bg", "Tree")); } break; } } TileSetEditor::TileSetEditor(EditorNode *p_editor) { - editor = p_editor; undo_redo = EditorNode::get_undo_redo(); current_tile = -1; @@ -358,19 +335,21 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { left_container->add_child(texture_list); texture_list->set_v_size_flags(SIZE_EXPAND_FILL); texture_list->set_custom_minimum_size(Size2(200, 0)); - texture_list->connect("item_selected", this, "_on_texture_list_selected"); + texture_list->connect("item_selected", callable_mp(this, &TileSetEditor::_on_texture_list_selected)); texture_list->set_drag_forwarding(this); HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer); left_container->add_child(tileset_toolbar_container); - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton); - tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", varray(TOOL_TILESET_ADD_TEXTURE)); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(Button); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_flat(true); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_ADD_TEXTURE)); tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]); tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet.")); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton); - tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", varray(TOOL_TILESET_REMOVE_TEXTURE)); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(Button); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_flat(true); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed), varray(TOOL_TILESET_REMOVE_TEXTURE)); tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]); tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove selected Texture from TileSet.")); @@ -383,7 +362,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE); tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE); - tileset_toolbar_tools->get_popup()->connect("id_pressed", this, "_on_tileset_toolbar_button_pressed"); + tileset_toolbar_tools->get_popup()->connect("id_pressed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_button_pressed)); tileset_toolbar_container->add_child(tileset_toolbar_tools); //--------------- @@ -416,7 +395,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_workspacemode[i]->set_text(workspace_label[i]); tool_workspacemode[i]->set_toggle_mode(true); tool_workspacemode[i]->set_button_group(g); - tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", varray(i)); + tool_workspacemode[i]->connect("pressed", callable_mp(this, &TileSetEditor::_on_workspace_mode_changed), varray(i)); tool_hb->add_child(tool_workspacemode[i]); } @@ -425,18 +404,20 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_hb->add_child(spacer); tool_hb->move_child(spacer, WORKSPACE_CREATE_SINGLE); - tools[SELECT_NEXT] = memnew(ToolButton); + tools[SELECT_NEXT] = memnew(Button); tool_hb->add_child(tools[SELECT_NEXT]); tool_hb->move_child(tools[SELECT_NEXT], WORKSPACE_CREATE_SINGLE); + tools[SELECT_NEXT]->set_flat(true); 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]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_NEXT)); tools[SELECT_NEXT]->set_tooltip(TTR("Select the next shape, subtile, or Tile.")); - tools[SELECT_PREVIOUS] = memnew(ToolButton); + tools[SELECT_PREVIOUS] = memnew(Button); tool_hb->add_child(tools[SELECT_PREVIOUS]); tool_hb->move_child(tools[SELECT_PREVIOUS], WORKSPACE_CREATE_SINGLE); + tools[SELECT_PREVIOUS]->set_flat(true); 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)); + tools[SELECT_PREVIOUS]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SELECT_PREVIOUS)); VSeparator *separator_shape_selection = memnew(VSeparator); tool_hb->add_child(separator_shape_selection); @@ -466,7 +447,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { tool_editmode[i]->set_text(label[i]); tool_editmode[i]->set_toggle_mode(true); tool_editmode[i]->set_button_group(g); - tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", varray(i)); + tool_editmode[i]->connect("pressed", callable_mp(this, &TileSetEditor::_on_edit_mode_changed), varray(i)); tool_hb->add_child(tool_editmode[i]); } tool_editmode[EDITMODE_COLLISION]->set_pressed(true); @@ -488,50 +469,60 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { toolbar = memnew(HBoxContainer); Ref<ButtonGroup> tg(memnew(ButtonGroup)); - tools[TOOL_SELECT] = memnew(ToolButton); + tools[TOOL_SELECT] = memnew(Button); toolbar->add_child(tools[TOOL_SELECT]); + tools[TOOL_SELECT]->set_flat(true); tools[TOOL_SELECT]->set_toggle_mode(true); tools[TOOL_SELECT]->set_button_group(tg); tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", varray(TOOL_SELECT)); + tools[TOOL_SELECT]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(TOOL_SELECT)); separator_bitmask = memnew(VSeparator); toolbar->add_child(separator_bitmask); - tools[BITMASK_COPY] = memnew(ToolButton); + tools[BITMASK_COPY] = memnew(Button); + tools[BITMASK_COPY]->set_flat(true); tools[BITMASK_COPY]->set_tooltip(TTR("Copy bitmask.")); - tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_COPY)); + tools[BITMASK_COPY]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_COPY)); toolbar->add_child(tools[BITMASK_COPY]); - tools[BITMASK_PASTE] = memnew(ToolButton); + tools[BITMASK_PASTE] = memnew(Button); + tools[BITMASK_PASTE]->set_flat(true); tools[BITMASK_PASTE]->set_tooltip(TTR("Paste bitmask.")); - tools[BITMASK_PASTE]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_PASTE)); + tools[BITMASK_PASTE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_PASTE)); toolbar->add_child(tools[BITMASK_PASTE]); - tools[BITMASK_CLEAR] = memnew(ToolButton); + tools[BITMASK_CLEAR] = memnew(Button); + tools[BITMASK_CLEAR]->set_flat(true); tools[BITMASK_CLEAR]->set_tooltip(TTR("Erase bitmask.")); - tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", varray(BITMASK_CLEAR)); + tools[BITMASK_CLEAR]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(BITMASK_CLEAR)); toolbar->add_child(tools[BITMASK_CLEAR]); - tools[SHAPE_NEW_RECTANGLE] = memnew(ToolButton); + tools[SHAPE_NEW_RECTANGLE] = memnew(Button); toolbar->add_child(tools[SHAPE_NEW_RECTANGLE]); + tools[SHAPE_NEW_RECTANGLE]->set_flat(true); 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_RECTANGLE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_NEW_RECTANGLE)); - tools[SHAPE_NEW_POLYGON] = memnew(ToolButton); + tools[SHAPE_NEW_POLYGON] = memnew(Button); toolbar->add_child(tools[SHAPE_NEW_POLYGON]); + tools[SHAPE_NEW_POLYGON]->set_flat(true); 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.")); + tools[SHAPE_NEW_POLYGON]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_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)); + tools[SHAPE_TOGGLE_TYPE] = memnew(Button); + tools[SHAPE_TOGGLE_TYPE]->set_flat(true); + tools[SHAPE_TOGGLE_TYPE]->connect("pressed", callable_mp(this, &TileSetEditor::_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); - tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", varray(SHAPE_DELETE)); + tools[SHAPE_DELETE] = memnew(Button); + tools[SHAPE_DELETE]->set_flat(true); + tools[SHAPE_DELETE]->connect("pressed", callable_mp(this, &TileSetEditor::_on_tool_clicked), varray(SHAPE_DELETE)); toolbar->add_child(tools[SHAPE_DELETE]); spin_priority = memnew(SpinBox); @@ -539,50 +530,56 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { spin_priority->set_max(255); spin_priority->set_step(1); spin_priority->set_custom_minimum_size(Size2(100, 0)); - spin_priority->connect("value_changed", this, "_on_priority_changed"); + spin_priority->connect("value_changed", callable_mp(this, &TileSetEditor::_on_priority_changed)); spin_priority->hide(); toolbar->add_child(spin_priority); spin_z_index = memnew(SpinBox); - spin_z_index->set_min(VS::CANVAS_ITEM_Z_MIN); - spin_z_index->set_max(VS::CANVAS_ITEM_Z_MAX); + spin_z_index->set_min(RS::CANVAS_ITEM_Z_MIN); + spin_z_index->set_max(RS::CANVAS_ITEM_Z_MAX); spin_z_index->set_step(1); spin_z_index->set_custom_minimum_size(Size2(100, 0)); - spin_z_index->connect("value_changed", this, "_on_z_index_changed"); + spin_z_index->connect("value_changed", callable_mp(this, &TileSetEditor::_on_z_index_changed)); spin_z_index->hide(); toolbar->add_child(spin_z_index); separator_grid = memnew(VSeparator); toolbar->add_child(separator_grid); - tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); + tools[SHAPE_KEEP_INSIDE_TILE] = memnew(Button); + tools[SHAPE_KEEP_INSIDE_TILE]->set_flat(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_tooltip(TTR("Keep polygon inside region Rect.")); toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); - tools[TOOL_GRID_SNAP] = memnew(ToolButton); + tools[TOOL_GRID_SNAP] = memnew(Button); + tools[TOOL_GRID_SNAP]->set_flat(true); tools[TOOL_GRID_SNAP]->set_toggle_mode(true); tools[TOOL_GRID_SNAP]->set_tooltip(TTR("Enable snap and show grid (configurable via the Inspector).")); - tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); + tools[TOOL_GRID_SNAP]->connect("toggled", callable_mp(this, &TileSetEditor::_on_grid_snap_toggled)); toolbar->add_child(tools[TOOL_GRID_SNAP]); Control *separator = memnew(Control); separator->set_h_size_flags(SIZE_EXPAND_FILL); toolbar->add_child(separator); - tools[ZOOM_OUT] = memnew(ToolButton); - tools[ZOOM_OUT]->connect("pressed", this, "_zoom_out"); + tools[ZOOM_OUT] = memnew(Button); + tools[ZOOM_OUT]->set_flat(true); + tools[ZOOM_OUT]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_out)); toolbar->add_child(tools[ZOOM_OUT]); tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out")); - tools[ZOOM_1] = memnew(ToolButton); - tools[ZOOM_1]->connect("pressed", this, "_zoom_reset"); + tools[ZOOM_1] = memnew(Button); + tools[ZOOM_1]->set_flat(true); + tools[ZOOM_1]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_reset)); toolbar->add_child(tools[ZOOM_1]); tools[ZOOM_1]->set_tooltip(TTR("Zoom Reset")); - tools[ZOOM_IN] = memnew(ToolButton); - tools[ZOOM_IN]->connect("pressed", this, "_zoom_in"); + tools[ZOOM_IN] = memnew(Button); + tools[ZOOM_IN]->set_flat(true); + tools[ZOOM_IN]->connect("pressed", callable_mp(this, &TileSetEditor::_zoom_in)); toolbar->add_child(tools[ZOOM_IN]); tools[ZOOM_IN]->set_tooltip(TTR("Zoom In")); - tools[VISIBLE_INFO] = memnew(ToolButton); + tools[VISIBLE_INFO] = memnew(Button); + tools[VISIBLE_INFO]->set_flat(true); tools[VISIBLE_INFO]->set_toggle_mode(true); tools[VISIBLE_INFO]->set_tooltip(TTR("Display Tile Names (Hold Alt Key)")); toolbar->add_child(tools[VISIBLE_INFO]); @@ -592,6 +589,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { scroll = memnew(ScrollContainer); main_vb->add_child(scroll); scroll->set_v_size_flags(SIZE_EXPAND_FILL); + scroll->connect("gui_input", callable_mp(this, &TileSetEditor::_on_scroll_container_input)); scroll->set_clip_contents(true); empty_message = memnew(Label); @@ -607,17 +605,17 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { scroll->add_child(workspace_container); workspace_overlay = memnew(Control); - workspace_overlay->connect("draw", this, "_on_workspace_overlay_draw"); + workspace_overlay->connect("draw", callable_mp(this, &TileSetEditor::_on_workspace_overlay_draw)); workspace_container->add_child(workspace_overlay); workspace = memnew(Control); workspace->set_focus_mode(FOCUS_ALL); - workspace->connect("draw", this, "_on_workspace_draw"); - workspace->connect("gui_input", this, "_on_workspace_input"); + workspace->connect("draw", callable_mp(this, &TileSetEditor::_on_workspace_draw)); + workspace->connect("gui_input", callable_mp(this, &TileSetEditor::_on_workspace_input)); workspace->set_draw_behind_parent(true); workspace_overlay->add_child(workspace); - preview = memnew(Sprite); + preview = memnew(Sprite2D); workspace->add_child(preview); preview->set_centered(false); preview->set_draw_behind_parent(true); @@ -626,7 +624,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { //--------------- cd = memnew(ConfirmationDialog); add_child(cd); - cd->connect("confirmed", this, "_on_tileset_toolbar_confirm"); + cd->connect("confirmed", callable_mp(this, &TileSetEditor::_on_tileset_toolbar_confirm)); //--------------- err_dialog = memnew(AcceptDialog); @@ -635,17 +633,16 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { //--------------- texture_dialog = memnew(EditorFileDialog); texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); - texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES); + texture_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); texture_dialog->clear_filters(); List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + ResourceLoader::get_recognized_extensions_for_type("Texture2D", &extensions); for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper()); } add_child(texture_dialog); - texture_dialog->connect("files_selected", this, "_on_textures_added"); + texture_dialog->connect("files_selected", callable_mp(this, &TileSetEditor::_on_textures_added)); //--------------- helper = memnew(TilesetEditorContext(this)); @@ -658,15 +655,16 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) { } TileSetEditor::~TileSetEditor() { - if (helper) + if (helper) { memdelete(helper); + } } void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { option = p_index; switch (option) { case TOOL_TILESET_ADD_TEXTURE: { - texture_dialog->popup_centered_ratio(); + texture_dialog->popup_file_dialog(); } break; case TOOL_TILESET_REMOVE_TEXTURE: { if (get_current_texture().is_valid()) { @@ -678,12 +676,10 @@ void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { } } break; case TOOL_TILESET_CREATE_SCENE: { - cd->set_text(TTR("Create from scene? This will overwrite all current tiles.")); cd->popup_centered(Size2(300, 60)); } break; case TOOL_TILESET_MERGE_SCENE: { - cd->set_text(TTR("Merge from scene?")); cd->popup_centered(Size2(300, 60)); } break; @@ -711,16 +707,16 @@ void TileSetEditor::_on_tileset_toolbar_confirm() { } break; case TOOL_TILESET_MERGE_SCENE: case TOOL_TILESET_CREATE_SCENE: { - EditorNode *en = editor; Node *scene = en->get_edited_scene(); - if (!scene) + if (!scene) { break; + } List<int> ids; tileset->get_tile_list(&ids); - undo_redo->create_action(TTR(option == TOOL_TILESET_MERGE_SCENE ? "Merge Tileset from Scene" : "Create Tileset from Scene")); + undo_redo->create_action(option == TOOL_TILESET_MERGE_SCENE ? TTR("Merge Tileset from Scene") : TTR("Create Tileset from Scene")); undo_redo->add_do_method(this, "_undo_redo_import_scene", scene, option == TOOL_TILESET_MERGE_SCENE); undo_redo->add_undo_method(tileset.ptr(), "clear"); for (List<int>::Element *E = ids.front(); E; E = E->next()) { @@ -741,7 +737,7 @@ void TileSetEditor::_on_texture_list_selected(int p_index) { update_workspace_minsize(); } else { current_item_index = -1; - preview->set_texture(NULL); + preview->set_texture(nullptr); workspace->set_custom_minimum_size(Size2i()); update_workspace_tile_mode(); } @@ -750,10 +746,10 @@ void TileSetEditor::_on_texture_list_selected(int p_index) { workspace->update(); } -void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { +void TileSetEditor::_on_textures_added(const PackedStringArray &p_paths) { int invalid_count = 0; for (int i = 0; i < p_paths.size(); i++) { - Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i])); + Ref<Texture2D> t = Ref<Texture2D>(ResourceLoader::load(p_paths[i])); ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture."); @@ -910,9 +906,9 @@ void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) { } void TileSetEditor::_on_workspace_draw() { - - if (tileset.is_null() || !get_current_texture().is_valid()) + if (tileset.is_null() || !get_current_texture().is_valid()) { return; + } const Color COLOR_AUTOTILE = Color(0.3, 0.6, 1); const Color COLOR_SINGLE = Color(1, 1, 0.3); @@ -1071,12 +1067,13 @@ void TileSetEditor::_on_workspace_draw() { Rect2i region = tileset->tile_get_region(t_id); region.position += WORKSPACE_MARGIN; Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { c = COLOR_SINGLE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { c = COLOR_AUTOTILE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { c = COLOR_ATLAS; + } draw_tile_subdivision(t_id, COLOR_SUBDIVISION); workspace->draw_rect(region, c, false); } @@ -1087,39 +1084,43 @@ void TileSetEditor::_on_workspace_draw() { if (workspace_mode != WORKSPACE_EDIT) { Rect2i region = edited_region; Color c; - if (workspace_mode == WORKSPACE_CREATE_SINGLE) + if (workspace_mode == WORKSPACE_CREATE_SINGLE) { c = COLOR_SINGLE; - else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) + } else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) { c = COLOR_AUTOTILE; - else if (workspace_mode == WORKSPACE_CREATE_ATLAS) + } else if (workspace_mode == WORKSPACE_CREATE_ATLAS) { c = COLOR_ATLAS; + } workspace->draw_rect(region, c, false); draw_edited_region_subdivision(); } else { int t_id = get_current_tile(); - if (t_id < 0) + if (t_id < 0) { return; + } Rect2i region; - if (draw_edited_region) + if (draw_edited_region) { region = edited_region; - else { + } else { region = tileset->tile_get_region(t_id); region.position += WORKSPACE_MARGIN; } - if (draw_edited_region) + if (draw_edited_region) { draw_edited_region_subdivision(); - else + } else { draw_tile_subdivision(t_id, COLOR_SUBDIVISION); + } Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { c = COLOR_SINGLE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { c = COLOR_AUTOTILE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { c = COLOR_ATLAS; + } workspace->draw_rect(region, c, false); } } @@ -1128,7 +1129,6 @@ void TileSetEditor::_on_workspace_draw() { } void TileSetEditor::_on_workspace_process() { - if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) { if (!tile_names_visible) { tile_names_visible = true; @@ -1141,9 +1141,9 @@ void TileSetEditor::_on_workspace_process() { } void TileSetEditor::_on_workspace_overlay_draw() { - - if (!tileset.is_valid() || !get_current_texture().is_valid()) + if (!tileset.is_valid() || !get_current_texture().is_valid()) { return; + } const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); @@ -1155,21 +1155,23 @@ void TileSetEditor::_on_workspace_overlay_draw() { tileset->get_tile_list(tiles); for (List<int>::Element *E = tiles->front(); E; E = E->next()) { int t_id = E->get(); - if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) + if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) { continue; + } Rect2 region = tileset->tile_get_region(t_id); region.position += WORKSPACE_MARGIN; region.position *= workspace->get_scale().x; Color c; - if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) { c = COLOR_SINGLE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) { c = COLOR_AUTOTILE; - else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + } else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) { c = COLOR_ATLAS; + } String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); - Ref<Font> font = get_font("font", "Label"); + Ref<Font> font = get_theme_font("font", "Label"); region.set_size(font->get_string_size(tile_id_name)); workspace_overlay->draw_rect(region, c); region.position.y += region.size.y - 2; @@ -1180,10 +1182,11 @@ void TileSetEditor::_on_workspace_overlay_draw() { } int t_id = get_current_tile(); - if (t_id < 0) + if (t_id < 0) { return; + } - Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); + Ref<Texture2D> handle = get_theme_icon("EditorHandle", "EditorIcons"); if (draw_handles) { for (int i = 0; i < current_shape.size(); i++) { workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); @@ -1216,10 +1219,31 @@ bool TileSetEditor::is_within_grabbing_distance_of_first_point(const Vector2 &p_ return distance < p_grab_threshold; } -void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { +void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) { + const Ref<InputEventMouseButton> mb = p_event; - if (tileset.is_null() || !get_current_texture().is_valid()) + if (mb.is_valid()) { + // Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer + // to allow performing this action anywhere, even if the cursor isn't + // hovering the texture in the workspace. + if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) { + print_line("zooming in"); + _zoom_in(); + // Don't scroll up after zooming in. + accept_event(); + } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) { + print_line("zooming out"); + _zoom_out(); + // Don't scroll down after zooming out. + accept_event(); + } + } +} + +void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { + if (tileset.is_null() || !get_current_texture().is_valid()) { return; + } static bool dragging; static bool erasing; @@ -1232,8 +1256,8 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } current_tile_region.position += WORKSPACE_MARGIN; - Ref<InputEventMouseButton> mb = p_ie; - Ref<InputEventMouseMotion> mm = p_ie; + const Ref<InputEventMouseButton> mb = p_ie; + const Ref<InputEventMouseMotion> mm = p_ie; if (mb.is_valid()) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) { @@ -1257,13 +1281,6 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { delete tiles; } } - - // Mouse Wheel Event - if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) { - _zoom_in(); - } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) { - _zoom_out(); - } } // Drag Middle Mouse if (mm.is_valid()) { @@ -1618,16 +1635,14 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { if (dragging_point >= 0) { dragging_point = -1; - PoolVector<Vector2> polygon; + Vector<Vector2> polygon; polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + Vector2 *w = polygon.ptrw(); for (int i = 0; i < current_shape.size(); i++) { w[i] = current_shape[i] - shape_anchor; } - w.release(); - undo_redo->create_action(TTR("Edit Occlusion Polygon")); undo_redo->add_do_method(edited_occlusion_shape.ptr(), "set_polygon", polygon); undo_redo->add_undo_method(edited_occlusion_shape.ptr(), "set_polygon", edited_occlusion_shape->get_polygon()); @@ -1639,18 +1654,16 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { if (dragging_point >= 0) { dragging_point = -1; - PoolVector<Vector2> polygon; + Vector<Vector2> polygon; Vector<int> indices; polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + Vector2 *w = polygon.ptrw(); for (int i = 0; i < current_shape.size(); i++) { w[i] = current_shape[i] - shape_anchor; indices.push_back(i); } - w.release(); - undo_redo->create_action(TTR("Edit Navigation Polygon")); undo_redo->add_do_method(edited_navigation_shape.ptr(), "set_vertices", polygon); undo_redo->add_undo_method(edited_navigation_shape.ptr(), "set_vertices", edited_navigation_shape->get_vertices()); @@ -1677,7 +1690,6 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { pos = snap_point(pos); if (creating_shape) { if (current_shape.size() > 2) { - if (is_within_grabbing_distance_of_first_point(mb->get_position(), grab_threshold)) { close_shape(shape_anchor); workspace->update(); @@ -1727,7 +1739,6 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { if (creating_shape) { - // if the first two corners are within grabbing distance of one another, expand the rect to fill the tile if (is_within_grabbing_distance_of_first_point(current_shape[1], grab_threshold)) { current_shape.set(0, snap_point(shape_anchor)); @@ -1794,13 +1805,13 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { Array sd = tileset->call("tile_get_shapes", get_current_tile()); if (convex.is_valid()) { - // Make concave + // 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 + // Make convex. undo_redo->create_action(TTR("Make Polygon Convex")); Ref<ConvexPolygonShape2D> _convex = memnew(ConvexPolygonShape2D); edited_collision_shape = _convex; @@ -1810,14 +1821,20 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { 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; } } + + undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D(), false, edited_shape_coord); + } else { + undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), edited_collision_shape, Transform2D()); + } + undo_redo->add_do_method(this, "_select_edited_shape_coord"); + undo_redo->add_undo_method(this, "_select_edited_shape_coord"); + undo_redo->commit_action(); + _update_toggle_shape_button(); workspace->update(); workspace_container->update(); @@ -1911,7 +1928,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { } } } - } else if (p_tool == TOOL_SELECT) { + } else if (p_tool == TOOL_SELECT || p_tool == SHAPE_NEW_POLYGON || p_tool == SHAPE_NEW_RECTANGLE) { if (creating_shape) { // Cancel Creation creating_shape = false; @@ -1922,8 +1939,9 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { } void TileSetEditor::_on_priority_changed(float val) { - if ((int)val == tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)) + if ((int)val == tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord)) { return; + } undo_redo->create_action(TTR("Edit Tile Priority")); undo_redo->add_do_method(tileset.ptr(), "autotile_set_subtile_priority", get_current_tile(), edited_shape_coord, (int)val); @@ -1934,8 +1952,9 @@ void TileSetEditor::_on_priority_changed(float val) { } void TileSetEditor::_on_z_index_changed(float val) { - if ((int)val == tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)) + if ((int)val == tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)) { return; + } undo_redo->create_action(TTR("Edit Tile Z Index")); undo_redo->add_do_method(tileset.ptr(), "autotile_set_z_index", get_current_tile(), edited_shape_coord, (int)val); @@ -1976,26 +1995,24 @@ void TileSetEditor::_set_edited_shape_points(const Vector<Vector2> &points) { 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; + } else if (concave.is_valid() && points.size() > 1) { + PackedVector2Array 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) + 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) { @@ -2036,10 +2053,10 @@ void TileSetEditor::_update_toggle_shape_button() { 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_icon(get_theme_icon("ConvexPolygonShape2D", "EditorIcons")); tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Convex")); } else if (convex.is_valid()) { - tools[SHAPE_TOGGLE_TYPE]->set_icon(get_icon("ConcavePolygonShape2D", "EditorIcons")); + tools[SHAPE_TOGGLE_TYPE]->set_icon(get_theme_icon("ConcavePolygonShape2D", "EditorIcons")); tools[SHAPE_TOGGLE_TYPE]->set_text(TTR("Make Concave")); } else { // Shouldn't happen @@ -2339,8 +2356,9 @@ void TileSetEditor::_set_snap_sep(Vector2 p_val) { } void TileSetEditor::_validate_current_tile_id() { - if (get_current_tile() >= 0 && !tileset->has_tile(get_current_tile())) + if (get_current_tile() >= 0 && !tileset->has_tile(get_current_tile())) { set_current_tile(-1); + } } void TileSetEditor::_select_edited_shape_coord() { @@ -2367,12 +2385,12 @@ void TileSetEditor::_undo_tile_removal(int p_id) { undo_redo->add_undo_method(tileset.ptr(), "tile_set_light_occluder", p_id, tileset->tile_get_light_occluder(p_id)); undo_redo->add_undo_method(tileset.ptr(), "tile_set_navigation_polygon", p_id, tileset->tile_get_navigation_polygon(p_id)); } else { - Map<Vector2, Ref<OccluderPolygon2D> > oclusion_map = tileset->autotile_get_light_oclusion_map(p_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = oclusion_map.front(); E; E = E->next()) { + Map<Vector2, Ref<OccluderPolygon2D>> oclusion_map = tileset->autotile_get_light_oclusion_map(p_id); + for (Map<Vector2, Ref<OccluderPolygon2D>>::Element *E = oclusion_map.front(); E; E = E->next()) { undo_redo->add_undo_method(tileset.ptr(), "autotile_set_light_occluder", p_id, E->value(), E->key()); } - Map<Vector2, Ref<NavigationPolygon> > navigation_map = tileset->autotile_get_navigation_map(p_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) { + Map<Vector2, Ref<NavigationPolygon>> navigation_map = tileset->autotile_get_navigation_map(p_id); + for (Map<Vector2, Ref<NavigationPolygon>>::Element *E = navigation_map.front(); E; E = E->next()) { undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key()); } Map<Vector2, uint32_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id); @@ -2404,6 +2422,7 @@ void TileSetEditor::_zoom_in() { workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } } + void TileSetEditor::_zoom_out() { float scale = workspace->get_scale().x; if (scale > min_scale) { @@ -2413,6 +2432,7 @@ void TileSetEditor::_zoom_out() { workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } } + void TileSetEditor::_zoom_reset() { workspace->set_scale(Vector2(1, 1)); workspace_container->set_custom_minimum_size(workspace->get_rect().size); @@ -2420,7 +2440,6 @@ void TileSetEditor::_zoom_reset() { } void TileSetEditor::draw_highlight_current_tile() { - Color shadow_color = Color(0.3, 0.3, 0.3, 0.3); if ((workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) || !edited_region.has_no_area()) { Rect2 region; @@ -2431,21 +2450,24 @@ void TileSetEditor::draw_highlight_current_tile() { region = edited_region; } - if (region.position.y >= 0) + if (region.position.y >= 0) { workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), shadow_color); - if (region.position.x >= 0) + } + if (region.position.x >= 0) { workspace->draw_rect(Rect2(0, MAX(0, region.position.y), region.position.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color); - if (region.position.x + region.size.x <= workspace->get_rect().size.x) + } + if (region.position.x + region.size.x <= workspace->get_rect().size.x) { workspace->draw_rect(Rect2(region.position.x + region.size.x, MAX(0, region.position.y), workspace->get_rect().size.x - region.position.x - region.size.x, MIN(workspace->get_rect().size.y - region.position.y, MIN(region.size.y, region.position.y + region.size.y))), shadow_color); - if (region.position.y + region.size.y <= workspace->get_rect().size.y) + } + if (region.position.y + region.size.y <= workspace->get_rect().size.y) { workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), shadow_color); + } } else { workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), shadow_color); } } void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted) { - Color shadow_color = Color(0.3, 0.3, 0.3, 0.3); Vector2 size = tileset->autotile_get_size(get_current_tile()); int spacing = tileset->autotile_get_spacing(get_current_tile()); @@ -2455,14 +2477,18 @@ void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> coord += region.position; coord += WORKSPACE_MARGIN; - if (coord.y >= 0) + if (coord.y >= 0) { workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), shadow_color); - if (coord.x >= 0) + } + if (coord.x >= 0) { workspace->draw_rect(Rect2(0, MAX(0, coord.y), coord.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color); - if (coord.x + size.x <= workspace->get_rect().size.x) + } + if (coord.x + size.x <= workspace->get_rect().size.x) { workspace->draw_rect(Rect2(coord.x + size.x, MAX(0, coord.y), workspace->get_rect().size.x - coord.x - size.x, MIN(workspace->get_rect().size.y - coord.y, MIN(size.y, coord.y + size.y))), shadow_color); - if (coord.y + size.y <= workspace->get_rect().size.y) + } + if (coord.y + size.y <= workspace->get_rect().size.y) { workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), shadow_color); + } coord += Vector2(1, 1) / workspace->get_scale().x; workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); @@ -2595,10 +2621,10 @@ void TileSetEditor::draw_grid_snap() { } void TileSetEditor::draw_polygon_shapes() { - int t_id = get_current_tile(); - if (t_id < 0) + if (t_id < 0) { return; + } switch (edit_mode) { case EDITMODE_COLLISION: { @@ -2654,17 +2680,18 @@ void TileSetEditor::draw_polygon_shapes() { } } - if (polygon.size() < 3) + 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) { + if (!creating_shape && 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[j], polygon[j + 1], c_border, 1); } - 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); } if (shape == edited_collision_shape) { draw_handles = true; @@ -2697,21 +2724,19 @@ void TileSetEditor::draw_polygon_shapes() { } workspace->draw_polygon(polygon, colors); - if (!creating_shape) { - 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); + if (!creating_shape && polygon.size() > 1) { + for (int j = 0; j < polygon.size() - 1; j++) { + workspace->draw_line(polygon[j], polygon[j + 1], c_border, 1); } + workspace->draw_line(polygon[polygon.size() - 1], polygon[0], c_border, 1); } if (shape == edited_occlusion_shape) { draw_handles = true; } } } else { - Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { + Map<Vector2, Ref<OccluderPolygon2D>> map = tileset->autotile_get_light_oclusion_map(t_id); + for (Map<Vector2, Ref<OccluderPolygon2D>>::Element *E = map.front(); E; E = E->next()) { Vector2 coord = E->key(); Vector2 anchor = tileset->autotile_get_size(t_id); anchor.x += tileset->autotile_get_spacing(t_id); @@ -2747,11 +2772,11 @@ void TileSetEditor::draw_polygon_shapes() { workspace->draw_polygon(polygon, colors); if (coord == edited_shape_coord) { - if (!creating_shape) { + if (!creating_shape && 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[j], polygon[j + 1], c_border, 1); } - 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); } if (shape == edited_occlusion_shape) { draw_handles = true; @@ -2779,7 +2804,7 @@ void TileSetEditor::draw_polygon_shapes() { colors.push_back(c_bg); } } else { - PoolVector<Vector2> vertices = shape->get_vertices(); + Vector<Vector2> vertices = shape->get_vertices(); for (int j = 0; j < shape->get_polygon(0).size(); j++) { polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); colors.push_back(c_bg); @@ -2787,19 +2812,19 @@ void TileSetEditor::draw_polygon_shapes() { } workspace->draw_polygon(polygon, colors); - if (!creating_shape) { + if (!creating_shape && 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[j], polygon[j + 1], c_border, 1); } - 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); } if (shape == edited_navigation_shape) { draw_handles = true; } } } else { - Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { + Map<Vector2, Ref<NavigationPolygon>> map = tileset->autotile_get_navigation_map(t_id); + for (Map<Vector2, Ref<NavigationPolygon>>::Element *E = map.front(); E; E = E->next()) { Vector2 coord = E->key(); Vector2 anchor = tileset->autotile_get_size(t_id); anchor.x += tileset->autotile_get_spacing(t_id); @@ -2827,7 +2852,7 @@ void TileSetEditor::draw_polygon_shapes() { colors.push_back(c_bg); } } else { - PoolVector<Vector2> vertices = shape->get_vertices(); + Vector<Vector2> vertices = shape->get_vertices(); for (int j = 0; j < shape->get_polygon(0).size(); j++) { polygon.push_back(vertices[shape->get_polygon(0)[j]] + anchor); colors.push_back(c_bg); @@ -2836,11 +2861,11 @@ void TileSetEditor::draw_polygon_shapes() { workspace->draw_polygon(polygon, colors); if (coord == edited_shape_coord) { - if (!creating_shape) { + if (!creating_shape && 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[j], polygon[j + 1], c_border, 1); } - 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); } if (shape == edited_navigation_shape) { draw_handles = true; @@ -2854,17 +2879,16 @@ void TileSetEditor::draw_polygon_shapes() { } } - if (creating_shape) { + if (creating_shape && current_shape.size() > 1) { for (int j = 0; j < current_shape.size() - 1; j++) { - workspace->draw_line(current_shape[j], current_shape[j + 1], Color(0, 1, 1), 1, true); + workspace->draw_line(current_shape[j], current_shape[j + 1], Color(0, 1, 1), 1); } - workspace->draw_line(current_shape[current_shape.size() - 1], snap_point(workspace->get_local_mouse_position()), Color(0, 1, 1), 1, true); + workspace->draw_line(current_shape[current_shape.size() - 1], snap_point(workspace->get_local_mouse_position()), Color(0, 1, 1), 1); draw_handles = true; } } void TileSetEditor::close_shape(const Vector2 &shape_anchor) { - creating_shape = false; if (edit_mode == EDITMODE_COLLISION) { @@ -2877,14 +2901,16 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { for (int i = 0; i < current_shape.size(); i++) { points.push_back(current_shape[i] - shape_anchor); - if (i != current_shape.size() - 1) + 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))); - else + } else { p_total += ((current_shape[0].x - current_shape[i].x) * (-current_shape[0].y + (-current_shape[i].y))); + } } - if (p_total < 0) + if (p_total < 0) { points.invert(); + } shape->set_points(points); @@ -2899,10 +2925,11 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } } undo_redo->add_do_method(tileset.ptr(), "tile_set_shapes", get_current_tile(), sd); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D(), false, edited_shape_coord); - else + } else { undo_redo->add_do_method(tileset.ptr(), "tile_add_shape", get_current_tile(), shape, Transform2D()); + } tools[TOOL_SELECT]->set_pressed(true); undo_redo->add_do_method(this, "_select_edited_shape_coord"); undo_redo->add_undo_method(this, "_select_edited_shape_coord"); @@ -2914,15 +2941,14 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } else if (edit_mode == EDITMODE_OCCLUSION) { Ref<OccluderPolygon2D> shape = memnew(OccluderPolygon2D); - PoolVector<Vector2> polygon; + Vector<Vector2> polygon; polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + Vector2 *w = polygon.ptrw(); for (int i = 0; i < current_shape.size(); i++) { w[i] = current_shape[i] - shape_anchor; } - w.release(); shape->set_polygon(polygon); undo_redo->create_action(TTR("Create Occlusion Polygon")); @@ -2940,17 +2966,16 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { } else if (edit_mode == EDITMODE_NAVIGATION) { Ref<NavigationPolygon> shape = memnew(NavigationPolygon); - PoolVector<Vector2> polygon; + Vector<Vector2> polygon; Vector<int> indices; polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + Vector2 *w = polygon.ptrw(); for (int i = 0; i < current_shape.size(); i++) { w[i] = current_shape[i] - shape_anchor; indices.push_back(i); } - w.release(); shape->set_vertices(polygon); shape->add_polygon(indices); @@ -2972,18 +2997,22 @@ 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) + current_shape = PackedVector2Array(); + if (get_current_tile() == -1) { return; + } Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); 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)) + if (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())) + } + 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())) + } + if (edited_navigation_shape != tileset->tile_get_navigation_polygon(get_current_tile())) { edited_navigation_shape = tileset->tile_get_navigation_polygon(get_current_tile()); + } if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); @@ -3003,7 +3032,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_shape.resize(0); if (edited_navigation_shape.is_valid()) { if (edited_navigation_shape->get_polygon_count() > 0) { - PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); + Vector<Vector2> vertices = edited_navigation_shape->get_vertices(); for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position); } @@ -3015,18 +3044,22 @@ void TileSetEditor::select_coord(const Vector2 &coord) { bool found_collision_shape = false; for (int i = 0; i < sd.size(); i++) { if (sd[i].autotile_coord == coord) { - if (edited_collision_shape != sd[i].shape) + if (edited_collision_shape != sd[i].shape) { _set_edited_collision_shape(sd[i].shape); + } found_collision_shape = true; break; } } - if (!found_collision_shape) - _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(NULL)); - if (edited_occlusion_shape != tileset->autotile_get_light_occluder(get_current_tile(), coord)) + if (!found_collision_shape) { + _set_edited_collision_shape(Ref<ConvexPolygonShape2D>(nullptr)); + } + 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)) + } + if (edited_navigation_shape != tileset->autotile_get_navigation_polygon(get_current_tile(), coord)) { edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), coord); + } int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->autotile_get_size(get_current_tile()); @@ -3052,7 +3085,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_shape.resize(0); if (edited_navigation_shape.is_valid()) { if (edited_navigation_shape->get_polygon_count() > 0) { - PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); + Vector<Vector2> vertices = edited_navigation_shape->get_vertices(); for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + shape_anchor); } @@ -3076,6 +3109,7 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { anchor += tileset->tile_get_region(get_current_tile()).position; anchor += WORKSPACE_MARGIN; Rect2 region(anchor, tile_size); + Rect2 tile_region(tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN, tileset->tile_get_region(get_current_tile()).size); if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN; region.size = tileset->tile_get_region(get_current_tile()).size; @@ -3085,26 +3119,45 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { p.x = Math::snap_scalar_separation(snap_offset.x, snap_step.x, p.x, snap_separation.x); p.y = Math::snap_scalar_separation(snap_offset.y, snap_step.y, p.y, snap_separation.y); } + if (tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { - if (p.x < region.position.x) + if (p.x < region.position.x) { p.x = region.position.x; - if (p.y < region.position.y) + } + if (p.y < region.position.y) { p.y = region.position.y; - if (p.x > region.position.x + region.size.x) + } + if (p.x > region.position.x + region.size.x) { p.x = region.position.x + region.size.x; - if (p.y > region.position.y + region.size.y) + } + if (p.y > region.position.y + region.size.y) { p.y = region.position.y + region.size.y; + } + } + + if (p.x < tile_region.position.x) { + p.x = tile_region.position.x; + } + if (p.y < tile_region.position.y) { + p.y = tile_region.position.y; + } + if (p.x > (tile_region.position.x + tile_region.size.x)) { + p.x = (tile_region.position.x + tile_region.size.x); } + if (p.y > (tile_region.position.y + tile_region.size.y)) { + p.y = (tile_region.position.y + tile_region.size.y); + } + return p; } -void TileSetEditor::add_texture(Ref<Texture> p_texture) { +void TileSetEditor::add_texture(Ref<Texture2D> p_texture) { texture_list->add_item(p_texture->get_path().get_file()); texture_map.insert(p_texture->get_rid(), p_texture); texture_list->set_item_metadata(texture_list->get_item_count() - 1, p_texture->get_rid()); } -void TileSetEditor::remove_texture(Ref<Texture> p_texture) { +void TileSetEditor::remove_texture(Ref<Texture2D> p_texture) { texture_list->remove_item(texture_list->find_metadata(p_texture->get_rid())); texture_map.erase(p_texture->get_rid()); @@ -3117,7 +3170,7 @@ void TileSetEditor::remove_texture(Ref<Texture> p_texture) { } void TileSetEditor::update_texture_list() { - Ref<Texture> selected_texture = get_current_texture(); + Ref<Texture2D> selected_texture = get_current_texture(); helper->set_tileset(tileset); @@ -3141,8 +3194,9 @@ void TileSetEditor::update_texture_list() { if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) { texture_list->select(texture_list->find_metadata(selected_texture->get_rid())); - if (texture_list->get_selected_items().size() > 0) + if (texture_list->get_selected_items().size() > 0) { _on_texture_list_selected(texture_list->get_selected_items()[0]); + } } else if (get_current_texture().is_valid()) { _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid())); } else { @@ -3155,7 +3209,6 @@ void TileSetEditor::update_texture_list() { } 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]); @@ -3166,7 +3219,6 @@ void TileSetEditor::update_texture_list_icon() { } void TileSetEditor::update_workspace_tile_mode() { - if (!get_current_texture().is_valid()) { tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); workspace_mode = WORKSPACE_EDIT; @@ -3242,19 +3294,21 @@ void TileSetEditor::update_workspace_tile_mode() { tool_editmode[EDITMODE_PRIORITY]->hide(); tool_editmode[EDITMODE_Z_INDEX]->hide(); } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - if (edit_mode == EDITMODE_ICON) + if (edit_mode == EDITMODE_ICON) { select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); - else + } else { _select_edited_shape_coord(); + } } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { tool_editmode[EDITMODE_COLLISION]->set_pressed(true); edit_mode = EDITMODE_COLLISION; } - if (edit_mode == EDITMODE_ICON) + if (edit_mode == EDITMODE_ICON) { select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); - else + } else { _select_edited_shape_coord(); + } tool_editmode[EDITMODE_BITMASK]->hide(); } @@ -3326,15 +3380,15 @@ void TileSetEditor::set_current_tile(int p_id) { } } -Ref<Texture> TileSetEditor::get_current_texture() { - if (texture_list->get_selected_items().size() == 0) - return Ref<Texture>(); - else +Ref<Texture2D> TileSetEditor::get_current_texture() { + if (texture_list->get_selected_items().size() == 0) { + return Ref<Texture2D>(); + } else { return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])]; + } } void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) { - tileset = p_tileset; } @@ -3344,7 +3398,6 @@ void TilesetEditorContext::set_snap_options_visible(bool p_visible) { } bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name.operator String(); if (name == "options_offset") { @@ -3363,8 +3416,9 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value String name2 = p_name.operator String().right(5); bool v = false; - if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) { return false; + } if (name2 == "autotile_bitmask_mode") { tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); @@ -3410,7 +3464,6 @@ bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value } bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const { - String name = p_name.operator String(); bool v = false; @@ -3426,10 +3479,12 @@ bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const } else if (name.left(5) == "tile_") { name = name.right(5); - if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) { return false; - if (!tileset->has_tile(tileset_editor->get_current_tile())) + } + if (!tileset->has_tile(tileset_editor->get_current_tile())) { return false; + } if (name == "autotile_bitmask_mode") { r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v); @@ -3476,7 +3531,6 @@ bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const } void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const { - if (snap_options_visible) { p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP)); p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset")); @@ -3487,7 +3541,7 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const int id = tileset_editor->get_current_tile(); p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP)); p_list->push_back(PropertyInfo(Variant::STRING, "tile_name")); - p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset")); p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate")); @@ -3504,13 +3558,13 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1")); } 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)); + p_list->push_back(PropertyInfo(Variant::FLOAT, "selected_collision_one_way_margin", PROPERTY_HINT_NONE)); } } if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) { @@ -3525,25 +3579,21 @@ void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const } void TilesetEditorContext::_bind_methods() { - ClassDB::bind_method("_hide_script_from_inspector", &TilesetEditorContext::_hide_script_from_inspector); } 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)); } } bool TileSetEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("TileSet") || p_node->is_class("TilesetEditorContext"); } @@ -3551,16 +3601,15 @@ void TileSetEditorPlugin::make_visible(bool p_visible) { if (p_visible) { tileset_editor_button->show(); editor->make_bottom_panel_item_visible(tileset_editor); - get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process"); + get_tree()->connect_compat("idle_frame", tileset_editor, "_on_workspace_process"); } else { editor->hide_bottom_panel(); tileset_editor_button->hide(); - get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process"); + get_tree()->disconnect_compat("idle_frame", tileset_editor, "_on_workspace_process"); } } Dictionary TileSetEditorPlugin::get_state() const { - Dictionary state; state["snap_offset"] = tileset_editor->snap_offset; state["snap_step"] = tileset_editor->snap_step; @@ -3572,7 +3621,6 @@ Dictionary TileSetEditorPlugin::get_state() const { } void TileSetEditorPlugin::set_state(const Dictionary &p_state) { - Dictionary state = p_state; if (state.has("snap_step")) { tileset_editor->_set_snap_step(state["snap_step"]); diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 0e0bd6448c..72eb14941c 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -32,7 +32,7 @@ #define TILE_SET_EDITOR_PLUGIN_H #include "editor/editor_node.h" -#include "scene/2d/sprite.h" +#include "scene/2d/sprite_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" @@ -41,13 +41,12 @@ class TilesetEditorContext; class TileSetEditor : public HSplitContainer { - friend class TileSetEditorPlugin; friend class TilesetEditorContext; GDCLASS(TileSetEditor, HSplitContainer); - enum TextureToolButtons { + enum TextureButtons { TOOL_TILESET_ADD_TEXTURE, TOOL_TILESET_REMOVE_TEXTURE, TOOL_TILESET_CREATE_SCENE, @@ -112,9 +111,9 @@ class TileSetEditor : public HSplitContainer { ItemList *texture_list; int option; - ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX]; + Button *tileset_toolbar_buttons[TOOL_TILESET_MAX]; MenuButton *tileset_toolbar_tools; - Map<RID, Ref<Texture> > texture_map; + Map<RID, Ref<Texture2D>> texture_map; bool creating_shape; int dragging_point; @@ -123,7 +122,7 @@ class TileSetEditor : public HSplitContainer { Rect2 edited_region; bool draw_edited_region; Vector2 edited_shape_coord; - PoolVector2Array current_shape; + PackedVector2Array current_shape; Map<Vector2i, SubtileData> current_tile_data; Map<Vector2, uint32_t> bitmask_map_copy; @@ -136,7 +135,7 @@ class TileSetEditor : public HSplitContainer { Ref<NavigationPolygon> edited_navigation_shape; int current_item_index; - Sprite *preview; + Sprite2D *preview; ScrollContainer *scroll; Label *empty_message; Control *workspace_container; @@ -147,7 +146,7 @@ class TileSetEditor : public HSplitContainer { Button *tool_editmode[EDITMODE_MAX]; HSeparator *separator_editmode; HBoxContainer *toolbar; - ToolButton *tools[TOOL_MAX]; + Button *tools[TOOL_MAX]; VSeparator *separator_shape_toggle; VSeparator *separator_bitmask; VSeparator *separator_delete; @@ -165,10 +164,10 @@ class TileSetEditor : public HSplitContainer { void update_texture_list(); void update_texture_list_icon(); - void add_texture(Ref<Texture> p_texture); - void remove_texture(Ref<Texture> p_texture); + void add_texture(Ref<Texture2D> p_texture); + void remove_texture(Ref<Texture2D> p_texture); - Ref<Texture> get_current_texture(); + Ref<Texture2D> get_current_texture(); static void _import_node(Node *p_node, Ref<TileSet> p_library); static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); @@ -178,7 +177,7 @@ class TileSetEditor : public HSplitContainer { Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); - void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1); + void _file_load_request(const Vector<String> &p_path, int p_at_pos = -1); protected: static void _bind_methods(); @@ -195,12 +194,13 @@ private: void _on_tileset_toolbar_button_pressed(int p_index); void _on_tileset_toolbar_confirm(); void _on_texture_list_selected(int p_index); - void _on_textures_added(const PoolStringArray &p_paths); + void _on_textures_added(const PackedStringArray &p_paths); void _on_edit_mode_changed(int p_edit_mode); void _on_workspace_mode_changed(int p_workspace_mode); void _on_workspace_overlay_draw(); void _on_workspace_draw(); void _on_workspace_process(); + void _on_scroll_container_input(const Ref<InputEvent> &p_event); void _on_workspace_input(const Ref<InputEvent> &p_ie); void _on_tool_clicked(int p_tool); void _on_priority_changed(float val); @@ -252,7 +252,6 @@ private: }; class TilesetEditorContext : public Object { - friend class TileSetEditor; GDCLASS(TilesetEditorContext, Object); @@ -278,7 +277,6 @@ public: }; class TileSetEditorPlugin : public EditorPlugin { - GDCLASS(TileSetEditorPlugin, EditorPlugin); TileSetEditor *tileset_editor; @@ -286,13 +284,13 @@ class TileSetEditorPlugin : public EditorPlugin { EditorNode *editor; public: - virtual String get_name() const { return "TileSet"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); - void set_state(const Dictionary &p_state); - Dictionary get_state() const; + virtual String get_name() const override { return "TileSet"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_node) override; + virtual bool handles(Object *p_node) const override; + virtual void make_visible(bool p_visible) override; + void set_state(const Dictionary &p_state) override; + Dictionary get_state() const override; TileSetEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index c53fc7e6c5..cfbe54ef61 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -35,18 +35,9 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" -VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = NULL; +VersionControlEditorPlugin *VersionControlEditorPlugin::singleton = nullptr; void VersionControlEditorPlugin::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_selected_a_vcs"), &VersionControlEditorPlugin::_selected_a_vcs); - ClassDB::bind_method(D_METHOD("_initialize_vcs"), &VersionControlEditorPlugin::_initialize_vcs); - ClassDB::bind_method(D_METHOD("_send_commit_msg"), &VersionControlEditorPlugin::_send_commit_msg); - ClassDB::bind_method(D_METHOD("_refresh_stage_area"), &VersionControlEditorPlugin::_refresh_stage_area); - ClassDB::bind_method(D_METHOD("_stage_all"), &VersionControlEditorPlugin::_stage_all); - ClassDB::bind_method(D_METHOD("_stage_selected"), &VersionControlEditorPlugin::_stage_selected); - ClassDB::bind_method(D_METHOD("_view_file_diff"), &VersionControlEditorPlugin::_view_file_diff); - ClassDB::bind_method(D_METHOD("_refresh_file_diff"), &VersionControlEditorPlugin::_refresh_file_diff); ClassDB::bind_method(D_METHOD("popup_vcs_set_up_dialog"), &VersionControlEditorPlugin::popup_vcs_set_up_dialog); // Used to track the status of files in the staging area @@ -58,20 +49,16 @@ void VersionControlEditorPlugin::_bind_methods() { } void VersionControlEditorPlugin::_selected_a_vcs(int p_id) { - List<StringName> available_addons = get_available_vcs_names(); const StringName selected_vcs = set_up_choice->get_item_text(p_id); } void VersionControlEditorPlugin::_populate_available_vcs_names() { - static bool called = false; if (!called) { - List<StringName> available_addons = get_available_vcs_names(); for (int i = 0; i < available_addons.size(); i++) { - set_up_choice->add_item(available_addons[i]); } @@ -80,16 +67,13 @@ void VersionControlEditorPlugin::_populate_available_vcs_names() { } VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() { - return singleton ? singleton : memnew(VersionControlEditorPlugin); } void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) { - fetch_available_vcs_addon_names(); List<StringName> available_addons = get_available_vcs_names(); if (available_addons.size() >= 1) { - Size2 popup_size = Size2(400, 100); Size2 window_size = p_gui_base->get_viewport_rect().size; popup_size.x = MIN(window_size.x * 0.5, popup_size.x); @@ -99,13 +83,11 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba set_up_dialog->popup_centered_clamped(popup_size * EDSCALE); } else { - EditorNode::get_singleton()->show_warning(TTR("No VCS addons are available."), TTR("Error")); } } void VersionControlEditorPlugin::_initialize_vcs() { - register_editor(); ERR_FAIL_COND_MSG(EditorVCSInterface::get_singleton(), EditorVCSInterface::get_singleton()->get_vcs_name() + " is already active"); @@ -124,10 +106,10 @@ void VersionControlEditorPlugin::_initialize_vcs() { ERR_FAIL_COND_MSG(!addon_script_instance, "Failed to create addon script instance."); // The addon is attached as a script to the VCS interface as a proxy end-point - vcs_interface->set_script_and_instance(script.get_ref_ptr(), addon_script_instance); + vcs_interface->set_script_and_instance(script, addon_script_instance); EditorVCSInterface::set_singleton(vcs_interface); - EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_refresh_stage_area"); + EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); String res_dir = OS::get_singleton()->get_resource_dir(); @@ -137,18 +119,14 @@ void VersionControlEditorPlugin::_initialize_vcs() { } void VersionControlEditorPlugin::_send_commit_msg() { - String msg = commit_message->get_text(); if (msg == "") { - commit_status->set_text(TTR("No commit message was provided")); return; } if (EditorVCSInterface::get_singleton()) { - if (staged_files_count == 0) { - commit_status->set_text(TTR("No files added to stage")); return; } @@ -158,7 +136,6 @@ void VersionControlEditorPlugin::_send_commit_msg() { commit_message->set_text(""); version_control_dock_button->set_pressed(false); } else { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); } @@ -168,20 +145,16 @@ void VersionControlEditorPlugin::_send_commit_msg() { } void VersionControlEditorPlugin::_refresh_stage_area() { - if (EditorVCSInterface::get_singleton()) { - staged_files_count = 0; clear_stage_area(); Dictionary modified_file_paths = EditorVCSInterface::get_singleton()->get_modified_files_data(); String file_path; for (int i = 0; i < modified_file_paths.size(); i++) { - file_path = modified_file_paths.get_key_at_index(i); - TreeItem *found = stage_files->search_item_text(file_path, 0, true); + TreeItem *found = stage_files->search_item_text(file_path, nullptr, true); if (!found) { - ChangeType change_index = (ChangeType)(int)modified_file_paths.get_value_at_index(i); String change_text = file_path + " (" + change_type_to_strings[change_index] + ")"; Color &change_color = change_type_to_color[change_index]; @@ -193,24 +166,19 @@ void VersionControlEditorPlugin::_refresh_stage_area() { new_item->set_checked(0, true); new_item->set_editable(0, true); } else { - if (found->get_metadata(0) == diff_file_name->get_text()) { - _refresh_file_diff(); } } commit_status->set_text("New changes detected"); } } else { - - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu.") + WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu."); } } void VersionControlEditorPlugin::_stage_selected() { - if (!EditorVCSInterface::get_singleton()) { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); return; } @@ -218,19 +186,15 @@ void VersionControlEditorPlugin::_stage_selected() { staged_files_count = 0; TreeItem *root = stage_files->get_root(); if (root) { - TreeItem *file_entry = root->get_children(); while (file_entry) { - if (file_entry->is_checked(0)) { - EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor")); + file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor")); staged_files_count++; } else { - EditorVCSInterface::get_singleton()->unstage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor")); } file_entry = file_entry->get_next(); @@ -241,9 +205,7 @@ void VersionControlEditorPlugin::_stage_selected() { } void VersionControlEditorPlugin::_stage_all() { - if (!EditorVCSInterface::get_singleton()) { - WARN_PRINT("No VCS addon is initialized. Select a Version Control Addon from Project menu"); return; } @@ -251,12 +213,10 @@ void VersionControlEditorPlugin::_stage_all() { staged_files_count = 0; TreeItem *root = stage_files->get_root(); if (root) { - TreeItem *file_entry = root->get_children(); while (file_entry) { - EditorVCSInterface::get_singleton()->stage_file(file_entry->get_metadata(0)); - file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor")); + file_entry->set_icon_modulate(0, EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor")); file_entry->set_checked(0, true); staged_files_count++; @@ -268,7 +228,6 @@ void VersionControlEditorPlugin::_stage_all() { } void VersionControlEditorPlugin::_view_file_diff() { - version_control_dock_button->set_pressed(true); String file_path = stage_files->get_selected()->get_metadata(0); @@ -277,26 +236,21 @@ void VersionControlEditorPlugin::_view_file_diff() { } void VersionControlEditorPlugin::_display_file_diff(String p_file_path) { - Array diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path); diff_file_name->set_text(p_file_path); diff->clear(); - diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts")); + diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font("source", "EditorFonts")); for (int i = 0; i < diff_content.size(); i++) { - Dictionary line_result = diff_content[i]; if (line_result["status"] == "+") { - - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor")); + diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor")); } else if (line_result["status"] == "-") { - - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor")); } else { - - diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Label")); + diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color("font_color", "Label")); } diff->add_text((String)line_result["content"]); @@ -307,42 +261,33 @@ void VersionControlEditorPlugin::_display_file_diff(String p_file_path) { } void VersionControlEditorPlugin::_refresh_file_diff() { - String open_file = diff_file_name->get_text(); if (open_file != "") { - _display_file_diff(diff_file_name->get_text()); } } void VersionControlEditorPlugin::_clear_file_diff() { - diff->clear(); diff_file_name->set_text(""); version_control_dock_button->set_pressed(false); } void VersionControlEditorPlugin::_update_stage_status() { - String status; if (staged_files_count == 1) { - status = "Stage contains 1 file"; } else { - status = "Stage contains " + String::num_int64(staged_files_count) + " files"; } commit_status->set_text(status); } void VersionControlEditorPlugin::_update_commit_status() { - String status; if (staged_files_count == 1) { - status = "Committed 1 file"; } else { - status = "Committed " + String::num_int64(staged_files_count) + " files "; } commit_status->set_text(status); @@ -350,50 +295,43 @@ void VersionControlEditorPlugin::_update_commit_status() { } void VersionControlEditorPlugin::register_editor() { - if (!EditorVCSInterface::get_singleton()) { - EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock); TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control(); dock_vbc->set_tab_title(version_commit_dock->get_index(), TTR("Commit")); - ToolButton *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock); + Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock); set_version_control_tool_button(vc); } } void VersionControlEditorPlugin::fetch_available_vcs_addon_names() { - List<StringName> global_classes; ScriptServer::get_global_class_list(&global_classes); for (int i = 0; i != global_classes.size(); i++) { - String path = ScriptServer::get_global_class_path(global_classes[i]); Ref<Script> script = ResourceLoader::load(path); ERR_FAIL_COND(script.is_null()); if (script->get_instance_base_type() == "EditorVCSInterface") { - available_addons.push_back(global_classes[i]); } } } void VersionControlEditorPlugin::clear_stage_area() { - stage_files->get_root()->clear_children(); } void VersionControlEditorPlugin::shut_down() { - if (EditorVCSInterface::get_singleton()) { - if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", this, "_refresh_stage_area")) { - EditorFileSystem::get_singleton()->disconnect("filesystem_changed", this, "_refresh_stage_area"); + if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area))) { + EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); } EditorVCSInterface::get_singleton()->shut_down(); memdelete(EditorVCSInterface::get_singleton()); - EditorVCSInterface::set_singleton(NULL); + EditorVCSInterface::set_singleton(nullptr); EditorNode::get_singleton()->remove_control_from_dock(version_commit_dock); EditorNode::get_singleton()->remove_bottom_panel_item(version_control_dock); @@ -401,26 +339,22 @@ void VersionControlEditorPlugin::shut_down() { } bool VersionControlEditorPlugin::is_vcs_initialized() const { - return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->is_vcs_initialized() : false; } const String VersionControlEditorPlugin::get_vcs_name() const { - return EditorVCSInterface::get_singleton() ? EditorVCSInterface::get_singleton()->get_vcs_name() : ""; } VersionControlEditorPlugin::VersionControlEditorPlugin() { - singleton = this; staged_files_count = 0; version_control_actions = memnew(PopupMenu); - version_control_actions->set_v_size_flags(BoxContainer::SIZE_SHRINK_CENTER); set_up_dialog = memnew(AcceptDialog); set_up_dialog->set_title(TTR("Set Up Version Control")); - set_up_dialog->set_custom_minimum_size(Size2(400, 100)); + set_up_dialog->set_min_size(Size2(400, 100)); version_control_actions->add_child(set_up_dialog); set_up_ok_button = set_up_dialog->get_ok(); @@ -444,19 +378,16 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { set_up_choice = memnew(OptionButton); set_up_choice->set_h_size_flags(HBoxContainer::SIZE_EXPAND_FILL); - set_up_choice->connect("item_selected", this, "_selected_a_vcs"); + set_up_choice->connect("item_selected", callable_mp(this, &VersionControlEditorPlugin::_selected_a_vcs)); set_up_hbc->add_child(set_up_choice); - set_up_init_settings = NULL; + set_up_init_settings = nullptr; set_up_init_button = memnew(Button); set_up_init_button->set_text(TTR("Initialize")); - set_up_init_button->connect("pressed", this, "_initialize_vcs"); + set_up_init_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_initialize_vcs)); set_up_vbc->add_child(set_up_init_button); - version_control_actions->set_v_size_flags(PopupMenu::SIZE_EXPAND_FILL); - version_control_actions->set_h_size_flags(PopupMenu::SIZE_EXPAND_FILL); - version_commit_dock = memnew(VBoxContainer); version_commit_dock->set_visible(false); @@ -478,8 +409,8 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { refresh_button = memnew(Button); refresh_button->set_tooltip(TTR("Detect new changes")); refresh_button->set_text(TTR("Refresh")); - refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Reload", "EditorIcons")); - refresh_button->connect("pressed", this, "_refresh_stage_area"); + refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Reload", "EditorIcons")); + refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area)); stage_tools->add_child(refresh_button); stage_files = memnew(Tree); @@ -492,7 +423,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { stage_files->set_allow_rmb_select(true); stage_files->set_select_mode(Tree::SelectMode::SELECT_MULTI); stage_files->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); - stage_files->connect("cell_selected", this, "_view_file_diff"); + stage_files->connect("cell_selected", callable_mp(this, &VersionControlEditorPlugin::_view_file_diff)); stage_files->create_item(); stage_files->set_hide_root(true); commit_box_vbc->add_child(stage_files); @@ -503,11 +434,11 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { change_type_to_strings[CHANGE_TYPE_DELETED] = TTR("Deleted"); change_type_to_strings[CHANGE_TYPE_TYPECHANGE] = TTR("Typechange"); - change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor"); - change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"); - change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_color("disabled_font_color", "Editor"); - change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"); - change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_color("font_color", "Editor"); + change_type_to_color[CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("success_color", "Editor"); + change_type_to_color[CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor"); + change_type_to_color[CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("disabled_font_color", "Editor"); + change_type_to_color[CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor"); + change_type_to_color[CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color("font_color", "Editor"); stage_buttons = memnew(HSplitContainer); stage_buttons->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN_COLLAPSED); @@ -516,12 +447,12 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { stage_selected_button = memnew(Button); stage_selected_button->set_h_size_flags(Button::SIZE_EXPAND_FILL); stage_selected_button->set_text(TTR("Stage Selected")); - stage_selected_button->connect("pressed", this, "_stage_selected"); + stage_selected_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_selected)); stage_buttons->add_child(stage_selected_button); stage_all_button = memnew(Button); stage_all_button->set_text(TTR("Stage All")); - stage_all_button->connect("pressed", this, "_stage_all"); + stage_all_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_stage_all)); stage_buttons->add_child(stage_all_button); commit_box_vbc->add_child(memnew(HSeparator)); @@ -537,7 +468,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { commit_button = memnew(Button); commit_button->set_text(TTR("Commit Changes")); - commit_button->connect("pressed", this, "_send_commit_msg"); + commit_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_send_commit_msg)); commit_box_vbc->add_child(commit_button); commit_status = memnew(Label); @@ -570,8 +501,8 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { diff_refresh_button = memnew(Button); diff_refresh_button->set_tooltip(TTR("Detect changes in file diff")); - diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Reload", "EditorIcons")); - diff_refresh_button->connect("pressed", this, "_refresh_file_diff"); + diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Reload", "EditorIcons")); + diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff)); diff_hbc->add_child(diff_refresh_button); diff = memnew(RichTextLabel); @@ -582,7 +513,6 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { } VersionControlEditorPlugin::~VersionControlEditorPlugin() { - shut_down(); memdelete(version_control_dock); memdelete(version_commit_dock); diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h index 4a98c8580e..248a1435fd 100644 --- a/editor/plugins/version_control_editor_plugin.h +++ b/editor/plugins/version_control_editor_plugin.h @@ -39,7 +39,6 @@ #include "scene/gui/tree.h" class VersionControlEditorPlugin : public EditorPlugin { - GDCLASS(VersionControlEditorPlugin, EditorPlugin) public: @@ -91,7 +90,7 @@ private: Label *commit_status; PanelContainer *version_control_dock; - ToolButton *version_control_dock_button; + Button *version_control_dock_button; VBoxContainer *diff_vbc; HBoxContainer *diff_hbc; Button *diff_refresh_button; @@ -122,7 +121,7 @@ public: static VersionControlEditorPlugin *get_singleton(); void popup_vcs_set_up_dialog(const Control *p_gui_base); - void set_version_control_tool_button(ToolButton *p_button) { version_control_dock_button = p_button; } + void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; } PopupMenu *get_version_control_actions_panel() const { return version_control_actions; } VBoxContainer *get_version_commit_dock() const { return version_commit_dock; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e334d4b093..7a70f4c5b6 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -30,38 +30,603 @@ #include "visual_shader_editor_plugin.h" +#include "core/input/input.h" #include "core/io/resource_loader.h" #include "core/math/math_defs.h" -#include "core/os/input.h" #include "core/os/keyboard.h" #include "core/project_settings.h" +#include "core/version.h" #include "editor/editor_log.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" -#include "scene/main/viewport.h" +#include "scene/main/window.h" #include "scene/resources/visual_shader_nodes.h" -#include "servers/visual/shader_types.h" +#include "servers/display_server.h" +#include "servers/rendering/shader_types.h" Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) { - if (get_script_instance()) { return get_script_instance()->call("create_editor", p_parent_resource, p_node); } - return NULL; + return nullptr; } void VisualShaderNodePlugin::_bind_methods() { - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "create_editor", PropertyInfo(Variant::OBJECT, "parent_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::OBJECT, "for_node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode"))); } /////////////////// -void VisualShaderEditor::edit(VisualShader *p_visual_shader) { +static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { + Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); + style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); + style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); + style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * EDSCALE); + style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); + return style; +} + +/////////////////// + +VisualShaderGraphPlugin::VisualShaderGraphPlugin() { +} + +void VisualShaderGraphPlugin::_bind_methods() { + ClassDB::bind_method("add_node", &VisualShaderGraphPlugin::add_node); + ClassDB::bind_method("remove_node", &VisualShaderGraphPlugin::remove_node); + ClassDB::bind_method("connect_nodes", &VisualShaderGraphPlugin::connect_nodes); + ClassDB::bind_method("disconnect_nodes", &VisualShaderGraphPlugin::disconnect_nodes); + ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position); + ClassDB::bind_method("set_node_size", &VisualShaderGraphPlugin::set_node_size); + ClassDB::bind_method("show_port_preview", &VisualShaderGraphPlugin::show_port_preview); + ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node); + ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred); + ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value); + ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name); +} + +void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) { + visual_shader = Ref<VisualShader>(p_shader); +} + +void VisualShaderGraphPlugin::set_connections(List<VisualShader::Connection> &p_connections) { + connections = p_connections; +} + +void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) { + if (visual_shader->get_shader_type() == p_type && links.has(p_node_id)) { + for (Map<int, Port>::Element *E = links[p_node_id].output_ports.front(); E; E = E->next()) { + E->value().preview_button->set_pressed(false); + } + + if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) { + links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box); + memdelete(links[p_node_id].preview_box); + links[p_node_id].graph_node->set_size(Vector2(-1, -1)); + links[p_node_id].preview_visible = false; + } + + if (p_port_id != -1) { + if (is_dirty()) { + links[p_node_id].preview_pos = links[p_node_id].graph_node->get_child_count(); + } + + VBoxContainer *vbox = memnew(VBoxContainer); + links[p_node_id].graph_node->add_child(vbox); + if (links[p_node_id].preview_pos != -1) { + links[p_node_id].graph_node->move_child(vbox, links[p_node_id].preview_pos); + } + + Control *offset = memnew(Control); + offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); + vbox->add_child(offset); + + VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); + port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id); + port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER); + vbox->add_child(port_preview); + links[p_node_id].preview_visible = true; + links[p_node_id].preview_box = vbox; + links[p_node_id].output_ports[p_port_id].preview_button->set_pressed(true); + } + } +} + +void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) { + call_deferred("update_node", p_type, p_node_id); +} + +void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) { + if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { + return; + } + remove_node(p_type, p_node_id); + add_node(p_type, p_node_id); +} + +void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value) { + if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { + return; + } + + Button *button = links[p_node_id].input_ports[p_port_id].default_input_button; + + switch (p_value.get_type()) { + case Variant::COLOR: { + button->set_custom_minimum_size(Size2(30, 0) * EDSCALE); + if (!button->is_connected("draw", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_draw_color_over_button))) { + button->connect("draw", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_draw_color_over_button), varray(button, p_value)); + } + } break; + case Variant::BOOL: { + button->set_text(((bool)p_value) ? "true" : "false"); + } break; + case Variant::INT: + case Variant::FLOAT: { + button->set_text(String::num(p_value, 4)); + } break; + case Variant::VECTOR3: { + Vector3 v = p_value; + button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3)); + } break; + default: { + } + } +} + +void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name) { + if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].uniform_name != nullptr) { + links[p_node_id].uniform_name->set_text(p_name); + } +} + +void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) { + links[p_node_id].input_ports.insert(p_port_id, { p_button }); +} + +void VisualShaderGraphPlugin::update_uniform_refs() { + for (Map<int, Link>::Element *E = links.front(); E; E = E->next()) { + VisualShaderNodeUniformRef *ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().visual_node); + if (ref) { + remove_node(E->get().type, E->key()); + add_node(E->get().type, E->key()); + } + } +} + +VisualShader::Type VisualShaderGraphPlugin::get_shader_type() const { + return visual_shader->get_shader_type(); +} + +void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) { + if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { + links[p_id].graph_node->set_offset(p_position); + } +} + +void VisualShaderGraphPlugin::set_node_size(VisualShader::Type p_type, int p_id, const Vector2 &p_size) { + if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { + links[p_id].graph_node->set_size(p_size); + } +} + +bool VisualShaderGraphPlugin::is_preview_visible(int p_id) const { + return links[p_id].preview_visible; +} + +void VisualShaderGraphPlugin::clear_links() { + links.clear(); +} + +bool VisualShaderGraphPlugin::is_dirty() const { + return dirty; +} + +void VisualShaderGraphPlugin::make_dirty(bool p_enabled) { + dirty = p_enabled; +} + +void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) { + links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr }); +} + +void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) { + links[p_node_id].output_ports.insert(p_port, { p_button }); +} + +void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_uniform_name) { + links[p_node_id].uniform_name = p_uniform_name; +} + +void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { + if (p_type != visual_shader->get_shader_type()) { + return; + } + + Control *offset; + + static Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1); + + static const Color type_color[6] = { + Color(0.38, 0.85, 0.96), // scalar (float) + Color(0.49, 0.78, 0.94), // scalar (int) + Color(0.84, 0.49, 0.93), // vector + Color(0.55, 0.65, 0.94), // boolean + Color(0.96, 0.66, 0.43), // transform + Color(1.0, 1.0, 0.0), // sampler + }; + + Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id); + + Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr()); + bool is_group = !group_node.is_null(); + Size2 size = Size2(0, 0); + + Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr()); + bool is_expression = !expression_node.is_null(); + String expression = ""; + + GraphNode *node = memnew(GraphNode); + register_link(p_type, p_id, vsnode.ptr(), node); + + if (is_group) { + size = group_node->get_size(); + + node->set_resizable(true); + node->connect("resize_request", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_resized), varray((int)p_type, p_id)); + } + if (is_expression) { + expression = expression_node->get_expression(); + } + + node->set_offset(visual_shader->get_node_position(p_type, p_id)); + node->set_title(vsnode->get_caption()); + node->set_name(itos(p_id)); + + if (p_id >= 2) { + node->set_show_close_button(true); + node->connect("close_request", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_delete_request), varray(p_id), CONNECT_DEFERRED); + } + + node->connect("dragged", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_dragged), varray(p_id)); + + Control *custom_editor = nullptr; + int port_offset = 0; + + if (is_group) { + port_offset += 2; + } + + Ref<VisualShaderNodeUniform> uniform = vsnode; + if (uniform.is_valid()) { + VisualShaderEditor::get_singleton()->graph->add_child(node); + VisualShaderEditor::get_singleton()->_update_created_node(node); + + LineEdit *uniform_name = memnew(LineEdit); + register_uniform_name(p_id, uniform_name); + uniform_name->set_text(uniform->get_uniform_name()); + node->add_child(uniform_name); + uniform_name->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id)); + uniform_name->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_focus_out), varray(uniform_name, p_id)); + + if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") { + //shortcut + VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); + node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); + if (!vsnode->is_use_prop_slots()) { + return; + } + } + port_offset++; + } + + for (int i = 0; i < VisualShaderEditor::get_singleton()->plugins.size(); i++) { + vsnode->set_meta("id", p_id); + vsnode->set_meta("shader_type", (int)p_type); + custom_editor = VisualShaderEditor::get_singleton()->plugins.write[i]->create_editor(visual_shader, vsnode); + vsnode->remove_meta("id"); + vsnode->remove_meta("shader_type"); + if (custom_editor) { + if (vsnode->is_show_prop_names()) { + custom_editor->call_deferred("_show_prop_names", true); + } + break; + } + } + + if (custom_editor && !vsnode->is_use_prop_slots() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { + //will be embedded in first port + } else if (custom_editor) { + port_offset++; + node->add_child(custom_editor); + if (vsnode->is_use_prop_slots()) { + return; + } + custom_editor = nullptr; + } + + if (is_group) { + offset = memnew(Control); + offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE)); + node->add_child(offset); + + if (group_node->is_editable()) { + HBoxContainer *hb2 = memnew(HBoxContainer); + + Button *add_input_btn = memnew(Button); + add_input_btn->set_text(TTR("Add Input")); + add_input_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_add_input_port), varray(p_id, group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_input_btn); + + hb2->add_spacer(); + + Button *add_output_btn = memnew(Button); + add_output_btn->set_text(TTR("Add Output")); + add_output_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_add_output_port), varray(p_id, group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_output_btn); + + node->add_child(hb2); + } + } + + for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { + if (vsnode->is_port_separator(i)) { + node->add_child(memnew(HSeparator)); + port_offset++; + } + + bool valid_left = i < vsnode->get_input_port_count(); + VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR; + bool port_left_used = false; + String name_left; + if (valid_left) { + name_left = vsnode->get_input_port_name(i); + port_left = vsnode->get_input_port_type(i); + for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { + if (E->get().to_node == p_id && E->get().to_port == i) { + port_left_used = true; + } + } + } + + bool valid_right = i < vsnode->get_output_port_count(); + VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR; + String name_right; + if (valid_right) { + name_right = vsnode->get_output_port_name(i); + port_right = vsnode->get_output_port_type(i); + } + + HBoxContainer *hb = memnew(HBoxContainer); + hb->add_theme_constant_override("separation", 7 * EDSCALE); + + Variant default_value; + + if (valid_left && !port_left_used) { + default_value = vsnode->get_input_port_default_value(i); + } + + Button *button = memnew(Button); + hb->add_child(button); + register_default_input_button(p_id, i, button); + button->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_edit_port_default_input), varray(button, p_id, i)); + if (default_value.get_type() != Variant::NIL) { // only a label + set_input_port_default_value(p_type, p_id, i, default_value); + } else { + button->hide(); + } + + if (i == 0 && custom_editor) { + hb->add_child(custom_editor); + custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); + } else { + if (valid_left) { + if (is_group) { + OptionButton *type_box = memnew(OptionButton); + hb->add_child(type_box); + type_box->add_item(TTR("Float")); + type_box->add_item(TTR("Int")); + type_box->add_item(TTR("Vector")); + type_box->add_item(TTR("Boolean")); + type_box->add_item(TTR("Transform")); + type_box->add_item(TTR("Sampler")); + type_box->select(group_node->get_input_port_type(i)); + type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + type_box->connect("item_selected", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_type), varray(p_id, i), CONNECT_DEFERRED); + + LineEdit *name_box = memnew(LineEdit); + hb->add_child(name_box); + name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); + name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); + name_box->set_text(name_left); + name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i)); + name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, false)); + + Button *remove_btn = memnew(Button); + remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons")); + remove_btn->set_tooltip(TTR("Remove") + " " + name_left); + remove_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_remove_input_port), varray(p_id, i), CONNECT_DEFERRED); + hb->add_child(remove_btn); + } else { + Label *label = memnew(Label); + label->set_text(name_left); + label->add_theme_style_override("normal", label_style); //more compact + hb->add_child(label); + + if (vsnode->get_input_port_default_hint(i) != "" && !port_left_used) { + Label *hint_label = memnew(Label); + hint_label->set_text("[" + vsnode->get_input_port_default_hint(i) + "]"); + hint_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color("font_color_readonly", "TextEdit")); + hint_label->add_theme_style_override("normal", label_style); + hb->add_child(hint_label); + } + } + } + + if (!is_group) { + hb->add_spacer(); + } + + if (valid_right) { + if (is_group) { + Button *remove_btn = memnew(Button); + remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Remove", "EditorIcons")); + remove_btn->set_tooltip(TTR("Remove") + " " + name_left); + remove_btn->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_remove_output_port), varray(p_id, i), CONNECT_DEFERRED); + hb->add_child(remove_btn); + + LineEdit *name_box = memnew(LineEdit); + hb->add_child(name_box); + name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); + name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); + name_box->set_text(name_right); + name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i)); + name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, true)); + + OptionButton *type_box = memnew(OptionButton); + hb->add_child(type_box); + type_box->add_item(TTR("Float")); + type_box->add_item(TTR("Int")); + type_box->add_item(TTR("Vector")); + type_box->add_item(TTR("Boolean")); + type_box->add_item(TTR("Transform")); + type_box->select(group_node->get_output_port_type(i)); + type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + type_box->connect("item_selected", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_type), varray(p_id, i), CONNECT_DEFERRED); + } else { + Label *label = memnew(Label); + label->set_text(name_right); + label->add_theme_style_override("normal", label_style); //more compact + hb->add_child(label); + } + } + } + + if (valid_right && visual_shader->get_shader_type() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { + TextureButton *preview = memnew(TextureButton); + preview->set_toggle_mode(true); + preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); + preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons")); + preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + + register_output_port(p_id, i, preview); + + preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, i), CONNECT_DEFERRED); + hb->add_child(preview); + } + + if (is_group) { + offset = memnew(Control); + offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); + node->add_child(offset); + port_offset++; + } + + node->add_child(hb); + + node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); + } + + if (vsnode->get_output_port_for_preview() >= 0) { + show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview()); + } + + offset = memnew(Control); + offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE)); + node->add_child(offset); + + String error = vsnode->get_warning(visual_shader->get_mode(), p_type); + if (error != String()) { + Label *error_label = memnew(Label); + error_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color("error_color", "Editor")); + error_label->set_text(error); + node->add_child(error_label); + } + + if (is_expression) { + CodeEdit *expression_box = memnew(CodeEdit); + Ref<CodeHighlighter> expression_syntax_highlighter; + expression_syntax_highlighter.instance(); + expression_node->set_control(expression_box, 0); + node->add_child(expression_box); + + Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); + Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); + Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color members_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + + expression_box->set_syntax_highlighter(expression_syntax_highlighter); + expression_box->add_theme_color_override("background_color", background_color); + for (List<String>::Element *E = VisualShaderEditor::get_singleton()->keyword_list.front(); E; E = E->next()) { + expression_syntax_highlighter->add_keyword_color(E->get(), keyword_color); + } + + expression_box->add_theme_font_override("font", VisualShaderEditor::get_singleton()->get_theme_font("expression", "EditorFonts")); + expression_box->add_theme_color_override("font_color", text_color); + expression_syntax_highlighter->set_number_color(number_color); + expression_syntax_highlighter->set_symbol_color(symbol_color); + expression_syntax_highlighter->set_function_color(function_color); + expression_syntax_highlighter->set_member_variable_color(members_color); + expression_syntax_highlighter->add_color_region("/*", "*/", comment_color, false); + expression_syntax_highlighter->add_color_region("//", "", comment_color, true); + + expression_box->set_text(expression); + expression_box->set_context_menu_enabled(false); + expression_box->set_draw_line_numbers(true); + + expression_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expression_focus_out), varray(expression_box, p_id)); + } + + if (!uniform.is_valid()) { + VisualShaderEditor::get_singleton()->graph->add_child(node); + VisualShaderEditor::get_singleton()->_update_created_node(node); + if (is_group) { + VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size); + } + } +} + +void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id) { + if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { + links[p_id].graph_node->get_parent()->remove_child(links[p_id].graph_node); + memdelete(links[p_id].graph_node); + links.erase(p_id); + } +} + +void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { + if (visual_shader->get_shader_type() == p_type) { + VisualShaderEditor::get_singleton()->graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) { + links[p_to_node].input_ports[p_to_port].default_input_button->hide(); + } + } +} + +void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { + if (visual_shader->get_shader_type() == p_type) { + VisualShaderEditor::get_singleton()->graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr && links[p_to_node].visual_node->get_input_port_default_value(p_to_port).get_type() != Variant::NIL) { + links[p_to_node].input_ports[p_to_port].default_input_button->show(); + set_input_port_default_value(p_type, p_to_node, p_to_port, links[p_to_node].visual_node->get_input_port_default_value(p_to_port)); + } + } +} + +VisualShaderGraphPlugin::~VisualShaderGraphPlugin() { +} + +///////////////// + +void VisualShaderEditor::edit(VisualShader *p_visual_shader) { bool changed = false; if (p_visual_shader) { if (visual_shader.is_null()) { @@ -72,14 +637,22 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } visual_shader = Ref<VisualShader>(p_visual_shader); - if (!visual_shader->is_connected("changed", this, "_update_preview")) { - visual_shader->connect("changed", this, "_update_preview"); + graph_plugin->register_shader(visual_shader.ptr()); + if (!visual_shader->is_connected("changed", callable_mp(this, &VisualShaderEditor::_update_preview))) { + visual_shader->connect("changed", callable_mp(this, &VisualShaderEditor::_update_preview)); } +#ifndef DISABLE_DEPRECATED + String version = VERSION_BRANCH; + if (visual_shader->get_version() != version) { + visual_shader->update_version(version); + } +#endif visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE); + _set_mode(visual_shader->get_mode()); } else { if (visual_shader.is_valid()) { - if (visual_shader->is_connected("changed", this, "")) { - visual_shader->disconnect("changed", this, "_update_preview"); + if (visual_shader->is_connected("changed", callable_mp(this, &VisualShaderEditor::_update_preview))) { + visual_shader->disconnect("changed", callable_mp(this, &VisualShaderEditor::_update_preview)); } } visual_shader.unref(); @@ -92,14 +665,15 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { _clear_buffer(); _update_options_menu(); _update_preview(); + _update_graph(); } - _update_graph(); } } void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) { - if (plugins.find(p_plugin) != -1) + if (plugins.find(p_plugin) != -1) { return; + } plugins.push_back(p_plugin); } @@ -116,15 +690,15 @@ void VisualShaderEditor::clear_custom_types() { } } -void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory) { - +void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend) { ERR_FAIL_COND(!p_name.is_valid_identifier()); ERR_FAIL_COND(!p_script.is_valid()); for (int i = 0; i < add_options.size(); i++) { if (add_options[i].is_custom) { - if (add_options[i].script == p_script) + if (add_options[i].script == p_script) { return; + } } } @@ -134,14 +708,15 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> ao.return_type = p_return_icon_type; ao.description = p_description; ao.category = p_category; - ao.sub_category = p_subcategory; + ao.highend = p_highend; ao.is_custom = true; bool begin = false; + String root = p_category.split("/")[0]; for (int i = 0; i < add_options.size(); i++) { if (add_options[i].is_custom) { - if (add_options[i].category == p_category) { + if (add_options[i].category == root) { if (!begin) { begin = true; } @@ -157,40 +732,22 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> } bool VisualShaderEditor::_is_available(int p_mode) { - int current_mode = edit_type->get_selected(); if (p_mode != -1) { - switch (current_mode) { - case VisualShader::TYPE_VERTEX: + case 0: // Vertex or Emit current_mode = 1; break; - case VisualShader::TYPE_FRAGMENT: + case 1: // Fragment or Process current_mode = 2; break; - case VisualShader::TYPE_LIGHT: + case 2: // Light or End current_mode = 4; break; default: break; } - - int temp_mode = 0; - - if (p_mode & VisualShader::TYPE_FRAGMENT) { - temp_mode |= 2; - } - - if (p_mode & VisualShader::TYPE_LIGHT) { - temp_mode |= 4; - } - - if (temp_mode == 0) { - temp_mode |= 1; - } - - p_mode = temp_mode; } return (p_mode == -1 || (p_mode & current_mode) != 0); @@ -206,7 +763,6 @@ void VisualShaderEditor::update_custom_nodes() { Dictionary added; for (int i = 0; i < class_list.size(); i++) { if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") { - String script_path = ScriptServer::get_global_class_path(class_list[i]); Ref<Resource> res = ResourceLoader::load(script_path); ERR_FAIL_COND(res.is_null()); @@ -215,7 +771,7 @@ void VisualShaderEditor::update_custom_nodes() { Ref<VisualShaderNodeCustom> ref; ref.instance(); - ref->set_script(script.get_ref_ptr()); + ref->set_script(script); String name; if (ref->has_method("_get_name")) { @@ -238,31 +794,35 @@ void VisualShaderEditor::update_custom_nodes() { if (ref->has_method("_get_category")) { category = (String)ref->call("_get_category"); } - if (category == "") { - category = "Custom"; - } String subcategory = ""; if (ref->has_method("_get_subcategory")) { subcategory = (String)ref->call("_get_subcategory"); } + bool highend = false; + if (ref->has_method("_is_highend")) { + highend = (bool)ref->call("_is_highend"); + } + Dictionary dict; dict["name"] = name; dict["script"] = script; dict["description"] = description; dict["return_icon_type"] = return_icon_type; - dict["category"] = category; - dict["subcategory"] = subcategory; - String key; - key = category; - key += "/"; + category = category.rstrip("/"); + category = category.lstrip("/"); + category = "Addons/" + category; if (subcategory != "") { - key += subcategory; - key += "/"; + category += "/" + subcategory; } - key += name; + + dict["category"] = category; + dict["highend"] = highend; + + String key; + key = category + "/" + name; added[key] = dict; } @@ -272,216 +832,261 @@ void VisualShaderEditor::update_custom_nodes() { keys.sort(); for (int i = 0; i < keys.size(); i++) { - const Variant &key = keys.get(i); const Dictionary &value = (Dictionary)added[key]; - add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["subcategory"]); + add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]); } _update_options_menu(); } String VisualShaderEditor::_get_description(int p_idx) { - if (add_options[p_idx].highend) { - return TTR("(GLES3 only)") + " " + add_options[p_idx].description; // TODO: change it to (Vulkan Only) when its ready - } else { - return add_options[p_idx].description; - } + return add_options[p_idx].description; } void VisualShaderEditor::_update_options_menu() { - node_desc->set_text(""); members_dialog->get_ok()->set_disabled(true); - String prev_category; - String prev_sub_category; - members->clear(); TreeItem *root = members->create_item(); - TreeItem *category = NULL; - TreeItem *sub_category = NULL; String filter = node_filter->get_text().strip_edges(); bool use_filter = !filter.empty(); - Vector<String> categories; - Vector<String> sub_categories; - - int item_count = 0; - int item_count2 = 0; bool is_first_item = true; - Color unsupported_color = get_color("error_color", "Editor"); - Color supported_color = get_color("warning_color", "Editor"); + Color unsupported_color = get_theme_color("error_color", "Editor"); + Color supported_color = get_theme_color("warning_color", "Editor"); static bool low_driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES2"; + Map<String, TreeItem *> folders; + int current_func = -1; if (!visual_shader.is_null()) { current_func = visual_shader->get_mode(); } - for (int i = 0; i < add_options.size() + 1; i++) { + Vector<AddOption> custom_options; + Vector<AddOption> embedded_options; - if (i == add_options.size()) { - if (sub_category != NULL && item_count2 == 0) { - memdelete(sub_category); - --item_count; + for (int i = 0; i < add_options.size(); i++) { + if (!use_filter || add_options[i].name.findn(filter) != -1) { + if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) { + continue; } - if (category != NULL && item_count == 0) { - memdelete(category); + const_cast<AddOption &>(add_options[i]).temp_idx = i; // save valid id + if (add_options[i].is_custom) { + custom_options.push_back(add_options[i]); + } else { + embedded_options.push_back(add_options[i]); } - break; } + } + Vector<AddOption> options; + SortArray<AddOption, _OptionComparator> sorter; + sorter.sort(custom_options.ptrw(), custom_options.size()); - if (!use_filter || add_options[i].name.findn(filter) != -1) { + options.append_array(custom_options); + options.append_array(embedded_options); - if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) - continue; - - if (prev_category != add_options[i].category) { - if (category != NULL && item_count == 0) { - memdelete(category); - } + for (int i = 0; i < options.size(); i++) { + String path = options[i].category; + Vector<String> subfolders = path.split("/"); + TreeItem *category = nullptr; - item_count = 0; - prev_sub_category = ""; - category = members->create_item(root); - category->set_text(0, add_options[i].category); - category->set_selectable(0, false); - if (!use_filter) - category->set_collapsed(true); - } - - if (add_options[i].sub_category != "") { - if (prev_sub_category != add_options[i].sub_category) { - if (category != NULL) { - if (sub_category != NULL && item_count2 == 0) { - memdelete(sub_category); - --item_count; - } - ++item_count; - item_count2 = 0; - sub_category = members->create_item(category); - sub_category->set_text(0, add_options[i].sub_category); - sub_category->set_selectable(0, false); - if (!use_filter) - sub_category->set_collapsed(true); - } - } - } else { - sub_category = NULL; - } - - TreeItem *p_category = NULL; - - if (sub_category != NULL) { - p_category = sub_category; - ++item_count2; - } else if (category != NULL) { - p_category = category; - ++item_count; - } - - if (p_category != NULL) { - TreeItem *item = members->create_item(p_category); - if (add_options[i].highend && low_driver) - item->set_custom_color(0, unsupported_color); - else if (add_options[i].highend) - item->set_custom_color(0, supported_color); - item->set_text(0, add_options[i].name); - if (is_first_item && use_filter) { - item->select(0); - node_desc->set_text(_get_description(i)); - is_first_item = false; - } - switch (add_options[i].return_type) { - case VisualShaderNode::PORT_TYPE_SCALAR: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons")); - break; - case VisualShaderNode::PORT_TYPE_VECTOR: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons")); - break; - case VisualShaderNode::PORT_TYPE_BOOLEAN: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons")); - break; - case VisualShaderNode::PORT_TYPE_TRANSFORM: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons")); - break; - case VisualShaderNode::PORT_TYPE_SAMPLER: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons")); - break; - default: - break; + if (!folders.has(path)) { + category = root; + String path_temp = ""; + for (int j = 0; j < subfolders.size(); j++) { + path_temp += subfolders[j]; + if (!folders.has(path_temp)) { + category = members->create_item(category); + category->set_selectable(0, false); + category->set_collapsed(!use_filter); + category->set_text(0, subfolders[j]); + folders.insert(path_temp, category); + } else { + category = folders[path_temp]; } - item->set_meta("id", i); } + } else { + category = folders[path]; + } - prev_sub_category = add_options[i].sub_category; - prev_category = add_options[i].category; + TreeItem *item = members->create_item(category); + if (options[i].highend && low_driver) { + item->set_custom_color(0, unsupported_color); + } else if (options[i].highend) { + item->set_custom_color(0, supported_color); + } + item->set_text(0, options[i].name); + if (is_first_item && use_filter) { + item->select(0); + node_desc->set_text(options[i].description); + is_first_item = false; + } + switch (options[i].return_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons")); + break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons")); + break; + case VisualShaderNode::PORT_TYPE_VECTOR: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons")); + break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons")); + break; + case VisualShaderNode::PORT_TYPE_TRANSFORM: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons")); + break; + case VisualShaderNode::PORT_TYPE_SAMPLER: + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons")); + break; + default: + break; } + item->set_meta("id", options[i].temp_idx); } } -Size2 VisualShaderEditor::get_minimum_size() const { +void VisualShaderEditor::_set_mode(int p_which) { + if (p_which == VisualShader::MODE_PARTICLES) { + edit_type_standart->set_visible(false); + edit_type_particles->set_visible(true); + edit_type = edit_type_particles; + particles_mode = true; + } else { + edit_type_particles->set_visible(false); + edit_type_standart->set_visible(true); + edit_type = edit_type_standart; + particles_mode = false; + } + visual_shader->set_shader_type(get_current_shader_type()); +} +Size2 VisualShaderEditor::get_minimum_size() const { return Size2(10, 200); } void VisualShaderEditor::_draw_color_over_button(Object *obj, Color p_color) { - Button *button = Object::cast_to<Button>(obj); - if (!button) + if (!button) { return; + } - Ref<StyleBox> normal = get_stylebox("normal", "Button"); + Ref<StyleBox> normal = get_theme_stylebox("normal", "Button"); button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color); } -static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { - Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty)); - style->set_default_margin(MARGIN_LEFT, p_margin_left * EDSCALE); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * EDSCALE); - style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * EDSCALE); - style->set_default_margin(MARGIN_TOP, p_margin_top * EDSCALE); - return style; -} - void VisualShaderEditor::_update_created_node(GraphNode *node) { - if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) { - Ref<StyleBoxFlat> sb = node->get_stylebox("frame", "GraphNode"); + Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode"); 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); + Color ic; + Color mono_color; + if (((c.r + c.g + c.b) / 3) < 0.7) { + mono_color = Color(1.0, 1.0, 1.0); + ic = Color(0.0, 0.0, 0.0, 0.7); + } else { + mono_color = Color(0.0, 0.0, 0.0); + ic = Color(1.0, 1.0, 1.0, 0.7); + } mono_color.a = 0.85; c = mono_color; - node->add_color_override("title_color", c); + node->add_theme_color_override("title_color", c); c.a = 0.7; - node->add_color_override("close_color", c); - node->add_color_override("resizer_color", c); + node->add_theme_color_override("close_color", c); + node->add_theme_color_override("resizer_color", ic); + } +} + +void VisualShaderEditor::_update_uniforms(bool p_update_refs) { + VisualShaderNodeUniformRef::clear_uniforms(); + + for (int t = 0; t < VisualShader::TYPE_MAX; t++) { + Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t); + for (int i = 0; i < tnodes.size(); i++) { + Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]); + Ref<VisualShaderNodeUniform> uniform = vsnode; + + if (uniform.is_valid()) { + Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode; + Ref<VisualShaderNodeIntUniform> int_uniform = vsnode; + Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode; + Ref<VisualShaderNodeColorUniform> color_uniform = vsnode; + Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode; + Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode; + + VisualShaderNodeUniformRef::UniformType uniform_type; + if (float_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT; + } else if (int_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT; + } else if (bool_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN; + } else if (vec3_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR; + } else if (transform_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM; + } else if (color_uniform.is_valid()) { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR; + } else { + uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER; + } + VisualShaderNodeUniformRef::add_uniform(uniform->get_uniform_name(), uniform_type); + } + } + } + if (p_update_refs) { + graph_plugin->update_uniform_refs(); } } -void VisualShaderEditor::_update_graph() { +void VisualShaderEditor::_update_uniform_refs(Set<String> &p_deleted_names) { + for (int i = 0; i < VisualShader::TYPE_MAX; i++) { + VisualShader::Type type = VisualShader::Type(i); - if (updating) + Vector<int> nodes = visual_shader->get_node_list(type); + for (int j = 0; j < nodes.size(); j++) { + if (j > 0) { + Ref<VisualShaderNodeUniformRef> ref = visual_shader->get_node(type, nodes[j]); + if (ref.is_valid()) { + if (p_deleted_names.has(ref->get_uniform_name())) { + undo_redo->add_do_method(ref.ptr(), "set_uniform_name", "[None]"); + undo_redo->add_undo_method(ref.ptr(), "set_uniform_name", ref->get_uniform_name()); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]); + } + } + } + } + } +} + +void VisualShaderEditor::_update_graph() { + if (updating) { return; + } - if (visual_shader.is_null()) + if (visual_shader.is_null()) { return; + } graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE); - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); + graph->clear_connections(); //erase all nodes for (int i = 0; i < graph->get_child_count(); i++) { - if (Object::cast_to<GraphNode>(graph->get_child(i))) { Node *node = graph->get_child(i); graph->remove_child(node); @@ -490,381 +1095,24 @@ void VisualShaderEditor::_update_graph() { } } - static const Color type_color[5] = { - Color(0.38, 0.85, 0.96), // scalar - Color(0.84, 0.49, 0.93), // vector - Color(0.55, 0.65, 0.94), // boolean - Color(0.96, 0.66, 0.43), // transform - Color(1.0, 1.0, 0.0) // sampler - }; - List<VisualShader::Connection> connections; visual_shader->get_node_connections(type, &connections); - - Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1); + graph_plugin->set_connections(connections); Vector<int> nodes = visual_shader->get_node_list(type); - Control *offset; - - for (int n_i = 0; n_i < nodes.size(); n_i++) { - - Vector2 position = visual_shader->get_node_position(type, nodes[n_i]); - Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, nodes[n_i]); - - Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr()); - bool is_group = !group_node.is_null(); - Size2 size = Size2(0, 0); - - Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr()); - bool is_expression = !expression_node.is_null(); - String expression = ""; - - GraphNode *node = memnew(GraphNode); - - if (is_group) { - size = group_node->get_size(); - - node->set_resizable(true); - node->connect("resize_request", this, "_node_resized", varray((int)type, nodes[n_i])); - } - if (is_expression) { - expression = expression_node->get_expression(); - } - - /*if (!vsnode->is_connected("changed", this, "_node_changed")) { - vsnode->connect("changed", this, "_node_changed", varray(vsnode->get_instance_id()), CONNECT_DEFERRED); - }*/ - - node->set_offset(position); - - node->set_title(vsnode->get_caption()); - node->set_name(itos(nodes[n_i])); - - if (nodes[n_i] >= 2) { - node->set_show_close_button(true); - node->connect("close_request", this, "_delete_request", varray(nodes[n_i]), CONNECT_DEFERRED); - } - - node->connect("dragged", this, "_node_dragged", varray(nodes[n_i])); - - Control *custom_editor = NULL; - int port_offset = 0; - - if (is_group) { - port_offset += 2; - } - - Ref<VisualShaderNodeUniform> uniform = vsnode; - if (uniform.is_valid()) { - graph->add_child(node); - _update_created_node(node); - - LineEdit *uniform_name = memnew(LineEdit); - uniform_name->set_text(uniform->get_uniform_name()); - node->add_child(uniform_name); - uniform_name->connect("text_entered", this, "_line_edit_changed", varray(uniform_name, nodes[n_i])); - uniform_name->connect("focus_exited", this, "_line_edit_focus_out", varray(uniform_name, nodes[n_i])); - - if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") { - //shortcut - VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); - node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); - continue; - } - port_offset++; - } - - for (int i = 0; i < plugins.size(); i++) { - custom_editor = plugins.write[i]->create_editor(visual_shader, vsnode); - if (custom_editor) { - break; - } - } - - if (custom_editor && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) { - //will be embedded in first port - } else if (custom_editor) { - port_offset++; - node->add_child(custom_editor); - custom_editor = NULL; - } - - if (is_group) { - - offset = memnew(Control); - offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE)); - node->add_child(offset); - - if (group_node->is_editable()) { - HBoxContainer *hb2 = memnew(HBoxContainer); - - Button *add_input_btn = memnew(Button); - add_input_btn->set_text(TTR("Add Input")); - add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_input_btn); + _update_uniforms(false); - hb2->add_spacer(); + graph_plugin->clear_links(); + graph_plugin->make_dirty(true); - Button *add_output_btn = memnew(Button); - add_output_btn->set_text(TTR("Add Output")); - add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_output_btn); - - node->add_child(hb2); - } - } - - for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { - - if (vsnode->is_port_separator(i)) { - node->add_child(memnew(HSeparator)); - port_offset++; - } - - bool valid_left = i < vsnode->get_input_port_count(); - VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR; - bool port_left_used = false; - String name_left; - if (valid_left) { - name_left = vsnode->get_input_port_name(i); - port_left = vsnode->get_input_port_type(i); - for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { - if (E->get().to_node == nodes[n_i] && E->get().to_port == i) { - port_left_used = true; - } - } - } - - bool valid_right = i < vsnode->get_output_port_count(); - VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR; - String name_right; - if (valid_right) { - name_right = vsnode->get_output_port_name(i); - port_right = vsnode->get_output_port_type(i); - } - - HBoxContainer *hb = memnew(HBoxContainer); - hb->add_constant_override("separation", 7 * EDSCALE); - - Variant default_value; - - if (valid_left && !port_left_used) { - default_value = vsnode->get_input_port_default_value(i); - } - - if (default_value.get_type() != Variant::NIL) { // only a label - Button *button = memnew(Button); - hb->add_child(button); - button->connect("pressed", this, "_edit_port_default_input", varray(button, nodes[n_i], i)); - - switch (default_value.get_type()) { - - case Variant::COLOR: { - button->set_custom_minimum_size(Size2(30, 0) * EDSCALE); - button->connect("draw", this, "_draw_color_over_button", varray(button, default_value)); - } break; - case Variant::BOOL: { - button->set_text(((bool)default_value) ? "true" : "false"); - } break; - case Variant::INT: - case Variant::REAL: { - button->set_text(String::num(default_value, 4)); - } break; - case Variant::VECTOR3: { - Vector3 v = default_value; - button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3)); - } break; - default: { - } - } - } - - if (i == 0 && custom_editor) { - hb->add_child(custom_editor); - custom_editor->set_h_size_flags(SIZE_EXPAND_FILL); - } else { - - if (valid_left) { - - if (is_group) { - OptionButton *type_box = memnew(OptionButton); - hb->add_child(type_box); - type_box->add_item(TTR("Scalar")); - type_box->add_item(TTR("Vector")); - type_box->add_item(TTR("Boolean")); - type_box->add_item(TTR("Transform")); - type_box->add_item(TTR("Sampler")); - type_box->select(group_node->get_input_port_type(i)); - type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - type_box->connect("item_selected", this, "_change_input_port_type", varray(nodes[n_i], i), CONNECT_DEFERRED); - - LineEdit *name_box = memnew(LineEdit); - hb->add_child(name_box); - name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); - name_box->set_h_size_flags(SIZE_EXPAND_FILL); - name_box->set_text(name_left); - name_box->connect("text_entered", this, "_change_input_port_name", varray(name_box, nodes[n_i], i)); - name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, nodes[n_i], i, false)); - - Button *remove_btn = memnew(Button); - remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons")); - remove_btn->set_tooltip(TTR("Remove") + " " + name_left); - remove_btn->connect("pressed", this, "_remove_input_port", varray(nodes[n_i], i), CONNECT_DEFERRED); - hb->add_child(remove_btn); - } else { - - Label *label = memnew(Label); - label->set_text(name_left); - label->add_style_override("normal", label_style); //more compact - hb->add_child(label); - - if (vsnode->get_input_port_default_hint(i) != "" && !port_left_used) { - - Label *hint_label = memnew(Label); - hint_label->set_text("[" + vsnode->get_input_port_default_hint(i) + "]"); - hint_label->add_color_override("font_color", get_color("font_color_readonly", "TextEdit")); - hint_label->add_style_override("normal", label_style); - hb->add_child(hint_label); - } - } - } - - if (!is_group) { - hb->add_spacer(); - } - - if (valid_right) { - if (is_group) { - Button *remove_btn = memnew(Button); - remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons")); - remove_btn->set_tooltip(TTR("Remove") + " " + name_left); - remove_btn->connect("pressed", this, "_remove_output_port", varray(nodes[n_i], i), CONNECT_DEFERRED); - hb->add_child(remove_btn); - - LineEdit *name_box = memnew(LineEdit); - hb->add_child(name_box); - name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); - name_box->set_h_size_flags(SIZE_EXPAND_FILL); - name_box->set_text(name_right); - name_box->connect("text_entered", this, "_change_output_port_name", varray(name_box, nodes[n_i], i)); - name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, nodes[n_i], i, true)); - - OptionButton *type_box = memnew(OptionButton); - hb->add_child(type_box); - type_box->add_item(TTR("Scalar")); - type_box->add_item(TTR("Vector")); - type_box->add_item(TTR("Boolean")); - type_box->add_item(TTR("Transform")); - type_box->select(group_node->get_output_port_type(i)); - type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - type_box->connect("item_selected", this, "_change_output_port_type", varray(nodes[n_i], i), CONNECT_DEFERRED); - } else { - Label *label = memnew(Label); - label->set_text(name_right); - label->add_style_override("normal", label_style); //more compact - hb->add_child(label); - } - } - } - - if (valid_right && edit_type->get_selected() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { - TextureButton *preview = memnew(TextureButton); - preview->set_toggle_mode(true); - preview->set_normal_texture(get_icon("GuiVisibilityHidden", "EditorIcons")); - preview->set_pressed_texture(get_icon("GuiVisibilityVisible", "EditorIcons")); - preview->set_v_size_flags(SIZE_SHRINK_CENTER); - - if (vsnode->get_output_port_for_preview() == i) { - preview->set_pressed(true); - } - - preview->connect("pressed", this, "_preview_select_port", varray(nodes[n_i], i), CONNECT_DEFERRED); - hb->add_child(preview); - } - - if (is_group) { - offset = memnew(Control); - offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); - node->add_child(offset); - port_offset++; - } - - node->add_child(hb); - - node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); - } - - if (vsnode->get_output_port_for_preview() >= 0) { - int port_type = vsnode->get_output_port_type(vsnode->get_output_port_for_preview()); - - if (port_type != VisualShaderNode::PORT_TYPE_TRANSFORM && port_type != VisualShaderNode::PORT_TYPE_SAMPLER) { - offset = memnew(Control); - offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); - node->add_child(offset); - - VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); - port_preview->setup(visual_shader, type, nodes[n_i], vsnode->get_output_port_for_preview()); - port_preview->set_h_size_flags(SIZE_SHRINK_CENTER); - node->add_child(port_preview); - } - } - - offset = memnew(Control); - offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE)); - node->add_child(offset); - - String error = vsnode->get_warning(visual_shader->get_mode(), type); - if (error != String()) { - Label *error_label = memnew(Label); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); - error_label->set_text(error); - node->add_child(error_label); - } - - if (is_expression) { - - TextEdit *expression_box = memnew(TextEdit); - expression_node->set_control(expression_box, 0); - node->add_child(expression_box); - - Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); - Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); - Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); - Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); - - expression_box->set_syntax_coloring(true); - expression_box->add_color_override("background_color", background_color); - - for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { - - expression_box->add_keyword_color(E->get(), keyword_color); - } - - expression_box->add_font_override("font", get_font("expression", "EditorFonts")); - expression_box->add_color_override("font_color", text_color); - expression_box->add_color_override("symbol_color", symbol_color); - expression_box->add_color_region("/*", "*/", comment_color, false); - expression_box->add_color_region("//", "", comment_color, false); - - expression_box->set_text(expression); - expression_box->set_context_menu_enabled(false); - expression_box->set_show_line_numbers(true); - - expression_box->connect("focus_exited", this, "_expression_focus_out", varray(expression_box, nodes[n_i])); - } - - if (!uniform.is_valid()) { - graph->add_child(node); - _update_created_node(node); - if (is_group) - call_deferred("_set_node_size", (int)type, nodes[n_i], size); - } + for (int n_i = 0; n_i < nodes.size(); n_i++) { + graph_plugin->add_node(type, nodes[n_i]); } - for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { + graph_plugin->make_dirty(false); + for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { int from = E->get().from_node; int from_idx = E->get().from_port; int to = E->get().to_node; @@ -874,9 +1122,18 @@ void VisualShaderEditor::_update_graph() { } } -void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) { +VisualShader::Type VisualShaderEditor::get_current_shader_type() const { + VisualShader::Type type; + if (particles_mode) { + type = VisualShader::Type(edit_type->get_selected() + 3); + } else { + type = VisualShader::Type(edit_type->get_selected()); + } + return type; +} - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); +void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) { + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -885,16 +1142,13 @@ void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type undo_redo->create_action(TTR("Add input port")); undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name); undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_type, const String &p_name) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -903,16 +1157,13 @@ void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_typ undo_redo->create_action(TTR("Add output port")); undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name); undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -921,16 +1172,13 @@ void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_p undo_redo->create_action(TTR("Change input port type")); undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type); undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port)); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -939,16 +1187,13 @@ void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_ undo_redo->create_action(TTR("Change output port type")); undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type); undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port)); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *line_edit, int p_node_id, int p_port_id) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id); ERR_FAIL_COND(!node.is_valid()); @@ -956,14 +1201,13 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *l undo_redo->create_action(TTR("Change input port name")); undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, p_text); undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id)); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node_id); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node_id); undo_redo->commit_action(); } void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *line_edit, int p_node_id, int p_port_id) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id); ERR_FAIL_COND(!node.is_valid()); @@ -971,14 +1215,13 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object * undo_redo->create_action(TTR("Change output port name")); undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, p_text); undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, node->get_output_port_name(p_port_id)); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node_id); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node_id); undo_redo->commit_action(); } void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -989,7 +1232,6 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { List<VisualShader::Connection> conns; visual_shader->get_node_connections(type, &conns); for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { - int from_node = E->get().from_node; int from_port = E->get().from_port; int to_node = E->get().to_node; @@ -999,12 +1241,21 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { if (to_port == p_port) { undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); } else if (to_port > p_port) { undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port - 1); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port - 1); + + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port - 1); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port - 1); } } } @@ -1012,18 +1263,14 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { undo_redo->add_do_method(node.ptr(), "remove_input_port", p_port); undo_redo->add_undo_method(node.ptr(), "add_input_port", p_port, (int)node->get_input_port_type(p_port), node->get_input_port_name(p_port)); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -1034,7 +1281,6 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { List<VisualShader::Connection> conns; visual_shader->get_node_connections(type, &conns); for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { - int from_node = E->get().from_node; int from_port = E->get().from_port; int to_node = E->get().to_node; @@ -1044,12 +1290,21 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { if (from_port == p_port) { undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); } else if (from_port > p_port) { undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port - 1, to_node, to_port); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - 1, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - 1, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - 1, to_node, to_port); } } } @@ -1057,46 +1312,33 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) { undo_redo->add_do_method(node.ptr(), "remove_output_port", p_port); undo_redo->add_undo_method(node.ptr(), "add_output_port", p_port, (int)node->get_output_port_type(p_port), node->get_output_port_name(p_port)); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); - - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); undo_redo->commit_action(); } -void VisualShaderEditor::_expression_focus_out(Object *text_edit, int p_node) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); +void VisualShaderEditor::_expression_focus_out(Object *code_edit, int p_node) { + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; } - TextEdit *expression_box = Object::cast_to<TextEdit>(text_edit); + CodeEdit *expression_box = Object::cast_to<CodeEdit>(code_edit); - if (node->get_expression() == expression_box->get_text()) + if (node->get_expression() == expression_box->get_text()) { return; + } undo_redo->create_action(TTR("Set expression")); undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text()); undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression()); - undo_redo->add_do_method(this, "_rebuild"); - undo_redo->add_undo_method(this, "_rebuild"); undo_redo->commit_action(); } -void VisualShaderEditor::_rebuild() { - if (visual_shader != NULL) { - EditorNode::get_singleton()->get_log()->clear(); - visual_shader->rebuild(); - } -} - void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) { - - VisualShader::Type type = VisualShader::Type(p_type); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -1112,12 +1354,13 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p group_node->set_size(size); - GraphNode *gn = NULL; + GraphNode *gn = nullptr; if (edit_type->get_selected() == p_type) { // check - otherwise the error will be emitted Node *node2 = graph->get_node(itos(p_node)); gn = Object::cast_to<GraphNode>(node2); - if (!gn) + if (!gn) { return; + } gn->set_custom_minimum_size(size); gn->set_size(Size2(1, 1)); @@ -1127,7 +1370,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p if (!expression_node.is_null()) { Control *text_box = expression_node->get_control(0); Size2 box_size = size; - if (gn != NULL) { + if (gn != nullptr) { if (box_size.x < 150 * EDSCALE || box_size.y < 0) { box_size.x = gn->get_size().x; } @@ -1142,8 +1385,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p } void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) { - - VisualShader::Type type = VisualShader::Type(p_type); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; @@ -1156,54 +1398,57 @@ void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, in } void VisualShaderEditor::_preview_select_port(int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node); if (node.is_null()) { return; } - + int prev_port = node->get_output_port_for_preview(); if (node->get_output_port_for_preview() == p_port) { p_port = -1; //toggle it } - undo_redo->create_action(TTR("Set Uniform Name")); + undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview")); 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"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port); + undo_redo->add_do_method(graph_plugin.ptr(), "show_port_preview", (int)type, p_node, p_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "show_port_preview", (int)type, p_node, prev_port); undo_redo->commit_action(); } -void VisualShaderEditor::_line_edit_changed(const String &p_text, Object *line_edit, int p_node_id) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); +void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) { + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeUniform> node = visual_shader->get_node(type, p_node_id); ERR_FAIL_COND(!node.is_valid()); String validated_name = visual_shader->validate_uniform_name(p_text, node); - updating = true; + if (validated_name == node->get_uniform_name()) { + return; + } + 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"); - undo_redo->add_undo_method(this, "_update_graph"); - undo_redo->commit_action(); - updating = false; + undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name); + undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name()); - Object::cast_to<LineEdit>(line_edit)->set_text(validated_name); -} + undo_redo->add_do_method(this, "_update_uniforms", true); + undo_redo->add_undo_method(this, "_update_uniforms", true); -void VisualShaderEditor::_line_edit_focus_out(Object *line_edit, int p_node_id) { + Set<String> changed_names; + changed_names.insert(node->get_uniform_name()); + _update_uniform_refs(changed_names); - String text = Object::cast_to<LineEdit>(line_edit)->get_text(); - _line_edit_changed(text, line_edit, p_node_id); + undo_redo->commit_action(); } -void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) { +void VisualShaderEditor::_uniform_line_edit_focus_out(Object *line_edit, int p_node_id) { + _uniform_line_edit_changed(Object::cast_to<LineEdit>(line_edit)->get_text(), p_node_id); +} - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); +void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) { + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id); ERR_FAIL_COND(!node.is_valid()); @@ -1211,22 +1456,28 @@ void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, String text = Object::cast_to<LineEdit>(line_edit)->get_text(); if (!p_output) { - if (node->get_input_port_name(p_port_id) == text) + if (node->get_input_port_name(p_port_id) == text) { return; + } } else { - if (node->get_output_port_name(p_port_id) == text) + if (node->get_output_port_name(p_port_id) == text) { return; + } } List<String> input_names; List<String> output_names; for (int i = 0; i < node->get_input_port_count(); i++) { - if (!p_output && i == p_port_id) continue; + if (!p_output && i == p_port_id) { + continue; + } input_names.push_back(node->get_input_port_name(i)); } for (int i = 0; i < node->get_output_port_count(); i++) { - if (p_output && i == p_port_id) continue; + if (p_output && i == p_port_id) { + continue; + } output_names.push_back(node->get_output_port_name(i)); } @@ -1248,8 +1499,7 @@ void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, } void VisualShaderEditor::_port_edited() { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Variant value = property_editor->get_variant(); Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node); @@ -1258,31 +1508,29 @@ void VisualShaderEditor::_port_edited() { 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"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, value); + undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port)); undo_redo->commit_action(); property_editor->hide(); } void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNode> vsn = visual_shader->get_node(type, p_node); Button *button = Object::cast_to<Button>(p_button); ERR_FAIL_COND(!button); Variant value = vsn->get_input_port_default_value(p_port); - property_editor->set_global_position(button->get_global_position() + Vector2(0, button->get_size().height)); - property_editor->edit(NULL, "", value.get_type(), value, 0, ""); + property_editor->set_position(button->get_screen_position() + Vector2(0, button->get_size().height)); + property_editor->edit(nullptr, "", value.get_type(), value, 0, ""); property_editor->popup(); editing_node = p_node; editing_port = p_port; } void VisualShaderEditor::_add_custom_node(const String &p_path) { - int idx = -1; for (int i = custom_node_option_idx; i < add_options.size(); i++) { @@ -1304,8 +1552,7 @@ void VisualShaderEditor::_add_texture_node(const String &p_path) { } VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { - - ERR_FAIL_INDEX_V(p_idx, add_options.size(), NULL); + ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr); Ref<VisualShaderNode> vsnode; @@ -1313,17 +1560,17 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { if (!is_custom && add_options[p_idx].type != String()) { VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); - ERR_FAIL_COND_V(!vsn, NULL); + ERR_FAIL_COND_V(!vsn, nullptr); - VisualShaderNodeScalarConstant *constant = Object::cast_to<VisualShaderNodeScalarConstant>(vsn); + VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn); if (constant) { - if ((int)add_options[p_idx].value != -1) + if ((int)add_options[p_idx].value != -1) { constant->set_constant(add_options[p_idx].value); + } } if (p_op_idx != -1) { - VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn); if (input) { @@ -1354,16 +1601,28 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx); } - VisualShaderNodeScalarOp *scalarOp = Object::cast_to<VisualShaderNodeScalarOp>(vsn); + VisualShaderNodeFloatOp *floatOp = Object::cast_to<VisualShaderNodeFloatOp>(vsn); + + if (floatOp) { + floatOp->set_operator((VisualShaderNodeFloatOp::Operator)p_op_idx); + } + + VisualShaderNodeIntOp *intOp = Object::cast_to<VisualShaderNodeIntOp>(vsn); - if (scalarOp) { - scalarOp->set_operator((VisualShaderNodeScalarOp::Operator)p_op_idx); + if (intOp) { + intOp->set_operator((VisualShaderNodeIntOp::Operator)p_op_idx); } - VisualShaderNodeScalarFunc *scalarFunc = Object::cast_to<VisualShaderNodeScalarFunc>(vsn); + VisualShaderNodeFloatFunc *floatFunc = Object::cast_to<VisualShaderNodeFloatFunc>(vsn); - if (scalarFunc) { - scalarFunc->set_function((VisualShaderNodeScalarFunc::Function)p_op_idx); + if (floatFunc) { + floatFunc->set_function((VisualShaderNodeFloatFunc::Function)p_op_idx); + } + + VisualShaderNodeIntFunc *intFunc = Object::cast_to<VisualShaderNodeIntFunc>(vsn); + + if (intFunc) { + intFunc->set_function((VisualShaderNodeIntFunc::Function)p_op_idx); } VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(vsn); @@ -1395,16 +1654,22 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { if (vderFunc) { vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx); } + + VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(vsn); + + if (fmaFunc) { + fmaFunc->set_type((VisualShaderNodeMultiplyAdd::Type)p_op_idx); + } } vsnode = Ref<VisualShaderNode>(vsn); } else { - ERR_FAIL_COND_V(add_options[p_idx].script.is_null(), NULL); + ERR_FAIL_COND_V(add_options[p_idx].script.is_null(), nullptr); String base_type = add_options[p_idx].script->get_instance_base_type(); VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(base_type)); - ERR_FAIL_COND_V(!vsn, NULL); + ERR_FAIL_COND_V(!vsn, nullptr); vsnode = Ref<VisualShaderNode>(vsn); - vsnode->set_script(add_options[p_idx].script.get_ref_ptr()); + vsnode->set_script(add_options[p_idx].script); } Point2 position = graph->get_scroll_ofs(); @@ -1417,13 +1682,15 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { } saved_node_pos_dirty = false; - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); int id_to_use = visual_shader->get_valid_node_id(type); 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(graph_plugin.ptr(), "add_node", type, id_to_use); + undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_to_use); VisualShaderNodeExpression *expr = Object::cast_to<VisualShaderNodeExpression>(vsnode.ptr()); if (expr) { @@ -1432,51 +1699,53 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { if (to_node != -1 && to_slot != -1) { if (vsnode->get_output_port_count() > 0) { - int _from_node = id_to_use; int _from_slot = 0; if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(_from_slot), visual_shader->get_node(type, to_node)->get_input_port_type(to_slot))) { undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot); } } } else if (from_node != -1 && from_slot != -1) { if (vsnode->get_input_port_count() > 0) { - int _to_node = id_to_use; int _to_slot = 0; if (visual_shader->is_port_types_compatible(visual_shader->get_node(type, from_node)->get_output_port_type(from_slot), vsnode->get_input_port_type(_to_slot))) { - undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot); + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot); } } } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr()); + if (uniform) { + undo_redo->add_do_method(this, "_update_uniforms", true); + undo_redo->add_undo_method(this, "_update_uniforms", true); + } + undo_redo->commit_action(); return vsnode.ptr(); } void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node) { + VisualShader::Type type = get_current_shader_type(); - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); - - updating = true; 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"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(graph_plugin.ptr(), "set_node_position", type, p_node, p_to); + undo_redo->add_undo_method(graph_plugin.ptr(), "set_node_position", type, p_node, p_from); undo_redo->commit_action(); - updating = false; } void VisualShaderEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); int from = p_from.to_int(); int to = p_to.to_int(); @@ -1494,33 +1763,32 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in if (E->get().to_node == to && E->get().to_port == p_to_index) { undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); } } undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index); - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->commit_action(); } void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) { - graph->disconnect_node(p_from, p_from_index, p_to, p_to_index); - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); int from = p_from.to_int(); int to = p_to.to_int(); - //updating = true; seems graph edit can handle this, no need to protect 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"); - undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index); undo_redo->commit_action(); - //updating = false; } void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) { @@ -1536,13 +1804,22 @@ void VisualShaderEditor::_connection_from_empty(const String &p_to, int p_to_slo } void VisualShaderEditor::_delete_request(int which) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNode> node = Ref<VisualShaderNode>(visual_shader->get_node(type, which)); undo_redo->create_action(TTR("Delete Node")); + + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == which || E->get().to_node == which) { + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + } + undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, which); undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, which), which); + undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, which); undo_redo->add_do_method(this, "_clear_buffer"); undo_redo->add_undo_method(this, "_clear_buffer"); @@ -1561,23 +1838,31 @@ void VisualShaderEditor::_delete_request(int which) { undo_redo->add_undo_method(expression, "set_expression", expression->get_expression()); } - List<VisualShader::Connection> conns; - visual_shader->get_node_connections(type, &conns); - for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { if (E->get().from_node == which || E->get().to_node == which) { undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); } } + // delete a node from the graph + undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, which); + + VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr()); + if (uniform) { + undo_redo->add_do_method(this, "_update_uniforms", true); + undo_redo->add_undo_method(this, "_update_uniforms", true); + + Set<String> uniform_names; + uniform_names.insert(uniform->get_uniform_name()); + + _update_uniform_refs(uniform_names); + } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); undo_redo->commit_action(); } void VisualShaderEditor::_node_selected(Object *p_node) { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + VisualShader::Type type = get_current_shader_type(); GraphNode *gn = Object::cast_to<GraphNode>(p_node); ERR_FAIL_COND(!gn); @@ -1592,15 +1877,34 @@ void VisualShaderEditor::_node_selected(Object *p_node) { } void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) - _show_members_dialog(true); + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + List<int> to_change; + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_change.push_back(gn->get_name().operator String().to_int()); + } + } + } + if (to_change.empty() && copy_nodes_buffer.empty()) { + _show_members_dialog(true); + } else { + popup_menu->set_item_disabled(NodeMenuOptions::COPY, to_change.empty()); + popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_nodes_buffer.empty()); + popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.empty()); + popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.empty()); + menu_point = graph->get_local_mouse_position(); + Point2 gpos = Input::get_singleton()->get_mouse_position(); + popup_menu->set_position(gpos); + popup_menu->popup(); + } + } } void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) { - if (at_mouse_pos) { saved_node_pos_dirty = true; saved_node_pos = graph->get_local_mouse_position(); @@ -1615,8 +1919,8 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) { } // keep dialog within window bounds - Size2 window_size = OS::get_singleton()->get_window_size(); - Rect2 dialog_rect = members_dialog->get_global_rect(); + Size2 window_size = DisplayServer::get_singleton()->window_get_size(); + Rect2 dialog_rect = Rect2(members_dialog->get_position(), members_dialog->get_size()); if (dialog_rect.position.y + dialog_rect.size.y > window_size.y) { int difference = dialog_rect.position.y + dialog_rect.size.y - window_size.y; members_dialog->set_position(members_dialog->get_position() - Point2(0, difference)); @@ -1632,11 +1936,10 @@ void VisualShaderEditor::_show_members_dialog(bool at_mouse_pos) { void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) { Ref<InputEventKey> ie = p_ie; - if (ie.is_valid() && (ie->get_scancode() == KEY_UP || - ie->get_scancode() == KEY_DOWN || - ie->get_scancode() == KEY_ENTER || - ie->get_scancode() == KEY_KP_ENTER)) { - + if (ie.is_valid() && (ie->get_keycode() == KEY_UP || + ie->get_keycode() == KEY_DOWN || + ie->get_keycode() == KEY_ENTER || + ie->get_keycode() == KEY_KP_ENTER)) { members->call("_gui_input", ie); node_filter->accept_event(); } @@ -1644,7 +1947,6 @@ void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) { void VisualShaderEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - node_filter->set_clear_button_enabled(true); // collapse tree by default @@ -1671,13 +1973,14 @@ void VisualShaderEditor::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + highend_label->set_modulate(get_theme_color("vulkan_color", "Editor")); - error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); - error_label->add_color_override("font_color", get_color("error_color", "Editor")); + error_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); - node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons")); + node_filter->set_right_icon(Control::get_theme_icon("Search", "EditorIcons")); - preview_shader->set_icon(Control::get_icon("Shader", "EditorIcons")); + preview_shader->set_icon(Control::get_theme_icon("Shader", "EditorIcons")); { Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); @@ -1685,42 +1988,51 @@ void VisualShaderEditor::_notification(int p_what) { Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color members_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); - preview_text->add_color_override("background_color", background_color); + preview_text->add_theme_color_override("background_color", background_color); for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { - - preview_text->add_keyword_color(E->get(), keyword_color); + syntax_highlighter->add_keyword_color(E->get(), keyword_color); } - preview_text->add_font_override("font", get_font("expression", "EditorFonts")); - preview_text->add_color_override("font_color", text_color); - preview_text->add_color_override("symbol_color", symbol_color); - preview_text->add_color_region("/*", "*/", comment_color, false); - preview_text->add_color_region("//", "", comment_color, false); + preview_text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts")); + preview_text->add_theme_color_override("font_color", text_color); + syntax_highlighter->set_number_color(number_color); + syntax_highlighter->set_symbol_color(symbol_color); + syntax_highlighter->set_function_color(function_color); + syntax_highlighter->set_member_variable_color(members_color); + syntax_highlighter->clear_color_regions(); + syntax_highlighter->add_color_region("/*", "*/", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); - error_text->add_font_override("font", get_font("status_source", "EditorFonts")); - error_text->add_color_override("font_color", get_color("error_color", "Editor")); + error_text->add_theme_font_override("font", get_theme_font("status_source", "EditorFonts")); + error_text->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); } - tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons")); + tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Tools", "EditorIcons")); - if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) + if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) { _update_graph(); + } } } void VisualShaderEditor::_scroll_changed(const Vector2 &p_scroll) { - if (updating) + if (updating) { return; + } updating = true; visual_shader->set_graph_offset(p_scroll / EDSCALE); updating = false; } void VisualShaderEditor::_node_changed(int p_id) { - if (updating) + if (updating) { return; + } if (is_visible_in_tree()) { _update_graph(); @@ -1732,7 +2044,6 @@ void VisualShaderEditor::_dup_update_excluded(int p_type, Set<int> &r_excluded) VisualShader::Type type = (VisualShader::Type)p_type; for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); if (gn) { int id = String(gn->get_name()).to_int(); @@ -1748,14 +2059,12 @@ void VisualShaderEditor::_dup_update_excluded(int p_type, Set<int> &r_excluded) } void VisualShaderEditor::_dup_copy_nodes(int p_type, List<int> &r_nodes, Set<int> &r_excluded) { - VisualShader::Type type = (VisualShader::Type)p_type; selection_center.x = 0.0f; selection_center.y = 0.0f; for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); if (gn) { int id = String(gn->get_name()).to_int(); @@ -1778,7 +2087,6 @@ void VisualShaderEditor::_dup_copy_nodes(int p_type, List<int> &r_nodes, Set<int } void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<int> &r_nodes, Set<int> &r_excluded, const Vector2 &p_offset, bool p_select) { - VisualShader::Type type = (VisualShader::Type)p_type; VisualShader::Type pasted_type = (VisualShader::Type)p_pasted_type; @@ -1788,7 +2096,6 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in Set<int> unsupported_set; for (List<int>::Element *E = r_nodes.front(); E; E = E->next()) { - connection_remap[E->get()] = id_from; Ref<VisualShaderNode> node = visual_shader->get_node(pasted_type, E->get()); @@ -1809,12 +2116,13 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in Ref<VisualShaderNode> dupli = node->duplicate(); undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, dupli, visual_shader->get_node_position(pasted_type, E->get()) + p_offset, id_from); - undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from); + undo_redo->add_do_method(graph_plugin.ptr(), "add_node", type, id_from); // duplicate size, inputs and outputs if node is group Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr()); if (!group.is_null()) { undo_redo->add_do_method(dupli.ptr(), "set_size", group->get_size()); + undo_redo->add_do_method(graph_plugin.ptr(), "set_node_size", type, id_from, group->get_size()); undo_redo->add_do_method(dupli.ptr(), "set_inputs", group->get_inputs()); undo_redo->add_do_method(dupli.ptr(), "set_outputs", group->get_outputs()); } @@ -1835,18 +2143,24 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in continue; } if (connection_remap.has(E->get().from_node) && connection_remap.has(E->get().to_node)) { - undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port); + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port); } } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + id_from = base_id; + for (List<int>::Element *E = r_nodes.front(); E; E = E->next()) { + undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from); + undo_redo->add_undo_method(graph_plugin.ptr(), "remove_node", type, id_from); + id_from++; + } + undo_redo->commit_action(); if (p_select) { // reselect duplicated nodes by excluding the other ones for (int i = 0; i < graph->get_child_count(); i++) { - GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); if (gn) { int id = String(gn->get_name()).to_int(); @@ -1861,13 +2175,11 @@ void VisualShaderEditor::_dup_paste_nodes(int p_type, int p_pasted_type, List<in } void VisualShaderEditor::_clear_buffer() { - copy_nodes_buffer.clear(); copy_nodes_excluded_buffer.clear(); } void VisualShaderEditor::_duplicate_nodes() { - int type = edit_type->get_selected(); List<int> nodes; @@ -1875,8 +2187,9 @@ void VisualShaderEditor::_duplicate_nodes() { _dup_copy_nodes(type, nodes, excluded); - if (nodes.empty()) + if (nodes.empty()) { return; + } undo_redo->create_action(TTR("Duplicate Nodes")); @@ -1884,7 +2197,6 @@ void VisualShaderEditor::_duplicate_nodes() { } void VisualShaderEditor::_copy_nodes() { - copy_type = edit_type->get_selected(); _clear_buffer(); @@ -1892,10 +2204,10 @@ void VisualShaderEditor::_copy_nodes() { _dup_copy_nodes(copy_type, copy_nodes_buffer, copy_nodes_excluded_buffer); } -void VisualShaderEditor::_paste_nodes() { - - if (copy_nodes_buffer.empty()) +void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2 &p_custom_position) { + if (copy_nodes_buffer.empty()) { return; + } int type = edit_type->get_selected(); @@ -1903,14 +2215,20 @@ void VisualShaderEditor::_paste_nodes() { float scale = graph->get_zoom(); - _dup_paste_nodes(type, copy_type, copy_nodes_buffer, copy_nodes_excluded_buffer, (graph->get_scroll_ofs() / scale + graph->get_local_mouse_position() / scale - selection_center), false); + Vector2 mpos; + if (p_use_custom_position) { + mpos = p_custom_position; + } else { + mpos = graph->get_local_mouse_position(); + } + + _dup_paste_nodes(type, copy_type, copy_nodes_buffer, copy_nodes_excluded_buffer, (graph->get_scroll_ofs() / scale + mpos / scale - selection_center), false); _dup_update_excluded(type, copy_nodes_excluded_buffer); // to prevent selection of previous copies at new paste } -void VisualShaderEditor::_on_nodes_delete() { - - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); +void VisualShaderEditor::_delete_nodes() { + VisualShader::Type type = get_current_shader_type(); List<int> to_erase; for (int i = 0; i < graph->get_child_count(); i++) { @@ -1922,17 +2240,31 @@ void VisualShaderEditor::_on_nodes_delete() { } } - if (to_erase.empty()) + if (to_erase.empty()) { return; + } undo_redo->create_action(TTR("Delete Nodes")); + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == F->get() || E->get().to_node == F->get()) { + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + } + } + Set<String> uniform_names; + + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { Ref<VisualShaderNode> node = visual_shader->get_node(type, F->get()); undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F->get()); undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F->get()), F->get()); + undo_redo->add_undo_method(graph_plugin.ptr(), "add_node", type, F->get()); undo_redo->add_do_method(this, "_clear_buffer"); undo_redo->add_undo_method(this, "_clear_buffer"); @@ -1950,16 +2282,17 @@ void VisualShaderEditor::_on_nodes_delete() { if (expression) { undo_redo->add_undo_method(expression, "set_expression", expression->get_expression()); } - } - List<VisualShader::Connection> conns; - visual_shader->get_node_connections(type, &conns); + VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr()); + if (uniform) { + uniform_names.insert(uniform->get_uniform_name()); + } + } List<VisualShader::Connection> used_conns; for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { if (E->get().from_node == F->get() || E->get().to_node == F->get()) { - bool cancel = false; for (List<VisualShader::Connection>::Element *R = used_conns.front(); R; R = R->next()) { if (R->get().from_node == E->get().from_node && R->get().from_port == E->get().from_port && R->get().to_node == E->get().to_node && R->get().to_port == E->get().to_port) { @@ -1969,53 +2302,121 @@ void VisualShaderEditor::_on_nodes_delete() { } if (!cancel) { undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); used_conns.push_back(E->get()); } } } } - undo_redo->add_do_method(this, "_update_graph"); - undo_redo->add_undo_method(this, "_update_graph"); + // delete nodes from the graph + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F->get()); + } + + // update uniform refs if any uniform has been deleted + if (uniform_names.size() > 0) { + undo_redo->add_do_method(this, "_update_uniforms", true); + undo_redo->add_undo_method(this, "_update_uniforms", true); + + _update_uniform_refs(uniform_names); + } + undo_redo->commit_action(); } void VisualShaderEditor::_mode_selected(int p_id) { - + visual_shader->set_shader_type(particles_mode ? VisualShader::Type(p_id + 3) : VisualShader::Type(p_id)); _update_options_menu(); _update_graph(); } -void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, String name) { +void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) { + String prev_name = p_input->get_input_name(); - String prev_name = input->get_input_name(); - - if (name == prev_name) + if (p_name == prev_name) { return; + } - bool type_changed = input->get_input_type_by_name(name) != input->get_input_type_by_name(prev_name); + bool type_changed = p_input->get_input_type_by_name(p_name) != p_input->get_input_type_by_name(prev_name); UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); 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); - - if (type_changed) { - //restore connections if type changed - VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); - int id = visual_shader->find_node_id(type, input); - List<VisualShader::Connection> conns; - visual_shader->get_node_connections(type, &conns); - for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { - if (E->get().from_node == id) { - undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name); + undo_redo->add_undo_method(p_input.ptr(), "set_input_name", prev_name); + + // update output port + for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) { + VisualShader::Type type = VisualShader::Type(type_id); + int id = visual_shader->find_node_id(type, p_input); + if (id != VisualShader::NODE_ID_INVALID) { + if (type_changed) { + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == id) { + if (visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, E->get().to_node)->get_input_port_type(E->get().to_port))) { + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + continue; + } + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + } } + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id); + break; } } - undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph"); - undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph"); + undo_redo->commit_action(); +} + +void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) { + String prev_name = p_uniform_ref->get_uniform_name(); + + if (p_name == prev_name) { + return; + } + + bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name); + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(TTR("UniformRef Name Changed")); + + undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name); + undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name); + + // update output port + for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) { + VisualShader::Type type = VisualShader::Type(type_id); + int id = visual_shader->find_node_id(type, p_uniform_ref); + if (id != VisualShader::NODE_ID_INVALID) { + if (type_changed) { + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == id) { + if (visual_shader->is_port_types_compatible(p_uniform_ref->get_uniform_type_by_name(p_name), visual_shader->get_node(type, E->get().to_node)->get_input_port_type(E->get().to_port))) { + continue; + } + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + } + } + } + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id); + break; + } + } undo_redo->commit_action(); } @@ -2027,10 +2428,12 @@ void VisualShaderEditor::_member_filter_changed(const String &p_text) { void VisualShaderEditor::_member_selected() { TreeItem *item = members->get_selected(); - if (item != NULL && item->has_meta("id")) { + if (item != nullptr && item->has_meta("id")) { members_dialog->get_ok()->set_disabled(false); + highend_label->set_visible(add_options[item->get_meta("id")].highend); node_desc->set_text(_get_description(item->get_meta("id"))); } else { + highend_label->set_visible(false); members_dialog->get_ok()->set_disabled(true); node_desc->set_text(""); } @@ -2041,7 +2444,7 @@ void VisualShaderEditor::_member_unselected() { void VisualShaderEditor::_member_create() { TreeItem *item = members->get_selected(); - if (item != NULL && item->has_meta("id")) { + if (item != nullptr && item->has_meta("id")) { int idx = members->get_selected()->get_meta("id"); _add_node(idx, add_options[idx].sub_func); members_dialog->hide(); @@ -2056,7 +2459,6 @@ void VisualShaderEditor::_member_cancel() { } void VisualShaderEditor::_tools_menu_option(int p_idx) { - TreeItem *category = members->get_root()->get_children(); switch (p_idx) { @@ -2092,14 +2494,35 @@ void VisualShaderEditor::_tools_menu_option(int p_idx) { } } -Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { +void VisualShaderEditor::_node_menu_id_pressed(int p_idx) { + switch (p_idx) { + case NodeMenuOptions::ADD: + _show_members_dialog(true); + break; + case NodeMenuOptions::COPY: + _copy_nodes(); + break; + case NodeMenuOptions::PASTE: + _paste_nodes(true, menu_point); + break; + case NodeMenuOptions::DELETE: + _delete_nodes(); + break; + case NodeMenuOptions::DUPLICATE: + _duplicate_nodes(); + break; + } +} +Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { if (p_from == members) { TreeItem *it = members->get_item_at_position(p_point); - if (!it) + if (!it) { return Variant(); - if (!it->has_meta("id")) + } + if (!it->has_meta("id")) { return Variant(); + } int id = it->get_meta("id"); AddOption op = add_options[id]; @@ -2121,9 +2544,7 @@ Variant VisualShaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f } bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - if (p_from == graph) { - Dictionary d = p_data; if (d.has("id")) { @@ -2138,9 +2559,7 @@ bool VisualShaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant & } void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { - if (p_from == graph) { - Dictionary d = p_data; if (d.has("id")) { @@ -2149,12 +2568,10 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da saved_node_pos_dirty = true; _add_node(idx, add_options[idx].sub_func); } else if (d.has("files")) { - if (d["files"].get_type() == Variant::POOL_STRING_ARRAY) { - + if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) { int j = 0; - PoolStringArray arr = d["files"]; + PackedStringArray arr = d["files"]; for (int i = 0; i < arr.size(); i++) { - String type = ResourceLoader::get_resource_type(arr[i]); if (type == "GDScript") { Ref<Script> script = ResourceLoader::load(arr[i]); @@ -2164,7 +2581,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da _add_custom_node(arr[i]); j++; } - } else if (ClassDB::get_parent_class(type) == "Texture") { + } else if (ClassDB::get_parent_class(type) == "Texture2D") { saved_node_pos = p_point + Vector2(0, j * 210 * EDSCALE); saved_node_pos_dirty = true; _add_texture_node(arr[i]); @@ -2187,8 +2604,12 @@ void VisualShaderEditor::_show_preview_text() { } } -void VisualShaderEditor::_update_preview() { +static ShaderLanguage::DataType _get_global_variable_type(const StringName &p_variable) { + RS::GlobalVariableType gvt = RS::get_singleton()->global_variable_get_type(p_variable); + return RS::global_variable_type_get_shader_datatype(gvt); +} +void VisualShaderEditor::_update_preview() { if (!preview_showed) { pending_update_preview = true; return; @@ -2200,7 +2621,7 @@ void VisualShaderEditor::_update_preview() { ShaderLanguage sl; - Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types()); + Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type); for (int i = 0; i < preview_text->get_line_count(); i++) { preview_text->set_line_as_marked(i, false); @@ -2219,66 +2640,27 @@ void VisualShaderEditor::_update_preview() { } void VisualShaderEditor::_bind_methods() { - ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu); - ClassDB::bind_method("_expression_focus_out", &VisualShaderEditor::_expression_focus_out); ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node); - ClassDB::bind_method("_node_dragged", &VisualShaderEditor::_node_dragged); - ClassDB::bind_method("_connection_request", &VisualShaderEditor::_connection_request); - ClassDB::bind_method("_disconnection_request", &VisualShaderEditor::_disconnection_request); - ClassDB::bind_method("_node_selected", &VisualShaderEditor::_node_selected); - ClassDB::bind_method("_scroll_changed", &VisualShaderEditor::_scroll_changed); - ClassDB::bind_method("_delete_request", &VisualShaderEditor::_delete_request); - ClassDB::bind_method("_on_nodes_delete", &VisualShaderEditor::_on_nodes_delete); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); - ClassDB::bind_method("_edit_port_default_input", &VisualShaderEditor::_edit_port_default_input); - ClassDB::bind_method("_port_edited", &VisualShaderEditor::_port_edited); - ClassDB::bind_method("_connection_to_empty", &VisualShaderEditor::_connection_to_empty); - ClassDB::bind_method("_connection_from_empty", &VisualShaderEditor::_connection_from_empty); - ClassDB::bind_method("_line_edit_focus_out", &VisualShaderEditor::_line_edit_focus_out); - ClassDB::bind_method("_line_edit_changed", &VisualShaderEditor::_line_edit_changed); - ClassDB::bind_method("_port_name_focus_out", &VisualShaderEditor::_port_name_focus_out); - ClassDB::bind_method("_duplicate_nodes", &VisualShaderEditor::_duplicate_nodes); - ClassDB::bind_method("_copy_nodes", &VisualShaderEditor::_copy_nodes); - ClassDB::bind_method("_paste_nodes", &VisualShaderEditor::_paste_nodes); - ClassDB::bind_method("_mode_selected", &VisualShaderEditor::_mode_selected); ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item); - ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port); - ClassDB::bind_method("_graph_gui_input", &VisualShaderEditor::_graph_gui_input); - ClassDB::bind_method("_add_input_port", &VisualShaderEditor::_add_input_port); - ClassDB::bind_method("_change_input_port_type", &VisualShaderEditor::_change_input_port_type); - ClassDB::bind_method("_change_input_port_name", &VisualShaderEditor::_change_input_port_name); - ClassDB::bind_method("_remove_input_port", &VisualShaderEditor::_remove_input_port); - ClassDB::bind_method("_add_output_port", &VisualShaderEditor::_add_output_port); - ClassDB::bind_method("_change_output_port_type", &VisualShaderEditor::_change_output_port_type); - ClassDB::bind_method("_change_output_port_name", &VisualShaderEditor::_change_output_port_name); - ClassDB::bind_method("_remove_output_port", &VisualShaderEditor::_remove_output_port); - ClassDB::bind_method("_node_resized", &VisualShaderEditor::_node_resized); + ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item); ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size); ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer); - ClassDB::bind_method("_show_preview_text", &VisualShaderEditor::_show_preview_text); - ClassDB::bind_method("_update_preview", &VisualShaderEditor::_update_preview); + ClassDB::bind_method("_update_uniforms", &VisualShaderEditor::_update_uniforms); + ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); ClassDB::bind_method(D_METHOD("drop_data_fw"), &VisualShaderEditor::drop_data_fw); ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); - ClassDB::bind_method("_tools_menu_option", &VisualShaderEditor::_tools_menu_option); - ClassDB::bind_method("_show_members_dialog", &VisualShaderEditor::_show_members_dialog); - ClassDB::bind_method("_sbox_input", &VisualShaderEditor::_sbox_input); - ClassDB::bind_method("_member_filter_changed", &VisualShaderEditor::_member_filter_changed); - ClassDB::bind_method("_member_selected", &VisualShaderEditor::_member_selected); - ClassDB::bind_method("_member_unselected", &VisualShaderEditor::_member_unselected); - ClassDB::bind_method("_member_create", &VisualShaderEditor::_member_create); - ClassDB::bind_method("_member_cancel", &VisualShaderEditor::_member_cancel); } -VisualShaderEditor *VisualShaderEditor::singleton = NULL; +VisualShaderEditor *VisualShaderEditor::singleton = nullptr; VisualShaderEditor::VisualShaderEditor() { - singleton = this; updating = false; saved_node_pos_dirty = false; @@ -2306,30 +2688,38 @@ VisualShaderEditor::VisualShaderEditor() { main_box->add_child(graph); graph->set_drag_forwarding(this); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_TRANSFORM); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SAMPLER); //graph->add_valid_left_disconnect_type(0); graph->set_v_size_flags(SIZE_EXPAND_FILL); - graph->connect("connection_request", this, "_connection_request", varray(), CONNECT_DEFERRED); - graph->connect("disconnection_request", this, "_disconnection_request", varray(), CONNECT_DEFERRED); - graph->connect("node_selected", this, "_node_selected"); - graph->connect("scroll_offset_changed", this, "_scroll_changed"); - graph->connect("duplicate_nodes_request", this, "_duplicate_nodes"); - graph->connect("copy_nodes_request", this, "_copy_nodes"); - graph->connect("paste_nodes_request", this, "_paste_nodes"); - graph->connect("delete_nodes_request", this, "_on_nodes_delete"); - graph->connect("gui_input", this, "_graph_gui_input"); - graph->connect("connection_to_empty", this, "_connection_to_empty"); - graph->connect("connection_from_empty", this, "_connection_from_empty"); + graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), varray(), CONNECT_DEFERRED); + graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), varray(), CONNECT_DEFERRED); + graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected)); + graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed)); + graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes)); + graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes)); + graph->connect("paste_nodes_request", callable_mp(this, &VisualShaderEditor::_paste_nodes)); + graph->connect("delete_nodes_request", callable_mp(this, &VisualShaderEditor::_delete_nodes)); + graph->connect("gui_input", callable_mp(this, &VisualShaderEditor::_graph_gui_input)); + graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty)); + graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty)); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_VECTOR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShaderNode::PORT_TYPE_BOOLEAN); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR_INT); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_BOOLEAN); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_SCALAR_INT); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM); @@ -2339,26 +2729,40 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->add_child(vs); graph->get_zoom_hbox()->move_child(vs, 0); - edit_type = memnew(OptionButton); - edit_type->add_item(TTR("Vertex")); - edit_type->add_item(TTR("Fragment")); - edit_type->add_item(TTR("Light")); - edit_type->select(1); - edit_type->connect("item_selected", this, "_mode_selected"); - graph->get_zoom_hbox()->add_child(edit_type); - graph->get_zoom_hbox()->move_child(edit_type, 0); - - add_node = memnew(ToolButton); + edit_type_standart = memnew(OptionButton); + edit_type_standart->add_item(TTR("Vertex")); + edit_type_standart->add_item(TTR("Fragment")); + edit_type_standart->add_item(TTR("Light")); + edit_type_standart->select(1); + edit_type_standart->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); + + edit_type_particles = memnew(OptionButton); + edit_type_particles->add_item(TTR("Emit")); + edit_type_particles->add_item(TTR("Process")); + edit_type_particles->add_item(TTR("End")); + edit_type_particles->select(0); + edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); + + edit_type = edit_type_standart; + + graph->get_zoom_hbox()->add_child(edit_type_particles); + graph->get_zoom_hbox()->move_child(edit_type_particles, 0); + graph->get_zoom_hbox()->add_child(edit_type_standart); + graph->get_zoom_hbox()->move_child(edit_type_standart, 0); + + add_node = memnew(Button); + add_node->set_flat(true); graph->get_zoom_hbox()->add_child(add_node); add_node->set_text(TTR("Add Node...")); graph->get_zoom_hbox()->move_child(add_node, 0); - add_node->connect("pressed", this, "_show_members_dialog", varray(false)); + add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false)); - preview_shader = memnew(ToolButton); + preview_shader = memnew(Button); + preview_shader->set_flat(true); preview_shader->set_toggle_mode(true); preview_shader->set_tooltip(TTR("Show resulted shader code.")); graph->get_zoom_hbox()->add_child(preview_shader); - preview_shader->connect("pressed", this, "_show_preview_text"); + preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text)); /////////////////////////////////////// // PREVIEW PANEL @@ -2367,13 +2771,14 @@ VisualShaderEditor::VisualShaderEditor() { preview_vbox = memnew(VBoxContainer); preview_vbox->set_visible(preview_showed); main_box->add_child(preview_vbox); - preview_text = memnew(TextEdit); + preview_text = memnew(CodeEdit); + syntax_highlighter.instance(); preview_vbox->add_child(preview_text); preview_text->set_h_size_flags(SIZE_EXPAND_FILL); preview_text->set_v_size_flags(SIZE_EXPAND_FILL); preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); - preview_text->set_syntax_coloring(true); - preview_text->set_show_line_numbers(true); + preview_text->set_syntax_highlighter(syntax_highlighter); + preview_text->set_draw_line_numbers(true); preview_text->set_readonly(true); error_text = memnew(Label); @@ -2381,6 +2786,20 @@ VisualShaderEditor::VisualShaderEditor() { error_text->set_visible(false); /////////////////////////////////////// + // POPUP MENU + /////////////////////////////////////// + + popup_menu = memnew(PopupMenu); + add_child(popup_menu); + popup_menu->add_item("Add Node", NodeMenuOptions::ADD); + popup_menu->add_separator(); + popup_menu->add_item("Copy", NodeMenuOptions::COPY); + popup_menu->add_item("Paste", NodeMenuOptions::PASTE); + popup_menu->add_item("Delete", NodeMenuOptions::DELETE); + popup_menu->add_item("Duplicate", NodeMenuOptions::DUPLICATE); + popup_menu->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_node_menu_id_pressed)); + + /////////////////////////////////////// // SHADER NODES TREE /////////////////////////////////////// @@ -2392,15 +2811,15 @@ VisualShaderEditor::VisualShaderEditor() { node_filter = memnew(LineEdit); filter_hb->add_child(node_filter); - node_filter->connect("text_changed", this, "_member_filter_changed"); - node_filter->connect("gui_input", this, "_sbox_input"); + node_filter->connect("text_changed", callable_mp(this, &VisualShaderEditor::_member_filter_changed)); + node_filter->connect("gui_input", callable_mp(this, &VisualShaderEditor::_sbox_input)); node_filter->set_h_size_flags(SIZE_EXPAND_FILL); node_filter->set_placeholder(TTR("Search")); tools = memnew(MenuButton); filter_hb->add_child(tools); tools->set_tooltip(TTR("Options")); - tools->get_popup()->connect("id_pressed", this, "_tools_menu_option"); + tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option)); tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL); tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL); @@ -2413,14 +2832,26 @@ VisualShaderEditor::VisualShaderEditor() { members->set_allow_reselect(true); members->set_hide_folding(false); members->set_custom_minimum_size(Size2(180 * EDSCALE, 200 * EDSCALE)); - members->connect("item_activated", this, "_member_create"); - members->connect("item_selected", this, "_member_selected"); - members->connect("nothing_selected", this, "_member_unselected"); + members->connect("item_activated", callable_mp(this, &VisualShaderEditor::_member_create)); + members->connect("item_selected", callable_mp(this, &VisualShaderEditor::_member_selected)); + members->connect("nothing_selected", callable_mp(this, &VisualShaderEditor::_member_unselected)); + + HBoxContainer *desc_hbox = memnew(HBoxContainer); + members_vb->add_child(desc_hbox); Label *desc_label = memnew(Label); - members_vb->add_child(desc_label); + desc_hbox->add_child(desc_label); desc_label->set_text(TTR("Description:")); + desc_hbox->add_spacer(); + + highend_label = memnew(Label); + desc_hbox->add_child(highend_label); + highend_label->set_visible(false); + highend_label->set_text("Vulkan"); + highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP); + highend_label->set_tooltip(TTR("High-end node")); + node_desc = memnew(RichTextLabel); members_vb->add_child(node_desc); node_desc->set_h_size_flags(SIZE_EXPAND_FILL); @@ -2429,17 +2860,15 @@ VisualShaderEditor::VisualShaderEditor() { members_dialog = memnew(ConfirmationDialog); members_dialog->set_title(TTR("Create Shader Node")); + members_dialog->set_exclusive(false); members_dialog->add_child(members_vb); members_dialog->get_ok()->set_text(TTR("Create")); - members_dialog->get_ok()->connect("pressed", this, "_member_create"); + members_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create)); members_dialog->get_ok()->set_disabled(true); - members_dialog->set_resizable(true); - members_dialog->set_as_minsize(); - members_dialog->connect("hide", this, "_member_cancel"); + members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel)); add_child(members_dialog); alert = memnew(AcceptDialog); - alert->set_as_minsize(); alert->get_label()->set_autowrap(true); alert->get_label()->set_align(Label::ALIGN_CENTER); alert->get_label()->set_valign(Label::VALIGN_CENTER); @@ -2498,6 +2927,7 @@ VisualShaderEditor::VisualShaderEditor() { // INPUT // SPATIAL-FOR-ALL + const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes."); add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); @@ -2528,168 +2958,252 @@ VisualShaderEditor::VisualShaderEditor() { const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode."); const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode."); const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode."); + const String input_param_for_emit_shader_mode = TTR("'%s' input parameter for emit shader mode."); + const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode."); + const String input_param_for_end_shader_mode = TTR("'%s' input parameter for end shader mode."); + const String input_param_for_emit_and_process_shader_mode = TTR("'%s' input parameter for emit and process shader mode."); const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader mode."); - add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL)); - - add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "transmission"), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); - - add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); - add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + + add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "transmission"), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + + add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); // CANVASITEM INPUTS - add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM)); - - add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightHeight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_height"), "light_height", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_uv"), "light_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightVector", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vec"), "light_vec", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM)); - - add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Projection", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); - add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM)); + + add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightHeight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_height"), "light_height", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_uv"), "light_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightVector", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vec"), "light_vec", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("ShadowVec", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_vec"), "shadow_vec", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM)); + + add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Projection", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); + add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); // PARTICLES INPUTS - add_options.push_back(AddOption("Active", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Custom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("CustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Delta", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("EmissionTransform", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Index", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("LifeTime", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Restart", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Time", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Transform", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Velocity", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Active", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Alpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Color", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Custom", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CustomAlpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Delta", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("EmissionTransform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Index", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("LifeTime", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Restart", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Time", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Transform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Velocity", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + + add_options.push_back(AddOption("Active", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Alpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Color", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Custom", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CustomAlpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Delta", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("EmissionTransform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Index", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("LifeTime", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Restart", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Time", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Transform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Velocity", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + + add_options.push_back(AddOption("Active", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Alpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Color", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Custom", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CustomAlpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Delta", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("EmissionTransform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Index", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("LifeTime", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Restart", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Time", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Transform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Velocity", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); + + // SKY INPUTS + + add_options.push_back(AddOption("AtCubeMapPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("AtHalfResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("AtQuarterResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("EyeDir", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("HalfResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("HalfResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light0Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light0Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light0Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light0Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light1Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light1Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light1Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light1Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light2Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light2Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light2Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light2Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light3Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light3Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light3Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Light3Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Position", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("QuarterResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("QuarterResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Radiance", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("SkyCoords", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); + add_options.push_back(AddOption("Time", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY)); // SCALAR - add_options.push_back(AddOption("ScalarFunc", "Scalar", "Common", "VisualShaderNodeScalarFunc", TTR("Scalar function."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ScalarOp", "Scalar", "Common", "VisualShaderNodeScalarOp", TTR("Scalar operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("IntFunc", "Scalar", "Common", "VisualShaderNodeIntFunc", TTR("Integer function."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("FloatOp", "Scalar", "Common", "VisualShaderNodeFloatOp", TTR("Float operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("IntOp", "Scalar", "Common", "VisualShaderNodeIntOp", TTR("Integer operator."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT)); //CONSTANTS - add_options.push_back(AddOption("E", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("E constant (2.718282). Represents the base of the natural logarithm."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_E)); - add_options.push_back(AddOption("Epsilon", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Epsilon constant (0.00001). Smallest possible scalar number."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, CMP_EPSILON)); - add_options.push_back(AddOption("Phi", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Phi constant (1.618034). Golden ratio."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, 1.618034f)); - add_options.push_back(AddOption("Pi/4", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi/4 constant (0.785398) or 45 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 4)); - add_options.push_back(AddOption("Pi/2", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi/2 constant (1.570796) or 90 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 2)); - add_options.push_back(AddOption("Pi", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Pi constant (3.141593) or 180 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI)); - add_options.push_back(AddOption("Tau", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Tau constant (6.283185) or 360 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_TAU)); - add_options.push_back(AddOption("Sqrt2", "Scalar", "Constants", "VisualShaderNodeScalarConstant", TTR("Sqrt2 constant (1.414214). Square root of 2."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_SQRT2)); + add_options.push_back(AddOption("E", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("E constant (2.718282). Represents the base of the natural logarithm."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_E)); + add_options.push_back(AddOption("Epsilon", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Epsilon constant (0.00001). Smallest possible scalar number."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, CMP_EPSILON)); + add_options.push_back(AddOption("Phi", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Phi constant (1.618034). Golden ratio."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, 1.618034f)); + add_options.push_back(AddOption("Pi/4", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Pi/4 constant (0.785398) or 45 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 4)); + add_options.push_back(AddOption("Pi/2", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Pi/2 constant (1.570796) or 90 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI / 2)); + add_options.push_back(AddOption("Pi", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Pi constant (3.141593) or 180 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_PI)); + add_options.push_back(AddOption("Tau", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Tau constant (6.283185) or 360 degrees."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_TAU)); + add_options.push_back(AddOption("Sqrt2", "Scalar", "Constants", "VisualShaderNodeFloatConstant", TTR("Sqrt2 constant (1.414214). Square root of 2."), -1, VisualShaderNode::PORT_TYPE_SCALAR, -1, -1, Math_SQRT2)); // FUNCTIONS - add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeScalarFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeScalarOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeFloatFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Abs", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the absolute value of the parameter."), VisualShaderNodeIntFunc::FUNC_ABS, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("ACos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ACOS, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ACosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ACOSH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ASin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ASIN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ASinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_ASINH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ATan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the arc-tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_ATAN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeFloatOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeFloatFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeScalarClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeScalarFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeScalarFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-e Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 Exponential."), VisualShaderNodeScalarFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeScalarFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeScalarFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Natural logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Base-2 logarithm."), VisualShaderNodeScalarFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the greater of two values."), VisualShaderNodeScalarOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the lesser of two values."), VisualShaderNodeScalarOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Constrains a value to lie between two further values."), VisualShaderNodeIntFunc::FUNC_CLAMP, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeFloatFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Exp", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-e Exponential."), VisualShaderNodeFloatFunc::FUNC_EXP, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Exp2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 Exponential."), VisualShaderNodeFloatFunc::FUNC_EXP2, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Floor", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer less than or equal to the parameter."), VisualShaderNodeFloatFunc::FUNC_FLOOR, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Fract", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Computes the fractional part of the argument."), VisualShaderNodeFloatFunc::FUNC_FRAC, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("InverseSqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse of the square root of the parameter."), VisualShaderNodeFloatFunc::FUNC_INVERSE_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Log", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Natural logarithm."), VisualShaderNodeFloatFunc::FUNC_LOG, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), VisualShaderNodeFloatFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), VisualShaderNodeFloatOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), VisualShaderNodeFloatOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeScalarFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 - scalar"), VisualShaderNodeScalarFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeScalarOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeScalarFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("1.0 / scalar"), VisualShaderNodeScalarFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the nearest even integer to the parameter."), VisualShaderNodeScalarFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeScalarFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), VisualShaderNodeMultiplyAdd::TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeFloatFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeIntFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("OneMinus", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), VisualShaderNodeFloatFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Pow", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), VisualShaderNodeFloatOp::OP_POW, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Radians", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), VisualShaderNodeFloatFunc::FUNC_RADIANS, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Reciprocal", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), VisualShaderNodeFloatFunc::FUNC_RECIPROCAL, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Round", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), VisualShaderNodeFloatFunc::FUNC_ROUND, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("RoundEven", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Saturate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Clamps the value between 0.0 and 1.0."), VisualShaderNodeFloatFunc::FUNC_SATURATE, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeFloatFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Sign", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Extracts the sign of the parameter."), VisualShaderNodeIntFunc::FUNC_SIGN, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeFloatFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR)); - - add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Adds scalar to scalar."), VisualShaderNodeScalarOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Divides scalar by scalar."), VisualShaderNodeScalarOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Multiplies scalar by scalar."), VisualShaderNodeScalarOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Returns the remainder of the two scalars."), VisualShaderNodeScalarOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeScalarOp", TTR("Subtracts scalar from scalar."), VisualShaderNodeScalarOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR)); - - add_options.push_back(AddOption("ScalarConstant", "Scalar", "Variables", "VisualShaderNodeScalarConstant", TTR("Scalar constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("ScalarUniform", "Scalar", "Variables", "VisualShaderNodeScalarUniform", TTR("Scalar uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeFloatOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeFloatFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR)); + + add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), VisualShaderNodeFloatOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Add", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), VisualShaderNodeIntOp::OP_ADD, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), VisualShaderNodeFloatOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Divide", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), VisualShaderNodeIntOp::OP_DIV, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), VisualShaderNodeFloatOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Multiply", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), VisualShaderNodeIntOp::OP_MUL, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Returns the remainder of the two floating-point scalars."), VisualShaderNodeFloatOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Remainder", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Returns the remainder of the two integer scalars."), VisualShaderNodeIntOp::OP_MOD, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), VisualShaderNodeFloatOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Subtract", "Scalar", "Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), VisualShaderNodeIntOp::OP_SUB, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + + add_options.push_back(AddOption("FloatConstant", "Scalar", "Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("IntConstant", "Scalar", "Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("FloatUniform", "Scalar", "Variables", "VisualShaderNodeFloatUniform", TTR("Scalar floating-point uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("IntUniform", "Scalar", "Variables", "VisualShaderNodeIntUniform", TTR("Scalar integer uniform."), -1, VisualShaderNode::PORT_TYPE_SCALAR_INT)); // TEXTURES - add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, -1)); + add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1)); texture_node_option_idx = add_options.size(); - add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, -1)); + add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), -1, -1)); + add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1)); + add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), -1, -1)); - add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, -1)); + add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1)); add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1)); - add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup."), -1, -1, -1, -1, -1)); + add_options.push_back(AddOption("Texture3DUniform", "Textures", "Variables", "VisualShaderNodeTexture3DUniform", TTR("3D texture uniform lookup."), -1, -1, -1, -1, -1)); // TRANSFORM @@ -2746,6 +3260,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeVectorScalarMix", TTR("Linear interpolation between two vectors using scalar."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), VisualShaderNodeMultiplyAdd::TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("OneMinus", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -2783,16 +3298,17 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside."))); add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); + add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform."))); - add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); - add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); + add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true)); custom_node_option_idx = add_options.size(); ///////////////////////////////////////////////////////////////////// @@ -2812,24 +3328,25 @@ VisualShaderEditor::VisualShaderEditor() { default_plugin.instance(); add_plugin(default_plugin); + graph_plugin.instance(); + property_editor = memnew(CustomPropertyEditor); add_child(property_editor); - property_editor->connect("variant_changed", this, "_port_edited"); + property_editor->connect("variant_changed", callable_mp(this, &VisualShaderEditor::_port_edited)); } -void VisualShaderEditorPlugin::edit(Object *p_object) { +///////////////// +void VisualShaderEditorPlugin::edit(Object *p_object) { visual_shader_editor->edit(Object::cast_to<VisualShader>(p_object)); } bool VisualShaderEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("VisualShader"); } void VisualShaderEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { //editor->hide_animation_player_editors(); //editor->animation_panel_make_visible(true); @@ -2839,9 +3356,9 @@ void VisualShaderEditorPlugin::make_visible(bool p_visible) { visual_shader_editor->set_process_input(true); //visual_shader_editor->set_process(true); } else { - - if (visual_shader_editor->is_visible_in_tree()) + if (visual_shader_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); + } button->hide(); visual_shader_editor->set_process_input(false); //visual_shader_editor->set_process(false); @@ -2849,7 +3366,6 @@ void VisualShaderEditorPlugin::make_visible(bool p_visible) { } VisualShaderEditorPlugin::VisualShaderEditorPlugin(EditorNode *p_node) { - editor = p_node; visual_shader_editor = memnew(VisualShaderEditor); visual_shader_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE); @@ -2868,15 +3384,10 @@ class VisualShaderNodePluginInputEditor : public OptionButton { Ref<VisualShaderNodeInput> input; -protected: - static void _bind_methods() { - ClassDB::bind_method("_item_selected", &VisualShaderNodePluginInputEditor::_item_selected); - } - public: void _notification(int p_what) { if (p_what == NOTIFICATION_READY) { - connect("item_selected", this, "_item_selected"); + connect("item_selected", callable_mp(this, &VisualShaderNodePluginInputEditor::_item_selected)); } } @@ -2886,12 +3397,13 @@ public: void setup(const Ref<VisualShaderNodeInput> &p_input) { input = p_input; - Ref<Texture> type_icon[5] = { - EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"), + Ref<Texture2D> type_icon[6] = { + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"), }; add_item("[None]"); @@ -2909,26 +3421,75 @@ public: } }; +//////////////// + +class VisualShaderNodePluginUniformRefEditor : public OptionButton { + GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton); + + Ref<VisualShaderNodeUniformRef> uniform_ref; + +public: + void _notification(int p_what) { + if (p_what == NOTIFICATION_READY) { + connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected)); + } + } + + void _item_selected(int p_item) { + VisualShaderEditor::get_singleton()->call_deferred("_uniform_select_item", uniform_ref, get_item_text(p_item)); + } + + void setup(const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) { + uniform_ref = p_uniform_ref; + + Ref<Texture2D> type_icon[7] = { + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"), + }; + + add_item("[None]"); + int to_select = -1; + for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) { + if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) { + to_select = i + 1; + } + add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i)); + } + + if (to_select >= 0) { + select(to_select); + } + } +}; + +//////////////// + class VisualShaderNodePluginDefaultEditor : public VBoxContainer { GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer); Ref<Resource> parent_resource; + int node_id; + VisualShader::Type shader_type; public: - void _property_changed(const String &prop, const Variant &p_value, const String &p_field, bool p_changing = false) { - - if (p_changing) + void _property_changed(const String &p_property, const Variant &p_value, const String &p_field = "", bool p_changing = false) { + if (p_changing) { return; + } UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); updating = true; - 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->create_action(TTR("Edit Visual Property") + ": " + p_property, UndoRedo::MERGE_ENDS); + undo_redo->add_do_property(node.ptr(), p_property, p_value); + undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property)); if (p_value.get_type() == Variant::OBJECT) { - - RES prev_res = node->get(prop); + RES prev_res = node->get(p_property); RES curr_res = p_value; if (curr_res.is_null()) { @@ -2941,8 +3502,10 @@ public: } else { undo_redo->add_undo_method(this, "_open_inspector", (RES)parent_resource.ptr()); } - undo_redo->add_do_method(this, "_refresh_request"); - undo_redo->add_undo_method(this, "_refresh_request"); + } + if (p_property != "constant") { + undo_redo->add_do_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id); + undo_redo->add_undo_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id); } undo_redo->commit_action(); @@ -2950,17 +3513,14 @@ public: } void _node_changed() { - if (updating) + if (updating) { return; + } for (int i = 0; i < properties.size(); i++) { properties[i]->update_property(); } } - void _refresh_request() { - VisualShaderEditor::get_singleton()->call_deferred("_update_graph"); - } - void _resource_selected(const String &p_path, RES p_resource) { _open_inspector(p_resource); } @@ -2972,6 +3532,13 @@ public: bool updating; Ref<VisualShaderNode> node; Vector<EditorProperty *> properties; + Vector<Label *> prop_names; + + void _show_prop_names(bool p_show) { + for (int i = 0; i < prop_names.size(); i++) { + prop_names[i]->set_visible(p_show); + } + } void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, Ref<VisualShaderNode> p_node) { parent_resource = p_parent_resource; @@ -2979,34 +3546,51 @@ public: node = p_node; properties = p_properties; + node_id = (int)p_node->get_meta("id"); + shader_type = VisualShader::Type((int)p_node->get_meta("shader_type")); + for (int i = 0; i < p_properties.size(); i++) { + HBoxContainer *hbox = memnew(HBoxContainer); + hbox->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(hbox); - add_child(p_properties[i]); + Label *prop_name = memnew(Label); + String prop_name_str = p_names[i]; + prop_name_str = prop_name_str.capitalize() + ":"; + prop_name->set_text(prop_name_str); + prop_name->set_visible(false); + hbox->add_child(prop_name); + prop_names.push_back(prop_name); + + p_properties[i]->set_h_size_flags(SIZE_EXPAND_FILL); + hbox->add_child(p_properties[i]); bool res_prop = Object::cast_to<EditorPropertyResource>(p_properties[i]); if (res_prop) { - p_properties[i]->connect("resource_selected", this, "_resource_selected"); + p_properties[i]->connect("resource_selected", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_resource_selected)); } - properties[i]->connect("property_changed", this, "_property_changed"); + properties[i]->connect("property_changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_property_changed)); properties[i]->set_object_and_property(node.ptr(), p_names[i]); properties[i]->update_property(); properties[i]->set_name_split_ratio(0); } - node->connect("changed", this, "_node_changed"); - node->connect("editor_refresh_request", this, "_refresh_request", varray(), CONNECT_DEFERRED); + node->connect("changed", callable_mp(this, &VisualShaderNodePluginDefaultEditor::_node_changed)); } static void _bind_methods() { - ClassDB::bind_method("_property_changed", &VisualShaderNodePluginDefaultEditor::_property_changed, DEFVAL(String()), DEFVAL(false)); - ClassDB::bind_method("_node_changed", &VisualShaderNodePluginDefaultEditor::_node_changed); - ClassDB::bind_method("_refresh_request", &VisualShaderNodePluginDefaultEditor::_refresh_request); - ClassDB::bind_method("_resource_selected", &VisualShaderNodePluginDefaultEditor::_resource_selected); - ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); + ClassDB::bind_method("_open_inspector", &VisualShaderNodePluginDefaultEditor::_open_inspector); // Used by UndoRedo. + ClassDB::bind_method("_show_prop_names", &VisualShaderNodePluginDefaultEditor::_show_prop_names); // Used with call_deferred. } }; Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) { + if (p_node->is_class("VisualShaderNodeUniformRef")) { + //create input + VisualShaderNodePluginUniformRefEditor *uniform_editor = memnew(VisualShaderNodePluginUniformRefEditor); + uniform_editor->setup(p_node); + return uniform_editor; + } if (p_node->is_class("VisualShaderNodeInput")) { //create input @@ -3017,7 +3601,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par Vector<StringName> properties = p_node->get_editable_properties(); if (properties.size() == 0) { - return NULL; + return nullptr; } List<PropertyInfo> props; @@ -3026,7 +3610,6 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par Vector<PropertyInfo> pinfo; for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - for (int i = 0; i < properties.size(); i++) { if (E->get().name == String(properties[i])) { pinfo.push_back(E->get()); @@ -3034,8 +3617,9 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par } } - if (pinfo.size() == 0) - return NULL; + if (pinfo.size() == 0) { + return nullptr; + } properties.clear(); @@ -3043,10 +3627,10 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par Vector<EditorProperty *> editors; for (int i = 0; i < pinfo.size(); i++) { - EditorProperty *prop = EditorInspector::instantiate_property_editor(node.ptr(), pinfo[i].type, pinfo[i].name, pinfo[i].hint, pinfo[i].hint_string, pinfo[i].usage); - if (!prop) - return NULL; + if (!prop) { + return nullptr; + } if (Object::cast_to<EditorPropertyResource>(prop)) { Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false); @@ -3069,25 +3653,28 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par } void EditorPropertyShaderMode::_option_selected(int p_which) { - //will not use this, instead will do all the logic setting manually //emit_signal("property_changed", get_edited_property(), p_which); Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object())); - if (visual_shader->get_mode() == p_which) + if (visual_shader->get_mode() == p_which) { return; + } UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); 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()); + + undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_set_mode", p_which); + undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_set_mode", visual_shader->get_mode()); + //now undo is hell //1. restore connections to output for (int i = 0; i < VisualShader::TYPE_MAX; i++) { - VisualShader::Type type = VisualShader::Type(i); List<VisualShader::Connection> conns; visual_shader->get_node_connections(type, &conns); @@ -3099,7 +3686,6 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { } //2. restore input indices for (int i = 0; i < VisualShader::TYPE_MAX; i++) { - VisualShader::Type type = VisualShader::Type(i); Vector<int> nodes = visual_shader->get_node_list(type); for (int j = 0; j < nodes.size(); j++) { @@ -3117,7 +3703,6 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { visual_shader->get_property_list(&props); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - if (E->get().name.begins_with("flags/") || E->get().name.begins_with("modes/")) { undo_redo->add_undo_property(visual_shader.ptr(), E->get().name, visual_shader->get(E->get().name)); } @@ -3134,7 +3719,6 @@ void EditorPropertyShaderMode::_option_selected(int p_which) { } void EditorPropertyShaderMode::update_property() { - int which = get_edited_object()->get(get_edited_property()); options->select(which); } @@ -3150,8 +3734,6 @@ void EditorPropertyShaderMode::set_option_button_clip(bool p_enable) { } void EditorPropertyShaderMode::_bind_methods() { - - ClassDB::bind_method(D_METHOD("_option_selected"), &EditorPropertyShaderMode::_option_selected); } EditorPropertyShaderMode::EditorPropertyShaderMode() { @@ -3159,7 +3741,7 @@ EditorPropertyShaderMode::EditorPropertyShaderMode() { options->set_clip_text(true); add_child(options); add_focusable(options); - options->connect("item_selected", this, "_option_selected"); + options->connect("item_selected", callable_mp(this, &EditorPropertyShaderMode::_option_selected)); } bool EditorInspectorShaderModePlugin::can_handle(Object *p_object) { @@ -3170,10 +3752,8 @@ void EditorInspectorShaderModePlugin::parse_begin(Object *p_object) { //do none } -bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { - +bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) { - EditorPropertyShaderMode *editor = memnew(EditorPropertyShaderMode); Vector<String> options = p_hint_text.split(","); editor->setup(options); @@ -3188,6 +3768,7 @@ bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, Variant:: void EditorInspectorShaderModePlugin::parse_end() { //do none } + ////////////////////////////////// void VisualShaderNodePortPreview::_shader_changed() { @@ -3213,11 +3794,11 @@ void VisualShaderNodePortPreview::_shader_changed() { for (int i = EditorNode::get_singleton()->get_editor_history()->get_path_size() - 1; i >= 0; i--) { Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_history()->get_path_object(i)); - if (!object) + if (!object) { continue; + } ShaderMaterial *src_mat = Object::cast_to<ShaderMaterial>(object); if (src_mat && src_mat->get_shader().is_valid()) { - List<PropertyInfo> params; src_mat->get_shader()->get_param_list(¶ms); for (List<PropertyInfo>::Element *E = params.front(); E; E = E->next()) { @@ -3230,9 +3811,8 @@ void VisualShaderNodePortPreview::_shader_changed() { } void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port) { - shader = p_shader; - shader->connect("changed", this, "_shader_changed"); + shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed)); type = p_type; port = p_port; node = p_node; @@ -3267,7 +3847,6 @@ void VisualShaderNodePortPreview::_notification(int p_what) { } void VisualShaderNodePortPreview::_bind_methods() { - ClassDB::bind_method("_shader_changed", &VisualShaderNodePortPreview::_shader_changed); } VisualShaderNodePortPreview::VisualShaderNodePortPreview() { @@ -3276,18 +3855,15 @@ VisualShaderNodePortPreview::VisualShaderNodePortPreview() { ////////////////////////////////// String VisualShaderConversionPlugin::converts_to() const { - return "Shader"; } bool VisualShaderConversionPlugin::handles(const Ref<Resource> &p_resource) const { - Ref<VisualShader> vshader = p_resource; return vshader.is_valid(); } Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resource) const { - Ref<VisualShader> vshader = p_resource; ERR_FAIL_COND_V(!vshader.is_valid(), Ref<Resource>()); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 8c5dd8e82f..531a117156 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -41,7 +41,6 @@ #include "scene/resources/visual_shader.h" class VisualShaderNodePlugin : public Reference { - GDCLASS(VisualShaderNodePlugin, Reference); protected: @@ -51,9 +50,72 @@ public: virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node); }; -class VisualShaderEditor : public VBoxContainer { +class VisualShaderGraphPlugin : public Reference { + GDCLASS(VisualShaderGraphPlugin, Reference); + +private: + struct InputPort { + Button *default_input_button; + }; + + struct Port { + TextureButton *preview_button; + }; + + struct Link { + VisualShader::Type type; + VisualShaderNode *visual_node; + GraphNode *graph_node; + bool preview_visible; + int preview_pos; + Map<int, InputPort> input_ports; + Map<int, Port> output_ports; + VBoxContainer *preview_box; + LineEdit *uniform_name; + }; + + Ref<VisualShader> visual_shader; + Map<int, Link> links; + List<VisualShader::Connection> connections; + bool dirty = false; + +protected: + static void _bind_methods(); + +public: + void register_shader(VisualShader *p_visual_shader); + void set_connections(List<VisualShader::Connection> &p_connections); + void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node); + void register_output_port(int p_id, int p_port, TextureButton *p_button); + void register_uniform_name(int p_id, LineEdit *p_uniform_name); + void clear_links(); + void set_shader_type(VisualShader::Type p_type); + bool is_preview_visible(int p_id) const; + bool is_dirty() const; + void make_dirty(bool p_enabled); + void update_node(VisualShader::Type p_type, int p_id); + void update_node_deferred(VisualShader::Type p_type, int p_node_id); + void add_node(VisualShader::Type p_type, int p_id); + void remove_node(VisualShader::Type p_type, int p_id); + void connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + void disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port); + void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id); + void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position); + void set_node_size(VisualShader::Type p_type, int p_id, const Vector2 &p_size); + void refresh_node_ports(VisualShader::Type p_type, int p_node); + void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value); + void register_default_input_button(int p_node_id, int p_port_id, Button *p_button); + void update_uniform_refs(); + void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name); + VisualShader::Type get_shader_type() const; + + VisualShaderGraphPlugin(); + ~VisualShaderGraphPlugin(); +}; +class VisualShaderEditor : public VBoxContainer { GDCLASS(VisualShaderEditor, VBoxContainer); + friend class VisualShaderGraphPlugin; CustomPropertyEditor *property_editor; int editing_node; @@ -62,10 +124,12 @@ class VisualShaderEditor : public VBoxContainer { Ref<VisualShader> visual_shader; HSplitContainer *main_box; GraphEdit *graph; - ToolButton *add_node; - ToolButton *preview_shader; + Button *add_node; + Button *preview_shader; - OptionButton *edit_type; + OptionButton *edit_type = nullptr; + OptionButton *edit_type_standart; + OptionButton *edit_type_particles; PanelContainer *error_panel; Label *error_label; @@ -73,7 +137,8 @@ class VisualShaderEditor : public VBoxContainer { bool pending_update_preview; bool shader_error; VBoxContainer *preview_vbox; - TextEdit *preview_text; + CodeEdit *preview_text; + Ref<CodeHighlighter> syntax_highlighter; Label *error_text; UndoRedo *undo_redo; @@ -81,19 +146,43 @@ class VisualShaderEditor : public VBoxContainer { bool saved_node_pos_dirty; ConfirmationDialog *members_dialog; + PopupMenu *popup_menu; MenuButton *tools; bool preview_showed; + bool particles_mode; + + enum TypeFlags { + TYPE_FLAGS_VERTEX = 1, + TYPE_FLAGS_FRAGMENT = 2, + TYPE_FLAGS_LIGHT = 4, + }; + + enum ParticlesTypeFlags { + TYPE_FLAGS_EMIT = 1, + TYPE_FLAGS_PROCESS = 2, + TYPE_FLAGS_END = 4 + }; enum ToolsMenuOptions { EXPAND_ALL, COLLAPSE_ALL }; + enum NodeMenuOptions { + ADD, + SEPARATOR, // ignore + COPY, + PASTE, + DELETE, + DUPLICATE, + }; + Tree *members; AcceptDialog *alert; LineEdit *node_filter; RichTextLabel *node_desc; + Label *highend_label; void _tools_menu_option(int p_idx); void _show_members_dialog(bool at_mouse_pos); @@ -103,7 +192,6 @@ class VisualShaderEditor : public VBoxContainer { struct AddOption { String name; String category; - String sub_category; String type; String description; int sub_func; @@ -115,12 +203,12 @@ class VisualShaderEditor : public VBoxContainer { float value; bool highend; bool is_custom; + int temp_idx; AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) { name = p_name; type = p_type; - category = p_category; - sub_category = p_sub_category; + category = p_category + "/" + p_sub_category; description = p_description; sub_func = p_sub_func; return_type = p_return_type; @@ -134,8 +222,7 @@ class VisualShaderEditor : public VBoxContainer { AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) { name = p_name; type = p_type; - category = p_category; - sub_category = p_sub_category; + category = p_category + "/" + p_sub_category; description = p_description; sub_func = 0; sub_func_str = p_sub_func; @@ -147,18 +234,26 @@ class VisualShaderEditor : public VBoxContainer { is_custom = false; } }; + struct _OptionComparator { + _FORCE_INLINE_ bool operator()(const AddOption &a, const AddOption &b) const { + return a.category.count("/") > b.category.count("/") || (a.category + "/" + a.name).naturalnocasecmp_to(b.category + "/" + b.name) < 0; + } + }; Vector<AddOption> add_options; int texture_node_option_idx; int custom_node_option_idx; List<String> keyword_list; + List<VisualShaderNodeUniformRef> uniform_refs; + void _draw_color_over_button(Object *obj, Color p_color); void _add_custom_node(const String &p_path); void _add_texture_node(const String &p_path); VisualShaderNode *_add_node(int p_idx, int p_op_idx = -1); void _update_options_menu(); + void _set_mode(int p_which); void _show_preview_text(); void _update_preview(); @@ -176,7 +271,7 @@ class VisualShaderEditor : public VBoxContainer { void _node_selected(Object *p_node); void _delete_request(int); - void _on_nodes_delete(); + void _delete_nodes(); void _removed_from_graph(); @@ -193,8 +288,8 @@ class VisualShaderEditor : public VBoxContainer { void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position); void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position); - void _line_edit_changed(const String &p_text, Object *line_edit, int p_node_id); - void _line_edit_focus_out(Object *line_edit, int p_node_id); + void _uniform_line_edit_changed(const String &p_text, int p_node_id); + void _uniform_line_edit_focus_out(Object *line_edit, int p_node_id); void _port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output); @@ -211,14 +306,17 @@ class VisualShaderEditor : public VBoxContainer { void _clear_buffer(); void _copy_nodes(); - void _paste_nodes(); + void _paste_nodes(bool p_use_custom_position = false, const Vector2 &p_custom_position = Vector2()); - Vector<Ref<VisualShaderNodePlugin> > plugins; + Vector<Ref<VisualShaderNodePlugin>> plugins; + Ref<VisualShaderGraphPlugin> graph_plugin; void _mode_selected(int p_id); - void _rebuild(); void _input_select_item(Ref<VisualShaderNodeInput> input, String name); + void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name); + + VisualShader::Type get_current_shader_type() const; void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name); void _remove_input_port(int p_node, int p_port); @@ -230,7 +328,7 @@ class VisualShaderEditor : public VBoxContainer { void _change_output_port_type(int p_type, int p_node, int p_port); void _change_output_port_name(const String &p_text, Object *line_edit, int p_node, int p_port); - void _expression_focus_out(Object *text_edit, int p_node); + void _expression_focus_out(Object *code_edit, int p_node); void _set_node_size(int p_type, int p_node, const Size2 &p_size); void _node_resized(const Vector2 &p_new_size, int p_type, int p_node); @@ -245,12 +343,17 @@ class VisualShaderEditor : public VBoxContainer { void _member_create(); void _member_cancel(); + Vector2 menu_point; + void _node_menu_id_pressed(int p_idx); + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool _is_available(int p_mode); void _update_created_node(GraphNode *node); + void _update_uniforms(bool p_update_refs); + void _update_uniform_refs(Set<String> &p_names); protected: void _notification(int p_what); @@ -262,17 +365,17 @@ public: void remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); static VisualShaderEditor *get_singleton() { return singleton; } + VisualShaderGraphPlugin *get_graph_plugin() { return graph_plugin.ptr(); } void clear_custom_types(); - void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory); + void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend); - virtual Size2 get_minimum_size() const; + virtual Size2 get_minimum_size() const override; void edit(VisualShader *p_visual_shader); VisualShaderEditor(); }; class VisualShaderEditorPlugin : public EditorPlugin { - GDCLASS(VisualShaderEditorPlugin, EditorPlugin); VisualShaderEditor *visual_shader_editor; @@ -280,22 +383,21 @@ class VisualShaderEditorPlugin : public EditorPlugin { Button *button; public: - virtual String get_name() const { return "VisualShader"; } - 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); + virtual String get_name() const override { return "VisualShader"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; VisualShaderEditorPlugin(EditorNode *p_node); ~VisualShaderEditorPlugin(); }; class VisualShaderNodePluginDefault : public VisualShaderNodePlugin { - GDCLASS(VisualShaderNodePluginDefault, VisualShaderNodePlugin); public: - virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node); + virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) override; }; class EditorPropertyShaderMode : public EditorProperty { @@ -309,7 +411,7 @@ protected: public: void setup(const Vector<String> &p_options); - virtual void update_property(); + virtual void update_property() override; void set_option_button_clip(bool p_enable); EditorPropertyShaderMode(); }; @@ -318,10 +420,10 @@ class EditorInspectorShaderModePlugin : public EditorInspectorPlugin { GDCLASS(EditorInspectorShaderModePlugin, EditorInspectorPlugin); public: - virtual bool can_handle(Object *p_object); - virtual void parse_begin(Object *p_object); - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); - virtual void parse_end(); + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual void parse_end() override; }; class VisualShaderNodePortPreview : public Control { @@ -336,7 +438,7 @@ protected: static void _bind_methods(); public: - virtual Size2 get_minimum_size() const; + virtual Size2 get_minimum_size() const override; void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port); VisualShaderNodePortPreview(); }; @@ -345,9 +447,9 @@ class VisualShaderConversionPlugin : public EditorResourceConversionPlugin { GDCLASS(VisualShaderConversionPlugin, EditorResourceConversionPlugin); public: - virtual String converts_to() const; - virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; + virtual String converts_to() const override; + virtual bool handles(const Ref<Resource> &p_resource) const override; + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override; }; #endif // VISUAL_SHADER_EDITOR_PLUGIN_H |