summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp75
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h18
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.h5
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp16
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp38
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h2
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/editor_preview_plugins.cpp2
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp12
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp2
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp59
-rw-r--r--editor/plugins/mesh_library_editor_plugin.h14
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp101
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h19
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp57
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp49
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.h4
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp24
-rw-r--r--editor/plugins/script_editor_plugin.cpp56
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--editor/plugins/script_text_editor.cpp41
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp5
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp126
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h1
-rw-r--r--editor/plugins/text_editor.cpp5
-rw-r--r--editor/plugins/text_editor.h1
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp120
-rw-r--r--editor/plugins/texture_region_editor_plugin.h4
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp12
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp39
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp56
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp136
-rw-r--r--editor/plugins/tiles/tile_map_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp252
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp225
-rw-r--r--editor/plugins/tiles/tile_set_editor.h1
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp4
44 files changed, 1041 insertions, 566 deletions
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 030d90eeca..24cb660f7a 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -66,9 +66,13 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
_update_options_menu();
}
-void AnimationNodeBlendTreeEditor::_update_options_menu() {
+void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports) {
add_node->get_popup()->clear();
+ add_node->get_popup()->set_size(Size2i(-1, -1));
for (int i = 0; i < add_options.size(); i++) {
+ if (p_has_input_ports && add_options[i].input_port_count == 0) {
+ continue;
+ }
add_node->get_popup()->add_item(add_options[i].name, i);
}
@@ -309,6 +313,11 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
return;
}
+ if (!from_node.is_empty() && anode->get_input_count() == 0) {
+ from_node = "";
+ return;
+ }
+
Point2 instance_pos = graph->get_scroll_ofs();
if (use_popup_menu_position) {
instance_pos += popup_menu_position;
@@ -328,11 +337,51 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
undo_redo->create_action(TTR("Add Node to BlendTree"));
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
+
+ if (!from_node.is_empty()) {
+ undo_redo->add_do_method(blend_tree.ptr(), "connect_node", name, 0, from_node);
+ from_node = "";
+ }
+ if (!to_node.is_empty() && to_slot != -1) {
+ undo_redo->add_do_method(blend_tree.ptr(), "connect_node", to_node, to_slot, name);
+ to_node = "";
+ to_slot = -1;
+ }
+
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
}
+void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position) {
+ _update_options_menu(p_has_input_ports);
+ use_popup_menu_position = true;
+ popup_menu_position = p_popup_position;
+ add_node->get_popup()->set_position(p_node_position);
+ add_node->get_popup()->popup();
+}
+
+void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ _popup(false, graph->get_local_mouse_position(), p_position);
+}
+
+void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
+ Ref<AnimationNode> node = blend_tree->get_node(p_from);
+ if (node.is_valid()) {
+ from_node = p_from;
+ _popup(true, p_release_position, graph->get_global_mouse_position());
+ }
+}
+
+void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ Ref<AnimationNode> node = blend_tree->get_node(p_to);
+ if (node.is_valid()) {
+ to_node = p_to;
+ to_slot = p_to_slot;
+ _popup(false, p_release_position, graph->get_global_mouse_position());
+ }
+}
+
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"));
@@ -431,14 +480,6 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
undo_redo->commit_action();
}
-void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
- _update_options_menu();
- use_popup_menu_position = true;
- popup_menu_position = graph->get_local_mouse_position();
- add_node->get_popup()->set_position(p_position);
- add_node->get_popup()->popup();
-}
-
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -890,6 +931,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
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));
+ graph->connect("connection_to_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_to_empty));
+ graph->connect("connection_from_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_from_empty));
float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
@@ -905,13 +948,13 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
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"));
- add_options.push_back(AddOption("Add2", "AnimationNodeAdd2"));
- add_options.push_back(AddOption("Add3", "AnimationNodeAdd3"));
- add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2"));
- add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3"));
- add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek"));
- add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale"));
+ add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
+ add_options.push_back(AddOption("Add2", "AnimationNodeAdd2", 2));
+ add_options.push_back(AddOption("Add3", "AnimationNodeAdd3", 3));
+ add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2", 2));
+ add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3", 3));
+ add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek", 1));
+ add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale", 1));
add_options.push_back(AddOption("Transition", "AnimationNodeTransition"));
add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree"));
add_options.push_back(AddOption("BlendSpace1D", "AnimationNodeBlendSpace1D"));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 9f09069719..0fcafad40e 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -64,22 +64,28 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
Map<StringName, ProgressBar *> animations;
Vector<EditorProperty *> visible_properties;
+ String to_node = "";
+ int to_slot = -1;
+ String from_node = "";
+
void _update_graph();
struct AddOption {
String name;
String type;
Ref<Script> script;
- AddOption(const String &p_name = String(), const String &p_type = String()) :
+ int input_port_count;
+ AddOption(const String &p_name = String(), const String &p_type = String(), bool p_input_port_count = 0) :
name(p_name),
- type(p_type) {
+ type(p_type),
+ input_port_count(p_input_port_count) {
}
};
Vector<AddOption> add_options;
void _add_node(int p_idx);
- void _update_options_menu();
+ void _update_options_menu(bool p_has_input_ports = false);
static AnimationNodeBlendTreeEditor *singleton;
@@ -98,7 +104,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
void _delete_nodes_request();
- void _popup_request(const Vector2 &p_position);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
@@ -106,6 +111,11 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
+ void _popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position);
+ void _popup_request(const Vector2 &p_position);
+ 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 _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _removed_from_graph();
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 830b010d01..68b143358a 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -120,7 +120,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
Ref<Image> autoplay_img = autoplay_icon->get_image();
Ref<Image> reset_img = reset_icon->get_image();
Ref<Image> autoplay_reset_img;
- Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height());
+ Size2 icon_size = autoplay_img->get_size();
autoplay_reset_img.instantiate();
autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format());
autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2());
@@ -904,7 +904,7 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
}
}
-void AnimationPlayerEditor::forward_canvas_force_draw_over_viewport(Control *p_overlay) {
+void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) {
if (!onion.can_overlay) {
return;
}
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index be80b7f4e3..0a514d3ff1 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -238,7 +238,7 @@ public:
void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
void edit(AnimationPlayer *p_player);
- void forward_canvas_force_draw_over_viewport(Control *p_overlay);
+ void forward_force_draw_over_viewport(Control *p_overlay);
AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin);
};
@@ -262,7 +262,8 @@ public:
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) override { 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_force_draw_over_viewport(p_overlay); }
+ virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
AnimationPlayerEditorPlugin(EditorNode *p_node);
~AnimationPlayerEditorPlugin();
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 5405723d10..664b2f521e 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -230,7 +230,7 @@ void EditorAssetLibraryItemDescription::configure(const String &p_title, int p_a
description->add_text(TTR("View Files"));
description->pop();
description->add_text("\n" + TTR("Description:") + "\n\n");
- description->append_bbcode(p_description);
+ description->append_text(p_description);
set_title(p_title);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index d96cc1cd18..1758ba7048 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -387,7 +387,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
// Self center
if ((is_snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
if (p_self_canvas_item->_edit_use_rect()) {
- Point2 center = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_position() + p_self_canvas_item->_edit_get_rect().get_size() / 2.0);
+ Point2 center = p_self_canvas_item->get_global_transform_with_canvas().xform(p_self_canvas_item->_edit_get_rect().get_center());
_snap_if_closer_point(p_target, output, snap_target, center, SNAP_TARGET_SELF, rotation);
} else {
Point2 position = p_self_canvas_item->get_global_transform_with_canvas().xform(Point2());
@@ -525,7 +525,7 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li
// Handles the first element
CanvasItem *canvas_item = p_list.front()->get();
- Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2());
+ Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().get_center()), Size2());
// Expand with the other ones
for (CanvasItem *canvas_item2 : p_list) {
@@ -564,7 +564,7 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform();
Rect2 rect = canvas_item->_edit_get_rect();
if (r_first) {
- r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2());
+ r_rect = Rect2(xform.xform(rect.get_center()), Size2());
r_first = false;
}
r_rect.expand_to(xform.xform(rect.position));
@@ -1295,7 +1295,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() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
- (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V)) {
+ (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V && tool == TOOL_SELECT && k->get_modifiers_mask() == 0)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
// Filters the selection with nodes that allow setting the pivot
@@ -3968,7 +3968,7 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
void CanvasItemEditor::_update_context_menu_stylebox() {
// This must be called when the theme changes to follow the new accent color.
Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat);
- const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor");
+ const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor"));
context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
// Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
context_menu_stylebox->set_border_color(accent_color);
@@ -4896,7 +4896,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
};
if (p_op == VIEW_CENTER_TO_SELECTION) {
- center = rect.position + rect.size / 2;
+ center = rect.get_center();
Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
view_offset.x -= Math::round(offset.x / zoom);
view_offset.y -= Math::round(offset.y / zoom);
@@ -5204,7 +5204,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
snap_rotation = false;
snap_scale = false;
snap_relative = false;
- snap_pixel = false;
+ // Enable pixel snapping even if pixel snap rendering is disabled in the Project Settings.
+ // This results in crisper visuals by preventing 2D nodes from being placed at subpixel coordinates.
+ snap_pixel = true;
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index bfcc293625..fb32d7b1fd 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -39,7 +39,7 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/segment_shape_2d.h"
#include "scene/resources/separation_ray_shape_2d.h"
-#include "scene/resources/world_margin_shape_2d.h"
+#include "scene/resources/world_boundary_shape_2d.h"
void CollisionShape2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
@@ -70,13 +70,13 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
case CONVEX_POLYGON_SHAPE: {
} break;
- case WORLD_MARGIN_SHAPE: {
- Ref<WorldMarginShape2D> line = node->get_shape();
+ case WORLD_BOUNDARY_SHAPE: {
+ Ref<WorldBoundaryShape2D> world_boundary = node->get_shape();
if (idx == 0) {
- return line->get_distance();
+ return world_boundary->get_distance();
} else {
- return line->get_normal();
+ return world_boundary->get_normal();
}
} break;
@@ -147,14 +147,14 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
case CONVEX_POLYGON_SHAPE: {
} break;
- case WORLD_MARGIN_SHAPE: {
+ case WORLD_BOUNDARY_SHAPE: {
if (idx < 2) {
- Ref<WorldMarginShape2D> line = node->get_shape();
+ Ref<WorldBoundaryShape2D> world_boundary = node->get_shape();
if (idx == 0) {
- line->set_distance(p_point.length());
+ world_boundary->set_distance(p_point.length());
} else {
- line->set_normal(p_point.normalized());
+ world_boundary->set_normal(p_point.normalized());
}
canvas_item_editor->update_viewport();
@@ -255,18 +255,18 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
// Cannot be edited directly, use CollisionPolygon2D instead.
} break;
- case WORLD_MARGIN_SHAPE: {
- Ref<WorldMarginShape2D> line = node->get_shape();
+ case WORLD_BOUNDARY_SHAPE: {
+ Ref<WorldBoundaryShape2D> world_boundary = node->get_shape();
if (idx == 0) {
- undo_redo->add_do_method(line.ptr(), "set_distance", line->get_distance());
+ undo_redo->add_do_method(world_boundary.ptr(), "set_distance", world_boundary->get_distance());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(line.ptr(), "set_distance", p_org);
+ undo_redo->add_undo_method(world_boundary.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());
+ undo_redo->add_do_method(world_boundary.ptr(), "set_normal", world_boundary->get_normal());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(line.ptr(), "set_normal", p_org);
+ undo_redo->add_undo_method(world_boundary.ptr(), "set_normal", p_org);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
@@ -421,8 +421,8 @@ void CollisionShape2DEditor::_get_current_shape_type() {
shape_type = CONCAVE_POLYGON_SHAPE;
} else if (Object::cast_to<ConvexPolygonShape2D>(*s)) {
shape_type = CONVEX_POLYGON_SHAPE;
- } else if (Object::cast_to<WorldMarginShape2D>(*s)) {
- shape_type = WORLD_MARGIN_SHAPE;
+ } else if (Object::cast_to<WorldBoundaryShape2D>(*s)) {
+ shape_type = WORLD_BOUNDARY_SHAPE;
} else if (Object::cast_to<SeparationRayShape2D>(*s)) {
shape_type = SEPARATION_RAY_SHAPE;
} else if (Object::cast_to<RectangleShape2D>(*s)) {
@@ -490,8 +490,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
case CONVEX_POLYGON_SHAPE: {
} break;
- case WORLD_MARGIN_SHAPE: {
- Ref<WorldMarginShape2D> shape = node->get_shape();
+ case WORLD_BOUNDARY_SHAPE: {
+ Ref<WorldBoundaryShape2D> shape = node->get_shape();
handles.resize(2);
handles.write[0] = shape->get_normal() * shape->get_distance();
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index 421e674df8..ab95600a52 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -46,7 +46,7 @@ class CollisionShape2DEditor : public Control {
CIRCLE_SHAPE,
CONCAVE_POLYGON_SHAPE,
CONVEX_POLYGON_SHAPE,
- WORLD_MARGIN_SHAPE,
+ WORLD_BOUNDARY_SHAPE,
SEPARATION_RAY_SHAPE,
RECTANGLE_SHAPE,
SEGMENT_SHAPE
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 6f246c1661..fb9f8696fe 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -83,7 +83,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
}
img->convert(Image::FORMAT_RGBA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
- Size2i s = Size2(img->get_width(), img->get_height());
+ Size2i s = img->get_size();
ERR_FAIL_COND(s.width == 0 || s.height == 0);
Vector<Point2> valid_positions;
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 415832ab3b..4cb2c0a76b 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -718,7 +718,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2
RS::get_singleton()->instance_set_base(mesh_instance, mesh->get_rid());
AABB aabb = mesh->get_aabb();
- Vector3 ofs = aabb.position + aabb.size * 0.5;
+ Vector3 ofs = aabb.get_center();
aabb.position -= ofs;
Transform3D xform;
xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125);
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index dd91df747a..44c789b145 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -158,7 +158,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
img->convert(Image::FORMAT_RGBA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_RGBA8);
- Size2i s = Size2(img->get_width(), img->get_height());
+ Size2i s = img->get_size();
ERR_FAIL_COND(s.width == 0 || s.height == 0);
Vector<Point2> valid_positions;
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 94966d4fe6..30945826bb 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -278,6 +278,8 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
@@ -315,6 +317,8 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
@@ -352,6 +356,8 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
@@ -389,6 +395,8 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource>
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
@@ -426,6 +434,8 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
@@ -463,5 +473,7 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
}
smat->set_render_priority(mat->get_render_priority());
+ smat->set_local_to_scene(mat->is_local_to_scene());
+ smat->set_name(mat->get_name());
return smat;
}
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 768f29e15a..dc16a7a325 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -80,7 +80,7 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
_update_rotation();
AABB aabb = mesh->get_aabb();
- Vector3 ofs = aabb.position + aabb.size * 0.5;
+ Vector3 ofs = aabb.get_center();
float m = aabb.get_longest_axis_size();
if (m != 0) {
m = 1.0 / m;
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 9a2b222f21..574d3ef27e 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -202,7 +202,8 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- Vector<Ref<Shape3D>> shapes = mesh->convex_decompose();
+ Mesh::ConvexDecompositionSettings settings;
+ Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(settings);
if (!shapes.size()) {
err_dialog->set_text(TTR("Couldn't create any collision shapes."));
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index b3f92c9d95..18e7480287 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -47,23 +47,25 @@ void MeshLibraryEditor::edit(const Ref<MeshLibrary> &p_mesh_library) {
}
}
-void MeshLibraryEditor::_menu_confirm() {
+void MeshLibraryEditor::_menu_remove_confirm() {
switch (option) {
case MENU_OPTION_REMOVE_ITEM: {
mesh_library->remove_item(to_erase);
} break;
- case MENU_OPTION_UPDATE_FROM_SCENE: {
- String existing = mesh_library->get_meta("_editor_source_scene");
- ERR_FAIL_COND(existing == "");
- _import_scene_cbk(existing);
-
- } break;
default: {
};
}
}
-void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge) {
+void MeshLibraryEditor::_menu_update_confirm(bool p_apply_xforms) {
+ cd_update->hide();
+ apply_xforms = p_apply_xforms;
+ String existing = mesh_library->get_meta("_editor_source_scene");
+ ERR_FAIL_COND(existing == "");
+ _import_scene_cbk(existing);
+}
+
+void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms) {
if (!p_merge) {
p_library->clear();
}
@@ -108,6 +110,13 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
}
p_library->set_item_mesh(id, mesh);
+
+ if (p_apply_xforms) {
+ p_library->set_item_mesh_transform(id, mi->get_transform());
+ } else {
+ p_library->set_item_mesh_transform(id, Transform3D());
+ }
+
mesh_instances[id] = mi;
Vector<MeshLibrary::ShapeData> collisions;
@@ -197,15 +206,16 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'.");
- _import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE);
+ _import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE, apply_xforms);
memdelete(scene);
mesh_library->set_meta("_editor_source_scene", p_str);
+
menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), false);
}
-Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge) {
- _import_scene(p_base_scene, ml, p_merge);
+Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge, bool p_apply_xforms) {
+ _import_scene(p_base_scene, ml, p_merge, p_apply_xforms);
return OK;
}
@@ -219,16 +229,21 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
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));
+ cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase));
+ cd_remove->popup_centered(Size2(300, 60));
}
} break;
case MENU_OPTION_IMPORT_FROM_SCENE: {
+ apply_xforms = false;
+ file->popup_file_dialog();
+ } break;
+ case MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS: {
+ apply_xforms = true;
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));
+ cd_update->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene"))));
+ cd_update->popup_centered(Size2(500, 60));
} break;
}
}
@@ -258,16 +273,22 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
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("Import from Scene (Ignore Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE);
+ menu->get_popup()->add_item(TTR("Import from Scene (Apply Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS);
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", callable_mp(this, &MeshLibraryEditor::_menu_cbk));
menu->hide();
editor = p_editor;
- cd = memnew(ConfirmationDialog);
- add_child(cd);
- cd->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_confirm));
+ cd_remove = memnew(ConfirmationDialog);
+ add_child(cd_remove);
+ cd_remove->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_remove_confirm));
+ cd_update = memnew(ConfirmationDialog);
+ add_child(cd_update);
+ cd_update->get_ok_button()->set_text("Apply without Transforms");
+ cd_update->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(false));
+ cd_update->add_button("Apply with Transforms")->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(true));
}
void MeshLibraryEditorPlugin::edit(Object *p_node) {
diff --git a/editor/plugins/mesh_library_editor_plugin.h b/editor/plugins/mesh_library_editor_plugin.h
index 6c33c8bb9e..9e225ffb9b 100644
--- a/editor/plugins/mesh_library_editor_plugin.h
+++ b/editor/plugins/mesh_library_editor_plugin.h
@@ -41,23 +41,27 @@ class MeshLibraryEditor : public Control {
EditorNode *editor;
MenuButton *menu;
- ConfirmationDialog *cd;
+ ConfirmationDialog *cd_remove;
+ ConfirmationDialog *cd_update;
EditorFileDialog *file;
+ bool apply_xforms;
int to_erase;
enum {
MENU_OPTION_ADD_ITEM,
MENU_OPTION_REMOVE_ITEM,
MENU_OPTION_UPDATE_FROM_SCENE,
- MENU_OPTION_IMPORT_FROM_SCENE
+ MENU_OPTION_IMPORT_FROM_SCENE,
+ MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS
};
int option;
void _import_scene_cbk(const String &p_str);
void _menu_cbk(int p_option);
- void _menu_confirm();
+ void _menu_remove_confirm();
+ void _menu_update_confirm(bool p_apply_xforms);
- static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge);
+ static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms);
protected:
static void _bind_methods();
@@ -66,7 +70,7 @@ public:
MenuButton *get_menu_button() const { return menu; }
void edit(const Ref<MeshLibrary> &p_mesh_library);
- static Error update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge = true);
+ static Error update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge = true, bool p_apply_xforms = false);
MeshLibraryEditor(EditorNode *p_editor);
};
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index d04e88e915..eb771f2bc4 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -34,6 +34,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_polygon_3d.h"
@@ -45,7 +46,6 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
-#include "scene/3d/listener_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/occluder_instance_3d.h"
@@ -53,7 +53,7 @@
#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
-#include "scene/3d/soft_body_3d.h"
+#include "scene/3d/soft_dynamic_body_3d.h"
#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
@@ -69,7 +69,7 @@
#include "scene/resources/separation_ray_shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
#include "scene/resources/surface_tool.h"
-#include "scene/resources/world_margin_shape_3d.h"
+#include "scene/resources/world_boundary_shape_3d.h"
#define HANDLE_HALF_SIZE 9.5
@@ -1003,7 +1003,9 @@ String EditorNode3DGizmoPlugin::get_gizmo_name() const {
if (get_script_instance() && get_script_instance()->has_method("_get_gizmo_name")) {
return get_script_instance()->call("_get_gizmo_name");
}
- return TTR("Nameless gizmo");
+
+ WARN_PRINT_ONCE("A 3D editor gizmo has no name defined (it will appear as \"Unnamed Gizmo\" in the \"View > Gizmos\" menu). To resolve this, override the `_get_gizmo_name()` function to return a String in the script that extends EditorNode3DGizmoPlugin.");
+ return TTR("Unnamed Gizmo");
}
int EditorNode3DGizmoPlugin::get_priority() const {
@@ -1481,8 +1483,6 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
-//////
-
//// player gizmo
AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
@@ -1621,6 +1621,29 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
//////
+AudioListener3DGizmoPlugin::AudioListener3DGizmoPlugin() {
+ create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoAudioListener3D", "EditorIcons"));
+}
+
+bool AudioListener3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<AudioListener3D>(p_spatial) != nullptr;
+}
+
+String AudioListener3DGizmoPlugin::get_gizmo_name() const {
+ return "AudioListener3D";
+}
+
+int AudioListener3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+void AudioListener3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ const Ref<Material> icon = get_material("audio_listener_3d_icon", p_gizmo);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
+}
+
+//////
+
Camera3DGizmoPlugin::Camera3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
@@ -1866,7 +1889,7 @@ MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() {
}
bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftBody3D>(p_spatial) == nullptr;
+ return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftDynamicBody3D>(p_spatial) == nullptr;
}
String MeshInstance3DGizmoPlugin::get_gizmo_name() const {
@@ -2097,7 +2120,6 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
- //LocalVector<int> bones_to_process = skel->get_parentless_bones();
LocalVector<int> bones_to_process;
bones_to_process = skel->get_parentless_bones();
@@ -2109,19 +2131,18 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
child_bones_vector = skel->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
- // You have children but no parent, then you must be a root/parentless bone.
- if (child_bones_size >= 0 && skel->get_bone_parent(current_bone_idx) <= 0) {
- grests[current_bone_idx] = skel->global_pose_to_local_pose(current_bone_idx, skel->get_bone_global_pose(current_bone_idx));
+ if (skel->get_bone_parent(current_bone_idx) < 0) {
+ grests[current_bone_idx] = skel->get_bone_rest(current_bone_idx);
}
for (int i = 0; i < child_bones_size; i++) {
int child_bone_idx = child_bones_vector[i];
- grests[child_bone_idx] = skel->global_pose_to_local_pose(child_bone_idx, skel->get_bone_global_pose(child_bone_idx));
+ grests[child_bone_idx] = grests[current_bone_idx] * skel->get_bone_rest(child_bone_idx);
Vector3 v0 = grests[current_bone_idx].origin;
Vector3 v1 = grests[child_bone_idx].origin;
- Vector3 d = skel->get_bone_rest(child_bone_idx).origin.normalized();
- real_t dist = skel->get_bone_rest(child_bone_idx).origin.length();
+ Vector3 d = (v1 - v0).normalized();
+ real_t dist = v0.distance_to(v1);
// Find closest axis.
int closest = -1;
@@ -2491,30 +2512,30 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///////////
-SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() {
+SoftDynamicBody3DGizmoPlugin::SoftDynamicBody3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
create_material("shape_material", gizmo_color);
create_handle_material("handles");
}
-bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<SoftBody3D>(p_spatial) != nullptr;
+bool SoftDynamicBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<SoftDynamicBody3D>(p_spatial) != nullptr;
}
-String SoftBody3DGizmoPlugin::get_gizmo_name() const {
- return "SoftBody3D";
+String SoftDynamicBody3DGizmoPlugin::get_gizmo_name() const {
+ return "SoftDynamicBody3D";
}
-int SoftBody3DGizmoPlugin::get_priority() const {
+int SoftDynamicBody3DGizmoPlugin::get_priority() const {
return -1;
}
-bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const {
+bool SoftDynamicBody3DGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
-void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
p_gizmo->clear();
@@ -2550,22 +2571,22 @@ void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_triangles(tm);
}
-String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- return "SoftBody3D pin point";
+String SoftDynamicBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ return "SoftDynamicBody3D pin point";
}
-Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+Variant SoftDynamicBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
return Variant(soft_body->is_point_pinned(p_id));
}
-void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+void SoftDynamicBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
+ SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
soft_body->pin_point_toggle(p_id);
}
-bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+bool SoftDynamicBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
return soft_body->is_point_pinned(p_id);
}
@@ -2631,7 +2652,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
- Vector3 ofs = aabb.position + aabb.size * 0.5;
+ Vector3 ofs = aabb.get_center();
Vector3 axis;
axis[p_id] = 1.0;
@@ -2707,7 +2728,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
handles.push_back(ax);
}
- Vector3 center = aabb.position + aabb.size * 0.5;
+ Vector3 center = aabb.get_center();
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = 1.0;
@@ -2723,7 +2744,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
}
p_gizmo->add_handles(handles, get_material("handles"));
@@ -2822,7 +2843,7 @@ void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int
Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
- Vector3 ofs = aabb.position + aabb.size * 0.5;
+ Vector3 ofs = aabb.get_center();
Vector3 axis;
axis[p_id] = 1.0;
@@ -2898,7 +2919,7 @@ void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
handles.push_back(ax);
}
- Vector3 center = aabb.position + aabb.size * 0.5;
+ Vector3 center = aabb.get_center();
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = 1.0;
@@ -2914,7 +2935,7 @@ void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
}
p_gizmo->add_handles(handles, get_material("handles"));
@@ -4539,9 +4560,9 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_handles(handles, handles_material);
}
- if (Object::cast_to<WorldMarginShape3D>(*s)) {
- Ref<WorldMarginShape3D> ps = s;
- Plane p = ps->get_plane();
+ if (Object::cast_to<WorldBoundaryShape3D>(*s)) {
+ Ref<WorldBoundaryShape3D> wbs = s;
+ const Plane &p = wbs->get_plane();
Vector<Vector3> points;
Vector3 n1 = p.get_any_perpendicular_normal();
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 415ed5da5c..24b4a23d4b 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -249,6 +249,19 @@ public:
AudioStreamPlayer3DGizmoPlugin();
};
+class AudioListener3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(AudioListener3DGizmoPlugin, EditorNode3DGizmoPlugin);
+
+public:
+ bool has_gizmo(Node3D *p_spatial) override;
+ String get_gizmo_name() const override;
+ int get_priority() const override;
+
+ void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ AudioListener3DGizmoPlugin();
+};
+
class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin);
@@ -379,8 +392,8 @@ public:
VehicleWheel3DGizmoPlugin();
};
-class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
+class SoftDynamicBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(SoftDynamicBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -394,7 +407,7 @@ public:
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override;
bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
- SoftBody3DGizmoPlugin();
+ SoftDynamicBody3DGizmoPlugin();
};
class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 291cafab2b..d52a633fed 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -128,7 +128,7 @@ void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
const Color axis_color = axis_colors[direction];
const double alpha = focused ? 1.0 : ((p_axis.z_axis + 1.0) / 2.0) * 0.5 + 0.5;
- const Color c = focused ? Color(0.9, 0.9, 0.9) : Color(axis_color.r, axis_color.g, axis_color.b, alpha);
+ const Color c = focused ? Color(0.9, 0.9, 0.9) : Color(axis_color, alpha);
if (positive) {
// Draw axis lines for the positive axes.
@@ -265,15 +265,13 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
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");
- inertia = MAX(0.001, inertia);
+ const real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
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.lerp(cursor.eye_pos, CLAMP(factor, 0, 1));
- real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- orbit_inertia = MAX(0.0001, orbit_inertia);
+ const real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/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)));
@@ -289,24 +287,9 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
} else {
- //when not being manipulated, move softly
- real_t free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- real_t free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
- //when being manipulated, move more quickly
- real_t manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
- real_t manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
-
- real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
-
- //determine if being manipulated
- bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_CTRL);
-
- real_t orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
- real_t translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
- zoom_inertia = MAX(0.0001, zoom_inertia);
+ const real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ const real_t translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
+ const real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_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)));
@@ -835,7 +818,7 @@ void Node3DEditorViewport::_update_name() {
if (orthogonal) {
name = TTR("Left Orthogonal");
} else {
- name = TTR("Right Perspective");
+ name = TTR("Left Perspective");
}
} break;
case VIEW_TYPE_RIGHT: {
@@ -871,8 +854,8 @@ void Node3DEditorViewport::_update_name() {
}
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.click_ray = _get_ray(p_point);
+ _edit.click_ray_pos = _get_ray_pos(p_point);
_edit.plane = TRANSFORM_VIEW;
spatial_editor->update_transform_gizmo();
_edit.center = spatial_editor->get_gizmo_transform().origin;
@@ -951,8 +934,8 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
return false;
}
- Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
- Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
+ Vector3 ray_pos = _get_ray_pos(p_screenpos);
+ Vector3 ray = _get_ray(p_screenpos);
Transform3D gt = spatial_editor->get_gizmo_transform();
@@ -1015,7 +998,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
} else {
//handle plane translate
_edit.mode = TRANSFORM_TRANSLATE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _compute_edit(p_screenpos);
_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0));
}
return true;
@@ -1053,7 +1036,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
} else {
//handle rotate
_edit.mode = TRANSFORM_ROTATE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _compute_edit(p_screenpos);
_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
}
return true;
@@ -1119,7 +1102,7 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b
} else {
//handle scale
_edit.mode = TRANSFORM_SCALE;
- _compute_edit(Point2(p_screenpos.x, p_screenpos.y));
+ _compute_edit(p_screenpos);
_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0));
}
return true;
@@ -1831,6 +1814,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
motion = Vector3(scale, scale, scale);
}
+ motion /= click.distance_to(_edit.center);
+
// Disable local transformation for TRANSFORM_VIEW
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
@@ -4194,7 +4179,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
VBoxContainer *vbox = memnew(VBoxContainer);
surface->add_child(vbox);
- vbox->set_position(Point2(10, 10) * EDSCALE);
+ vbox->set_offset(SIDE_LEFT, 10 * EDSCALE);
+ vbox->set_offset(SIDE_TOP, 10 * EDSCALE);
view_menu = memnew(MenuButton);
view_menu->set_flat(false);
@@ -4818,7 +4804,7 @@ void _update_all_gizmos(Node *p_node) {
}
void Node3DEditor::update_all_gizmos(Node *p_node) {
- if (!p_node && get_tree()) {
+ if (!p_node && is_inside_tree()) {
p_node = get_tree()->get_edited_scene_root();
}
@@ -6028,7 +6014,7 @@ void fragment() {
void Node3DEditor::_update_context_menu_stylebox() {
// This must be called when the theme changes to follow the new accent color.
Ref<StyleBoxFlat> context_menu_stylebox = memnew(StyleBoxFlat);
- const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color("accent_color", "Editor");
+ const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), SNAME("Editor"));
context_menu_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
// Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
context_menu_stylebox->set_border_color(accent_color);
@@ -6861,9 +6847,10 @@ 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<AudioListener3DGizmoPlugin>(memnew(AudioListener3DGizmoPlugin)));
add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
- add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin)));
add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin)));
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index 0a949c8610..53c5b8dd70 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -31,6 +31,7 @@
#include "packed_scene_translation_parser_plugin.h"
#include "core/io/resource_loader.h"
+#include "scene/gui/option_button.h"
#include "scene/resources/packed_scene.h"
void PackedSceneEditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
@@ -50,21 +51,31 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
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")) {
+ String node_type = state->get_node_type(i);
+ if (!ClassDB::is_parent_class(node_type, "Control") && !ClassDB::is_parent_class(node_type, "Window")) {
continue;
}
+ // Find the `auto_translate` property, and abort the string parsing of the node if disabled.
+ bool auto_translating = true;
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;
+ if (state->get_node_property_name(i, j) == "auto_translate" && (bool)state->get_node_property_value(i, j) == false) {
+ auto_translating = false;
+ break;
}
+ }
+ if (!auto_translating) {
+ continue;
+ }
- property_value = state->get_node_property_value(i, j);
+ for (int j = 0; j < state->get_node_property_count(i); j++) {
+ String property_name = state->get_node_property_name(i, j);
+ if (!lookup_properties.has(property_name) || (exception_list.has(node_type) && exception_list[node_type].has(property_name))) {
+ continue;
+ }
+ Variant 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);
@@ -76,7 +87,16 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
parsed_strings.append_array(temp);
r_ids_ctx_plural->append_array(ids_context_plural);
}
- } else if (property_name == "filters") {
+ } else if ((node_type == "MenuButton" || node_type == "OptionButton") && property_name == "items") {
+ Vector<String> str_values = property_value;
+ int incr_value = node_type == "MenuButton" ? PopupMenu::ITEM_PROPERTY_SIZE : OptionButton::ITEM_PROPERTY_SIZE;
+ for (int k = 0; k < str_values.size(); k += incr_value) {
+ String desc = str_values[k].get_slice(";", 1).strip_edges();
+ if (!desc.is_empty()) {
+ parsed_strings.push_back(desc);
+ }
+ }
+ } else if (node_type == "FileDialog" && 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++) {
@@ -105,12 +125,17 @@ PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlug
lookup_properties.insert("text");
lookup_properties.insert("hint_tooltip");
lookup_properties.insert("placeholder_text");
+ lookup_properties.insert("items");
+ lookup_properties.insert("title");
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");
+ // Exception list (to prevent false positives).
+ exception_list.insert("LineEdit", Vector<StringName>());
+ exception_list["LineEdit"].append("text");
+ exception_list.insert("TextEdit", Vector<StringName>());
+ exception_list["TextEdit"].append("text");
+ exception_list.insert("CodeEdit", Vector<StringName>());
+ exception_list["CodeEdit"].append("text");
}
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.h b/editor/plugins/packed_scene_translation_parser_plugin.h
index e51d65414e..af0291b69c 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.h
+++ b/editor/plugins/packed_scene_translation_parser_plugin.h
@@ -37,7 +37,9 @@ class PackedSceneEditorTranslationParserPlugin : public EditorTranslationParserP
GDCLASS(PackedSceneEditorTranslationParserPlugin, EditorTranslationParserPlugin);
// Scene Node's properties that contain translation strings.
- Set<String> lookup_properties;
+ Set<StringName> lookup_properties;
+ // Properties from specific Nodes that should be ignored.
+ Map<StringName, Vector<StringName>> exception_list;
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) override;
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 782152b002..ac18ff9f1c 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -449,7 +449,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
if (mb.is_valid()) {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
- uv_drag_from = snap_point(Vector2(mb->get_position().x, mb->get_position().y));
+ uv_drag_from = snap_point(mb->get_position());
uv_drag = true;
points_prev = node->get_uv();
@@ -463,7 +463,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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)));
+ Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position()));
points_prev.push_back(tuv);
uv_create_to = tuv;
point_drag_index = 0;
@@ -483,7 +483,7 @@ 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)));
+ Vector2 tuv = mtx.affine_inverse().xform(snap_point(mb->get_position()));
// 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)) {
@@ -527,7 +527,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_create_bones_prev = node->call("_get_bones");
int internal_vertices = node->get_internal_vertex_count();
- Vector2 pos = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y)));
+ Vector2 pos = mtx.affine_inverse().xform(snap_point(mb->get_position()));
uv_create_poly_prev.push_back(pos);
uv_create_uv_prev.push_back(pos);
@@ -573,7 +573,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
for (int i = points_prev.size() - internal_vertices; i < points_prev.size(); i++) {
Vector2 tuv = mtx.xform(uv_create_poly_prev[i]);
- real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
+ real_t dist = tuv.distance_to(mb->get_position());
if (dist < 8 && dist < closest_dist) {
closest = i;
closest_dist = dist;
@@ -626,7 +626,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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) {
+ if (tuv.distance_to(mb->get_position()) < 8) {
uv_drag_from = tuv;
point_drag_index = i;
}
@@ -643,7 +643,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
for (int i = 0; i < points_prev.size(); i++) {
Vector2 tuv = mtx.xform(points_prev[i]);
- real_t dist = tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y));
+ real_t dist = tuv.distance_to(mb->get_position());
if (dist < 8 && dist < closest_dist) {
closest = i;
closest_dist = dist;
@@ -695,7 +695,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
polys.write[j] = mtx.xform(points_prev[idx]);
}
- if (Geometry2D::is_point_in_polygon(Vector2(mb->get_position().x, mb->get_position().y), polys)) {
+ if (Geometry2D::is_point_in_polygon(mb->get_position(), polys)) {
erase_index = i;
break;
}
@@ -791,7 +791,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
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)));
+ uv_create_to = mtx.affine_inverse().xform(snap_point(mm->get_position()));
}
} break;
case UV_MODE_EDIT_POINT: {
@@ -870,7 +870,7 @@ 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);
+ bone_paint_pos = mm->get_position();
} break;
default: {
}
@@ -905,10 +905,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->update();
CanvasItemEditor::get_singleton()->update_viewport();
} else if (polygon_create.size()) {
- uv_create_to = mtx.affine_inverse().xform(Vector2(mm->get_position().x, mm->get_position().y));
+ uv_create_to = mtx.affine_inverse().xform(mm->get_position());
uv_edit_draw->update();
} else if (uv_mode == UV_MODE_PAINT_WEIGHT || uv_mode == UV_MODE_CLEAR_WEIGHT) {
- bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y);
+ bone_paint_pos = mm->get_position();
uv_edit_draw->update();
}
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 7ef5993ec5..07e4d4ebf0 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -46,6 +46,7 @@
#include "editor/find_in_files.h"
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.h"
+#include "modules/visual_script/visual_script_editor.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#include "script_text_editor.h"
@@ -807,39 +808,35 @@ void ScriptEditor::_copy_script_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;
+ for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ if (i != current_idx) {
+ script_close_queue.push_back(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);
- continue;
- }
- }
-
- _close_current_tab(false);
}
+ _queue_close_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));
+ for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ script_close_queue.push_back(i);
+ }
+ _queue_close_tabs();
+}
+void ScriptEditor::_queue_close_tabs() {
+ while (!script_close_queue.is_empty()) {
+ int idx = script_close_queue.front()->get();
+ script_close_queue.pop_front();
+
+ tab_container->set_current_tab(idx);
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(idx));
if (se) {
- // Maybe there are unsaved changes
+ // Maybe there are unsaved changes.
if (se->is_unsaved()) {
_ask_close_current_unsaved_tab(se);
- continue;
+ erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), varray(), CONNECT_ONESHOT);
+ break;
}
}
@@ -1236,14 +1233,15 @@ void ScriptEditor::_menu_option(int p_option) {
_update_script_names();
} break;
case TOGGLE_SCRIPTS_PANEL: {
+ toggle_scripts_panel();
if (current) {
- ScriptTextEditor *editor = Object::cast_to<ScriptTextEditor>(current);
- toggle_scripts_panel();
- if (editor) {
- editor->update_toggle_scripts_button();
- }
+ current->update_toggle_scripts_button();
} else {
- toggle_scripts_panel();
+ Control *tab = tab_container->get_current_tab_control();
+ EditorHelp *editor_help = Object::cast_to<EditorHelp>(tab);
+ if (editor_help) {
+ editor_help->update_toggle_scripts_button();
+ }
}
}
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index e2420b4623..7620605570 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -161,6 +161,7 @@ public:
virtual void update_settings() = 0;
virtual void set_debugger_active(bool p_active) = 0;
virtual bool can_lose_focus_on_node_selection() { return true; }
+ virtual void update_toggle_scripts_button() {}
virtual bool show_members_overview() = 0;
@@ -308,6 +309,7 @@ class ScriptEditor : public PanelContainer {
int history_pos;
List<String> previous_scripts;
+ List<int> script_close_queue;
void _tab_changed(int p_which);
void _menu_option(int p_option);
@@ -340,6 +342,7 @@ class ScriptEditor : public PanelContainer {
void _close_docs_tab();
void _close_other_tabs();
void _close_all_tabs();
+ void _queue_close_tabs();
void _copy_script_path();
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index c44760807f..2b1ca068ee 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -158,7 +158,6 @@ void ScriptTextEditor::enable_editor() {
editor_enabled = true;
_enable_code_editor();
- _set_theme_for_script();
_validate_script();
}
@@ -877,9 +876,7 @@ String ScriptTextEditor::_get_absolute_path(const String &rel_path) {
}
void ScriptTextEditor::update_toggle_scripts_button() {
- if (code_editor != nullptr) {
- code_editor->update_toggle_scripts_button();
- }
+ code_editor->update_toggle_scripts_button();
}
void ScriptTextEditor::_update_connected_methods() {
@@ -1243,7 +1240,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
tx->set_caret_line(bpoints[bpoints.size() - 1]);
tx->center_viewport_to_caret();
} else {
- for (int i = bpoints.size(); i >= 0; i--) {
+ for (int i = bpoints.size() - 1; i >= 0; i--) {
int bline = bpoints[i];
if (bline < line) {
tx->unfold_line(bline);
@@ -1964,11 +1961,8 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F);
ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), KEY_NONE);
ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), KEY_NONE);
-#ifdef OSX_ENABLED
- ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
-#else
ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D);
-#endif
+ ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C);
ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E);
ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T);
ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Y);
@@ -1976,42 +1970,35 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD | KEY_I);
ED_SHORTCUT_AND_COMMAND("script_text_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F);
-#ifdef OSX_ENABLED
- ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_MASK_CMD | KEY_G);
- ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G);
- ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
-#else
+
ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/find_next", "macos", KEY_MASK_CMD | KEY_G);
+
ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT | KEY_F3);
+ ED_SHORTCUT_OVERRIDE("script_text_editor/find_previous", "macos", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G);
+
ED_SHORTCUT_AND_COMMAND("script_text_editor/replace", TTR("Replace..."), KEY_MASK_CMD | KEY_R);
-#endif
+ ED_SHORTCUT_OVERRIDE("script_text_editor/replace", "macos", KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
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);
-#else
ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_ALT | KEY_F1);
-#endif
+ ED_SHORTCUT_OVERRIDE("script_text_editor/contextual_help", "macos", KEY_MASK_ALT | KEY_MASK_SHIFT | KEY_SPACE);
ED_SHORTCUT("script_text_editor/toggle_bookmark", TTR("Toggle Bookmark"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_B);
ED_SHORTCUT("script_text_editor/goto_next_bookmark", TTR("Go to Next Bookmark"), KEY_MASK_CMD | KEY_B);
ED_SHORTCUT("script_text_editor/goto_previous_bookmark", TTR("Go to Previous Bookmark"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B);
ED_SHORTCUT("script_text_editor/remove_all_bookmarks", TTR("Remove All Bookmarks"), KEY_NONE);
-#ifdef OSX_ENABLED
- ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KEY_MASK_CTRL | KEY_MASK_CMD | KEY_J);
-#else
ED_SHORTCUT("script_text_editor/goto_function", TTR("Go to Function..."), KEY_MASK_ALT | KEY_MASK_CMD | KEY_F);
-#endif
+ ED_SHORTCUT_OVERRIDE("script_text_editor/goto_function", "macos", KEY_MASK_CTRL | KEY_MASK_CMD | KEY_J);
+
ED_SHORTCUT("script_text_editor/goto_line", TTR("Go to Line..."), KEY_MASK_CMD | KEY_L);
-#ifdef OSX_ENABLED
- ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B);
-#else
ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
-#endif
+ ED_SHORTCUT_OVERRIDE("script_text_editor/toggle_breakpoint", "macos", KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B);
+
ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_F9);
ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Go to Next Breakpoint"), KEY_MASK_CMD | KEY_PERIOD);
ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Go to Previous Breakpoint"), KEY_MASK_CMD | KEY_COMMA);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 4208d67f17..afe9a7453d 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -197,7 +197,7 @@ public:
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();
+ void update_toggle_scripts_button() override;
virtual void apply_code() override;
virtual RES get_edited_resource() const override;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 7ef680d7ef..c350004f0f 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -98,9 +98,10 @@ Skeleton2DEditor::Skeleton2DEditor() {
options->set_text(TTR("Skeleton2D"));
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Skeleton2D"), SNAME("EditorIcons")));
- options->get_popup()->add_item(TTR("Make Rest Pose (From Bones)"), MENU_OPTION_MAKE_REST);
+ options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_MAKE_REST);
options->get_popup()->add_separator();
- options->get_popup()->add_item(TTR("Set Bones to Rest Pose"), MENU_OPTION_SET_REST);
+ // Use the "Overwrite" word to highlight that this is a destructive operation.
+ options->get_popup()->add_item(TTR("Overwrite Rest Pose"), MENU_OPTION_SET_REST);
options->set_switch_on_hover(true);
options->get_popup()->connect("id_pressed", callable_mp(this, &Skeleton2DEditor::_menu_option));
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 0f889ce33d..eb5e527640 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -182,7 +182,7 @@ void Sprite2DEditor::_update_mesh_data() {
if (node->is_region_enabled()) {
rect = node->get_region_rect();
} else {
- rect.size = Size2(image->get_width(), image->get_height());
+ rect.size = image->get_size();
}
Ref<BitMap> bm;
@@ -209,7 +209,7 @@ void Sprite2DEditor::_update_mesh_data() {
computed_uv.clear();
computed_indices.clear();
- Size2 img_size = Vector2(image->get_width(), image->get_height());
+ Size2 img_size = image->get_size();
for (int i = 0; i < lines.size(); i++) {
lines.write[i] = expand(lines[i], rect, epsilon);
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 400f9f560f..8a8d80891a 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -54,22 +54,46 @@ void SpriteFramesEditor::_open_sprite_sheet() {
file_split_sheet->popup_file_dialog();
}
+int SpriteFramesEditor::_sheet_preview_position_to_frame_index(const Point2 &p_position) {
+ if (p_position.x < 0 || p_position.y < 0) {
+ return -1;
+ }
+
+ Size2i texture_size = split_sheet_preview->get_texture()->get_size();
+ int h = split_sheet_h->get_value();
+ int v = split_sheet_v->get_value();
+ if (h > texture_size.width || v > texture_size.height) {
+ return -1;
+ }
+
+ int x = int(p_position.x / sheet_zoom) / (texture_size.width / h);
+ int y = int(p_position.y / sheet_zoom) / (texture_size.height / v);
+ if (x >= h || y >= v) {
+ return -1;
+ }
+ return h * y + x;
+}
+
void SpriteFramesEditor::_sheet_preview_draw() {
- Size2i size = split_sheet_preview->get_size();
+ Size2i texture_size = split_sheet_preview->get_texture()->get_size();
int h = split_sheet_h->get_value();
int v = split_sheet_v->get_value();
- int width = size.width / h;
- int height = size.height / v;
+
+ real_t width = (texture_size.width / h) * sheet_zoom;
+ real_t height = (texture_size.height / v) * sheet_zoom;
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));
+
+ real_t y_end = v * height;
+ for (int i = 0; i <= h; i++) {
+ real_t x = i * width;
+ split_sheet_preview->draw_line(Point2(x, 0), Point2(x, y_end), Color(1, 1, 1, a));
+ split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, y_end), Color(0, 0, 0, a));
}
- for (int i = 1; i < v; i++) {
- int y = i * height;
- split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a));
- split_sheet_preview->draw_line(Point2(0, y + 1), Point2(size.width, y + 1), Color(0, 0, 0, a));
+ real_t x_end = h * width;
+ for (int i = 0; i <= v; i++) {
+ real_t y = i * height;
+ split_sheet_preview->draw_line(Point2(0, y), Point2(x_end, y), Color(1, 1, 1, a));
+ split_sheet_preview->draw_line(Point2(0, y + 1), Point2(x_end, y + 1), Color(0, 0, 0, a));
}
if (frames_selected.size() == 0) {
@@ -83,9 +107,9 @@ void SpriteFramesEditor::_sheet_preview_draw() {
for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) {
int idx = E->get();
int xp = idx % h;
- int yp = (idx - xp) / h;
- int x = xp * width;
- int y = yp * height;
+ int yp = idx / h;
+ real_t x = xp * width;
+ real_t y = yp * height;
split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true);
split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false);
@@ -103,46 +127,43 @@ void SpriteFramesEditor::_sheet_preview_draw() {
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- const Size2i size = split_sheet_preview->get_size();
- const int h = split_sheet_h->get_value();
- const int v = split_sheet_v->get_value();
-
- const int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1);
- const int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1);
-
- const int idx = h * y + x;
+ const int idx = _sheet_preview_position_to_frame_index(mb->get_position());
+
+ if (idx != -1) {
+ if (mb->is_shift_pressed() && last_frame_selected >= 0) {
+ //select multiple
+ int from = idx;
+ int to = last_frame_selected;
+ if (from > to) {
+ SWAP(from, to);
+ }
- if (mb->is_shift_pressed() && last_frame_selected >= 0) {
- //select multiple
- int from = idx;
- int to = last_frame_selected;
- if (from > to) {
- SWAP(from, to);
- }
+ for (int i = from; i <= to; i++) {
+ // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
+ frames_toggled_by_mouse_hover.insert(idx);
- for (int i = from; i <= to; i++) {
+ if (mb->is_ctrl_pressed()) {
+ frames_selected.erase(i);
+ } else {
+ frames_selected.insert(i);
+ }
+ }
+ } else {
// Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
frames_toggled_by_mouse_hover.insert(idx);
- if (mb->is_ctrl_pressed()) {
- frames_selected.erase(i);
+ if (frames_selected.has(idx)) {
+ frames_selected.erase(idx);
} else {
- frames_selected.insert(i);
+ frames_selected.insert(idx);
}
}
- } else {
- // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
- frames_toggled_by_mouse_hover.insert(idx);
-
- if (frames_selected.has(idx)) {
- frames_selected.erase(idx);
- } else {
- frames_selected.insert(idx);
- }
}
- last_frame_selected = idx;
- split_sheet_preview->update();
+ if (last_frame_selected != idx || idx != -1) {
+ last_frame_selected = idx;
+ split_sheet_preview->update();
+ }
}
if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
@@ -152,16 +173,9 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
// Select by holding down the mouse button on frames.
- const Size2i size = split_sheet_preview->get_size();
- const int h = split_sheet_h->get_value();
- const int v = split_sheet_v->get_value();
-
- const int x = CLAMP(int(mm->get_position().x) * h / size.width, 0, h - 1);
- const int y = CLAMP(int(mm->get_position().y) * v / size.height, 0, v - 1);
-
- const int idx = h * y + x;
+ const int idx = _sheet_preview_position_to_frame_index(mm->get_position());
- if (!frames_toggled_by_mouse_hover.has(idx)) {
+ if (idx != -1 && !frames_toggled_by_mouse_hover.has(idx)) {
// Only allow toggling each tile once per mouse hold.
// Otherwise, the selection would constantly "flicker" in and out when moving the mouse cursor.
// The mouse button must be released before it can be toggled again.
@@ -199,17 +213,17 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
}
void SpriteFramesEditor::_sheet_add_frames() {
- Size2i size = split_sheet_preview->get_texture()->get_size();
+ Size2i texture_size = split_sheet_preview->get_texture()->get_size();
int frame_count_x = split_sheet_h->get_value();
int frame_count_y = split_sheet_v->get_value();
- Size2 frame_size(size.width / frame_count_x, size.height / frame_count_y);
+ Size2 frame_size(texture_size.width / frame_count_x, texture_size.height / frame_count_y);
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
Point2 src_origin;
- Rect2 src_region(Point2(), size);
+ Rect2 src_region(Point2(), texture_size);
AtlasTexture *src_atlas = Object::cast_to<AtlasTexture>(*split_sheet_preview->get_texture());
if (src_atlas && src_atlas->get_atlas().is_valid()) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 17e30f0cab..5e3b2fb8c1 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -135,6 +135,7 @@ class SpriteFramesEditor : public HSplitContainer {
void _open_sprite_sheet();
void _prepare_sprite_sheet(const String &p_file);
+ int _sheet_preview_position_to_frame_index(const Vector2 &p_position);
void _sheet_preview_draw();
void _sheet_spin_changed(double);
void _sheet_preview_input(const Ref<InputEvent> &p_event);
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 32bcc1a4e6..06ba8a6168 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -513,6 +513,10 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
context_menu->popup();
}
+void TextEditor::update_toggle_scripts_button() {
+ code_editor->update_toggle_scripts_button();
+}
+
TextEditor::TextEditor() {
code_editor = memnew(CodeTextEditor);
add_child(code_editor);
@@ -521,6 +525,7 @@ TextEditor::TextEditor() {
code_editor->connect("validate_script", callable_mp(this, &TextEditor::_validate_script));
code_editor->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ code_editor->show_toggle_scripts_button();
update_settings();
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 6bf0042393..9308fec210 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -139,6 +139,7 @@ public:
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;
+ void update_toggle_scripts_button() override;
virtual Control *get_edit_menu() override;
virtual void clear_edit_menu() override;
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 1a6eb7b63b..cfb2d63bc7 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -63,16 +63,16 @@ void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) {
void TextureRegionEditor::_region_draw() {
Ref<Texture2D> base_tex = nullptr;
- if (node_sprite) {
- base_tex = node_sprite->get_texture();
+ if (atlas_tex.is_valid()) {
+ base_tex = atlas_tex->get_atlas();
+ } else if (node_sprite_2d) {
+ base_tex = node_sprite_2d->get_texture();
} else if (node_sprite_3d) {
base_tex = node_sprite_3d->get_texture();
} else if (node_ninepatch) {
base_tex = node_ninepatch->get_texture();
} else if (obj_styleBox.is_valid()) {
base_tex = obj_styleBox->get_texture();
- } else if (atlas_tex.is_valid()) {
- base_tex = atlas_tex->get_atlas();
}
if (base_tex.is_null()) {
@@ -321,35 +321,38 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
prev_margin = margins[3];
}
if (edited_margin >= 0) {
- drag_from = Vector2(mb->get_position().x, mb->get_position().y);
+ drag_from = mb->get_position();
drag = true;
}
}
if (edited_margin < 0 && snap_mode == SNAP_AUTOSLICE) {
- Vector2 point = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y));
+ Vector2 point = mtx.affine_inverse().xform(mb->get_position());
for (const Rect2 &E : autoslice_cache) {
if (E.has_point(point)) {
rect = E;
if (Input::get_singleton()->is_key_pressed(KEY_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(KEY_SHIFT | KEY_ALT)))) {
Rect2 r;
- if (node_sprite) {
- r = node_sprite->get_region_rect();
+ if (atlas_tex.is_valid()) {
+ r = atlas_tex->get_region();
+ } else if (node_sprite_2d) {
+ r = node_sprite_2d->get_region_rect();
} else if (node_sprite_3d) {
r = node_sprite_3d->get_region_rect();
} else if (node_ninepatch) {
r = node_ninepatch->get_region_rect();
} else if (obj_styleBox.is_valid()) {
r = obj_styleBox->get_region_rect();
- } else if (atlas_tex.is_valid()) {
- r = atlas_tex->get_region();
}
rect.expand_to(r.position);
- rect.expand_to(r.position + r.size);
+ rect.expand_to(r.get_end());
}
undo_redo->create_action(TTR("Set Region Rect"));
- if (node_sprite) {
- undo_redo->add_do_method(node_sprite, "set_region_rect", rect);
- undo_redo->add_undo_method(node_sprite, "set_region_rect", node_sprite->get_region_rect());
+ if (atlas_tex.is_valid()) {
+ undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect);
+ undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
+ } else if (node_sprite_2d) {
+ undo_redo->add_do_method(node_sprite_2d, "set_region_rect", rect);
+ undo_redo->add_undo_method(node_sprite_2d, "set_region_rect", node_sprite_2d->get_region_rect());
} else if (node_sprite_3d) {
undo_redo->add_do_method(node_sprite_3d, "set_region_rect", rect);
undo_redo->add_undo_method(node_sprite_3d, "set_region_rect", node_sprite_3d->get_region_rect());
@@ -359,9 +362,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
} else if (obj_styleBox.is_valid()) {
undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", rect);
undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
- } else if (atlas_tex.is_valid()) {
- undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect);
- undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
}
undo_redo->add_do_method(this, "_update_rect");
undo_redo->add_undo_method(this, "_update_rect");
@@ -372,28 +372,28 @@ 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));
+ drag_from = mtx.affine_inverse().xform(mb->get_position());
if (snap_mode == SNAP_PIXEL) {
drag_from = drag_from.snapped(Vector2(1, 1));
} else if (snap_mode == SNAP_GRID) {
drag_from = snap_point(drag_from);
}
drag = true;
- if (node_sprite) {
- rect_prev = node_sprite->get_region_rect();
+ if (atlas_tex.is_valid()) {
+ rect_prev = atlas_tex->get_region();
+ } else if (node_sprite_2d) {
+ rect_prev = node_sprite_2d->get_region_rect();
} else if (node_sprite_3d) {
rect_prev = node_sprite_3d->get_region_rect();
} else if (node_ninepatch) {
rect_prev = node_ninepatch->get_region_rect();
} else if (obj_styleBox.is_valid()) {
rect_prev = obj_styleBox->get_region_rect();
- } else if (atlas_tex.is_valid()) {
- rect_prev = atlas_tex->get_region();
}
for (int i = 0; i < 8; i++) {
Vector2 tuv = endpoints[i];
- if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < handle_radius) {
+ if (tuv.distance_to(mb->get_position()) < handle_radius) {
drag_index = i;
}
}
@@ -419,15 +419,15 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
edited_margin = -1;
} else {
undo_redo->create_action(TTR("Set Region Rect"));
- if (node_sprite) {
- undo_redo->add_do_method(node_sprite, "set_region_rect", node_sprite->get_region_rect());
- undo_redo->add_undo_method(node_sprite, "set_region_rect", rect_prev);
+ if (atlas_tex.is_valid()) {
+ undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
+ undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
+ } else if (node_sprite_2d) {
+ undo_redo->add_do_method(node_sprite_2d, "set_region_rect", node_sprite_2d->get_region_rect());
+ undo_redo->add_undo_method(node_sprite_2d, "set_region_rect", rect_prev);
} else if (node_sprite_3d) {
undo_redo->add_do_method(node_sprite_3d, "set_region_rect", node_sprite_3d->get_region_rect());
undo_redo->add_undo_method(node_sprite_3d, "set_region_rect", rect_prev);
- } else if (atlas_tex.is_valid()) {
- undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
- undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
} else if (node_ninepatch) {
undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev);
@@ -544,7 +544,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
switch (drag_index) {
case 0: {
- Vector2 p = rect_prev.position + rect_prev.size;
+ Vector2 p = rect_prev.get_end();
rect = Rect2(p, Size2());
rect.expand_to(new_pos);
apply_rect(rect);
@@ -693,22 +693,24 @@ void TextureRegionEditor::_zoom_out() {
}
void TextureRegionEditor::apply_rect(const Rect2 &p_rect) {
- if (node_sprite) {
- node_sprite->set_region_rect(p_rect);
+ if (atlas_tex.is_valid()) {
+ atlas_tex->set_region(p_rect);
+ } else if (node_sprite_2d) {
+ node_sprite_2d->set_region_rect(p_rect);
} else if (node_sprite_3d) {
node_sprite_3d->set_region_rect(p_rect);
} else if (node_ninepatch) {
node_ninepatch->set_region_rect(p_rect);
} else if (obj_styleBox.is_valid()) {
obj_styleBox->set_region_rect(p_rect);
- } else if (atlas_tex.is_valid()) {
- atlas_tex->set_region(p_rect);
}
}
void TextureRegionEditor::_update_rect() {
- if (node_sprite) {
- rect = node_sprite->get_region_rect();
+ if (atlas_tex.is_valid()) {
+ rect = atlas_tex->get_region();
+ } else if (node_sprite_2d) {
+ rect = node_sprite_2d->get_region_rect();
} else if (node_sprite_3d) {
rect = node_sprite_3d->get_region_rect();
} else if (node_ninepatch) {
@@ -718,8 +720,6 @@ void TextureRegionEditor::_update_rect() {
}
} else if (obj_styleBox.is_valid()) {
rect = obj_styleBox->get_region_rect();
- } else if (atlas_tex.is_valid()) {
- rect = atlas_tex->get_region();
}
}
@@ -728,16 +728,16 @@ void TextureRegionEditor::_update_autoslice() {
autoslice_cache.clear();
Ref<Texture2D> texture = nullptr;
- if (node_sprite) {
- texture = node_sprite->get_texture();
+ if (atlas_tex.is_valid()) {
+ texture = atlas_tex->get_atlas();
+ } else if (node_sprite_2d) {
+ texture = node_sprite_2d->get_texture();
} else if (node_sprite_3d) {
texture = node_sprite_3d->get_texture();
} else if (node_ninepatch) {
texture = node_ninepatch->get_texture();
} else if (obj_styleBox.is_valid()) {
texture = obj_styleBox->get_texture();
- } else if (atlas_tex.is_valid()) {
- texture = atlas_tex->get_atlas();
}
if (texture.is_null()) {
@@ -823,8 +823,8 @@ 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 = nullptr;
+ if (p_obj == node_sprite_2d || p_obj == node_sprite_3d || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
+ node_sprite_2d = nullptr;
node_sprite_3d = nullptr;
node_ninepatch = nullptr;
obj_styleBox = Ref<StyleBox>(nullptr);
@@ -852,17 +852,17 @@ bool TextureRegionEditor::is_ninepatch() {
return node_ninepatch != nullptr;
}
-Sprite3D *TextureRegionEditor::get_sprite_3d() {
- return node_sprite_3d;
+Sprite2D *TextureRegionEditor::get_sprite_2d() {
+ return node_sprite_2d;
}
-Sprite2D *TextureRegionEditor::get_sprite() {
- return node_sprite;
+Sprite3D *TextureRegionEditor::get_sprite_3d() {
+ return node_sprite_3d;
}
void TextureRegionEditor::edit(Object *p_obj) {
- if (node_sprite) {
- node_sprite->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
+ if (node_sprite_2d) {
+ node_sprite_2d->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (node_sprite_3d) {
node_sprite_3d->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
@@ -877,7 +877,7 @@ void TextureRegionEditor::edit(Object *p_obj) {
atlas_tex->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
if (p_obj) {
- node_sprite = Object::cast_to<Sprite2D>(p_obj);
+ node_sprite_2d = Object::cast_to<Sprite2D>(p_obj);
node_sprite_3d = Object::cast_to<Sprite3D>(p_obj);
node_ninepatch = Object::cast_to<NinePatchRect>(p_obj);
@@ -898,14 +898,14 @@ void TextureRegionEditor::edit(Object *p_obj) {
}
_edit_region();
} else {
- node_sprite = nullptr;
+ node_sprite_2d = 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_enabled()) || (node_sprite_3d && !node_sprite_3d->is_region_enabled())) {
+ if ((node_sprite_2d && !node_sprite_2d->is_region_enabled()) || (node_sprite_3d && !node_sprite_3d->is_region_enabled())) {
set_process(true);
}
if (!p_obj) {
@@ -922,16 +922,16 @@ void TextureRegionEditor::_texture_changed() {
void TextureRegionEditor::_edit_region() {
Ref<Texture2D> texture = nullptr;
- if (node_sprite) {
- texture = node_sprite->get_texture();
+ if (atlas_tex.is_valid()) {
+ texture = atlas_tex->get_atlas();
+ } else if (node_sprite_2d) {
+ texture = node_sprite_2d->get_texture();
} else if (node_sprite_3d) {
texture = node_sprite_3d->get_texture();
} else if (node_ninepatch) {
texture = node_ninepatch->get_texture();
} else if (obj_styleBox.is_valid()) {
texture = obj_styleBox->get_texture();
- } else if (atlas_tex.is_valid()) {
- texture = atlas_tex->get_atlas();
}
if (texture.is_null()) {
@@ -967,7 +967,7 @@ Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
}
TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
- node_sprite = nullptr;
+ node_sprite_2d = nullptr;
node_sprite_3d = nullptr;
node_ninepatch = nullptr;
obj_styleBox = Ref<StyleBoxTexture>(nullptr);
@@ -1122,7 +1122,9 @@ void TextureRegionEditorPlugin::_editor_visiblity_changed() {
void TextureRegionEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
texture_region_button->show();
- bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region_enabled()) || (region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region_enabled());
+ bool is_node_configured = region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch();
+ is_node_configured |= region_editor->get_sprite_2d() && region_editor->get_sprite_2d()->is_region_enabled();
+ is_node_configured |= region_editor->get_sprite_3d() && region_editor->get_sprite_3d()->is_region_enabled();
if ((is_node_configured && !manually_hidden) || texture_region_button->is_pressed()) {
editor->make_bottom_panel_item_visible(region_editor);
}
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index d3db0a08a9..c043d6ae33 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -83,7 +83,7 @@ class TextureRegionEditor : public VBoxContainer {
Vector2 snap_step;
Vector2 snap_separation;
- Sprite2D *node_sprite;
+ Sprite2D *node_sprite_2d;
Sprite3D *node_sprite_3d;
NinePatchRect *node_ninepatch;
Ref<StyleBoxTexture> obj_styleBox;
@@ -134,8 +134,8 @@ public:
bool is_stylebox();
bool is_atlas_texture();
bool is_ninepatch();
+ Sprite2D *get_sprite_2d();
Sprite3D *get_sprite_3d();
- Sprite2D *get_sprite();
void edit(Object *p_obj);
TextureRegionEditor(EditorNode *p_editor);
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index d54906c98c..2a8a3216ed 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -94,12 +94,14 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
}
// Copy the texture.
- Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id);
- Rect2 dst_rect_wide = Rect2i(new_tile_rect_in_altas.position * new_texture_region_size, new_tile_rect_in_altas.size * new_texture_region_size);
- if (dst_rect_wide.get_end().x > output_image->get_width() || dst_rect_wide.get_end().y > output_image->get_height()) {
- output_image->crop(MAX(dst_rect_wide.get_end().x, output_image->get_width()), MAX(dst_rect_wide.get_end().y, output_image->get_height()));
+ for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
+ Rect2i src_rect = atlas_source->get_tile_texture_region(tile_id, frame);
+ Rect2 dst_rect_wide = Rect2i(new_tile_rect_in_altas.position * new_texture_region_size, new_tile_rect_in_altas.size * new_texture_region_size);
+ if (dst_rect_wide.get_end().x > output_image->get_width() || dst_rect_wide.get_end().y > output_image->get_height()) {
+ output_image->crop(MAX(dst_rect_wide.get_end().x, output_image->get_width()), MAX(dst_rect_wide.get_end().y, output_image->get_height()));
+ }
+ output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, dst_rect_wide.get_center() - src_rect.size / 2);
}
- output_image->blit_rect(atlas_source->get_texture()->get_image(), src_rect, (dst_rect_wide.get_position() + dst_rect_wide.get_end()) / 2 - src_rect.size / 2);
}
// Compute the atlas offset.
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 0add83f64d..e98bd74b62 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -256,11 +256,15 @@ void TileAtlasView::_draw_base_tiles() {
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
- // Update the y to max value.
- Vector2i offset_pos = (margins + (atlas_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0));
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) {
+ // Update the y to max value.
+ int animation_columns = tile_set_atlas_source->get_tile_animation_columns(atlas_coords);
+ Vector2i frame_coords = atlas_coords + (tile_set_atlas_source->get_tile_size_in_atlas(atlas_coords) + tile_set_atlas_source->get_tile_animation_separation(atlas_coords)) * ((animation_columns > 0) ? Vector2i(frame % animation_columns, frame / animation_columns) : Vector2i(frame, 0));
+ Vector2i offset_pos = (margins + (frame_coords * texture_region_size) + tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame).size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0));
- // Draw the tile.
- TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0);
+ // Draw the tile.
+ TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame);
+ }
}
}
}
@@ -326,11 +330,18 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0);
- Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id);
- Vector2 origin = texture_region.position + (texture_region.size - tile_shape_size) / 2 + in_tile_base_offset;
- // Draw only if the tile shape fits in the texture region
- tile_set->draw_tile_shape(base_tiles_shape_grid, Rect2(origin, tile_shape_size), grid_color);
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(tile_id); frame++) {
+ Color color = grid_color;
+ if (frame > 0) {
+ color.a *= 0.3;
+ }
+ Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id);
+ Transform2D tile_xform;
+ tile_xform.set_origin(texture_region.get_center() + in_tile_base_offset);
+ tile_xform.set_scale(tile_shape_size);
+ tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, color);
+ }
}
}
@@ -358,7 +369,7 @@ void TileAtlasView::_draw_alternatives() {
Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i);
current_pos.x = 0;
int y_increment = 0;
- Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(atlas_coords);
+ Size2i texture_region_size = tile_set_atlas_source->get_tile_texture_region(atlas_coords).size;
int alternatives_count = tile_set_atlas_source->get_alternative_tiles_count(atlas_coords);
for (int j = 1; j < alternatives_count; j++) {
int alternative_id = tile_set_atlas_source->get_alternative_tile_id(atlas_coords, j);
@@ -368,18 +379,18 @@ void TileAtlasView::_draw_alternatives() {
// Update the y to max value.
Vector2i offset_pos = current_pos;
if (transposed) {
- offset_pos = (current_pos + Vector2(texture_region.size.y, texture_region.size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
- y_increment = MAX(y_increment, texture_region.size.x);
+ offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
+ y_increment = MAX(y_increment, texture_region_size.x);
} else {
- offset_pos = (current_pos + texture_region.size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
- y_increment = MAX(y_increment, texture_region.size.y);
+ offset_pos = (current_pos + texture_region_size / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, alternative_id));
+ y_increment = MAX(y_increment, texture_region_size.y);
}
// Draw the tile.
TileMap::draw_tile(alternatives_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, alternative_id);
// Increment the x position.
- current_pos.x += transposed ? texture_region.size.y : texture_region.size.x;
+ current_pos.x += transposed ? texture_region_size.y : texture_region_size.x;
}
if (alternatives_count > 1) {
current_pos.y += y_increment;
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index d406c2514c..ea7ca787c8 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -124,7 +124,9 @@ void GenericTilePolygonEditor::_base_control_draw() {
base_control->draw_set_transform_matrix(xform);
// Draw the tile shape filled.
- tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), Color(1.0, 1.0, 1.0, 0.3), true);
+ Transform2D tile_xform;
+ tile_xform.set_scale(tile_size);
+ tile_set->draw_tile_shape(base_control, tile_xform, Color(1.0, 1.0, 1.0, 0.3), true);
// Draw the background.
if (background_texture.is_valid()) {
@@ -213,7 +215,7 @@ void GenericTilePolygonEditor::_base_control_draw() {
// Draw the tile shape line.
base_control->draw_set_transform_matrix(xform);
- tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), grid_color, false);
+ tile_set->draw_tile_shape(base_control, tile_xform, grid_color, false);
base_control->draw_set_transform_matrix(Transform2D());
}
@@ -1072,14 +1074,15 @@ void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran
ERR_FAIL_COND(!tile_data);
Vector2i tile_set_tile_size = tile_set->get_tile_size();
- Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size);
Color color = Color(1.0, 0.0, 0.0);
if (p_selected) {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
color = selection_color;
}
- tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), color);
+ Transform2D tile_xform;
+ tile_xform.set_scale(tile_set_tile_size);
+ tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color);
}
void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
@@ -1465,12 +1468,13 @@ void TileDataTerrainsEditor::_tile_set_changed() {
ERR_FAIL_COND(!tile_set.is_valid());
// Fix if wrong values are selected.
- if (int(dummy_object->get("terrain_set")) > tile_set->get_terrain_sets_count()) {
+ int terrain_set = int(dummy_object->get("terrain_set"));
+ if (terrain_set >= tile_set->get_terrain_sets_count()) {
+ terrain_set = -1;
dummy_object->set("terrain_set", -1);
}
- int terrain_set = int(dummy_object->get("terrain"));
if (terrain_set >= 0) {
- if (int(dummy_object->get("terrain")) > tile_set->get_terrains_count(terrain_set)) {
+ if (int(dummy_object->get("terrain")) >= tile_set->get_terrains_count(terrain_set)) {
dummy_object->set("terrain", -1);
}
}
@@ -1491,7 +1495,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, 0));
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) {
// Draw hovered bit.
@@ -1513,9 +1517,10 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
}
} else {
// Draw hovered tile.
- Vector2i tile_size = tile_set->get_tile_size();
- Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size));
- tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true);
+ Transform2D tile_xform;
+ tile_xform.set_origin(position);
+ tile_xform.set_scale(tile_set->get_tile_size());
+ tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
}
}
}
@@ -1535,7 +1540,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
// Text
p_canvas_item->draw_set_transform_matrix(Transform2D());
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
Color color = Color(1, 1, 1);
String text;
@@ -1627,7 +1632,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
Vector2i coords = E->get().get_atlas_coords();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
@@ -1663,7 +1668,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative));
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
if (terrain_set == int(dummy_object->get("terrain_set"))) {
// Draw hovered bit.
@@ -1685,9 +1690,10 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
}
} else {
// Draw hovered tile.
- Vector2i tile_size = tile_set->get_tile_size();
- Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size));
- tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true);
+ Transform2D tile_xform;
+ tile_xform.set_origin(position);
+ tile_xform.set_scale(tile_set->get_tile_size());
+ tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
}
}
}
@@ -1709,7 +1715,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
// Text
p_canvas_item->draw_set_transform_matrix(Transform2D());
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
Color color = Color(1, 1, 1);
String text;
@@ -1790,7 +1796,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
// Set the terrains bits.
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
if (tile_data->is_valid_peering_bit_terrain(bit)) {
@@ -1818,7 +1824,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0));
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
@@ -1916,7 +1922,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
// Set the terrain bit.
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
@@ -2049,7 +2055,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit);
for (int j = 0; j < polygon.size(); j++) {
@@ -2132,7 +2138,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
// Set the terrains bits.
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(j);
if (tile_data->is_valid_peering_bit_terrain(bit)) {
@@ -2161,7 +2167,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile));
int terrain_set = tile_data->get_terrain_set();
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
@@ -2236,7 +2242,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
// Set the terrain bit.
Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) {
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 77084f551a..8b5b576369 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -636,8 +636,10 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
- Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - tile_shape_size / 2, tile_shape_size));
- tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0), false);
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_scale(tile_shape_size);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
}
}
@@ -734,10 +736,12 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
- Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size));
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
- tile_set->draw_tile_shape(p_overlay, cell_region, color, false);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, false);
}
}
}
@@ -745,11 +749,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the preview.
for (Map<Vector2i, TileMapCell>::Element *E = preview.front(); E; E = E->next()) {
- Vector2i size = tile_set->get_tile_size();
- Vector2 position = tile_map->map_to_world(E->key()) - size / 2;
- Rect2 cell_region = xform.xform(Rect2(position, size));
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(E->key()));
+ tile_xform.set_scale(tile_set->get_tile_size());
if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
- tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} else {
if (tile_set->has_source(E->get().source_id)) {
TileSetSource *source = *tile_set->get_source(E->get().source_id);
@@ -786,15 +790,15 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Get the tile modulation.
Color modulate = tile_data->get_modulate();
Color self_modulate = tile_map->get_self_modulate();
- modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g, modulate.b * self_modulate.b, modulate.a * self_modulate.a);
+ modulate *= self_modulate;
// Draw the tile.
p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping());
} else {
- tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
}
} else {
- tile_set->draw_tile_shape(p_overlay, cell_region, Color(0.0, 0.0, 0.0, 0.5), true);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true);
}
}
}
@@ -1452,13 +1456,25 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) {
if (E->get().source_id == source_id && E->get().alternative_tile == 0) {
- tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords()), selection_color, false);
+ for (int frame = 0; frame < atlas->get_tile_animation_frames_count(E->get().get_atlas_coords()); frame++) {
+ Color color = selection_color;
+ if (frame > 0) {
+ color.a *= 0.3;
+ }
+ tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords(), frame), color, false);
+ }
}
}
// Draw the hovered tile.
if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) {
- tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords()), Color(1.0, 1.0, 1.0), false);
+ for (int frame = 0; frame < atlas->get_tile_animation_frames_count(hovered_tile.get_atlas_coords()); frame++) {
+ Color color = Color(1.0, 1.0, 1.0);
+ if (frame > 0) {
+ color.a *= 0.3;
+ }
+ tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color, false);
+ }
}
// Draw the selection rect.
@@ -3177,7 +3193,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_pressed(true);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_E));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", KEY_D));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -3549,30 +3565,76 @@ void TileMapEditor::_update_layers_selection() {
tile_map_editor_plugins[tabs->get_current_tab()]->edit(tile_map_id, tile_map_layer);
}
-void TileMapEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
+void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
ERR_FAIL_COND(!undo_redo);
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
- if (tile_map) {
- if (p_property == "layers_count") {
- int new_layers_count = (int)p_new_value;
- if (new_layers_count < tile_map->get_layers_count()) {
- List<PropertyInfo> property_list;
- tile_map->get_property_list(&property_list);
-
- for (PropertyInfo property_info : property_list) {
- Vector<String> components = String(property_info.name).split("/", true, 2);
- if (components.size() == 2 && components[0].begins_with("layer_") && components[0].trim_prefix("layer_").is_valid_int()) {
- int index = components[0].trim_prefix("layer_").to_int();
- if (index >= new_layers_count) {
- undo_redo->add_undo_property(tile_map, property_info.name, tile_map->get(property_info.name));
- }
- }
+ if (!tile_map) {
+ return;
+ }
+
+ // Compute the array indices to save.
+ int begin = 0;
+ int end;
+ if (p_array_prefix == "layer_") {
+ end = tile_map->get_layers_count();
+ } else {
+ ERR_FAIL_MSG("Invalid array prefix for TileSet.");
+ }
+ if (p_from_index < 0) {
+ // Adding new.
+ if (p_to_pos >= 0) {
+ begin = p_to_pos;
+ } else {
+ end = 0; // Nothing to save when adding at the end.
+ }
+ } else if (p_to_pos < 0) {
+ // Removing.
+ begin = p_from_index;
+ } else {
+ // Moving.
+ begin = MIN(p_from_index, p_to_pos);
+ end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
+ }
+
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+ // Save layers' properties.
+ if (p_from_index < 0) {
+ undo_redo->add_undo_method(tile_map, "remove_layer", p_to_pos < 0 ? tile_map->get_layers_count() : p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_undo_method(tile_map, "add_layer", p_from_index);
+ }
+
+ List<PropertyInfo> properties;
+ tile_map->get_property_list(&properties);
+ for (PropertyInfo pi : properties) {
+ if (pi.name.begins_with(p_array_prefix)) {
+ String str = pi.name.trim_prefix(p_array_prefix);
+ int to_char_index = 0;
+ while (to_char_index < str.length()) {
+ if (str[to_char_index] < '0' || str[to_char_index] > '9') {
+ break;
+ }
+ to_char_index++;
+ }
+ if (to_char_index > 0) {
+ int array_index = str.left(to_char_index).to_int();
+ if (array_index >= begin && array_index < end) {
+ ADD_UNDO(tile_map, pi.name);
}
}
}
}
+#undef ADD_UNDO
+
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_map, "add_layer", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_map, "remove_layer", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_map, "move_layer", p_from_index, p_to_pos);
+ }
}
bool TileMapEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
@@ -3643,8 +3705,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
0.8);
// Draw the scaled tile.
- Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size)));
- tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture);
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(coords));
+ tile_xform.set_scale(tile_shape_size);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
}
// Draw the warning icon.
@@ -3700,10 +3764,12 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
- Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size));
+ Transform2D tile_xform;
+ tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
+ tile_xform.set_scale(tile_shape_size);
Color color = grid_color;
color.a = color.a * opacity;
- tile_set->draw_tile_shape(p_overlay, cell_region, color, false);
+ tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, false);
}
}
}
@@ -3851,7 +3917,7 @@ TileMapEditor::TileMapEditor() {
_tab_changed(0);
// Registers UndoRedo inspector callback.
- EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileMapEditor::_undo_redo_inspector_callback));
+ EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileMap"), callable_mp(this, &TileMapEditor::_move_tile_map_array_element));
}
TileMapEditor::~TileMapEditor() {
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 6e2f2ce2ba..6126db59e9 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -341,7 +341,7 @@ private:
void _update_layers_selection();
// Inspector undo/redo callback.
- void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
+ void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
protected:
void _notification(int p_what);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 432f48fa85..54185d1d2a 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -135,45 +135,81 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
const Vector2i &coords = tiles.front()->get().tile;
const int &alternative = tiles.front()->get().alternative;
- if (alternative == 0 && p_name == "atlas_coords") {
- Vector2i as_vector2i = Vector2i(p_value);
- ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, as_vector2i), false);
-
- if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
- tiles_set_atlas_source_editor->selection.clear();
- tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 });
- tiles_set_atlas_source_editor->_update_tile_id_label();
- }
-
- tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i);
- tiles.clear();
- tiles.insert({ as_vector2i, 0 });
- emit_signal(SNAME("changed"), "atlas_coords");
- return true;
- } else if (alternative == 0 && p_name == "size_in_atlas") {
- Vector2i as_vector2i = Vector2i(p_value);
- ERR_FAIL_COND_V(!tile_set_atlas_source->can_move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i), false);
+ if (alternative == 0) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (p_name == "atlas_coords") {
+ Vector2i as_vector2i = Vector2i(p_value);
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
+ ERR_FAIL_COND_V(!has_room_for_tile, false);
+
+ if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
+ tiles_set_atlas_source_editor->selection.clear();
+ tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 });
+ tiles_set_atlas_source_editor->_update_tile_id_label();
+ }
- tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
- emit_signal(SNAME("changed"), "size_in_atlas");
- return true;
- } else if (alternative > 0 && p_name == "alternative_id") {
- int as_int = int(p_value);
- ERR_FAIL_COND_V(as_int < 0, false);
- ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords));
-
- if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) {
- tiles_set_atlas_source_editor->selection.clear();
- tiles_set_atlas_source_editor->selection.insert({ coords, as_int });
+ tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i);
+ tiles.clear();
+ tiles.insert({ as_vector2i, 0 });
+ emit_signal(SNAME("changed"), "atlas_coords");
+ return true;
+ } else if (p_name == "size_in_atlas") {
+ Vector2i as_vector2i = Vector2i(p_value);
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, as_vector2i, tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
+ ERR_FAIL_COND_V(!has_room_for_tile, false);
+ tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
+ emit_signal(SNAME("changed"), "size_in_atlas");
+ return true;
+ } else if (p_name == "animation_columns") {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), p_value, tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
+ ERR_FAIL_COND_V(!has_room_for_tile, false);
+ tile_set_atlas_source->set_tile_animation_columns(coords, p_value);
+ emit_signal(SNAME("changed"), "animation_columns");
+ return true;
+ } else if (p_name == "animation_separation") {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), p_value, tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
+ ERR_FAIL_COND_V(!has_room_for_tile, false);
+ tile_set_atlas_source->set_tile_animation_separation(coords, p_value);
+ emit_signal(SNAME("changed"), "animation_separation");
+ return true;
+ } else if (p_name == "animation_speed") {
+ tile_set_atlas_source->set_tile_animation_speed(coords, p_value);
+ emit_signal(SNAME("changed"), "animation_speed");
+ return true;
+ } else if (p_name == "animation_frames_count") {
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), p_value, coords);
+ ERR_FAIL_COND_V(!has_room_for_tile, false);
+ tile_set_atlas_source->set_tile_animation_frames_count(coords, p_value);
+ notify_property_list_changed();
+ emit_signal(SNAME("changed"), "animation_separation");
+ return true;
+ } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[0].trim_prefix("animation_frame_").to_int();
+ ERR_FAIL_INDEX_V(frame, tile_set_atlas_source->get_tile_animation_frames_count(coords), false);
+ if (components[1] == "duration") {
+ tile_set_atlas_source->set_tile_animation_frame_duration(coords, frame, p_value);
+ return true;
+ }
}
+ } else if (alternative > 0) {
+ if (p_name == "alternative_id") {
+ int as_int = int(p_value);
+ ERR_FAIL_COND_V(as_int < 0, false);
+ ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords));
+
+ if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) {
+ tiles_set_atlas_source_editor->selection.clear();
+ tiles_set_atlas_source_editor->selection.insert({ coords, as_int });
+ }
- int previous_alternative_tile = alternative;
- tiles.clear();
- tiles.insert({ coords, as_int }); // tiles must be updated before.
- tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int);
+ int previous_alternative_tile = alternative;
+ tiles.clear();
+ tiles.insert({ coords, as_int }); // tiles must be updated before.
+ tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int);
- emit_signal(SNAME("changed"), "alternative_id");
- return true;
+ emit_signal(SNAME("changed"), "alternative_id");
+ return true;
+ }
}
}
@@ -206,15 +242,41 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
const Vector2i &coords = tiles.front()->get().tile;
const int &alternative = tiles.front()->get().alternative;
- if (alternative == 0 && p_name == "atlas_coords") {
- r_ret = coords;
- return true;
- } else if (alternative == 0 && p_name == "size_in_atlas") {
- r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords);
- return true;
- } else if (alternative > 0 && p_name == "alternative_id") {
- r_ret = alternative;
- return true;
+ if (alternative == 0) {
+ Vector<String> components = String(p_name).split("/", true, 2);
+ if (p_name == "atlas_coords") {
+ r_ret = coords;
+ return true;
+ } else if (p_name == "size_in_atlas") {
+ r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords);
+ return true;
+ } else if (p_name == "animation_columns") {
+ r_ret = tile_set_atlas_source->get_tile_animation_columns(coords);
+ return true;
+ } else if (p_name == "animation_separation") {
+ r_ret = tile_set_atlas_source->get_tile_animation_separation(coords);
+ return true;
+ } else if (p_name == "animation_speed") {
+ r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
+ return true;
+ } else if (p_name == "animation_frames_count") {
+ r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
+ return true;
+ } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[0].trim_prefix("animation_frame_").to_int();
+ if (components[1] == "duration") {
+ if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(coords)) {
+ return false;
+ }
+ r_ret = tile_set_atlas_source->get_tile_animation_frame_duration(coords, frame);
+ return true;
+ }
+ }
+ } else if (alternative > 0) {
+ if (p_name == "alternative_id") {
+ r_ret = alternative;
+ return true;
+ }
}
}
@@ -246,6 +308,20 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
if (tiles.front()->get().alternative == 0) {
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, ""));
+
+ // Animation.
+ p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
+ if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_frame_0/duration", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ } else {
+ for (int i = 0; i < tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile); i++) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, ""));
+ }
+ }
} else {
p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, ""));
}
@@ -846,7 +922,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
CursorShape cursor_shape = CURSOR_ARROW;
bool can_grow[4];
for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
}
for (int i = 0; i < 4; i++) {
@@ -869,7 +945,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
new_rect.size += Vector2i(1, 1);
// Check if the new tile can fit in the new rect.
- if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
// Move and resize the tile.
tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
drag_current_tile = new_rect.position;
@@ -908,7 +984,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
- if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) {
+ if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
selection.clear();
selection.insert({ coords, 0 });
@@ -948,7 +1024,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
}
- if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) {
+ if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
selection.clear();
selection.insert({ new_rect.position, 0 });
@@ -1056,7 +1132,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
CursorShape cursor_shape = CURSOR_ARROW;
bool can_grow[4];
for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
+ can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
}
for (int i = 0; i < 4; i++) {
@@ -1511,37 +1587,45 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
TileSelection selected = E->get();
if (selected.alternative == 0) {
// Draw the rect.
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- tile_atlas_control->draw_rect(region, selection_color, false);
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(selected.tile); frame++) {
+ Color color = selection_color;
+ if (frame > 0) {
+ color.a *= 0.3;
+ }
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile, frame);
+ tile_atlas_control->draw_rect(region, color, false);
+ }
}
}
if (selection.size() == 1) {
// Draw the resize handles (only when it's possible to expand).
TileSelection selected = selection.front()->get();
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4]) {
- tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false);
- } else {
- tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false);
+ if (selected.alternative == 0) {
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
}
- Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
- if (can_grow[i]) {
- tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
- } else {
- tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4]) {
+ tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false);
+ } else {
+ tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false);
+ }
+ Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4];
+ if (can_grow[i]) {
+ tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
+ } else {
+ tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
+ }
}
}
}
@@ -1550,7 +1634,9 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
if (drag_type == DRAG_TYPE_REMOVE_TILES) {
// Draw the tiles to be removed.
for (Set<Vector2i>::Element *E = drag_modified_tiles.front(); E; E = E->next()) {
- tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E->get()), Color(0.0, 0.0, 0.0), false);
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(E->get()); frame++) {
+ tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E->get(), frame), Color(0.0, 0.0, 0.0), false);
+ }
}
} else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
// Draw tiles to be removed.
@@ -1617,7 +1703,13 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i hovered_tile = tile_set_atlas_source->get_tile_at_coords(hovered_base_tile_coords);
if (hovered_tile != TileSetSource::INVALID_ATLAS_COORDS) {
// Draw existing hovered tile.
- tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile), Color(1.0, 1.0, 1.0), false);
+ for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(hovered_tile); frame++) {
+ Color color = Color(1.0, 1.0, 1.0);
+ if (frame > 0) {
+ color.a *= 0.3;
+ }
+ tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color, false);
+ }
} else {
// Draw empty tile, only in add/remove tiles mode.
if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
@@ -1638,7 +1730,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i coords = tile_set_atlas_source->get_tile_id(i);
Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
xform.translate(position);
@@ -1661,7 +1753,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
continue;
}
Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E->get().tile);
- Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0);
+ Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0);
Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
xform.translate(position);
@@ -1805,7 +1897,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
continue;
}
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
- Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+ Vector2 position = rect.get_center();
Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
xform.translate(position);
@@ -1829,7 +1921,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
continue;
}
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E->get().tile, E->get().alternative);
- Vector2 position = (rect.get_position() + rect.get_end()) / 2;
+ Vector2 position = rect.get_center();
Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
xform.translate(position);
@@ -1866,7 +1958,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
ERR_FAIL_COND(!undo_redo);
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, tile_data->get(property));
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited);
if (tile_data) {
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index ba98a7d6b3..48d0d9b333 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -330,11 +330,192 @@ void TileSetEditor::_tile_set_changed() {
tile_set_changed_needs_update = true;
}
+void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
+ UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo);
+
+ TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
+ if (!tile_set) {
+ return;
+ }
+
+ Vector<String> components = String(p_array_prefix).split("/", true, 2);
+
+ // Compute the array indices to save.
+ int begin = 0;
+ int end;
+ if (p_array_prefix == "occlusion_layer_") {
+ end = tile_set->get_occlusion_layers_count();
+ } else if (p_array_prefix == "physics_layer_") {
+ end = tile_set->get_physics_layers_count();
+ } else if (p_array_prefix == "terrain_set_") {
+ end = tile_set->get_terrain_sets_count();
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
+ int terrain_set = components[0].trim_prefix("terrain_set_").to_int();
+ end = tile_set->get_terrains_count(terrain_set);
+ } else if (p_array_prefix == "navigation_layer_") {
+ end = tile_set->get_navigation_layers_count();
+ } else if (p_array_prefix == "custom_data_layer_") {
+ end = tile_set->get_custom_data_layers_count();
+ } else {
+ ERR_FAIL_MSG("Invalid array prefix for TileSet.");
+ }
+ if (p_from_index < 0) {
+ // Adding new.
+ if (p_to_pos >= 0) {
+ begin = p_to_pos;
+ } else {
+ end = 0; // Nothing to save when adding at the end.
+ }
+ } else if (p_to_pos < 0) {
+ // Removing.
+ begin = p_from_index;
+ } else {
+ // Moving.
+ begin = MIN(p_from_index, p_to_pos);
+ end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
+ }
+
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+ // Save layers' properties.
+ List<PropertyInfo> properties;
+ tile_set->get_property_list(&properties);
+ for (PropertyInfo pi : properties) {
+ if (pi.name.begins_with(p_array_prefix)) {
+ String str = pi.name.trim_prefix(p_array_prefix);
+ int to_char_index = 0;
+ while (to_char_index < str.length()) {
+ if (str[to_char_index] < '0' || str[to_char_index] > '9') {
+ break;
+ }
+ to_char_index++;
+ }
+ if (to_char_index > 0) {
+ int array_index = str.left(to_char_index).to_int();
+ if (array_index >= begin && array_index < end) {
+ ADD_UNDO(tile_set, pi.name);
+ }
+ }
+ }
+ }
+
+ // Save properties for TileSetAtlasSources tile data
+ for (int i = 0; i < tile_set->get_source_count(); i++) {
+ int source_id = tile_set->get_source_id(i);
+
+ Ref<TileSetAtlasSource> tas = tile_set->get_source(source_id);
+ if (tas.is_valid()) {
+ for (int j = 0; j < tas->get_tiles_count(); j++) {
+ Vector2i tile_id = tas->get_tile_id(j);
+ for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
+ int alternative_id = tas->get_alternative_tile_id(tile_id, k);
+ TileData *tile_data = Object::cast_to<TileData>(tas->get_tile_data(tile_id, alternative_id));
+ ERR_FAIL_COND(!tile_data);
+
+ // Actually saving stuff.
+ if (p_array_prefix == "occlusion_layer_") {
+ for (int layer_index = begin; layer_index < end; layer_index++) {
+ ADD_UNDO(tile_data, vformat("occlusion_layer_%d/polygon", layer_index));
+ }
+ } else if (p_array_prefix == "physics_layer_") {
+ for (int layer_index = begin; layer_index < end; layer_index++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygons_count", layer_index));
+ for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(layer_index); polygon_index++) {
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", layer_index, polygon_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, polygon_index));
+ ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, polygon_index));
+ }
+ }
+ } else if (p_array_prefix == "terrain_set_") {
+ ADD_UNDO(tile_data, "terrain_set");
+ for (int terrain_set_index = begin; terrain_set_index < end; terrain_set_index++) {
+ for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
+ }
+ }
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
+ for (int terrain_index = 0; terrain_index < TileSet::CELL_NEIGHBOR_MAX; terrain_index++) {
+ TileSet::CellNeighbor bit = TileSet::CellNeighbor(terrain_index);
+ if (tile_data->is_valid_peering_bit_terrain(bit)) {
+ ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[terrain_index]));
+ }
+ }
+ } else if (p_array_prefix == "navigation_layer_") {
+ for (int layer_index = begin; layer_index < end; layer_index++) {
+ ADD_UNDO(tile_data, vformat("navigation_layer_%d/polygon", layer_index));
+ }
+ } else if (p_array_prefix == "custom_data_layer_") {
+ for (int layer_index = begin; layer_index < end; layer_index++) {
+ ADD_UNDO(tile_data, vformat("custom_data_%d", layer_index));
+ }
+ }
+ }
+ }
+ }
+ }
+#undef ADD_UNDO
+
+ // Add do method.
+ if (p_array_prefix == "occlusion_layer_") {
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_occlusion_layer", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_occlusion_layer", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_occlusion_layer", p_from_index, p_to_pos);
+ }
+ } else if (p_array_prefix == "physics_layer_") {
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_physics_layer", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_physics_layer", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_physics_layer", p_from_index, p_to_pos);
+ }
+ } else if (p_array_prefix == "terrain_set_") {
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_terrain_set", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_terrain_set", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_terrain_set", p_from_index, p_to_pos);
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
+ int terrain_set = components[0].trim_prefix("terrain_set_").to_int();
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_terrain", terrain_set, p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_terrain", terrain_set, p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_terrain", terrain_set, p_from_index, p_to_pos);
+ }
+ } else if (p_array_prefix == "navigation_layer_") {
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_navigation_layer", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_navigation_layer", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_navigation_layer", p_from_index, p_to_pos);
+ }
+ } else if (p_array_prefix == "custom_data_layer_") {
+ if (p_from_index < 0) {
+ undo_redo->add_do_method(tile_set, "add_custom_data_layer", p_to_pos);
+ } else if (p_to_pos < 0) {
+ undo_redo->add_do_method(tile_set, "remove_custom_data_layer", p_from_index);
+ } else {
+ undo_redo->add_do_method(tile_set, "move_custom_data_layer", p_from_index, p_to_pos);
+ }
+ }
+}
+
void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
ERR_FAIL_COND(!undo_redo);
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, tile_data->get(property));
+#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
if (tile_set) {
Vector<String> components = p_property.split("/", true, 3);
@@ -350,30 +531,7 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
TileData *tile_data = Object::cast_to<TileData>(tas->get_tile_data(tile_id, alternative_id));
ERR_FAIL_COND(!tile_data);
- if (p_property == "occlusion_layers_count") {
- int new_layer_count = p_new_value;
- int old_layer_count = tile_set->get_occlusion_layers_count();
- if (new_layer_count < old_layer_count) {
- for (int occclusion_layer_index = new_layer_count - 1; occclusion_layer_index < old_layer_count; occclusion_layer_index++) {
- ADD_UNDO(tile_data, vformat("occlusion_layer_%d/polygon", occclusion_layer_index));
- }
- }
- } else if (p_property == "physics_layers_count") {
- int new_layer_count = p_new_value;
- int old_layer_count = tile_set->get_physics_layers_count();
- if (new_layer_count < old_layer_count) {
- for (int physics_layer_index = new_layer_count - 1; physics_layer_index < old_layer_count; physics_layer_index++) {
- ADD_UNDO(tile_data, vformat("physics_layer_%d/polygons_count", physics_layer_index));
- for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(physics_layer_index); polygon_index++) {
- ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", physics_layer_index, polygon_index));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", physics_layer_index, polygon_index));
- ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", physics_layer_index, polygon_index));
- }
- }
- }
- } else if ((p_property == "terrains_sets_count" && tile_data->get_terrain_set() >= (int)p_new_value) ||
- (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") ||
- (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) {
+ if (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") {
ADD_UNDO(tile_data, "terrain_set");
for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(l);
@@ -381,22 +539,6 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l]));
}
}
- } else if (p_property == "navigation_layers_count") {
- int new_layer_count = p_new_value;
- int old_layer_count = tile_set->get_navigation_layers_count();
- if (new_layer_count < old_layer_count) {
- for (int navigation_layer_index = new_layer_count - 1; navigation_layer_index < old_layer_count; navigation_layer_index++) {
- ADD_UNDO(tile_data, vformat("navigation_layer_%d/polygon", navigation_layer_index));
- }
- }
- } else if (p_property == "custom_data_layers_count") {
- int new_layer_count = p_new_value;
- int old_layer_count = tile_set->get_custom_data_layers_count();
- if (new_layer_count < old_layer_count) {
- for (int custom_data_layer_index = new_layer_count - 1; custom_data_layer_index < old_layer_count; custom_data_layer_index++) {
- ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer_index));
- }
- }
} else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int() && components[1] == "type") {
int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_int();
ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer));
@@ -531,6 +673,7 @@ TileSetEditor::TileSetEditor() {
tile_set_scenes_collection_source_editor->hide();
// Registers UndoRedo inspector callback.
+ EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
}
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 970e3fabb6..fe854b2281 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -71,6 +71,7 @@ private:
void _tile_set_changed();
+ void _move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos);
void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value);
protected:
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 79b869b511..f51f4625a9 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -146,7 +146,7 @@ void TilesEditor::synchronize_atlas_view(Object *p_current) {
ERR_FAIL_COND(!tile_atlas_view);
if (tile_atlas_view->is_visible_in_tree()) {
- tile_atlas_view->set_transform(atlas_view_zoom, Vector2(atlas_view_scroll.x, atlas_view_scroll.y));
+ tile_atlas_view->set_transform(atlas_view_zoom, atlas_view_scroll);
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 50808a25af..27f30479cf 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1945,7 +1945,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
box_size.x -= 28 * EDSCALE;
box_size.y -= text_box->get_offset(SIDE_TOP);
box_size.y -= 28 * EDSCALE;
- text_box->set_custom_minimum_size(Size2(box_size.x, box_size.y));
+ text_box->set_custom_minimum_size(box_size);
text_box->set_size(Size2(1, 1));
}
}
@@ -4042,7 +4042,7 @@ VisualShaderEditor::VisualShaderEditor() {
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", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false));
+ add_node->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_members_dialog), varray(false, VisualShaderNode::PORT_TYPE_MAX, VisualShaderNode::PORT_TYPE_MAX));
preview_shader = memnew(Button);
preview_shader->set_flat(true);