summaryrefslogtreecommitdiff
path: root/editor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins')
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp30
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp98
-rw-r--r--editor/plugins/animation_state_machine_editor.h22
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp13
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp4
-rw-r--r--editor/plugins/bit_map_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp135
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h12
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/control_editor_plugin.cpp2
-rw-r--r--editor/plugins/control_editor_plugin.h2
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp12
-rw-r--r--editor/plugins/dedicated_server_export_plugin.cpp139
-rw-r--r--editor/plugins/dedicated_server_export_plugin.h58
-rw-r--r--editor/plugins/font_config_plugin.cpp9
-rw-r--r--editor/plugins/font_config_plugin.h6
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp2
-rw-r--r--editor/plugins/gradient_editor.cpp183
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp56
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp4
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.cpp36
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.h4
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp239
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp26
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp18
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.h5
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp2
-rw-r--r--editor/plugins/root_motion_editor_plugin.h2
-rw-r--r--editor/plugins/script_editor_plugin.cpp94
-rw-r--r--editor/plugins/script_editor_plugin.h18
-rw-r--r--editor/plugins/script_text_editor.cpp117
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp144
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp598
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h51
-rw-r--r--editor/plugins/text_editor.cpp71
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/text_shader_editor.cpp5
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp45
-rw-r--r--editor/plugins/texture_region_editor_plugin.h7
-rw-r--r--editor/plugins/theme_editor_plugin.cpp88
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp52
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h5
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp90
-rw-r--r--editor/plugins/tiles/tile_data_editors.h4
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp97
-rw-r--r--editor/plugins/tiles/tile_map_editor.h3
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp163
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h6
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp41
-rw-r--r--editor/plugins/tiles/tile_set_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp36
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h2
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp286
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h21
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp39
59 files changed, 2180 insertions, 1058 deletions
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 33aebe5883..df94815105 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/check_box.h"
+#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
@@ -335,6 +336,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
min_value->set_value(blend_space->get_min_space());
sync->set_pressed(blend_space->is_using_sync());
+ interpolation->select(blend_space->get_blend_mode());
label_value->set_text(blend_space->get_value_label());
@@ -361,6 +363,8 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());
undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
@@ -579,6 +583,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ interpolation->clear();
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), "", 0);
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), "", 1);
+ interpolation->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), "", 2);
} break;
case NOTIFICATION_PROCESS: {
@@ -639,6 +647,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
min_value->set_editable(!read_only);
max_value->set_editable(!read_only);
sync->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
@@ -707,6 +716,13 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
top_hb->add_child(sync);
sync->connect("toggled", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
+ top_hb->add_child(memnew(VSeparator));
+
+ top_hb->add_child(memnew(Label(TTR("Blend:"))));
+ interpolation = memnew(OptionButton);
+ top_hb->add_child(interpolation);
+ interpolation->connect("item_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
+
edit_hb = memnew(HBoxContainer);
top_hb->add_child(edit_hb);
edit_hb->add_child(memnew(VSeparator));
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index e71a4bd1b9..90104fc310 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -41,6 +41,7 @@
#include "scene/gui/tree.h"
class CheckBox;
+class OptionButton;
class PanelContainer;
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
@@ -66,6 +67,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
SpinBox *min_value = nullptr;
CheckBox *sync = nullptr;
+ OptionButton *interpolation = nullptr;
HBoxContainer *edit_hb = nullptr;
SpinBox *edit_value = nullptr;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f5f9ec11b3..77785b15ca 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -985,8 +985,6 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
undo_redo->create_action(TTR("Node Renamed"));
undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
- undo_redo->add_do_method(tree, "rename_parameter", base_path + prev_name, base_path + name);
- undo_redo->add_undo_method(tree, "rename_parameter", base_path + name, base_path + prev_name);
undo_redo->add_do_method(this, "update_graph");
undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
@@ -1111,7 +1109,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
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("TimeSeek", "AnimationNodeTimeSeek", 1));
add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale", 1));
add_options.push_back(AddOption("Transition", "AnimationNodeTransition"));
add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree"));
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 06241d07cf..c5bfd968d7 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -245,7 +245,7 @@ void AnimationPlayerEditor::_play_bw_pressed() {
player->stop(); //so it won't blend with itself
}
ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
- player->play(current, -1, -1, true);
+ player->play_backwards(current);
}
//unstop
@@ -262,7 +262,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() {
}
ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
player->seek(time);
- player->play(current, -1, -1, true);
+ player->play_backwards(current);
}
//unstop
@@ -452,7 +452,9 @@ float AnimationPlayerEditor::_get_editor_step() const {
}
void AnimationPlayerEditor::_animation_name_edited() {
- player->stop();
+ if (player->is_playing()) {
+ player->stop();
+ }
String new_name = name->get_text();
if (!AnimationLibrary::is_valid_animation_name(new_name)) {
@@ -1103,9 +1105,24 @@ void AnimationPlayerEditor::_animation_duplicate() {
return;
}
+ int count = 2;
String new_name = current;
- while (player->has_animation(new_name)) {
- new_name = new_name + " (copy)";
+ PackedStringArray split = new_name.split("_");
+ int last_index = split.size() - 1;
+ if (last_index > 0 && split[last_index].is_valid_int() && split[last_index].to_int() >= 0) {
+ count = split[last_index].to_int();
+ split.remove_at(last_index);
+ new_name = String("_").join(split);
+ }
+ while (true) {
+ String attempt = new_name;
+ attempt += vformat("_%d", count);
+ if (player->has_animation(attempt)) {
+ count++;
+ continue;
+ }
+ new_name = attempt;
+ break;
}
if (new_name.contains("/")) {
@@ -1117,6 +1134,7 @@ void AnimationPlayerEditor::_animation_duplicate() {
name_dialog_op = TOOL_DUPLICATE_ANIM;
name_dialog->set_title(TTR("Duplicate Animation"));
+ // TRANSLATORS: This is a label for the new name field in the "Duplicate Animation" dialog.
name_title->set_text(TTR("Duplicated Animation Name:"));
name->set_text(new_name);
name_dialog->popup_centered(Size2(300, 90));
@@ -1675,7 +1693,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
stop = memnew(Button);
stop->set_flat(true);
hb->add_child(stop);
- stop->set_tooltip_text(TTR("Stop animation playback. (S)"));
+ stop->set_tooltip_text(TTR("Pause/stop animation playback. (S)"));
play = memnew(Button);
play->set_flat(true);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index c0972d201e..9632670658 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -1127,7 +1127,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
connecting = false;
}
-void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions) {
+void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions) {
Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
Color icon_color(1, 1, 1);
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
@@ -1138,7 +1138,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
accent.a *= 0.6;
}
- const Ref<Texture2D> icons[6] = {
+ const Ref<Texture2D> icons[] = {
get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")),
get_theme_icon(SNAME("TransitionSyncBig"), SNAME("EditorIcons")),
get_theme_icon(SNAME("TransitionEndBig"), SNAME("EditorIcons")),
@@ -1146,6 +1146,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
get_theme_icon(SNAME("TransitionSyncAutoBig"), SNAME("EditorIcons")),
get_theme_icon(SNAME("TransitionEndAutoBig"), SNAME("EditorIcons"))
};
+ const int ICON_COUNT = sizeof(icons) / sizeof(*icons);
if (p_selected) {
state_machine_draw->draw_line(p_from, p_to, accent, 6);
@@ -1153,12 +1154,18 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
if (p_travel) {
linecolor = accent;
- linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v());
}
state_machine_draw->draw_line(p_from, p_to, linecolor, 2);
- Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)];
+ if (p_fade_ratio > 0.0) {
+ Color fade_linecolor = accent;
+ fade_linecolor.set_hsv(1.0, fade_linecolor.get_s(), fade_linecolor.get_v());
+ state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_linecolor, 2);
+ }
+ int icon_index = p_mode + (p_auto_advance ? ICON_COUNT / 2 : 0);
+ ERR_FAIL_COND(icon_index >= ICON_COUNT);
+ Ref<Texture2D> icon = icons[icon_index];
Transform2D xf;
xf.columns[0] = (p_to - p_from).normalized();
@@ -1327,7 +1334,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
}
- _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, false, false);
+ _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, 0.0, false, false);
}
Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons"));
@@ -1357,6 +1364,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl.mode = tr->get_switch_mode();
tl.width = tr_bidi_offset;
tl.travel = false;
+ tl.fade_ratio = 0.0;
tl.hidden = false;
if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists
@@ -1378,6 +1386,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
if (blend_from == local_from && current == local_to) {
tl.travel = true;
+ tl.fade_ratio = MIN(1.0, fading_pos / fading_time);
}
if (travel_path.size()) {
@@ -1418,7 +1427,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
for (int i = 0; i < transition_lines.size(); i++) {
TransitionLine tl = transition_lines[i];
if (!tl.hidden) {
- _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.auto_advance, !tl.multi_transitions.is_empty());
+ _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.fade_ratio, tl.auto_advance, !tl.multi_transitions.is_empty());
}
}
@@ -1508,25 +1517,24 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
state_machine_play_pos->queue_redraw();
}
-void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
+void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String p_name, float p_ratio) {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
if (!tree) {
return;
}
Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
-
if (!playback.is_valid() || !playback->is_playing()) {
return;
}
- if (playback->get_current_node() == state_machine->start_node || playback->get_current_node() == state_machine->end_node) {
+ if (p_name == state_machine->start_node || p_name == state_machine->end_node || p_name.is_empty()) {
return;
}
int idx = -1;
for (int i = 0; i < node_rects.size(); i++) {
- if (node_rects[i].node_name == playback->get_current_node()) {
+ if (node_rects[i].node_name == p_name) {
idx = i;
break;
}
@@ -1550,10 +1558,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
}
to.y = from.y;
- float len = MAX(0.0001, current_length);
-
- float pos = CLAMP(play_pos, 0, len);
- float c = pos / len;
+ float c = p_ratio;
Color fg = get_theme_color(SNAME("font_color"), SNAME("Label"));
Color bg = fg;
bg.a *= 0.3;
@@ -1565,6 +1570,32 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
state_machine_play_pos->draw_line(from, to, fg, 2);
}
+void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() {
+ AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
+ if (!tree) {
+ return;
+ }
+
+ Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
+ if (!playback.is_valid() || !playback->is_playing()) {
+ return;
+ }
+
+ {
+ float len = MAX(0.0001, current_length);
+ float pos = CLAMP(current_play_pos, 0, len);
+ float c = pos / len;
+ _state_machine_pos_draw_individual(playback->get_current_node(), c);
+ }
+
+ {
+ float len = MAX(0.0001, fade_from_length);
+ float pos = CLAMP(fade_from_current_play_pos, 0, len);
+ float c = pos / len;
+ _state_machine_pos_draw_individual(playback->get_fading_from_node(), c);
+ }
+}
+
void AnimationNodeStateMachineEditor::_update_graph() {
if (updating) {
return;
@@ -1687,17 +1718,28 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
Vector<StringName> tp;
bool is_playing = false;
StringName current_node;
- StringName blend_from_node;
- play_pos = 0;
+ StringName fading_from_node;
+
+ current_play_pos = 0;
current_length = 0;
+ fade_from_current_play_pos = 0;
+ fade_from_length = 0;
+
+ fading_time = 0;
+ fading_pos = 0;
+
if (playback.is_valid()) {
tp = playback->get_travel_path();
is_playing = playback->is_playing();
current_node = playback->get_current_node();
- blend_from_node = playback->get_fading_from_node();
- play_pos = playback->get_current_play_pos();
+ fading_from_node = playback->get_fading_from_node();
+ current_play_pos = playback->get_current_play_pos();
current_length = playback->get_current_length();
+ fade_from_current_play_pos = playback->get_fade_from_play_pos();
+ fade_from_length = playback->get_fade_from_length();
+ fading_time = playback->get_fading_time();
+ fading_pos = playback->get_fading_pos();
}
{
@@ -1714,12 +1756,19 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
}
//redraw if travel state changed
- if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) {
+ if (!same_travel_path ||
+ last_active != is_playing ||
+ last_current_node != current_node ||
+ last_fading_from_node != fading_from_node ||
+ last_fading_time != fading_time ||
+ last_fading_pos != fading_pos) {
state_machine_draw->queue_redraw();
last_travel_path = tp;
last_current_node = current_node;
last_active = is_playing;
- last_blend_from_node = blend_from_node;
+ last_fading_from_node = fading_from_node;
+ last_fading_time = fading_time;
+ last_fading_pos = fading_pos;
state_machine_play_pos->queue_redraw();
}
@@ -1737,14 +1786,15 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
// when current_node is a state machine, use playback of current_node to set play_pos
if (current_node_playback.is_valid()) {
- play_pos = current_node_playback->get_current_play_pos();
+ current_play_pos = current_node_playback->get_current_play_pos();
current_length = current_node_playback->get_current_length();
}
}
}
- if (last_play_pos != play_pos) {
- last_play_pos = play_pos;
+ if (last_play_pos != current_play_pos || fade_from_last_play_pos != fade_from_current_play_pos) {
+ last_play_pos = current_play_pos;
+ fade_from_last_play_pos = fade_from_current_play_pos;
state_machine_play_pos->queue_redraw();
}
} break;
@@ -2048,7 +2098,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
state_machine_draw->add_child(state_machine_play_pos);
state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent
state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
- state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw));
+ state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw_all));
v_scroll = memnew(VScrollBar);
state_machine_draw->add_child(v_scroll);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 46fe13ccc1..66338c820e 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -85,9 +85,12 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
static AnimationNodeStateMachineEditor *singleton;
void _state_machine_gui_input(const Ref<InputEvent> &p_event);
- void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance, bool p_multi_transitions);
+ void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions);
+
void _state_machine_draw();
- void _state_machine_pos_draw();
+
+ void _state_machine_pos_draw_individual(String p_name, float p_ratio);
+ void _state_machine_pos_draw_all();
void _update_graph();
@@ -150,6 +153,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
float width = 0;
bool selected;
bool travel;
+ float fade_ratio;
bool hidden;
int transition_index;
Vector<TransitionLine> multi_transitions;
@@ -204,13 +208,23 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
void _delete_tree_draw();
bool last_active = false;
- StringName last_blend_from_node;
+ StringName last_fading_from_node;
StringName last_current_node;
Vector<StringName> last_travel_path;
+
+ float fade_from_last_play_pos = 0.0f;
+ float fade_from_current_play_pos = 0.0f;
+ float fade_from_length = 0.0f;
+
float last_play_pos = 0.0f;
- float play_pos = 0.0f;
+ float current_play_pos = 0.0f;
float current_length = 0.0f;
+ float last_fading_time = 0.0f;
+ float last_fading_pos = 0.0f;
+ float fading_time = 0.0f;
+ float fading_pos = 0.0f;
+
float error_time = 0.0f;
String error_text;
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index 720deb0b92..ab46e8f04a 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -65,13 +65,14 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) {
tree = p_tree;
Vector<String> path;
- if (tree && tree->has_meta("_tree_edit_path")) {
- path = tree->get_meta("_tree_edit_path");
- } else {
- current_root = ObjectID();
+ if (tree) {
+ if (tree->has_meta("_tree_edit_path")) {
+ path = tree->get_meta("_tree_edit_path");
+ } else {
+ current_root = ObjectID();
+ }
+ edit_path(path);
}
-
- edit_path(path);
}
void AnimationTreeEditor::_node_removed(Node *p_node) {
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index eab5eb0404..2639765283 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -107,7 +107,7 @@ void EditorAssetLibraryItem::_bind_methods() {
EditorAssetLibraryItem::EditorAssetLibraryItem() {
Ref<StyleBoxEmpty> border;
border.instantiate();
- border->set_default_margin_all(5 * EDSCALE);
+ border->set_content_margin_all(5 * EDSCALE);
add_theme_style_override("panel", border);
HBoxContainer *hb = memnew(HBoxContainer);
@@ -1549,7 +1549,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
Ref<StyleBoxEmpty> border2;
border2.instantiate();
- border2->set_default_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
+ border2->set_content_margin_individual(15 * EDSCALE, 15 * EDSCALE, 35 * EDSCALE, 15 * EDSCALE);
PanelContainer *library_vb_border = memnew(PanelContainer);
library_scroll->add_child(library_vb_border);
diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp
index 4f82aaf071..30fc60b0e0 100644
--- a/editor/plugins/bit_map_editor_plugin.cpp
+++ b/editor/plugins/bit_map_editor_plugin.cpp
@@ -53,7 +53,7 @@ BitMapEditor::BitMapEditor() {
// Reduce extra padding on top and bottom of size label.
Ref<StyleBoxEmpty> stylebox;
stylebox.instantiate();
- stylebox->set_default_margin(SIDE_RIGHT, 4 * EDSCALE);
+ stylebox->set_content_margin(SIDE_RIGHT, 4 * EDSCALE);
size_label->add_theme_style_override("normal", stylebox);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 4c14755b03..0f9ce89f02 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -246,7 +246,7 @@ public:
}
};
-bool CanvasItemEditor::_is_node_locked(const Node *p_node) {
+bool CanvasItemEditor::_is_node_locked(const Node *p_node) const {
return p_node->get_meta("_edit_lock_", false);
}
@@ -770,7 +770,7 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
return still_selected;
}
-List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) {
+List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) const {
List<CanvasItem *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
@@ -1226,7 +1226,6 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
bool panner_active = panner->gui_input(p_event, warped_panning ? viewport->get_global_rect() : Rect2());
if (panner->is_panning() != pan_pressed) {
pan_pressed = panner->is_panning();
- _update_cursor();
}
if (panner_active) {
@@ -1260,57 +1259,25 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
}
- Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
- if (magnify_gesture.is_valid() && !p_already_accepted) {
- // Zoom gesture
- _zoom_on_position(zoom * magnify_gesture->get_factor(), magnify_gesture->get_position());
- return true;
- }
-
- Ref<InputEventPanGesture> pan_gesture = p_event;
- if (pan_gesture.is_valid() && !p_already_accepted) {
- // If ctrl key pressed, then zoom instead of pan.
- if (pan_gesture->is_ctrl_pressed()) {
- const real_t factor = pan_gesture->get_delta().y;
-
- zoom_widget->set_zoom_by_increments(1);
- if (factor != 1.f) {
- zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * factor + 1.f));
- }
- _zoom_on_position(zoom_widget->get_zoom(), pan_gesture->get_position());
-
- return true;
- }
-
- // Pan gesture
- const Vector2 delta = (pan_speed / zoom) * pan_gesture->get_delta();
- view_offset.x += delta.x;
- view_offset.y += delta.y;
- update_viewport();
- return true;
- }
-
return false;
}
-void CanvasItemEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
- _pan_callback(-p_scroll_vec * pan_speed);
-}
-
-void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec) {
+void CanvasItemEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
view_offset.x -= p_scroll_vec.x / zoom;
view_offset.y -= p_scroll_vec.y / zoom;
update_viewport();
}
-void CanvasItemEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- int scroll_sign = (int)SIGN(p_scroll_vec.y);
- // Inverted so that scrolling up (-1) zooms in, scrolling down (+1) zooms out.
- zoom_widget->set_zoom_by_increments(-scroll_sign, p_alt);
- if (!Math::is_equal_approx(ABS(p_scroll_vec.y), (real_t)1.0)) {
- // Handle high-precision (analog) scrolling.
- zoom_widget->set_zoom(zoom * ((zoom_widget->get_zoom() / zoom - 1.f) * ABS(p_scroll_vec.y) + 1.f));
+void CanvasItemEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ // Special behvior for scroll events, as the zoom_by_increment method can smartly end up on powers of two.
+ int increment = p_zoom_factor > 1.0 ? 1 : -1;
+ zoom_widget->set_zoom_by_increments(increment, mb->is_alt_pressed());
+ } else {
+ zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor);
}
+
_zoom_on_position(zoom_widget->get_zoom(), p_origin);
}
@@ -2570,8 +2537,10 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
// Handles the mouse hovering
_gui_input_hover(p_event);
- // Change the cursor
- _update_cursor();
+ if (mb.is_valid()) {
+ // Update the default cursor.
+ _update_cursor();
+ }
// Grab focus
if (!viewport->has_focus() && (!get_viewport()->gui_get_focus_owner() || !get_viewport()->gui_get_focus_owner()->is_text_field())) {
@@ -2580,6 +2549,31 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
}
void CanvasItemEditor::_update_cursor() {
+ // Choose the correct default cursor.
+ CursorShape c = CURSOR_ARROW;
+ switch (tool) {
+ case TOOL_MOVE:
+ c = CURSOR_MOVE;
+ break;
+ case TOOL_EDIT_PIVOT:
+ c = CURSOR_CROSS;
+ break;
+ case TOOL_PAN:
+ c = CURSOR_DRAG;
+ break;
+ case TOOL_RULER:
+ c = CURSOR_CROSS;
+ break;
+ default:
+ break;
+ }
+ if (pan_pressed) {
+ c = CURSOR_DRAG;
+ }
+ set_default_cursor_shape(c);
+}
+
+Control::CursorShape CanvasItemEditor::get_cursor_shape(const Point2 &p_pos) const {
// Compute an eventual rotation of the cursor
const CursorShape rotation_array[4] = { CURSOR_HSIZE, CURSOR_BDIAGSIZE, CURSOR_VSIZE, CURSOR_FDIAGSIZE };
int rotation_array_index = 0;
@@ -2601,26 +2595,8 @@ void CanvasItemEditor::_update_cursor() {
}
// Choose the correct cursor
- CursorShape c = CURSOR_ARROW;
+ CursorShape c = get_default_cursor_shape();
switch (drag_type) {
- case DRAG_NONE:
- switch (tool) {
- case TOOL_MOVE:
- c = CURSOR_MOVE;
- break;
- case TOOL_EDIT_PIVOT:
- c = CURSOR_CROSS;
- break;
- case TOOL_PAN:
- c = CURSOR_DRAG;
- break;
- case TOOL_RULER:
- c = CURSOR_CROSS;
- break;
- default:
- break;
- }
- break;
case DRAG_LEFT:
case DRAG_RIGHT:
c = rotation_array[rotation_array_index];
@@ -2662,16 +2638,7 @@ void CanvasItemEditor::_update_cursor() {
if (pan_pressed) {
c = CURSOR_DRAG;
}
-
- if (c != viewport->get_default_cursor_shape()) {
- viewport->set_default_cursor_shape(c);
-
- // Force refresh cursor if it's over the viewport.
- if (viewport->get_global_rect().has_point(get_global_mouse_position())) {
- DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)viewport->get_default_cursor_shape();
- DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
- }
- }
+ return c;
}
void CanvasItemEditor::_draw_text_at_position(Point2 p_position, String p_string, Side p_side) {
@@ -3869,7 +3836,7 @@ void CanvasItemEditor::_update_editor_settings() {
context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles")));
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
- pan_speed = int(EDITOR_GET("editors/panning/2d_editor_pan_speed"));
+ panner->set_scroll_speed(EDITOR_GET("editors/panning/2d_editor_pan_speed"));
warped_panning = bool(EDITOR_GET("editors/panning/warped_mouse_panning"));
}
@@ -3958,8 +3925,8 @@ void CanvasItemEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
select_sb->set_texture(get_theme_icon(SNAME("EditorRect2D"), SNAME("EditorIcons")));
- select_sb->set_margin_size_all(4);
- select_sb->set_default_margin_all(4);
+ select_sb->set_texture_margin_all(4);
+ select_sb->set_content_margin_all(4);
AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
@@ -3990,6 +3957,10 @@ void CanvasItemEditor::_selection_changed() {
}
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
+ if (!p_canvas_item) {
+ return;
+ }
+
Array selection = editor_selection->get_selected_nodes();
if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
_reset_drag();
@@ -5056,7 +5027,7 @@ CanvasItemEditor::CanvasItemEditor() {
zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
panner.instantiate();
- panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_scroll_callback), callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback));
+ panner->set_callbacks(callable_mp(this, &CanvasItemEditor::_pan_callback), callable_mp(this, &CanvasItemEditor::_zoom_callback));
viewport = memnew(CanvasItemEditorViewport(this));
viewport_scrollable->add_child(viewport);
@@ -5430,11 +5401,13 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) {
canvas_item_editor->show();
canvas_item_editor->set_physics_process(true);
RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), false);
+ RenderingServer::get_singleton()->viewport_set_environment_mode(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), RS::VIEWPORT_ENVIRONMENT_ENABLED);
} else {
canvas_item_editor->hide();
canvas_item_editor->set_physics_process(false);
RenderingServer::get_singleton()->viewport_set_disable_2d(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), true);
+ RenderingServer::get_singleton()->viewport_set_environment_mode(EditorNode::get_singleton()->get_scene_root()->get_viewport_rid(), RS::VIEWPORT_ENVIRONMENT_DISABLED);
}
}
@@ -5925,7 +5898,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
EditorNode::get_singleton()->get_gui_base()->add_child(selector);
selector->set_title(TTR("Change Default Type"));
selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
- selector->connect("cancelled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
+ selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
VBoxContainer *vbc = memnew(VBoxContainer);
selector->add_child(vbc);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index f4fcc8a3d2..ebe87a56f7 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -363,12 +363,10 @@ private:
Ref<ViewPanner> panner;
bool warped_panning = true;
- int pan_speed = 20;
- void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
- void _pan_callback(Vector2 p_scroll_vec);
- void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
+ void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
- bool _is_node_locked(const Node *p_node);
+ bool _is_node_locked(const Node *p_node) const;
bool _is_node_movable(const Node *p_node, bool p_popup_warning = false);
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false);
@@ -402,7 +400,7 @@ private:
void _prepare_grid_menu();
void _on_grid_menu_id_pressed(int p_id);
- List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
+ List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true) const;
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
void _expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true);
Rect2 _get_encompassing_rect(const Node *p_node);
@@ -552,6 +550,8 @@ public:
void focus_selection();
void center_at(const Point2 &p_pos);
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+
EditorSelection *editor_selection = nullptr;
CanvasItemEditor();
diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 723082c293..331b4749cc 100644
--- a/editor/plugins/cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_2d_editor_plugin.cpp
@@ -78,7 +78,7 @@ bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
}
} else if (pressed) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Set target_position"));
+ undo_redo->create_action(TTR("Set Target Position"));
undo_redo->add_do_property(node, "target_position", target_position);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_property(node, "target_position", original_target_position);
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index 470b90aa7f..3bf2b95c26 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -423,7 +423,7 @@ void EditorInspectorPluginControl::parse_group(Object *p_object, const String &p
add_custom_control(pos_warning);
}
-bool EditorInspectorPluginControl::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginControl::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
Control *control = Object::cast_to<Control>(p_object);
if (!control) {
return false;
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index 779637317d..19e004a390 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -129,7 +129,7 @@ class EditorInspectorPluginControl : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_group(Object *p_object, const String &p_group) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
// Toolbar controls.
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 28151800b6..224d221d9a 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -97,14 +97,10 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
debug_menu->add_separator();
debug_menu->add_submenu_item(TTR("Run Multiple Instances"), "run_instances");
- instances_menu->add_radio_check_item(TTR("Run 1 Instance"));
- instances_menu->set_item_metadata(0, 1);
- instances_menu->add_radio_check_item(TTR("Run 2 Instances"));
- instances_menu->set_item_metadata(1, 2);
- instances_menu->add_radio_check_item(TTR("Run 3 Instances"));
- instances_menu->set_item_metadata(2, 3);
- instances_menu->add_radio_check_item(TTR("Run 4 Instances"));
- instances_menu->set_item_metadata(3, 4);
+ for (int i = 1; i <= 4; i++) {
+ instances_menu->add_radio_check_item(vformat(TTRN("Run %d Instance", "Run %d Instances", i), i));
+ instances_menu->set_item_metadata(i - 1, i);
+ }
instances_menu->set_item_checked(0, true);
instances_menu->connect("index_pressed", callable_mp(this, &DebuggerEditorPlugin::_select_run_count));
debug_menu->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option));
diff --git a/editor/plugins/dedicated_server_export_plugin.cpp b/editor/plugins/dedicated_server_export_plugin.cpp
new file mode 100644
index 0000000000..013706034e
--- /dev/null
+++ b/editor/plugins/dedicated_server_export_plugin.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************/
+/* dedicated_server_export_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "dedicated_server_export_plugin.h"
+
+EditorExportPreset::FileExportMode DedicatedServerExportPlugin::_get_export_mode_for_path(const String &p_path) {
+ Ref<EditorExportPreset> preset = get_export_preset();
+ ERR_FAIL_COND_V(preset.is_null(), EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED);
+
+ EditorExportPreset::FileExportMode mode = preset->get_file_export_mode(p_path);
+ if (mode != EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED) {
+ return mode;
+ }
+
+ String path = p_path;
+ if (path.begins_with("res://")) {
+ path = path.substr(6);
+ }
+
+ Vector<String> parts = path.split("/");
+
+ while (parts.size() > 0) {
+ parts.resize(parts.size() - 1);
+
+ String test_path = "res://";
+ if (parts.size() > 0) {
+ test_path += String("/").join(parts) + "/";
+ }
+
+ mode = preset->get_file_export_mode(test_path);
+ if (mode != EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED) {
+ break;
+ }
+ }
+
+ return mode;
+}
+
+PackedStringArray DedicatedServerExportPlugin::_get_export_features(const Ref<EditorExportPlatform> &p_platform, bool p_debug) const {
+ PackedStringArray ret;
+
+ Ref<EditorExportPreset> preset = get_export_preset();
+ ERR_FAIL_COND_V(preset.is_null(), ret);
+
+ if (preset->is_dedicated_server()) {
+ ret.append("dedicated_server");
+ }
+ return ret;
+}
+
+uint64_t DedicatedServerExportPlugin::_get_customization_configuration_hash() const {
+ Ref<EditorExportPreset> preset = get_export_preset();
+ ERR_FAIL_COND_V(preset.is_null(), 0);
+
+ if (preset->get_export_filter() != EditorExportPreset::EXPORT_CUSTOMIZED) {
+ return 0;
+ }
+
+ return preset->get_customized_files().hash();
+}
+
+bool DedicatedServerExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) {
+ Ref<EditorExportPreset> preset = get_export_preset();
+ ERR_FAIL_COND_V(preset.is_null(), false);
+
+ current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
+
+ return preset->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED;
+}
+
+bool DedicatedServerExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) {
+ Ref<EditorExportPreset> preset = get_export_preset();
+ ERR_FAIL_COND_V(preset.is_null(), false);
+
+ current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
+
+ return preset->get_export_filter() == EditorExportPreset::EXPORT_CUSTOMIZED;
+}
+
+Node *DedicatedServerExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
+ // Simply set the export mode based on the scene path. All the real
+ // customization happens in _customize_resource().
+ current_export_mode = _get_export_mode_for_path(p_path);
+ return nullptr;
+}
+
+Ref<Resource> DedicatedServerExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
+ // If the resource has a path, we use that to get our export mode. But if it
+ // doesn't, we assume that this resource is embedded in the last resource with
+ // a path.
+ if (p_path != "") {
+ current_export_mode = _get_export_mode_for_path(p_path);
+ }
+
+ if (p_resource.is_valid() && current_export_mode == EditorExportPreset::MODE_FILE_STRIP && p_resource->has_method("create_placeholder")) {
+ Callable::CallError err;
+ Ref<Resource> result = const_cast<Resource *>(p_resource.ptr())->callp("create_placeholder", nullptr, 0, err);
+ if (err.error == Callable::CallError::CALL_OK) {
+ return result;
+ }
+ }
+
+ return Ref<Resource>();
+}
+
+void DedicatedServerExportPlugin::_end_customize_scenes() {
+ current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
+}
+
+void DedicatedServerExportPlugin::_end_customize_resources() {
+ current_export_mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
+}
diff --git a/editor/plugins/dedicated_server_export_plugin.h b/editor/plugins/dedicated_server_export_plugin.h
new file mode 100644
index 0000000000..cb014ae52d
--- /dev/null
+++ b/editor/plugins/dedicated_server_export_plugin.h
@@ -0,0 +1,58 @@
+/**************************************************************************/
+/* dedicated_server_export_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DEDICATED_SERVER_EXPORT_PLUGIN_H
+#define DEDICATED_SERVER_EXPORT_PLUGIN_H
+
+#include "editor/export/editor_export.h"
+
+class DedicatedServerExportPlugin : public EditorExportPlugin {
+private:
+ EditorExportPreset::FileExportMode current_export_mode;
+
+ EditorExportPreset::FileExportMode _get_export_mode_for_path(const String &p_path);
+
+protected:
+ String _get_name() const override { return "DedicatedServer"; }
+
+ PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_platform, bool p_debug) const override;
+ uint64_t _get_customization_configuration_hash() const override;
+
+ bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) override;
+ bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) override;
+
+ Node *_customize_scene(Node *p_root, const String &p_path) override;
+ Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path) override;
+
+ void _end_customize_scenes() override;
+ void _end_customize_resources() override;
+};
+
+#endif // DEDICATED_SERVER_EXPORT_PLUGIN_H
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index db4a103624..7618ec3903 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -310,7 +310,8 @@ void EditorPropertyFontMetaOverride::update_property() {
}
if (script_editor) {
- button_add = EditorInspector::create_inspector_action_button(TTR("Add Script"));
+ // TRANSLATORS: Script refers to a writing system.
+ button_add = EditorInspector::create_inspector_action_button(TTR("Add Script", "Locale"));
} else {
button_add = EditorInspector::create_inspector_action_button(TTR("Add Locale"));
}
@@ -874,7 +875,7 @@ bool EditorInspectorPluginFontVariation::can_handle(Object *p_object) {
return (Object::cast_to<FontVariation>(p_object) != nullptr) || (Object::cast_to<DynamicFontImportSettingsData>(p_object) != nullptr);
}
-bool EditorInspectorPluginFontVariation::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginFontVariation::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
if (p_path == "variation_opentype") {
add_property_editor(p_path, memnew(EditorPropertyOTVariation));
return true;
@@ -976,7 +977,7 @@ void EditorInspectorPluginFontPreview::parse_begin(Object *p_object) {
add_custom_control(editor);
}
-bool EditorInspectorPluginFontPreview::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginFontPreview::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
return false;
}
@@ -1035,7 +1036,7 @@ bool EditorInspectorPluginSystemFont::can_handle(Object *p_object) {
return Object::cast_to<SystemFont>(p_object) != nullptr;
}
-bool EditorInspectorPluginSystemFont::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginSystemFont::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
if (p_path == "font_names") {
EditorPropertyFontNamesArray *editor = memnew(EditorPropertyFontNamesArray);
editor->setup(p_type, p_hint_text);
diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h
index 150e97f7e2..6cea5967b2 100644
--- a/editor/plugins/font_config_plugin.h
+++ b/editor/plugins/font_config_plugin.h
@@ -212,7 +212,7 @@ class EditorInspectorPluginFontVariation : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
/*************************************************************************/
@@ -242,7 +242,7 @@ class EditorInspectorPluginFontPreview : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
/*************************************************************************/
@@ -269,7 +269,7 @@ class EditorInspectorPluginSystemFont : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
/*************************************************************************/
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index 72c234c1d4..477a094d01 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -77,7 +77,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_notification(int p_what) {
const Vector3i size = col_sdf->get_estimated_cell_size();
- const Vector3 extents = col_sdf->get_extents();
+ const Vector3 extents = col_sdf->get_size() / 2;
int data_size = 2;
const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 3676c2c222..2eb17b3f13 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -52,12 +52,12 @@ void GradientEditor::reverse_gradient() {
int GradientEditor::_get_point_from_pos(int x) {
int result = -1;
- int total_w = get_size().width - get_size().height - draw_spacing;
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
float min_distance = 1e20;
for (int i = 0; i < points.size(); i++) {
// Check if we clicked at point.
float distance = ABS(x - points[i].offset * total_w);
- float min = (handle_width / 2 * 1.7); // Make it easier to grab.
+ float min = handle_width * 0.85; // Allow the mouse to be more than half a handle width away for ease of grabbing.
if (distance <= min && distance < min_distance) {
result = i;
min_distance = distance;
@@ -198,116 +198,87 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- // Show color picker on double click.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
- grabbed = _get_point_from_pos(mb->get_position().x);
- _show_color_picker();
- accept_event();
- return;
- }
-
- // Delete point on right click.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
- grabbed = _get_point_from_pos(mb->get_position().x);
- if (grabbed != -1) {
- points.remove_at(grabbed);
- grabbed = -1;
- grabbing = false;
- queue_redraw();
- emit_signal(SNAME("ramp_changed"));
- accept_event();
- }
- }
-
- // Hold alt key to duplicate selected color.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) {
- int x = mb->get_position().x;
- grabbed = _get_point_from_pos(x);
- if (grabbed != -1) {
- int total_w = get_size().width - get_size().height - draw_spacing;
- Gradient::Point new_point = points[grabbed];
- new_point.offset = CLAMP(x / float(total_w), 0, 1);
+ if (mb.is_valid() && mb->is_pressed()) {
+ float adjusted_mb_x = mb->get_position().x - handle_width / 2;
- points.push_back(new_point);
- points.sort();
- for (int i = 0; i < points.size(); ++i) {
- if (points[i].offset == new_point.offset) {
- grabbed = i;
- break;
- }
+ // Delete point on right click.
+ if (mb->get_button_index() == MouseButton::RIGHT) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+ if (grabbed != -1) {
+ points.remove_at(grabbed);
+ grabbed = -1;
+ grabbing = false;
+ queue_redraw();
+ emit_signal(SNAME("ramp_changed"));
+ accept_event();
}
-
- emit_signal(SNAME("ramp_changed"));
- queue_redraw();
}
- }
- // Select.
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- queue_redraw();
- int x = mb->get_position().x;
- int total_w = get_size().width - get_size().height - draw_spacing;
+ // Hold Alt key to duplicate selected color.
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_alt_pressed()) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
- //Check if color selector was clicked.
- if (x > total_w + draw_spacing) {
- _show_color_picker();
- return;
- }
-
- grabbing = true;
+ if (grabbed != -1) {
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
+ Gradient::Point new_point = points[grabbed];
+ new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1);
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); ++i) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
+ }
- grabbed = _get_point_from_pos(x);
- //grab or select
- if (grabbed != -1) {
- return;
+ emit_signal(SNAME("ramp_changed"));
+ queue_redraw();
+ }
}
- // Insert point.
- Gradient::Point new_point;
- new_point.offset = CLAMP(x / float(total_w), 0, 1);
-
- Gradient::Point prev;
- Gradient::Point next;
+ // Select.
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ queue_redraw();
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
- int pos = -1;
- for (int i = 0; i < points.size(); i++) {
- if (points[i].offset < new_point.offset) {
- pos = i;
+ // Check if color selector was clicked or ramp was double-clicked.
+ if (adjusted_mb_x > total_w + draw_spacing) {
+ if (!mb->is_double_click()) {
+ _show_color_picker();
+ }
+ return;
+ } else if (mb->is_double_click()) {
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+ _show_color_picker();
+ accept_event();
+ return;
}
- }
- if (pos == -1) {
- prev.color = Color(0, 0, 0);
- prev.offset = 0;
- if (points.size()) {
- next = points[0];
- } else {
- next.color = Color(1, 1, 1);
- next.offset = 1.0;
- }
- } else {
- if (pos == points.size() - 1) {
- next.color = Color(1, 1, 1);
- next.offset = 1.0;
- } else {
- next = points[pos + 1];
+ grabbing = true;
+ grabbed = _get_point_from_pos(adjusted_mb_x);
+
+ // Grab or select.
+ if (grabbed != -1) {
+ return;
}
- prev = points[pos];
- }
- new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset));
+ // Insert point.
+ Gradient::Point new_point;
+ new_point.offset = CLAMP(adjusted_mb_x / float(total_w), 0, 1);
+ new_point.color = gradient->get_color_at_offset(new_point.offset);
- points.push_back(new_point);
- points.sort();
- for (int i = 0; i < points.size(); i++) {
- if (points[i].offset == new_point.offset) {
- grabbed = i;
- break;
+ points.push_back(new_point);
+ points.sort();
+ for (int i = 0; i < points.size(); i++) {
+ if (points[i].offset == new_point.offset) {
+ grabbed = i;
+ break;
+ }
}
- }
- emit_signal(SNAME("ramp_changed"));
+ emit_signal(SNAME("ramp_changed"));
+ }
}
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) {
@@ -321,18 +292,16 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && grabbing) {
- int total_w = get_size().width - get_size().height - draw_spacing;
-
- int x = mm->get_position().x;
-
- float newofs = CLAMP(x / float(total_w), 0, 1);
+ float adjusted_mm_x = mm->get_position().x - handle_width / 2;
+ int total_w = get_size().width - get_size().height - draw_spacing - handle_width;
+ float newofs = CLAMP(adjusted_mm_x / float(total_w), 0, 1);
// Snap to "round" coordinates if holding Ctrl.
// Be more precise if holding Shift as well.
if (mm->is_ctrl_pressed()) {
newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1);
} else if (mm->is_shift_pressed()) {
- // Snap to nearest point if holding just Shift
+ // Snap to nearest point if holding just Shift.
const float snap_threshold = 0.03;
float smallest_ofs = snap_threshold;
bool found = false;
@@ -421,7 +390,7 @@ void GradientEditor::_notification(int p_what) {
// Draw borders around color ramp if in focus.
if (has_focus()) {
- draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false);
+ draw_rect(Rect2(handle_width / 2, 0, total_w, h), Color(1, 1, 1, 0.9), false, 1);
}
// Draw point markers.
@@ -432,18 +401,18 @@ void GradientEditor::_notification(int p_what) {
draw_line(Vector2(points[i].offset * total_w + handle_width / 2, 0), Vector2(points[i].offset * total_w + handle_width / 2, h / 2), col);
Rect2 rect = Rect2(points[i].offset * total_w, h / 2, handle_width, h / 2);
draw_rect(rect, points[i].color, true);
- draw_rect(rect, col, false);
+ draw_rect(rect, col, false, 1);
if (grabbed == i) {
const Color focus_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
rect = rect.grow(-1);
if (has_focus()) {
- draw_rect(rect, focus_color, false);
+ draw_rect(rect, focus_color, false, 1);
} else {
- draw_rect(rect, focus_color.darkened(0.4), false);
+ draw_rect(rect, focus_color.darkened(0.4), false, 1);
}
rect = rect.grow(-1);
- draw_rect(rect, col, false);
+ draw_rect(rect, col, false, 1);
}
}
@@ -454,7 +423,7 @@ void GradientEditor::_notification(int p_what) {
// Draw with selection color.
draw_rect(Rect2(button_offset, 0, h, h), points[grabbed].color);
} else {
- // If no color selected draw grey color with 'X' on top.
+ // If no color selected draw gray color with 'X' on top.
draw_rect(Rect2(button_offset, 0, h, h), Color(0.5, 0.5, 0.5, 1));
draw_line(Vector2(button_offset, 0), Vector2(button_offset + h, h), Color(1, 1, 1, 0.6));
draw_line(Vector2(button_offset, h), Vector2(button_offset + h, 0), Color(1, 1, 1, 0.6));
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 1adcc2a3b4..519cfcaa94 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -35,12 +35,43 @@
void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
if (lightmap) {
- LightmapGI::BakeError err;
+ LightmapGI::BakeError err = LightmapGI::BAKE_ERROR_OK;
const uint64_t time_started = OS::get_singleton()->get_ticks_msec();
- if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
- err = lightmap->bake(lightmap, p_file, bake_func_step);
+ if (get_tree()->get_edited_scene_root()) {
+ Ref<LightmapGIData> lightmapGIData = lightmap->get_light_data();
+
+ if (lightmapGIData.is_valid()) {
+ String path = lightmapGIData->get_path();
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ err = LightmapGI::BAKE_ERROR_FOREIGN_DATA;
+ }
+ }
+ }
+
+ if (err == LightmapGI::BAKE_ERROR_OK) {
+ if (get_tree()->get_edited_scene_root() == lightmap) {
+ err = lightmap->bake(lightmap, p_file, bake_func_step);
+ } else {
+ err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step);
+ }
+ }
} else {
- err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step);
+ err = LightmapGI::BAKE_ERROR_NO_SCENE_ROOT;
}
bake_func_end(time_started);
@@ -59,16 +90,21 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
file_dialog->set_current_path(scene_path);
file_dialog->popup_file_dialog();
-
} break;
- case LightmapGI::BAKE_ERROR_NO_MESHES:
+ case LightmapGI::BAKE_ERROR_NO_MESHES: {
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
- break;
- case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE:
+ } break;
+ case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: {
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
- break;
+ } break;
+ case LightmapGI::BAKE_ERROR_NO_SCENE_ROOT: {
+ EditorNode::get_singleton()->show_warning(TTR("No editor scene root found."));
+ } break;
+ case LightmapGI::BAKE_ERROR_FOREIGN_DATA: {
+ EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene."));
+ } break;
default: {
- }
+ } break;
}
}
}
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 2981862291..cf8555d07d 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -232,8 +232,8 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
} break;
case MENU_OPTION_REMOVE_ITEM: {
String p = InspectorDock::get_inspector_singleton()->get_selected_path();
- if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) {
- to_erase = p.get_slice("/", 3).to_int();
+ if (p.begins_with("item") && p.get_slice_count("/") >= 2) {
+ to_erase = p.get_slice("/", 1).to_int();
cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase));
cd_remove->popup_centered(Size2(300, 60));
}
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp
index 21a1d839f0..dff92ced27 100644
--- a/editor/plugins/navigation_link_2d_editor_plugin.cpp
+++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp
@@ -65,20 +65,20 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- // Start location
- if (xform.xform(node->get_start_location()).distance_to(mb->get_position()) < grab_threshold) {
+ // Start position
+ if (xform.xform(node->get_start_position()).distance_to(mb->get_position()) < grab_threshold) {
start_grabbed = true;
- original_start_location = node->get_start_location();
+ original_start_position = node->get_start_position();
return true;
} else {
start_grabbed = false;
}
- // End location
- if (xform.xform(node->get_end_location()).distance_to(mb->get_position()) < grab_threshold) {
+ // End position
+ if (xform.xform(node->get_end_position()).distance_to(mb->get_position()) < grab_threshold) {
end_grabbed = true;
- original_end_location = node->get_end_location();
+ original_end_position = node->get_end_position();
return true;
} else {
@@ -87,10 +87,10 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
} else {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (start_grabbed) {
- undo_redo->create_action(TTR("Set start_location"));
- undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
+ undo_redo->create_action(TTR("Set start_position"));
+ undo_redo->add_do_method(node, "set_start_position", node->get_start_position());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(node, "set_start_location", original_start_location);
+ undo_redo->add_undo_method(node, "set_start_position", original_start_position);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
@@ -100,10 +100,10 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
}
if (end_grabbed) {
- undo_redo->create_action(TTR("Set end_location"));
- undo_redo->add_do_method(node, "set_end_location", node->get_end_location());
+ undo_redo->create_action(TTR("Set end_position"));
+ undo_redo->add_do_method(node, "set_end_position", node->get_end_position());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(node, "set_end_location", original_end_location);
+ undo_redo->add_undo_method(node, "set_end_position", original_end_position);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
@@ -120,14 +120,14 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
point = node->get_global_transform().affine_inverse().xform(point);
if (start_grabbed) {
- node->set_start_location(point);
+ node->set_start_position(point);
canvas_item_editor->update_viewport();
return true;
}
if (end_grabbed) {
- node->set_end_location(point);
+ node->set_end_position(point);
canvas_item_editor->update_viewport();
return true;
@@ -143,13 +143,13 @@ void NavigationLink2DEditor::forward_canvas_draw_over_viewport(Control *p_overla
}
Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Vector2 global_start_location = gt.xform(node->get_start_location());
- Vector2 global_end_location = gt.xform(node->get_end_location());
+ Vector2 global_start_position = gt.xform(node->get_start_position());
+ Vector2 global_end_position = gt.xform(node->get_end_position());
// Only drawing the handles here, since the debug rendering will fill in the rest.
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
- p_overlay->draw_texture(handle, global_start_location - handle->get_size() / 2);
- p_overlay->draw_texture(handle, global_end_location - handle->get_size() / 2);
+ p_overlay->draw_texture(handle, global_start_position - handle->get_size() / 2);
+ p_overlay->draw_texture(handle, global_end_position - handle->get_size() / 2);
}
void NavigationLink2DEditor::edit(NavigationLink2D *p_node) {
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.h b/editor/plugins/navigation_link_2d_editor_plugin.h
index 76444403d0..ea731ca2cd 100644
--- a/editor/plugins/navigation_link_2d_editor_plugin.h
+++ b/editor/plugins/navigation_link_2d_editor_plugin.h
@@ -43,10 +43,10 @@ class NavigationLink2DEditor : public Control {
NavigationLink2D *node = nullptr;
bool start_grabbed = false;
- Vector2 original_start_location;
+ Vector2 original_start_position;
bool end_grabbed = false;
- Vector2 original_end_location;
+ Vector2 original_end_position;
protected:
void _notification(int p_what);
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index bb71c27bff..bcb94b0f32 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -1805,7 +1805,7 @@ void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
} else {
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb);
- float d = ra.x * 2.0;
+ float d = ra.x * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -2099,7 +2099,7 @@ void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo,
Ref<BoxOccluder3D> bo = o;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (snap_enabled) {
d = Math::snapped(d, snap);
}
@@ -2109,7 +2109,7 @@ void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo,
}
Vector3 he = bo->get_size();
- he[p_id] = d * 2;
+ he[p_id] = d;
bo->set_size(he);
}
@@ -3184,7 +3184,7 @@ String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGiz
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
- return "Extents";
+ return "Size";
}
return "";
@@ -3198,7 +3198,7 @@ Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DG
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
- return Vector3(p_gizmo->get_node_3d()->call("get_extents"));
+ return Vector3(p_gizmo->get_node_3d()->call("get_size"));
}
return Variant();
@@ -3235,7 +3235,7 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
axis[p_id] = 1.0;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -3244,9 +3244,9 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
d = 0.001;
}
- Vector3 he = sn->call("get_extents");
+ Vector3 he = sn->call("get_size");
he[p_id] = d;
- sn->call("set_extents", he);
+ sn->call("set_size", he);
}
}
@@ -3268,14 +3268,14 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
if (p_cancel) {
- sn->call("set_extents", p_restore);
+ sn->call("set_size", p_restore);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Box Shape Extents"));
- ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
- ur->add_undo_method(sn, "set_extents", p_restore);
+ ur->create_action(TTR("Change Box Shape Size"));
+ ur->add_do_method(sn, "set_size", sn->call("get_size"));
+ ur->add_undo_method(sn, "set_size", p_restore);
ur->commit_action();
}
}
@@ -3342,8 +3342,8 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
Vector<Vector3> lines;
AABB aabb;
- aabb.position = -cs->call("get_extents").operator Vector3();
- aabb.size = aabb.position * -2;
+ aabb.size = cs->call("get_size").operator Vector3();
+ aabb.position = aabb.size / -2;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
@@ -3356,7 +3356,7 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 3; i++) {
Vector3 ax;
- ax[i] = cs->call("get_extents").operator Vector3()[i];
+ ax[i] = cs->call("get_size").operator Vector3()[i] / 2;
handles.push_back(ax);
}
@@ -3442,11 +3442,11 @@ int ReflectionProbeGizmoPlugin::get_priority() const {
String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
- return "Extents X";
+ return "Size X";
case 1:
- return "Extents Y";
+ return "Size Y";
case 2:
- return "Extents Z";
+ return "Size Z";
case 3:
return "Origin X";
case 4:
@@ -3460,7 +3460,7 @@ String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gi
Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
- return AABB(probe->get_extents(), probe->get_origin_offset());
+ return AABB(probe->get_origin_offset(), probe->get_size());
}
void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -3470,7 +3470,7 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
Transform3D gi = gt.affine_inverse();
if (p_id < 3) {
- Vector3 extents = probe->get_extents();
+ Vector3 size = probe->get_size();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -3482,7 +3482,7 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -3491,8 +3491,8 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
d = 0.001;
}
- extents[p_id] = d;
- probe->set_extents(extents);
+ size[p_id] = d;
+ probe->set_size(size);
} else {
p_id -= 3;
@@ -3526,17 +3526,17 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
AABB restore = p_restore;
if (p_cancel) {
- probe->set_extents(restore.position);
- probe->set_origin_offset(restore.size);
+ probe->set_origin_offset(restore.position);
+ probe->set_size(restore.size);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
+ ur->create_action(TTR("Change Probe Size"));
+ ur->add_do_method(probe, "set_size", probe->get_size());
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
- ur->add_undo_method(probe, "set_extents", restore.position);
- ur->add_undo_method(probe, "set_origin_offset", restore.size);
+ ur->add_undo_method(probe, "set_size", restore.size);
+ ur->add_undo_method(probe, "set_origin_offset", restore.position);
ur->commit_action();
}
@@ -3547,11 +3547,11 @@ void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> lines;
Vector<Vector3> internal_lines;
- Vector3 extents = probe->get_extents();
+ Vector3 size = probe->get_size();
AABB aabb;
- aabb.position = -extents;
- aabb.size = extents * 2;
+ aabb.position = -size / 2;
+ aabb.size = size;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
@@ -3593,7 +3593,7 @@ void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0);
+ p_gizmo->add_solid_box(solid_material, probe->get_size());
}
p_gizmo->add_unscaled_billboard(icon, 0.05);
@@ -3627,11 +3627,11 @@ int DecalGizmoPlugin::get_priority() const {
String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
- return "Extents X";
+ return "Size X";
case 1:
- return "Extents Y";
+ return "Size Y";
case 2:
- return "Extents Z";
+ return "Size Z";
}
return "";
@@ -3639,7 +3639,7 @@ String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p
Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
- return decal->get_extents();
+ return decal->get_size();
}
void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -3648,7 +3648,7 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bo
Transform3D gi = gt.affine_inverse();
- Vector3 extents = decal->get_extents();
+ Vector3 size = decal->get_size();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -3660,7 +3660,7 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bo
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -3669,8 +3669,8 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bo
d = 0.001;
}
- extents[p_id] = d;
- decal->set_extents(extents);
+ size[p_id] = d;
+ decal->set_size(size);
}
void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
@@ -3679,14 +3679,14 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
Vector3 restore = p_restore;
if (p_cancel) {
- decal->set_extents(restore);
+ decal->set_size(restore);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Decal Extents"));
- ur->add_do_method(decal, "set_extents", decal->get_extents());
- ur->add_undo_method(decal, "set_extents", restore);
+ ur->create_action(TTR("Change Decal Size"));
+ ur->add_do_method(decal, "set_size", decal->get_size());
+ ur->add_undo_method(decal, "set_size", restore);
ur->commit_action();
}
@@ -3696,11 +3696,11 @@ void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
Vector<Vector3> lines;
- Vector3 extents = decal->get_extents();
+ Vector3 size = decal->get_size();
AABB aabb;
- aabb.position = -extents;
- aabb.size = extents * 2;
+ aabb.position = -size / 2;
+ aabb.size = size;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
@@ -3718,8 +3718,9 @@ void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
- lines.push_back(Vector3(0, extents.y, 0));
- lines.push_back(Vector3(0, extents.y * 1.2, 0));
+ float half_size_y = size.y / 2;
+ lines.push_back(Vector3(0, half_size_y, 0));
+ lines.push_back(Vector3(0, half_size_y * 1.2, 0));
Vector<Vector3> handles;
@@ -3767,11 +3768,11 @@ int VoxelGIGizmoPlugin::get_priority() const {
String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
switch (p_id) {
case 0:
- return "Extents X";
+ return "Size X";
case 1:
- return "Extents Y";
+ return "Size Y";
case 2:
- return "Extents Z";
+ return "Size Z";
}
return "";
@@ -3779,7 +3780,7 @@ String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
- return probe->get_extents();
+ return probe->get_size();
}
void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -3788,7 +3789,7 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
Transform3D gt = probe->get_global_transform();
Transform3D gi = gt.affine_inverse();
- Vector3 extents = probe->get_extents();
+ Vector3 size = probe->get_size();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -3800,7 +3801,7 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -3809,8 +3810,8 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
d = 0.001;
}
- extents[p_id] = d;
- probe->set_extents(extents);
+ size[p_id] = d;
+ probe->set_size(size);
}
void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
@@ -3819,14 +3820,14 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
Vector3 restore = p_restore;
if (p_cancel) {
- probe->set_extents(restore);
+ probe->set_size(restore);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Probe Extents"));
- ur->add_do_method(probe, "set_extents", probe->get_extents());
- ur->add_undo_method(probe, "set_extents", restore);
+ ur->create_action(TTR("Change Probe Size"));
+ ur->add_do_method(probe, "set_size", probe->get_size());
+ ur->add_undo_method(probe, "set_size", restore);
ur->commit_action();
}
@@ -3840,11 +3841,11 @@ void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
Vector<Vector3> lines;
- Vector3 extents = probe->get_extents();
+ Vector3 size = probe->get_size();
static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 };
- AABB aabb = AABB(-extents, extents * 2);
+ AABB aabb = AABB(-size / 2, size);
int subdiv = subdivs[probe->get_subdiv()];
float cell_size = aabb.get_longest_axis_size() / subdiv;
@@ -4363,7 +4364,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
Ref<BoxShape3D> bs = s;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -4373,7 +4374,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
Vector3 he = bs->get_size();
- he[p_id] = d * 2;
+ he[p_id] = d;
bs->set_size(he);
}
@@ -4875,6 +4876,10 @@ NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() {
create_material("face_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color(), false, false, true);
create_material("edge_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_color());
create_material("edge_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_color());
+
+ Color baking_aabb_material_color = Color(0.8, 0.5, 0.7);
+ baking_aabb_material_color.a = 0.1;
+ create_material("baking_aabb_material", baking_aabb_material_color);
}
bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -4898,6 +4903,16 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
return;
}
+ AABB baking_aabb = navigationmesh->get_filter_baking_aabb();
+ if (baking_aabb.has_volume()) {
+ Vector3 baking_aabb_offset = navigationmesh->get_filter_baking_aabb_offset();
+
+ if (p_gizmo->is_selected()) {
+ Ref<Material> material = get_material("baking_aabb_material", p_gizmo);
+ p_gizmo->add_solid_box(material, baking_aabb.get_size(), baking_aabb.get_center() + baking_aabb_offset);
+ }
+ }
+
Vector<Vector3> vertices = navigationmesh->get_vertices();
const Vector3 *vr = vertices.ptr();
List<Face3> faces;
@@ -5057,8 +5072,8 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
Vector3::Axis up_axis = up_vector.max_axis_index();
- Vector3 start_location = link->get_start_location();
- Vector3 end_location = link->get_end_location();
+ Vector3 start_position = link->get_start_position();
+ Vector3 end_position = link->get_end_position();
Ref<Material> link_material = get_material("navigation_link_material", p_gizmo);
Ref<Material> link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo);
@@ -5068,10 +5083,10 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// Draw line between the points.
Vector<Vector3> lines;
- lines.append(start_location);
- lines.append(end_location);
+ lines.append(start_position);
+ lines.append(end_position);
- // Draw start location search radius
+ // Draw start position search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
@@ -5082,21 +5097,21 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
- lines.append(start_location + Vector3(0, a.x, a.y));
- lines.append(start_location + Vector3(0, b.x, b.y));
+ lines.append(start_position + Vector3(0, a.x, a.y));
+ lines.append(start_position + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
- lines.append(start_location + Vector3(a.x, 0, a.y));
- lines.append(start_location + Vector3(b.x, 0, b.y));
+ lines.append(start_position + Vector3(a.x, 0, a.y));
+ lines.append(start_position + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
- lines.append(start_location + Vector3(a.x, a.y, 0));
- lines.append(start_location + Vector3(b.x, b.y, 0));
+ lines.append(start_position + Vector3(a.x, a.y, 0));
+ lines.append(start_position + Vector3(b.x, b.y, 0));
break;
}
}
- // Draw end location search radius
+ // Draw end position search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
@@ -5107,16 +5122,16 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
- lines.append(end_location + Vector3(0, a.x, a.y));
- lines.append(end_location + Vector3(0, b.x, b.y));
+ lines.append(end_position + Vector3(0, a.x, a.y));
+ lines.append(end_position + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
- lines.append(end_location + Vector3(a.x, 0, a.y));
- lines.append(end_location + Vector3(b.x, 0, b.y));
+ lines.append(end_position + Vector3(a.x, 0, a.y));
+ lines.append(end_position + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
- lines.append(end_location + Vector3(a.x, a.y, 0));
- lines.append(end_location + Vector3(b.x, b.y, 0));
+ lines.append(end_position + Vector3(a.x, a.y, 0));
+ lines.append(end_position + Vector3(b.x, b.y, 0));
break;
}
}
@@ -5125,8 +5140,8 @@ void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(lines);
Vector<Vector3> handles;
- handles.append(start_location);
- handles.append(end_location);
+ handles.append(start_position);
+ handles.append(end_position);
p_gizmo->add_handles(handles, handles_material);
}
@@ -5136,7 +5151,7 @@ String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d());
- return p_id == 0 ? link->get_start_location() : link->get_end_location();
+ return p_id == 0 ? link->get_start_position() : link->get_end_position();
}
void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -5151,8 +5166,8 @@ void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
- Vector3 location = p_id == 0 ? link->get_start_location() : link->get_end_location();
- Plane move_plane = Plane(cam_dir, gt.xform(location));
+ Vector3 position = p_id == 0 ? link->get_start_position() : link->get_end_position();
+ Plane move_plane = Plane(cam_dir, gt.xform(position));
Vector3 intersection;
if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) {
@@ -5164,11 +5179,11 @@ void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
intersection.snap(Vector3(snap, snap, snap));
}
- location = gi.xform(intersection);
+ position = gi.xform(intersection);
if (p_id == 0) {
- link->set_start_location(location);
+ link->set_start_position(position);
} else if (p_id == 1) {
- link->set_end_location(location);
+ link->set_end_position(position);
}
}
@@ -5177,22 +5192,22 @@ void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
if (p_cancel) {
if (p_id == 0) {
- link->set_start_location(p_restore);
+ link->set_start_position(p_restore);
} else {
- link->set_end_location(p_restore);
+ link->set_end_position(p_restore);
}
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
- ur->create_action(TTR("Change Start Location"));
- ur->add_do_method(link, "set_start_location", link->get_start_location());
- ur->add_undo_method(link, "set_start_location", p_restore);
+ ur->create_action(TTR("Change Start Position"));
+ ur->add_do_method(link, "set_start_position", link->get_start_position());
+ ur->add_undo_method(link, "set_start_position", p_restore);
} else {
- ur->create_action(TTR("Change End Location"));
- ur->add_do_method(link, "set_end_location", link->get_end_location());
- ur->add_undo_method(link, "set_end_location", p_restore);
+ ur->create_action(TTR("Change End Position"));
+ ur->add_do_method(link, "set_end_position", link->get_end_position());
+ ur->add_undo_method(link, "set_end_position", p_restore);
}
ur->commit_action();
@@ -5902,11 +5917,11 @@ int FogVolumeGizmoPlugin::get_priority() const {
}
String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- return "Extents";
+ return "Size";
}
Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- return Vector3(p_gizmo->get_node_3d()->call("get_extents"));
+ return Vector3(p_gizmo->get_node_3d()->call("get_size"));
}
void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -5924,7 +5939,7 @@ void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id
axis[p_id] = 1.0;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
+ float d = ra[p_id] * 2;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
@@ -5933,23 +5948,23 @@ void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id
d = 0.001;
}
- Vector3 he = sn->call("get_extents");
+ Vector3 he = sn->call("get_size");
he[p_id] = d;
- sn->call("set_extents", he);
+ sn->call("set_size", he);
}
void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
Node3D *sn = p_gizmo->get_node_3d();
if (p_cancel) {
- sn->call("set_extents", p_restore);
+ sn->call("set_size", p_restore);
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Fog Volume Extents"));
- ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
- ur->add_undo_method(sn, "set_extents", p_restore);
+ ur->create_action(TTR("Change Fog Volume Size"));
+ ur->add_do_method(sn, "set_size", sn->call("get_size"));
+ ur->add_undo_method(sn, "set_size", p_restore);
ur->commit_action();
}
@@ -5968,8 +5983,8 @@ void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> lines;
AABB aabb;
- aabb.position = -cs->call("get_extents").operator Vector3();
- aabb.size = aabb.position * -2;
+ aabb.size = cs->call("get_size").operator Vector3();
+ aabb.position = aabb.size / -2;
for (int i = 0; i < 12; i++) {
Vector3 a, b;
@@ -5982,7 +5997,7 @@ void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 3; i++) {
Vector3 ax;
- ax[i] = cs->call("get_extents").operator Vector3()[i];
+ ax[i] = cs->call("get_size").operator Vector3()[i] / 2;
handles.push_back(ax);
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index f1b7ed73b8..96f5aeedf0 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1414,10 +1414,7 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const
// Recalculate orthogonalized scale without moving origin.
if (p_orthogonal) {
- s.basis = p_original_local.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1));
- // The scaled_orthogonal() does not require orthogonal Basis,
- // but it may make a bit skew by precision problems.
- s.basis.orthogonalize();
+ s.basis = p_original.basis.scaled_orthogonal(p_motion + Vector3(1, 1, 1));
}
}
@@ -1669,6 +1666,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
} break;
case TRANSFORM_Z_AXIS: {
_edit.plane = TRANSFORM_VIEW;
+ // TRANSLATORS: This refers to the transform of the view plane.
set_message(TTR("View Plane Transform."), 2);
} break;
@@ -3395,7 +3393,6 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_SHADELESS,
VIEW_DISPLAY_LIGHTING,
VIEW_DISPLAY_NORMAL_BUFFER,
- VIEW_DISPLAY_WIREFRAME,
VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO,
@@ -3425,7 +3422,6 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_UNSHADED,
Viewport::DEBUG_DRAW_LIGHTING,
Viewport::DEBUG_DRAW_NORMAL_BUFFER,
- Viewport::DEBUG_DRAW_WIREFRAME,
Viewport::DEBUG_DRAW_SHADOW_ATLAS,
Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS,
Viewport::DEBUG_DRAW_VOXEL_GI_ALBEDO,
@@ -3448,9 +3444,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_MOTION_VECTORS,
};
- int idx = 0;
-
- while (display_options[idx] != VIEW_MAX) {
+ for (int idx = 0; display_options[idx] != VIEW_MAX; idx++) {
int id = display_options[idx];
int item_idx = view_menu->get_popup()->get_item_index(id);
if (item_idx != -1) {
@@ -3464,7 +3458,6 @@ void Node3DEditorViewport::_menu_option(int p_option) {
if (id == p_option) {
viewport->set_debug_draw(debug_draw_modes[idx]);
}
- idx++;
}
} break;
}
@@ -4611,7 +4604,9 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
// TRANSLATORS: Refers to changing the scale of a node in the 3D editor.
set_message(TTR("Scaling:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
- motion = _edit.original.basis.inverse().xform(motion);
+ if (local_coords) {
+ motion = _edit.original.basis.inverse().xform(motion);
+ }
List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
@@ -4632,14 +4627,14 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
if (se->gizmo.is_valid()) {
for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
Transform3D xform = GE.value;
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // Force orthogonal with subgizmo.
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, _edit.plane != TRANSFORM_VIEW); // Force orthogonal with subgizmo.
if (!local_coords) {
new_xform = se->original.affine_inverse() * new_xform;
}
se->gizmo->set_subgizmo_transform(GE.key, new_xform);
}
} else {
- Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
+ Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS && _edit.plane != TRANSFORM_VIEW);
_transform_gizmo_apply(se->sp, new_xform, local_coords);
}
}
@@ -4712,7 +4707,9 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
// TRANSLATORS: Refers to changing the position of a node in the 3D editor.
set_message(TTR("Translating:") + " (" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
- motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion);
+ if (local_coords) {
+ motion = spatial_editor->get_gizmo_transform().basis.inverse().xform(motion);
+ }
List<Node *> &selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
@@ -4960,6 +4957,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION);
view_menu->get_popup()->add_separator();
+ // TRANSLATORS: "Normal" as in "normal life", not "normal vector".
view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 05fc464226..fb35668310 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -939,21 +939,13 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
}
-void Polygon2DEditor::_uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
- _uv_pan_callback(-p_scroll_vec * 32);
-}
-
-void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec) {
+void Polygon2DEditor::_uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
uv_hscroll->set_value(uv_hscroll->get_value() - p_scroll_vec.x);
uv_vscroll->set_value(uv_vscroll->get_value() - p_scroll_vec.y);
}
-void Polygon2DEditor::_uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- if (p_scroll_vec.y < 0) {
- uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * Math::abs(p_scroll_vec.y))));
- } else {
- uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * Math::abs(p_scroll_vec.y))));
- }
+void Polygon2DEditor::_uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
+ uv_zoom->set_value(uv_zoom->get_value() * p_zoom_factor);
}
void Polygon2DEditor::_uv_scroll_changed(real_t) {
@@ -1254,7 +1246,7 @@ Polygon2DEditor::Polygon2DEditor() {
uv_edit = memnew(AcceptDialog);
add_child(uv_edit);
uv_edit->set_title(TTR("Polygon 2D UV Editor"));
- uv_edit->connect("cancelled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
+ uv_edit->connect("canceled", callable_mp(this, &Polygon2DEditor::_uv_edit_popup_hide));
VBoxContainer *uv_main_vb = memnew(VBoxContainer);
uv_edit->add_child(uv_main_vb);
@@ -1478,7 +1470,7 @@ Polygon2DEditor::Polygon2DEditor() {
bone_scroll->add_child(bone_scroll_vb);
uv_panner.instantiate();
- uv_panner->set_callbacks(callable_mp(this, &Polygon2DEditor::_uv_scroll_callback), callable_mp(this, &Polygon2DEditor::_uv_pan_callback), callable_mp(this, &Polygon2DEditor::_uv_zoom_callback));
+ uv_panner->set_callbacks(callable_mp(this, &Polygon2DEditor::_uv_pan_callback), callable_mp(this, &Polygon2DEditor::_uv_zoom_callback));
uv_edit_draw->connect("draw", callable_mp(this, &Polygon2DEditor::_uv_draw));
uv_edit_draw->connect("gui_input", callable_mp(this, &Polygon2DEditor::_uv_input));
diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h
index 7246c08bea..2c55a5f631 100644
--- a/editor/plugins/polygon_2d_editor_plugin.h
+++ b/editor/plugins/polygon_2d_editor_plugin.h
@@ -90,9 +90,8 @@ class Polygon2DEditor : public AbstractPolygon2DEditor {
TextureRect *uv_icon_zoom = nullptr;
Ref<ViewPanner> uv_panner;
- void _uv_scroll_callback(Vector2 p_scroll_vec, bool p_alt);
- void _uv_pan_callback(Vector2 p_scroll_vec);
- void _uv_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ void _uv_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
+ void _uv_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
VBoxContainer *bone_scroll_main_vb = nullptr;
ScrollContainer *bone_scroll = nullptr;
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index d894ba4c4a..e8abecd115 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -229,7 +229,7 @@ bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) {
return true; // Can handle everything.
}
-bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) {
EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion);
add_property_editor(p_path, editor);
diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h
index f9b1a9f478..d27f0d30cc 100644
--- a/editor/plugins/root_motion_editor_plugin.h
+++ b/editor/plugins/root_motion_editor_plugin.h
@@ -63,7 +63,7 @@ class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
#endif // ROOT_MOTION_EDITOR_PLUGIN_H
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index e515b46b1e..ccbc7c3d74 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/file_access.h"
+#include "core/io/json.h"
#include "core/io/resource_loader.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -209,6 +210,27 @@ Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const {
return syntax_highlighter;
}
+////
+
+void EditorJSONSyntaxHighlighter::_update_cache() {
+ highlighter->set_text_edit(text_edit);
+ highlighter->clear_keyword_colors();
+ highlighter->clear_member_keyword_colors();
+ highlighter->clear_color_regions();
+
+ highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/symbol_color"));
+ highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/number_color"));
+
+ const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
+ highlighter->add_color_region("\"", "\"", string_color);
+}
+
+Ref<EditorSyntaxHighlighter> EditorJSONSyntaxHighlighter::_create() const {
+ Ref<EditorJSONSyntaxHighlighter> syntax_highlighter;
+ syntax_highlighter.instantiate();
+ return syntax_highlighter;
+}
+
////////////////////////////////////////////////////////////////////////////////
/*** SCRIPT EDITOR ****/
@@ -702,9 +724,10 @@ void ScriptEditor::_open_recent_script(int p_idx) {
if (FileAccess::exists(path)) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
+ ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
if (extensions.find(path.get_extension())) {
- Ref<Script> scr = ResourceLoader::load(path);
+ Ref<Resource> scr = ResourceLoader::load(path);
if (scr.is_valid()) {
edit(scr, true);
return;
@@ -1182,6 +1205,7 @@ void ScriptEditor::_menu_option(int p_option) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
+ ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
bool built_in = !path.is_resource_file();
if (extensions.find(path.get_extension()) || built_in) {
@@ -1196,7 +1220,7 @@ void ScriptEditor::_menu_option(int p_option) {
}
}
- Ref<Script> scr = ResourceLoader::load(path);
+ Ref<Resource> scr = ResourceLoader::load(path);
if (!scr.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + path, TTR("Error!"));
file_dialog_option = -1;
@@ -2319,12 +2343,23 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
}
se->add_syntax_highlighter(highlighter);
- if (scr != nullptr && !highlighter_set) {
- PackedStringArray languages = highlighter->_get_supported_languages();
+ if (highlighter_set) {
+ continue;
+ }
+
+ PackedStringArray languages = highlighter->_get_supported_languages();
+ // If script try language, else use extension.
+ if (scr != nullptr) {
if (languages.has(scr->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
+ continue;
+ }
+
+ if (languages.has(p_resource->get_path().get_extension())) {
+ se->set_syntax_highlighter(highlighter);
+ highlighter_set = true;
}
}
@@ -2483,7 +2518,7 @@ void ScriptEditor::save_all_scripts() {
} else {
// For built-in scripts, save their scenes instead.
const String scene_path = edited_res->get_path().get_slice("::", 0);
- if (!scenes_to_save.has(scene_path)) {
+ if (!scene_path.is_empty() && !scenes_to_save.has(scene_path)) {
scenes_to_save.push_back(scene_path);
}
}
@@ -2528,7 +2563,7 @@ void ScriptEditor::reload_scripts(bool p_refresh_only) {
}
Ref<Script> scr = edited_res;
- if (scr != nullptr) {
+ if (scr.is_valid()) {
Ref<Script> rel_scr = ResourceLoader::load(scr->get_path(), scr->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_CONTINUE(!rel_scr.is_valid());
scr->set_source_code(rel_scr->get_source_code());
@@ -2536,13 +2571,17 @@ void ScriptEditor::reload_scripts(bool p_refresh_only) {
scr->reload(true);
}
+ Ref<JSON> json = edited_res;
+ if (json != nullptr) {
+ Ref<JSON> rel_json = ResourceLoader::load(json->get_path(), json->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_json.is_valid());
+ json->parse(rel_json->get_parsed_text(), true);
+ json->set_last_modified_time(rel_json->get_last_modified_time());
+ }
+
Ref<TextFile> text_file = edited_res;
- if (text_file != nullptr) {
- Error err;
- Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err);
- ERR_CONTINUE(!rel_text_file.is_valid());
- text_file->set_text(rel_text_file->get_text());
- text_file->set_last_modified_time(rel_text_file->get_last_modified_time());
+ if (text_file.is_valid()) {
+ text_file->reload_from_file();
}
}
@@ -2568,8 +2607,9 @@ void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const
Ref<Resource> ScriptEditor::open_file(const String &p_file) {
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
+ ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
if (extensions.find(p_file.get_extension())) {
- Ref<Script> scr = ResourceLoader::load(p_file);
+ Ref<Resource> scr = ResourceLoader::load(p_file);
if (!scr.is_valid()) {
EditorNode::get_singleton()->show_warning(TTR("Could not load file at:") + "\n\n" + p_file, TTR("Error!"));
return Ref<Resource>();
@@ -2870,8 +2910,8 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data
if (file.is_empty() || !FileAccess::exists(file)) {
continue;
}
- if (ResourceLoader::exists(file, "Script")) {
- Ref<Script> scr = ResourceLoader::load(file);
+ if (ResourceLoader::exists(file, "Script") || ResourceLoader::exists(file, "JSON")) {
+ Ref<Resource> scr = ResourceLoader::load(file);
if (scr.is_valid()) {
return true;
}
@@ -2951,7 +2991,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
continue;
}
- if (!ResourceLoader::exists(file, "Script") && !textfile_extensions.has(file.get_extension())) {
+ if (!ResourceLoader::exists(file, "Script") && !ResourceLoader::exists(file, "JSON") && !textfile_extensions.has(file.get_extension())) {
continue;
}
@@ -3109,6 +3149,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
HashSet<String> loaded_scripts;
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
+ ResourceLoader::get_recognized_extensions_for_type("JSON", &extensions);
for (int i = 0; i < scripts.size(); i++) {
String path = scripts[i];
@@ -3127,7 +3168,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
loaded_scripts.insert(path);
if (extensions.find(path.get_extension())) {
- Ref<Script> scr = ResourceLoader::load(path);
+ Ref<Resource> scr = ResourceLoader::load(path);
if (!scr.is_valid()) {
continue;
}
@@ -3481,6 +3522,12 @@ void ScriptEditor::_open_script_request(const String &p_path) {
return;
}
+ Ref<JSON> json = ResourceLoader::load(p_path);
+ if (json.is_valid()) {
+ script_editor->edit(json, false);
+ return;
+ }
+
Error err;
Ref<TextFile> text_file = script_editor->_load_text_file(p_path, &err);
if (text_file.is_valid()) {
@@ -3543,7 +3590,8 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
return;
} else {
Ref<Script> scr = res;
- if (scr.is_valid()) {
+ Ref<JSON> json = res;
+ if (scr.is_valid() || json.is_valid()) {
edit(scr);
ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor());
@@ -3946,6 +3994,10 @@ ScriptEditor::ScriptEditor() {
add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), SNAME("EditorStyles")));
tab_container->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditor"), SNAME("EditorStyles")));
+
+ Ref<EditorJSONSyntaxHighlighter> json_syntax_highlighter;
+ json_syntax_highlighter.instantiate();
+ register_syntax_highlighter(json_syntax_highlighter);
}
ScriptEditor::~ScriptEditor() {
@@ -3967,6 +4019,8 @@ void ScriptEditorPlugin::edit(Object *p_object) {
}
}
script_editor->edit(p_script);
+ } else if (Object::cast_to<JSON>(p_object)) {
+ script_editor->edit(Object::cast_to<JSON>(p_object));
} else if (Object::cast_to<TextFile>(p_object)) {
script_editor->edit(Object::cast_to<TextFile>(p_object));
}
@@ -3981,6 +4035,10 @@ bool ScriptEditorPlugin::handles(Object *p_object) const {
return true;
}
+ if (Object::cast_to<JSON>(p_object)) {
+ return true;
+ }
+
return p_object->is_class("Script");
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 988d07621c..f8e684ae34 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -96,6 +96,24 @@ public:
virtual Ref<EditorSyntaxHighlighter> _create() const override;
};
+class EditorJSONSyntaxHighlighter : public EditorSyntaxHighlighter {
+ GDCLASS(EditorJSONSyntaxHighlighter, EditorSyntaxHighlighter)
+
+private:
+ Ref<CodeHighlighter> highlighter;
+
+public:
+ virtual void _update_cache() override;
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override { return highlighter->get_line_syntax_highlighting(p_line); }
+
+ virtual PackedStringArray _get_supported_languages() const override { return PackedStringArray{ "json" }; }
+ virtual String _get_name() const override { return TTR("JSON"); }
+
+ virtual Ref<EditorSyntaxHighlighter> _create() const override;
+
+ EditorJSONSyntaxHighlighter() { highlighter.instantiate(); }
+};
+
///////////////////////////////////////////////////////////////////////////////
class ScriptEditorQuickOpen : public ConfirmationDialog {
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 6bb725f7a0..9fe1d8af99 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -252,12 +252,14 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) {
} else if (p_line.get_type() == Variant::DICTIONARY) {
Dictionary meta = p_line.operator Dictionary();
const int line = meta["line"].operator int64_t() - 1;
+ const String code = meta["code"].operator String();
+ const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
CodeEdit *text_editor = code_editor->get_text_editor();
String prev_line = line > 0 ? text_editor->get_line(line - 1) : "";
if (prev_line.contains("@warning_ignore")) {
const int closing_bracket_idx = prev_line.find(")");
- const String text_to_insert = ", " + meta["code"].operator String();
+ const String text_to_insert = ", " + code.quote(quote_style);
prev_line = prev_line.insert(closing_bracket_idx, text_to_insert);
text_editor->set_line(line - 1, prev_line);
} else {
@@ -268,7 +270,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) {
} else {
annotation_indent = String(" ").repeat(text_editor->get_indent_size() * indent);
}
- text_editor->insert_line_at(line, annotation_indent + "@warning_ignore(" + meta["code"].operator String() + ")");
+ text_editor->insert_line_at(line, annotation_indent + "@warning_ignore(" + code.quote(quote_style) + ")");
}
_validate_script();
@@ -1360,11 +1362,36 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->remove_all_bookmarks();
} break;
case DEBUG_TOGGLE_BREAKPOINT: {
- for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
- int line = tx->get_caret_line(caret_idx);
- bool dobreak = !tx->is_line_breakpointed(line);
- tx->set_line_as_breakpoint(line, dobreak);
- EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak);
+ Vector<int> caret_edit_order = tx->get_caret_index_edit_order();
+ caret_edit_order.reverse();
+ int last_line = -1;
+ for (const int &c : caret_edit_order) {
+ int from = tx->has_selection(c) ? tx->get_selection_from_line(c) : tx->get_caret_line(c);
+ from += from == last_line ? 1 : 0;
+ int to = tx->has_selection(c) ? tx->get_selection_to_line(c) : tx->get_caret_line(c);
+ if (to < from) {
+ continue;
+ }
+ // Check first if there's any lines with breakpoints in the selection.
+ bool selection_has_breakpoints = false;
+ for (int line = from; line <= to; line++) {
+ if (tx->is_line_breakpointed(line)) {
+ selection_has_breakpoints = true;
+ break;
+ }
+ }
+
+ // Set breakpoint on caret or remove all bookmarks from the selection.
+ if (!selection_has_breakpoints) {
+ if (tx->get_caret_line(c) != last_line) {
+ tx->set_line_as_breakpoint(tx->get_caret_line(c), true);
+ }
+ } else {
+ for (int line = from; line <= to; line++) {
+ tx->set_line_as_breakpoint(line, false);
+ }
+ }
+ last_line = to;
}
} break;
case DEBUG_REMOVE_ALL_BREAKPOINTS: {
@@ -1818,30 +1845,72 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
color_position.x = row;
color_position.y = col;
- int begin = 0;
- int end = 0;
- bool valid = false;
+ int begin = -1;
+ int end = -1;
+ enum EXPRESSION_PATTERNS {
+ NOT_PARSED,
+ RGBA_PARAMETER, // Color(float,float,float) or Color(float,float,float,float)
+ COLOR_NAME, // Color.COLOR_NAME
+ } expression_pattern = NOT_PARSED;
+
for (int i = col; i < line.length(); i++) {
if (line[i] == '(') {
+ if (expression_pattern == NOT_PARSED) {
+ begin = i;
+ expression_pattern = RGBA_PARAMETER;
+ } else {
+ // Method call or '(' appearing twice.
+ expression_pattern = NOT_PARSED;
+
+ break;
+ }
+ } else if (expression_pattern == RGBA_PARAMETER && line[i] == ')' && end < 0) {
+ end = i + 1;
+
+ break;
+ } else if (expression_pattern == NOT_PARSED && line[i] == '.') {
begin = i;
+ expression_pattern = COLOR_NAME;
+ } else if (expression_pattern == COLOR_NAME && end < 0 && (line[i] == ' ' || line[i] == '\t')) {
+ // Including '.' and spaces.
continue;
- } else if (line[i] == ')') {
- end = i + 1;
- valid = true;
+ } else if (expression_pattern == COLOR_NAME && !(line[i] == '_' || ('A' <= line[i] && line[i] <= 'Z'))) {
+ end = i;
+
break;
}
}
- if (valid) {
- color_args = line.substr(begin, end - begin);
- String stripped = color_args.replace(" ", "").replace("(", "").replace(")", "");
- PackedFloat64Array color = stripped.split_floats(",");
- if (color.size() > 2) {
- float alpha = color.size() > 3 ? color[3] : 1.0f;
- color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
- }
+
+ switch (expression_pattern) {
+ case RGBA_PARAMETER: {
+ color_args = line.substr(begin, end - begin);
+ String stripped = color_args.replace(" ", "").replace("\t", "").replace("(", "").replace(")", "");
+ PackedFloat64Array color = stripped.split_floats(",");
+ if (color.size() > 2) {
+ float alpha = color.size() > 3 ? color[3] : 1.0f;
+ color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha));
+ }
+ } break;
+ case COLOR_NAME: {
+ if (end < 0) {
+ end = line.length();
+ }
+ color_args = line.substr(begin, end - begin);
+ const String color_name = color_args.replace(" ", "").replace("\t", "").replace(".", "");
+ const int color_index = Color::find_named_color(color_name);
+ if (0 <= color_index) {
+ const Color color_constant = Color::get_named_color(color_index);
+ color_picker->set_pick_color(color_constant);
+ } else {
+ has_color = false;
+ }
+ } break;
+ default:
+ has_color = false;
+ break;
+ }
+ if (has_color) {
color_panel->set_position(get_screen_position() + local_pos);
- } else {
- has_color = false;
}
}
_make_context_menu(tx->has_selection(), has_color, foldable, open_docs, goto_definition, local_pos);
@@ -2159,7 +2228,7 @@ ScriptTextEditor::ScriptTextEditor() {
connection_info_dialog = memnew(ConnectionInfoDialog);
- SET_DRAG_FORWARDING_GCD(code_editor, ScriptTextEditor);
+ SET_DRAG_FORWARDING_GCD(code_editor->get_text_editor(), ScriptTextEditor);
}
ScriptTextEditor::~ScriptTextEditor() {
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 3ee9823f3a..120cfbdefb 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -266,15 +266,15 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
if (!skeleton) {
return;
}
- const int bone_len = skeleton->get_bone_count();
- if (!bone_len) {
+ const int bone_count = skeleton->get_bone_count();
+ if (!bone_count) {
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
- for (int i = 0; i < bone_len; i++) {
+ for (int i = 0; i < bone_count; i++) {
ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i));
ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i));
ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i));
@@ -333,15 +333,15 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
if (!skeleton) {
return;
}
- const int bone_len = skeleton->get_bone_count();
- if (!bone_len) {
+ const int bone_count = skeleton->get_bone_count();
+ if (!bone_count) {
return;
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
- for (int i = 0; i < bone_len; i++) {
+ for (int i = 0; i < bone_count; i++) {
ur->add_do_method(skeleton, "set_bone_rest", i, skeleton->get_bone_pose(i));
ur->add_undo_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i));
}
@@ -362,57 +362,56 @@ void Skeleton3DEditor::create_physical_skeleton() {
ERR_FAIL_COND(!get_tree());
Node *owner = get_tree()->get_edited_scene_root();
- const int bc = skeleton->get_bone_count();
+ const int bone_count = skeleton->get_bone_count();
- if (!bc) {
+ if (!bone_count) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Cannot create a physical skeleton for a Skeleton3D node with no bones.")));
return;
}
Vector<BoneInfo> bones_infos;
- bones_infos.resize(bc);
+ bones_infos.resize(bone_count);
- if (bc > 0) {
- ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
- for (int bone_id = 0; bc > bone_id; ++bone_id) {
- const int parent = skeleton->get_bone_parent(bone_id);
+ ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
+ for (int bone_id = 0; bone_count > bone_id; ++bone_id) {
+ const int parent = skeleton->get_bone_parent(bone_id);
- if (parent < 0) {
- bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
- } else {
- const int parent_parent = skeleton->get_bone_parent(parent);
-
- bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
-
- // Create physical bone on parent.
- if (!bones_infos[parent].physical_bone) {
- PhysicalBone3D *physical_bone = create_physical_bone(parent, bone_id, bones_infos);
- if (physical_bone && physical_bone->get_child(0)) {
- CollisionShape3D *collision_shape = Object::cast_to<CollisionShape3D>(physical_bone->get_child(0));
- if (collision_shape) {
- bones_infos.write[parent].physical_bone = physical_bone;
-
- ur->add_do_method(skeleton, "add_child", physical_bone);
- ur->add_do_method(physical_bone, "set_owner", owner);
- ur->add_do_method(collision_shape, "set_owner", owner);
- ur->add_do_property(physical_bone, "bone_name", skeleton->get_bone_name(parent));
-
- // Create joint between parent of parent.
- if (parent_parent != -1) {
- ur->add_do_method(physical_bone, "set_joint_type", PhysicalBone3D::JOINT_TYPE_PIN);
- }
+ if (parent < 0) {
+ bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
+ } else {
+ const int parent_parent = skeleton->get_bone_parent(parent);
+
+ bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
+
+ // Create physical bone on parent.
+ if (!bones_infos[parent].physical_bone) {
+ PhysicalBone3D *physical_bone = create_physical_bone(parent, bone_id, bones_infos);
+ if (physical_bone && physical_bone->get_child(0)) {
+ CollisionShape3D *collision_shape = Object::cast_to<CollisionShape3D>(physical_bone->get_child(0));
+ if (collision_shape) {
+ bones_infos.write[parent].physical_bone = physical_bone;
+
+ ur->add_do_method(skeleton, "add_child", physical_bone);
+ ur->add_do_method(physical_bone, "set_owner", owner);
+ ur->add_do_method(collision_shape, "set_owner", owner);
+ ur->add_do_property(physical_bone, "bone_name", skeleton->get_bone_name(parent));
+
+ // Create joint between parent of parent.
+ if (parent_parent != -1) {
+ ur->add_do_method(physical_bone, "set_joint_type", PhysicalBone3D::JOINT_TYPE_PIN);
+ }
- ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, physical_bone);
- ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, collision_shape);
+ ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, physical_bone);
+ ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, collision_shape);
- ur->add_do_reference(physical_bone);
- ur->add_undo_method(skeleton, "remove_child", physical_bone);
- }
+ ur->add_do_reference(physical_bone);
+ ur->add_undo_method(skeleton, "remove_child", physical_bone);
}
}
}
}
- ur->commit_action();
}
+ ur->commit_action();
}
PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) {
@@ -457,6 +456,11 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
}
void Skeleton3DEditor::export_skeleton_profile() {
+ if (!skeleton->get_bone_count()) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Cannot export a SkeletonProfile for a Skeleton3D node with no bones.")));
+ return;
+ }
+
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Export Skeleton Profile As..."));
@@ -481,9 +485,9 @@ void Skeleton3DEditor::_file_selected(const String &p_file) {
Vector2 position_max;
Vector2 position_min;
- int len = skeleton->get_bone_count();
- sp->set_bone_size(len);
- for (int i = 0; i < len; i++) {
+ const int bone_count = skeleton->get_bone_count();
+ sp->set_bone_size(bone_count);
+ for (int i = 0; i < bone_count; i++) {
sp->set_bone_name(i, skeleton->get_bone_name(i));
int parent = skeleton->get_bone_parent(i);
if (parent >= 0) {
@@ -509,7 +513,7 @@ void Skeleton3DEditor::_file_selected(const String &p_file) {
Vector2 center = Vector2((position_max.x + position_min.x) * 0.5, (position_max.y + position_min.y) * 0.5);
float nrm = MAX(bound.x, bound.y);
if (nrm > 0) {
- for (int i = 0; i < len; i++) {
+ for (int i = 0; i < bone_count; i++) {
handle_positions.write[i] = (handle_positions[i] - center) / nrm * 0.9;
sp->set_handle_offset(i, Vector2(0.5 + handle_positions[i].x, 0.5 - handle_positions[i].y));
}
@@ -980,25 +984,31 @@ void Skeleton3DEditor::_draw_gizmo() {
}
void Skeleton3DEditor::_draw_handles() {
- handles_mesh_instance->show();
+ const int bone_count = skeleton->get_bone_count();
- const int bone_len = skeleton->get_bone_count();
handles_mesh->clear_surfaces();
- handles_mesh->surface_begin(Mesh::PRIMITIVE_POINTS);
- for (int i = 0; i < bone_len; i++) {
- Color c;
- if (i == selected_bone) {
- c = Color(1, 1, 0);
- } else {
- c = Color(0.1, 0.25, 0.8);
+ if (bone_count) {
+ handles_mesh_instance->show();
+
+ handles_mesh->surface_begin(Mesh::PRIMITIVE_POINTS);
+
+ for (int i = 0; i < bone_count; i++) {
+ Color c;
+ if (i == selected_bone) {
+ c = Color(1, 1, 0);
+ } else {
+ c = Color(0.1, 0.25, 0.8);
+ }
+ Vector3 point = skeleton->get_bone_global_pose(i).origin;
+ handles_mesh->surface_set_color(c);
+ handles_mesh->surface_add_vertex(point);
}
- Vector3 point = skeleton->get_bone_global_pose(i).origin;
- handles_mesh->surface_set_color(c);
- handles_mesh->surface_add_vertex(point);
+ handles_mesh->surface_end();
+ handles_mesh->surface_set_material(0, handle_material);
+ } else {
+ handles_mesh_instance->hide();
}
- handles_mesh->surface_end();
- handles_mesh->surface_set_material(0, handle_material);
}
TreeItem *Skeleton3DEditor::_find(TreeItem *p_node, const NodePath &p_path) {
@@ -1253,8 +1263,8 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi
Transform3D gt = skeleton->get_global_transform();
int closest_idx = -1;
real_t closest_dist = 1e10;
- const int bone_len = skeleton->get_bone_count();
- for (int i = 0; i < bone_len; i++) {
+ const int bone_count = skeleton->get_bone_count();
+ for (int i = 0; i < bone_count; i++) {
Vector3 joint_pos_3d = gt.xform(skeleton->get_bone_global_pose(i).origin);
Vector2 joint_pos_2d = p_camera->unproject_position(joint_pos_3d);
real_t dist_3d = ray_from.distance_to(joint_pos_3d);
@@ -1266,8 +1276,6 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi
}
if (closest_idx >= 0) {
- WARN_PRINT("ray:");
- WARN_PRINT(itos(closest_idx));
se->select_bone(closest_idx);
return closest_idx;
}
@@ -1291,7 +1299,7 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
Transform3D original_to_local;
int parent_idx = skeleton->get_bone_parent(p_id);
if (parent_idx >= 0) {
- original_to_local = original_to_local * skeleton->get_bone_global_pose(parent_idx);
+ original_to_local = skeleton->get_bone_global_pose(parent_idx);
}
Basis to_local = original_to_local.get_basis().inverse();
@@ -1349,6 +1357,10 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
+ if (!skeleton->get_bone_count()) {
+ return;
+ }
+
int selected = -1;
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
if (se) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 74c9286325..20b3cf3618 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -40,7 +40,6 @@
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
-#include "scene/3d/sprite_3d.h"
#include "scene/gui/center_container.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/panel_container.h"
@@ -252,8 +251,7 @@ void SpriteFramesEditor::_sheet_add_frames() {
const Size2i separation = _get_separation();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add Frame"));
-
+ undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
int fc = frames->get_frame_count(edited_anim);
for (const int &E : frames_selected) {
@@ -265,8 +263,8 @@ void SpriteFramesEditor::_sheet_add_frames() {
at->set_atlas(split_sheet_preview->get_texture());
at->set_region(Rect2(offset + frame_coords * (frame_size + separation), frame_size));
- undo_redo->add_do_method(frames, "add_frame", edited_anim, at, 1.0, -1);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc);
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, at, 1.0, -1);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, fc);
}
undo_redo->add_do_method(this, "_update_library");
@@ -415,8 +413,24 @@ void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) {
void SpriteFramesEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_ENTER_TREE: {
+ get_tree()->connect("node_removed", callable_mp(this, &SpriteFramesEditor::_node_removed));
+
+ [[fallthrough]];
+ }
case NOTIFICATION_THEME_CHANGED: {
+ autoplay_icon = get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons"));
+ stop_icon = get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ pause_icon = get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"));
+ _update_stop_icon();
+
+ autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
+ anim_loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
+ play->set_icon(get_theme_icon(SNAME("PlayStart"), SNAME("EditorIcons")));
+ play_from->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
+ play_bw->set_icon(get_theme_icon(SNAME("PlayStartBackwards"), SNAME("EditorIcons")));
+ play_bw_from->set_icon(get_theme_icon(SNAME("PlayBackwards"), SNAME("EditorIcons")));
+
load->set_icon(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")));
load_sheet->set_icon(get_theme_icon(SNAME("SpriteSheet"), SNAME("EditorIcons")));
copy->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
@@ -441,6 +455,10 @@ void SpriteFramesEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
add_theme_constant_override("autohide", 1); // Fixes the dragger always showing up.
} break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &SpriteFramesEditor::_node_removed));
+ } break;
}
}
@@ -471,14 +489,14 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add Frame"));
+ undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
int fc = frames->get_frame_count(edited_anim);
int count = 0;
for (const Ref<Texture2D> &E : resources) {
- undo_redo->add_do_method(frames, "add_frame", edited_anim, E, 1.0, p_at_pos == -1 ? -1 : p_at_pos + count);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos);
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, E, 1.0, p_at_pos == -1 ? -1 : p_at_pos + count);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, p_at_pos == -1 ? fc : p_at_pos);
count++;
}
undo_redo->add_do_method(this, "_update_library");
@@ -542,9 +560,9 @@ void SpriteFramesEditor::_paste_pressed() {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Paste Frame"));
- undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, frames->get_frame_count(edited_anim));
+ undo_redo->create_action(TTR("Paste Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, duration);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, frames->get_frame_count(edited_anim));
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -585,9 +603,9 @@ void SpriteFramesEditor::_empty_pressed() {
Ref<Texture2D> texture;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add Empty"));
- undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from);
+ undo_redo->create_action(TTR("Add Empty"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, from);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, from);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -609,9 +627,9 @@ void SpriteFramesEditor::_empty2_pressed() {
Ref<Texture2D> texture;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add Empty"));
- undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from + 1);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from + 1);
+ undo_redo->create_action(TTR("Add Empty"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, from + 1);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, from + 1);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -633,11 +651,11 @@ void SpriteFramesEditor::_up_pressed() {
sel -= 1;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Move Frame"));
- undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
- undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
- undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
- undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
+ undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
+ undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
+ undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
+ undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -659,11 +677,11 @@ void SpriteFramesEditor::_down_pressed() {
sel += 1;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Move Frame"));
- undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
- undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
- undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
- undo_redo->add_undo_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
+ undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
+ undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
+ undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
+ undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -682,15 +700,15 @@ void SpriteFramesEditor::_delete_pressed() {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Delete Resource"));
- undo_redo->add_do_method(frames, "remove_frame", edited_anim, to_delete);
- undo_redo->add_undo_method(frames, "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete);
+ undo_redo->create_action(TTR("Delete Resource"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "remove_frame", edited_anim, to_delete);
+ undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
}
-void SpriteFramesEditor::_animation_select() {
+void SpriteFramesEditor::_animation_selected() {
if (updating) {
return;
}
@@ -705,9 +723,42 @@ void SpriteFramesEditor::_animation_select() {
TreeItem *selected = animations->get_selected();
ERR_FAIL_COND(!selected);
edited_anim = selected->get_text(0);
+
+ if (animated_sprite) {
+ sprite_node_updating = true;
+ animated_sprite->call("set_animation", edited_anim);
+ sprite_node_updating = false;
+ }
+
_update_library(true);
}
+void SpriteFramesEditor::_sync_animation() {
+ if (!animated_sprite || sprite_node_updating) {
+ return;
+ }
+ _select_animation(animated_sprite->call("get_animation"), false);
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_select_animation(const String &p_name, bool p_update_node) {
+ TreeItem *selected = nullptr;
+ selected = animations->get_item_with_text(p_name);
+ if (!selected) {
+ return;
+ };
+
+ edited_anim = selected->get_text(0);
+
+ if (animated_sprite) {
+ if (p_update_node) {
+ animated_sprite->call("set_animation", edited_anim);
+ }
+ }
+
+ _update_library();
+}
+
static void _find_anim_sprites(Node *p_node, List<Node *> *r_nodes, Ref<SpriteFrames> p_sfames) {
Node *edited = EditorNode::get_singleton()->get_edited_scene();
if (!edited) {
@@ -756,35 +807,61 @@ void SpriteFramesEditor::_animation_name_edited() {
return;
}
+ if (new_name.is_empty()) {
+ new_name = "new_animation";
+ }
+
new_name = new_name.replace("/", "_").replace(",", " ");
String name = new_name;
int counter = 0;
while (frames->has_animation(name)) {
counter++;
- name = new_name + " " + itos(counter);
+ name = new_name + "_" + itos(counter);
}
- List<Node *> nodes;
- _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
-
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Rename Animation"));
- undo_redo->add_do_method(frames, "rename_animation", edited_anim, name);
- undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim);
-
- for (Node *E : nodes) {
- String current = E->call("get_animation");
- undo_redo->add_do_method(E, "set_animation", name);
- undo_redo->add_undo_method(E, "set_animation", edited_anim);
- }
-
+ undo_redo->create_action(TTR("Rename Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ _rename_node_animation(undo_redo, false, edited_anim, "", "");
+ undo_redo->add_do_method(frames.ptr(), "rename_animation", edited_anim, name);
+ undo_redo->add_undo_method(frames.ptr(), "rename_animation", name, edited_anim);
+ _rename_node_animation(undo_redo, false, edited_anim, name, name);
+ _rename_node_animation(undo_redo, true, edited_anim, edited_anim, edited_anim);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
+ undo_redo->commit_action();
- edited_anim = name;
+ _select_animation(name);
+ animations->grab_focus();
+}
- undo_redo->commit_action();
+void SpriteFramesEditor::_rename_node_animation(EditorUndoRedoManager *undo_redo, bool is_undo, const String &p_filter, const String &p_new_animation, const String &p_new_autoplay) {
+ List<Node *> nodes;
+ _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
+
+ if (is_undo) {
+ for (Node *E : nodes) {
+ String current_name = E->call("get_animation");
+ if (current_name == p_filter) {
+ undo_redo->add_undo_method(E, "set_animation", p_new_animation);
+ }
+ String autoplay_name = E->call("get_autoplay");
+ if (autoplay_name == p_filter) {
+ undo_redo->add_undo_method(E, "set_autoplay", p_new_autoplay);
+ }
+ }
+ } else {
+ for (Node *E : nodes) {
+ String current_name = E->call("get_animation");
+ if (current_name == p_filter) {
+ undo_redo->add_do_method(E, "set_animation", p_new_animation);
+ }
+ String autoplay_name = E->call("get_autoplay");
+ if (autoplay_name == p_filter) {
+ undo_redo->add_do_method(E, "set_autoplay", p_new_autoplay);
+ }
+ }
+ }
}
void SpriteFramesEditor::_animation_add() {
@@ -795,25 +872,15 @@ void SpriteFramesEditor::_animation_add() {
name = vformat("new_animation_%d", counter);
}
- List<Node *> nodes;
- _find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
-
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Add Animation"));
- undo_redo->add_do_method(frames, "add_animation", name);
- undo_redo->add_undo_method(frames, "remove_animation", name);
+ undo_redo->create_action(TTR("Add Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "add_animation", name);
+ undo_redo->add_undo_method(frames.ptr(), "remove_animation", name);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
-
- for (Node *E : nodes) {
- String current = E->call("get_animation");
- undo_redo->add_do_method(E, "set_animation", name);
- undo_redo->add_undo_method(E, "set_animation", current);
- }
-
- edited_anim = name;
-
undo_redo->commit_action();
+
+ _select_animation(name);
animations->grab_focus();
}
@@ -831,24 +898,39 @@ void SpriteFramesEditor::_animation_remove() {
}
void SpriteFramesEditor::_animation_remove_confirmed() {
+ StringName new_edited;
+ List<StringName> anim_names;
+ frames->get_animation_list(&anim_names);
+ anim_names.sort_custom<StringName::AlphCompare>();
+ if (anim_names.size() >= 2) {
+ if (edited_anim == anim_names[0]) {
+ new_edited = anim_names[1];
+ } else {
+ new_edited = anim_names[0];
+ }
+ } else {
+ new_edited = StringName();
+ }
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Remove Animation"));
- undo_redo->add_do_method(frames, "remove_animation", edited_anim);
- undo_redo->add_undo_method(frames, "add_animation", edited_anim);
- undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
- undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
+ undo_redo->create_action(TTR("Remove Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ _rename_node_animation(undo_redo, false, edited_anim, new_edited, "");
+ undo_redo->add_do_method(frames.ptr(), "remove_animation", edited_anim);
+ undo_redo->add_undo_method(frames.ptr(), "add_animation", edited_anim);
+ _rename_node_animation(undo_redo, true, edited_anim, edited_anim, edited_anim);
+ undo_redo->add_undo_method(frames.ptr(), "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
+ undo_redo->add_undo_method(frames.ptr(), "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
int fc = frames->get_frame_count(edited_anim);
for (int i = 0; i < fc; i++) {
Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, i);
float duration = frames->get_frame_duration(edited_anim, i);
- undo_redo->add_undo_method(frames, "add_frame", edited_anim, texture, duration);
+ undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, texture, duration);
}
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
-
- edited_anim = StringName();
-
undo_redo->commit_action();
+
+ _select_animation(new_edited);
}
void SpriteFramesEditor::_animation_search_text_changed(const String &p_text) {
@@ -861,9 +943,9 @@ void SpriteFramesEditor::_animation_loop_changed() {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Change Animation Loop"));
- undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed());
- undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
+ undo_redo->create_action(TTR("Change Animation Loop"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "set_animation_loop", edited_anim, anim_loop->is_pressed());
+ undo_redo->add_undo_method(frames.ptr(), "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
undo_redo->add_do_method(this, "_update_library", true);
undo_redo->add_undo_method(this, "_update_library", true);
undo_redo->commit_action();
@@ -875,9 +957,9 @@ void SpriteFramesEditor::_animation_speed_changed(double p_value) {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value);
- undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
+ undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "set_animation_speed", edited_anim, p_value);
+ undo_redo->add_undo_method(frames.ptr(), "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
undo_redo->add_do_method(this, "_update_library", true);
undo_redo->add_undo_method(this, "_update_library", true);
undo_redo->commit_action();
@@ -927,9 +1009,9 @@ void SpriteFramesEditor::_frame_duration_changed(double p_value) {
float old_duration = frames->get_frame_duration(edited_anim, index);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Set Frame Duration"));
- undo_redo->add_do_method(frames, "set_frame", edited_anim, index, texture, p_value);
- undo_redo->add_undo_method(frames, "set_frame", edited_anim, index, texture, old_duration);
+ undo_redo->create_action(TTR("Set Frame Duration"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "set_frame", edited_anim, index, texture, p_value);
+ undo_redo->add_undo_method(frames.ptr(), "set_frame", edited_anim, index, texture, old_duration);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -968,6 +1050,10 @@ void SpriteFramesEditor::_zoom_reset() {
}
void SpriteFramesEditor::_update_library(bool p_skip_selector) {
+ if (frames.is_null()) {
+ return;
+ }
+
updating = true;
frame_duration->set_value(1.0); // Default.
@@ -998,12 +1084,27 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
it->set_text(0, name);
it->set_editable(0, true);
+ if (animated_sprite) {
+ if (name == String(animated_sprite->call("get_autoplay"))) {
+ it->set_icon(0, autoplay_icon);
+ }
+ }
+
if (E == edited_anim) {
it->select(0);
}
}
}
+ if (animated_sprite) {
+ String autoplay_name = animated_sprite->call("get_autoplay");
+ if (autoplay_name.is_empty()) {
+ autoplay->set_pressed(false);
+ } else {
+ autoplay->set_pressed(String(edited_anim) == autoplay_name);
+ }
+ }
+
frame_list->clear();
if (!frames->has_animation(edited_anim)) {
@@ -1018,18 +1119,19 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
}
for (int i = 0; i < frames->get_frame_count(edited_anim); i++) {
- String name;
+ String name = itos(i);
Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, i);
float duration = frames->get_frame_duration(edited_anim, i);
- String duration_string;
- if (duration != 1.0f) {
- duration_string = String::utf8(" [ ×") + String::num_real(frames->get_frame_duration(edited_anim, i)) + " ]";
- }
if (texture.is_null()) {
- name = itos(i) + ": " + TTR("(empty)") + duration_string;
- } else {
- name = itos(i) + ": " + texture->get_name() + duration_string;
+ texture = empty_icon;
+ name += ": " + TTR("(empty)");
+ } else if (!texture->get_name().is_empty()) {
+ name += ": " + texture->get_name();
+ }
+
+ if (duration != 1.0f) {
+ name += String::utf8(" [× ") + String::num(duration, 2) + "]";
}
frame_list->add_item(name, texture);
@@ -1061,39 +1163,41 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
updating = false;
}
-void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
- bool new_read_only_state = false;
- if (p_frames) {
- new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_frames);
+void SpriteFramesEditor::_edit() {
+ if (!animated_sprite) {
+ return;
}
+ edit(animated_sprite->call("get_sprite_frames"));
+}
- if (frames == p_frames && new_read_only_state == read_only) {
+void SpriteFramesEditor::edit(Ref<SpriteFrames> p_frames) {
+ _update_stop_icon();
+
+ if (!p_frames.is_valid()) {
+ frames.unref();
+ hide();
return;
}
frames = p_frames;
- read_only = new_read_only_state;
-
- if (p_frames) {
- if (!p_frames->has_animation(edited_anim)) {
- List<StringName> anim_names;
- frames->get_animation_list(&anim_names);
- anim_names.sort_custom<StringName::AlphCompare>();
- if (anim_names.size()) {
- edited_anim = anim_names.front()->get();
- } else {
- edited_anim = StringName();
- }
- }
+ read_only = EditorNode::get_singleton()->is_resource_read_only(p_frames);
- _update_library();
- // Clear zoom and split sheet texture
- split_sheet_preview->set_texture(Ref<Texture2D>());
- _zoom_reset();
- } else {
- hide();
+ if (!p_frames->has_animation(edited_anim)) {
+ List<StringName> anim_names;
+ frames->get_animation_list(&anim_names);
+ anim_names.sort_custom<StringName::AlphCompare>();
+ if (anim_names.size()) {
+ edited_anim = anim_names.front()->get();
+ } else {
+ edited_anim = StringName();
+ }
}
+ _update_library();
+ // Clear zoom and split sheet texture
+ split_sheet_preview->set_texture(Ref<Texture2D>());
+ _zoom_reset();
+
add_anim->set_disabled(read_only);
delete_anim->set_disabled(read_only);
anim_speed->set_editable(!read_only);
@@ -1107,6 +1211,8 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
move_up->set_disabled(read_only);
move_down->set_disabled(read_only);
delete_frame->set_disabled(read_only);
+
+ _fetch_sprite_node(); // Fetch node after set frames.
}
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
@@ -1215,18 +1321,18 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
duration = frames->get_frame_duration(edited_anim, from_frame);
}
- undo_redo->create_action(TTR("Move Frame"));
- undo_redo->add_do_method(frames, "remove_frame", edited_anim, from_frame == -1 ? frames->get_frame_count(edited_anim) : from_frame);
- undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration, at_pos == -1 ? -1 : at_pos);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) - 1 : at_pos);
- undo_redo->add_undo_method(frames, "add_frame", edited_anim, texture, duration, from_frame);
+ undo_redo->create_action(TTR("Move Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "remove_frame", edited_anim, from_frame == -1 ? frames->get_frame_count(edited_anim) : from_frame);
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, duration, at_pos == -1 ? -1 : at_pos);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) - 1 : at_pos);
+ undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, texture, duration, from_frame);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
} else {
- undo_redo->create_action(TTR("Add Frame"));
- undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, at_pos == -1 ? -1 : at_pos);
- undo_redo->add_undo_method(frames, "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) : at_pos);
+ undo_redo->create_action(TTR("Add Frame"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_method(frames.ptr(), "add_frame", edited_anim, texture, 1.0, at_pos == -1 ? -1 : at_pos);
+ undo_redo->add_undo_method(frames.ptr(), "remove_frame", edited_anim, at_pos == -1 ? frames->get_frame_count(edited_anim) : at_pos);
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
undo_redo->commit_action();
@@ -1245,10 +1351,156 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
+void SpriteFramesEditor::_update_stop_icon() {
+ bool is_playing = false;
+ if (animated_sprite) {
+ is_playing = animated_sprite->call("is_playing");
+ }
+ if (is_playing) {
+ stop->set_icon(pause_icon);
+ } else {
+ stop->set_icon(stop_icon);
+ }
+}
+
+void SpriteFramesEditor::_remove_sprite_node() {
+ if (!animated_sprite) {
+ return;
+ }
+ if (animated_sprite->is_connected("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit))) {
+ animated_sprite->disconnect("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit));
+ }
+ if (animated_sprite->is_connected("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation))) {
+ animated_sprite->disconnect("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation));
+ }
+ if (animated_sprite->is_connected("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon))) {
+ animated_sprite->disconnect("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon));
+ }
+ animated_sprite = nullptr;
+}
+
+void SpriteFramesEditor::_fetch_sprite_node() {
+ Node *selected = nullptr;
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ if (editor_selection->get_selected_node_list().size() == 1) {
+ selected = editor_selection->get_selected_node_list()[0];
+ }
+
+ bool show_node_edit = false;
+ AnimatedSprite2D *as2d = Object::cast_to<AnimatedSprite2D>(selected);
+ AnimatedSprite3D *as3d = Object::cast_to<AnimatedSprite3D>(selected);
+ if (as2d || as3d) {
+ if (frames != selected->call("get_sprite_frames")) {
+ _remove_sprite_node();
+ } else {
+ animated_sprite = selected;
+ if (!animated_sprite->is_connected("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit))) {
+ animated_sprite->connect("sprite_frames_changed", callable_mp(this, &SpriteFramesEditor::_edit));
+ }
+ if (!animated_sprite->is_connected("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation))) {
+ animated_sprite->connect("animation_changed", callable_mp(this, &SpriteFramesEditor::_sync_animation), CONNECT_DEFERRED);
+ }
+ if (!animated_sprite->is_connected("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon))) {
+ animated_sprite->connect("animation_finished", callable_mp(this, &SpriteFramesEditor::_update_stop_icon));
+ }
+ show_node_edit = true;
+ }
+ } else {
+ _remove_sprite_node();
+ }
+
+ if (show_node_edit) {
+ _sync_animation();
+ autoplay_container->show();
+ playback_container->show();
+ } else {
+ _update_library(); // To init autoplay icon.
+ autoplay_container->hide();
+ playback_container->hide();
+ }
+}
+
+void SpriteFramesEditor::_play_pressed() {
+ if (animated_sprite) {
+ animated_sprite->call("stop");
+ animated_sprite->call("play", animated_sprite->call("get_animation"));
+ }
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_play_from_pressed() {
+ if (animated_sprite) {
+ animated_sprite->call("play", animated_sprite->call("get_animation"));
+ }
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_play_bw_pressed() {
+ if (animated_sprite) {
+ animated_sprite->call("stop");
+ animated_sprite->call("play_backwards", animated_sprite->call("get_animation"));
+ }
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_play_bw_from_pressed() {
+ if (animated_sprite) {
+ animated_sprite->call("play_backwards", animated_sprite->call("get_animation"));
+ }
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_stop_pressed() {
+ if (animated_sprite) {
+ if (animated_sprite->call("is_playing")) {
+ animated_sprite->call("pause");
+ } else {
+ animated_sprite->call("stop");
+ }
+ }
+ _update_stop_icon();
+}
+
+void SpriteFramesEditor::_autoplay_pressed() {
+ if (updating) {
+ return;
+ }
+
+ if (animated_sprite) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Toggle Autoplay"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ String current = animated_sprite->call("get_animation");
+ String current_auto = animated_sprite->call("get_autoplay");
+ if (current == current_auto) {
+ //unset
+ undo_redo->add_do_method(animated_sprite, "set_autoplay", "");
+ undo_redo->add_undo_method(animated_sprite, "set_autoplay", current_auto);
+ } else {
+ //set
+ undo_redo->add_do_method(animated_sprite, "set_autoplay", current);
+ undo_redo->add_undo_method(animated_sprite, "set_autoplay", current_auto);
+ }
+ undo_redo->add_do_method(this, "_update_library");
+ undo_redo->add_undo_method(this, "_update_library");
+ undo_redo->commit_action();
+ }
+
+ _update_library();
+}
+
void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false));
}
+void SpriteFramesEditor::_node_removed(Node *p_node) {
+ if (animated_sprite) {
+ if (animated_sprite != p_node) {
+ return;
+ }
+ _remove_sprite_node();
+ }
+}
+
SpriteFramesEditor::SpriteFramesEditor() {
VBoxContainer *vbc_animlist = memnew(VBoxContainer);
add_child(vbc_animlist);
@@ -1272,8 +1524,37 @@ SpriteFramesEditor::SpriteFramesEditor() {
delete_anim->set_disabled(true);
delete_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
+ autoplay_container = memnew(HBoxContainer);
+ hbc_animlist->add_child(autoplay_container);
+
+ autoplay_container->add_child(memnew(VSeparator));
+
+ autoplay = memnew(Button);
+ autoplay->set_flat(true);
+ autoplay->set_tooltip_text(TTR("Autoplay on Load"));
+ autoplay_container->add_child(autoplay);
+
+ hbc_animlist->add_child(memnew(VSeparator));
+
+ anim_loop = memnew(Button);
+ anim_loop->set_toggle_mode(true);
+ anim_loop->set_flat(true);
+ anim_loop->set_tooltip_text(TTR("Animation Looping"));
+ anim_loop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_loop_changed));
+ hbc_animlist->add_child(anim_loop);
+
+ anim_speed = memnew(SpinBox);
+ anim_speed->set_suffix(TTR("FPS"));
+ anim_speed->set_min(0);
+ anim_speed->set_max(120);
+ anim_speed->set_step(0.01);
+ anim_speed->set_custom_arrow_step(1);
+ anim_speed->set_tooltip_text(TTR("Animation Speed"));
+ anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_speed_changed));
+ hbc_animlist->add_child(anim_speed);
+
anim_search_box = memnew(LineEdit);
- hbc_animlist->add_child(anim_search_box);
+ sub_vb->add_child(anim_search_box);
anim_search_box->set_h_size_flags(SIZE_EXPAND_FILL);
anim_search_box->set_placeholder(TTR("Filter Animations"));
anim_search_box->set_clear_button_enabled(true);
@@ -1283,7 +1564,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
sub_vb->add_child(animations);
animations->set_v_size_flags(SIZE_EXPAND_FILL);
animations->set_hide_root(true);
- animations->connect("cell_selected", callable_mp(this, &SpriteFramesEditor::_animation_select));
+ animations->connect("cell_selected", callable_mp(this, &SpriteFramesEditor::_animation_selected));
animations->connect("item_edited", callable_mp(this, &SpriteFramesEditor::_animation_name_edited));
animations->set_allow_reselect(true);
@@ -1292,23 +1573,6 @@ SpriteFramesEditor::SpriteFramesEditor() {
delete_anim->set_shortcut_context(animations);
delete_anim->set_shortcut(ED_SHORTCUT("sprite_frames/delete_animation", TTR("Delete Animation"), Key::KEY_DELETE));
- HBoxContainer *hbc_anim_speed = memnew(HBoxContainer);
- hbc_anim_speed->add_child(memnew(Label(TTR("Speed:"))));
- vbc_animlist->add_child(hbc_anim_speed);
- anim_speed = memnew(SpinBox);
- anim_speed->set_suffix(TTR("FPS"));
- anim_speed->set_min(0);
- anim_speed->set_max(120);
- anim_speed->set_step(0.01);
- anim_speed->set_h_size_flags(SIZE_EXPAND_FILL);
- hbc_anim_speed->add_child(anim_speed);
- anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_speed_changed));
-
- anim_loop = memnew(CheckButton);
- anim_loop->set_text(TTR("Loop"));
- vbc_animlist->add_child(anim_loop);
- anim_loop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_loop_changed));
-
VBoxContainer *vbc = memnew(VBoxContainer);
add_child(vbc);
vbc->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1319,6 +1583,44 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *hbc = memnew(HBoxContainer);
sub_vb->add_child(hbc);
+ playback_container = memnew(HBoxContainer);
+ hbc->add_child(playback_container);
+
+ play_bw_from = memnew(Button);
+ play_bw_from->set_flat(true);
+ play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)"));
+ playback_container->add_child(play_bw_from);
+
+ play_bw = memnew(Button);
+ play_bw->set_flat(true);
+ play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)"));
+ playback_container->add_child(play_bw);
+
+ stop = memnew(Button);
+ stop->set_flat(true);
+ stop->set_tooltip_text(TTR("Pause/stop animation playback. (S)"));
+ playback_container->add_child(stop);
+
+ play = memnew(Button);
+ play->set_flat(true);
+ play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)"));
+ playback_container->add_child(play);
+
+ play_from = memnew(Button);
+ play_from->set_flat(true);
+ play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)"));
+ playback_container->add_child(play_from);
+
+ playback_container->add_child(memnew(VSeparator));
+
+ autoplay->connect("pressed", callable_mp(this, &SpriteFramesEditor::_autoplay_pressed));
+ autoplay->set_toggle_mode(true);
+ play->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_pressed));
+ play_from->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_from_pressed));
+ play_bw->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_bw_pressed));
+ play_bw_from->connect("pressed", callable_mp(this, &SpriteFramesEditor::_play_bw_from_pressed));
+ stop->connect("pressed", callable_mp(this, &SpriteFramesEditor::_stop_pressed));
+
load = memnew(Button);
load->set_flat(true);
hbc->add_child(load);
@@ -1369,9 +1671,11 @@ SpriteFramesEditor::SpriteFramesEditor() {
frame_duration = memnew(SpinBox);
frame_duration->set_prefix(String::utf8("×"));
- frame_duration->set_min(0);
+ frame_duration->set_min(SPRITE_FRAME_MINIMUM_DURATION); // Avoid zero div.
frame_duration->set_max(10);
frame_duration->set_step(0.01);
+ frame_duration->set_custom_arrow_step(0.1);
+ frame_duration->set_allow_lesser(false);
frame_duration->set_allow_greater(true);
hbc->add_child(frame_duration);
@@ -1616,16 +1920,16 @@ SpriteFramesEditor::SpriteFramesEditor() {
}
void SpriteFramesEditorPlugin::edit(Object *p_object) {
- SpriteFrames *s;
+ Ref<SpriteFrames> s;
AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object);
if (animated_sprite) {
- s = *animated_sprite->get_sprite_frames();
+ s = animated_sprite->get_sprite_frames();
} else {
AnimatedSprite3D *animated_sprite_3d = Object::cast_to<AnimatedSprite3D>(p_object);
if (animated_sprite_3d) {
- s = *animated_sprite_3d->get_sprite_frames();
+ s = animated_sprite_3d->get_sprite_frames();
} else {
- s = Object::cast_to<SpriteFrames>(p_object);
+ s = p_object;
}
}
@@ -1650,9 +1954,7 @@ void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
EditorNode::get_singleton()->make_bottom_panel_item_visible(frames_editor);
} else {
button->hide();
- if (frames_editor->is_visible_in_tree()) {
- EditorNode::get_singleton()->hide_bottom_panel();
- }
+ frames_editor->edit(Ref<SpriteFrames>());
}
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index a5e0e54fb8..1dfb909388 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -33,6 +33,7 @@
#include "editor/editor_plugin.h"
#include "scene/2d/animated_sprite_2d.h"
+#include "scene/3d/sprite_3d.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
#include "scene/gui/dialogs.h"
@@ -57,6 +58,9 @@ public:
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
+ Ref<SpriteFrames> frames;
+ Node *animated_sprite = nullptr;
+
enum {
PARAM_USE_CURRENT, // Used in callbacks to indicate `dominant_param` should be not updated.
PARAM_FRAME_COUNT, // Keep "Horizontal" & "Vertical" values.
@@ -66,6 +70,18 @@ class SpriteFramesEditor : public HSplitContainer {
bool read_only = false;
+ Ref<Texture2D> autoplay_icon;
+ Ref<Texture2D> stop_icon;
+ Ref<Texture2D> pause_icon;
+ Ref<Texture2D> empty_icon = memnew(ImageTexture);
+
+ HBoxContainer *playback_container = nullptr;
+ Button *stop = nullptr;
+ Button *play = nullptr;
+ Button *play_from = nullptr;
+ Button *play_bw = nullptr;
+ Button *play_bw_from = nullptr;
+
Button *load = nullptr;
Button *load_sheet = nullptr;
Button *delete_frame = nullptr;
@@ -85,18 +101,19 @@ class SpriteFramesEditor : public HSplitContainer {
Button *add_anim = nullptr;
Button *delete_anim = nullptr;
- LineEdit *anim_search_box = nullptr;
+ SpinBox *anim_speed = nullptr;
+ Button *anim_loop = nullptr;
+
+ HBoxContainer *autoplay_container = nullptr;
+ Button *autoplay = nullptr;
+ LineEdit *anim_search_box = nullptr;
Tree *animations = nullptr;
- SpinBox *anim_speed = nullptr;
- CheckButton *anim_loop = nullptr;
EditorFileDialog *file = nullptr;
AcceptDialog *dialog = nullptr;
- SpriteFrames *frames = nullptr;
-
StringName edited_anim;
ConfirmationDialog *delete_dialog = nullptr;
@@ -146,7 +163,15 @@ class SpriteFramesEditor : public HSplitContainer {
void _frame_duration_changed(double p_value);
void _update_library(bool p_skip_selector = false);
- void _animation_select();
+ void _update_stop_icon();
+ void _play_pressed();
+ void _play_from_pressed();
+ void _play_bw_pressed();
+ void _play_bw_from_pressed();
+ void _autoplay_pressed();
+ void _stop_pressed();
+
+ void _animation_selected();
void _animation_name_edited();
void _animation_add();
void _animation_remove();
@@ -183,12 +208,24 @@ class SpriteFramesEditor : public HSplitContainer {
void _sheet_zoom_reset();
void _sheet_select_clear_all_frames();
+ void _edit();
+ void _regist_scene_undo(EditorUndoRedoManager *undo_redo);
+ void _fetch_sprite_node();
+ void _remove_sprite_node();
+
+ bool sprite_node_updating = false;
+ void _sync_animation();
+
+ void _select_animation(const String &p_name, bool p_update_node = true);
+ void _rename_node_animation(EditorUndoRedoManager *undo_redo, bool is_undo, const String &p_filter, const String &p_new_animation, const String &p_new_autoplay);
+
protected:
void _notification(int p_what);
+ void _node_removed(Node *p_node);
static void _bind_methods();
public:
- void edit(SpriteFrames *p_frames);
+ void edit(Ref<SpriteFrames> p_frames);
SpriteFramesEditor();
};
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index a376699e54..ceb170d7d8 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -30,6 +30,7 @@
#include "text_editor.h"
+#include "core/io/json.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
@@ -67,12 +68,12 @@ void TextEditor::_load_theme_settings() {
String TextEditor::get_name() {
String name;
- name = text_file->get_path().get_file();
+ name = edited_res->get_path().get_file();
if (name.is_empty()) {
// This appears for newly created built-in text_files before saving the scene.
name = TTR("[unsaved]");
- } else if (text_file->is_built_in()) {
- const String &text_file_name = text_file->get_name();
+ } else if (edited_res->is_built_in()) {
+ const String &text_file_name = edited_res->get_name();
if (!text_file_name.is_empty()) {
// If the built-in text_file has a custom resource name defined,
// display the built-in text_file name as follows: `ResourceName (scene_file.tscn)`
@@ -88,20 +89,29 @@ String TextEditor::get_name() {
}
Ref<Texture2D> TextEditor::get_theme_icon() {
- return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), "");
+ return EditorNode::get_singleton()->get_object_icon(edited_res.ptr(), "TextFile");
}
Ref<Resource> TextEditor::get_edited_resource() const {
- return text_file;
+ return edited_res;
}
void TextEditor::set_edited_resource(const Ref<Resource> &p_res) {
- ERR_FAIL_COND(text_file.is_valid());
+ ERR_FAIL_COND(edited_res.is_valid());
ERR_FAIL_COND(p_res.is_null());
- text_file = p_res;
+ edited_res = p_res;
+
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ code_editor->get_text_editor()->set_text(text_file->get_text());
+ }
+
+ Ref<JSON> json_file = edited_res;
+ if (json_file != nullptr) {
+ code_editor->get_text_editor()->set_text(json_file->get_parsed_text());
+ }
- code_editor->get_text_editor()->set_text(text_file->get_text());
code_editor->get_text_editor()->clear_undo_history();
code_editor->get_text_editor()->tag_saved_version();
@@ -118,6 +128,8 @@ void TextEditor::enable_editor(Control *p_shortcut_context) {
_load_theme_settings();
+ _validate_script();
+
if (p_shortcut_context) {
for (int i = 0; i < edit_hb->get_child_count(); ++i) {
Control *c = cast_to<Control>(edit_hb->get_child(i));
@@ -143,7 +155,7 @@ PackedInt32Array TextEditor::get_breakpoints() {
}
void TextEditor::reload_text() {
- ERR_FAIL_COND(text_file.is_null());
+ ERR_FAIL_COND(edited_res.is_null());
CodeEdit *te = code_editor->get_text_editor();
int column = te->get_caret_column();
@@ -151,7 +163,16 @@ void TextEditor::reload_text() {
int h = te->get_h_scroll();
int v = te->get_v_scroll();
- te->set_text(text_file->get_text());
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ te->set_text(text_file->get_text());
+ }
+
+ Ref<JSON> json_file = edited_res;
+ if (json_file != nullptr) {
+ te->set_text(json_file->get_parsed_text());
+ }
+
te->set_caret_line(row);
te->set_caret_column(column);
te->set_h_scroll(h);
@@ -166,6 +187,20 @@ void TextEditor::reload_text() {
void TextEditor::_validate_script() {
emit_signal(SNAME("name_changed"));
emit_signal(SNAME("edited_script_changed"));
+
+ Ref<JSON> json_file = edited_res;
+ if (json_file != nullptr) {
+ CodeEdit *te = code_editor->get_text_editor();
+
+ te->set_line_background_color(code_editor->get_error_pos().x, Color(0, 0, 0, 0));
+ code_editor->set_error("");
+
+ if (json_file->parse(te->get_text(), true) != OK) {
+ code_editor->set_error(json_file->get_error_message());
+ code_editor->set_error_pos(json_file->get_error_line(), 0);
+ te->set_line_background_color(code_editor->get_error_pos().x, EDITOR_GET("text_editor/theme/highlighting/mark_color"));
+ }
+ }
}
void TextEditor::_update_bookmark_list() {
@@ -204,13 +239,22 @@ void TextEditor::_bookmark_item_pressed(int p_idx) {
}
void TextEditor::apply_code() {
- text_file->set_text(code_editor->get_text_editor()->get_text());
+ Ref<TextFile> text_file = edited_res;
+ if (text_file != nullptr) {
+ text_file->set_text(code_editor->get_text_editor()->get_text());
+ }
+
+ Ref<JSON> json_file = edited_res;
+ if (json_file != nullptr) {
+ json_file->parse(code_editor->get_text_editor()->get_text(), true);
+ }
+ code_editor->get_text_editor()->get_syntax_highlighter()->update_cache();
}
bool TextEditor::is_unsaved() {
const bool unsaved =
code_editor->get_text_editor()->get_version() != code_editor->get_text_editor()->get_saved_version() ||
- text_file->get_path().is_empty(); // In memory.
+ edited_res->get_path().is_empty(); // In memory.
return unsaved;
}
@@ -431,7 +475,7 @@ void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
}
static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
- if (Object::cast_to<TextFile>(*p_resource)) {
+ if (Object::cast_to<TextFile>(*p_resource) || Object::cast_to<JSON>(*p_resource)) {
return memnew(TextEditor);
}
return nullptr;
@@ -656,4 +700,5 @@ TextEditor::~TextEditor() {
}
void TextEditor::validate() {
+ this->code_editor->validate_script();
}
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 6db81508b3..85e0fee627 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -41,7 +41,7 @@ class TextEditor : public ScriptEditorBase {
private:
CodeTextEditor *code_editor = nullptr;
- Ref<TextFile> text_file;
+ Ref<Resource> edited_res;
bool editor_enabled = false;
HBoxContainer *edit_hb = nullptr;
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp
index 1b29999796..ffd9564816 100644
--- a/editor/plugins/text_shader_editor.cpp
+++ b/editor/plugins/text_shader_editor.cpp
@@ -383,11 +383,12 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
List<ScriptLanguage::CodeCompletionOption> pp_defines;
ShaderPreprocessor preprocessor;
String code;
- complete_from_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()).get_base_dir();
+ String resource_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path());
+ complete_from_path = resource_path.get_base_dir();
if (!complete_from_path.ends_with("/")) {
complete_from_path += "/";
}
- preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths);
+ preprocessor.preprocess(p_code, resource_path, code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths);
complete_from_path = String();
if (pp_options.size()) {
for (const ScriptLanguage::CodeCompletionOption &E : pp_options) {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 9bad2f2fbf..7fa16e6cc6 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -256,10 +256,10 @@ void TextureRegionEditor::_region_draw() {
margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT);
margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT);
} else if (obj_styleBox.is_valid()) {
- margins[0] = obj_styleBox->get_margin_size(SIDE_TOP);
- margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM);
- margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT);
- margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT);
+ margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP);
+ margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM);
+ margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT);
+ margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT);
}
Vector2 pos[4] = {
@@ -314,10 +314,10 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
margins[2] = node_ninepatch->get_patch_margin(SIDE_LEFT);
margins[3] = node_ninepatch->get_patch_margin(SIDE_RIGHT);
} else if (obj_styleBox.is_valid()) {
- margins[0] = obj_styleBox->get_margin_size(SIDE_TOP);
- margins[1] = obj_styleBox->get_margin_size(SIDE_BOTTOM);
- margins[2] = obj_styleBox->get_margin_size(SIDE_LEFT);
- margins[3] = obj_styleBox->get_margin_size(SIDE_RIGHT);
+ margins[0] = obj_styleBox->get_texture_margin(SIDE_TOP);
+ margins[1] = obj_styleBox->get_texture_margin(SIDE_BOTTOM);
+ margins[2] = obj_styleBox->get_texture_margin(SIDE_LEFT);
+ margins[3] = obj_styleBox->get_texture_margin(SIDE_RIGHT);
}
Vector2 pos[4] = {
@@ -431,8 +431,8 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
undo_redo->add_do_method(node_ninepatch, "set_patch_margin", side[edited_margin], node_ninepatch->get_patch_margin(side[edited_margin]));
undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", side[edited_margin], prev_margin);
} else if (obj_styleBox.is_valid()) {
- undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], obj_styleBox->get_margin_size(side[edited_margin]));
- undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", side[edited_margin], prev_margin);
+ undo_redo->add_do_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], obj_styleBox->get_texture_margin(side[edited_margin]));
+ undo_redo->add_undo_method(obj_styleBox.ptr(), "set_texture_margin", side[edited_margin], prev_margin);
obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed);
}
edited_margin = -1;
@@ -474,7 +474,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
node_ninepatch->set_patch_margin(side[edited_margin], prev_margin);
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->set_margin_size(side[edited_margin], prev_margin);
+ obj_styleBox->set_texture_margin(side[edited_margin], prev_margin);
}
edited_margin = -1;
} else {
@@ -535,7 +535,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
node_ninepatch->set_patch_margin(side[edited_margin], new_margin);
}
if (obj_styleBox.is_valid()) {
- obj_styleBox->set_margin_size(side[edited_margin], new_margin);
+ obj_styleBox->set_texture_margin(side[edited_margin], new_margin);
}
} else {
Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position());
@@ -620,22 +620,14 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
}
}
-void TextureRegionEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
- _pan_callback(-p_scroll_vec * 32);
-}
-
-void TextureRegionEditor::_pan_callback(Vector2 p_scroll_vec) {
+void TextureRegionEditor::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
p_scroll_vec /= draw_zoom;
hscroll->set_value(hscroll->get_value() - p_scroll_vec.x);
vscroll->set_value(vscroll->get_value() - p_scroll_vec.y);
}
-void TextureRegionEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- if (p_scroll_vec.y < 0) {
- _zoom_on_position(draw_zoom * ((0.95 + (0.05 * Math::abs(p_scroll_vec.y))) / 0.95), p_origin);
- } else {
- _zoom_on_position(draw_zoom * (1 - (0.05 * Math::abs(p_scroll_vec.y))), p_origin);
- }
+void TextureRegionEditor::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
+ _zoom_on_position(draw_zoom * p_zoom_factor, p_origin);
}
void TextureRegionEditor::_scroll_changed(float) {
@@ -748,6 +740,9 @@ void TextureRegionEditor::_update_rect() {
}
} else if (obj_styleBox.is_valid()) {
rect = obj_styleBox->get_region_rect();
+ if (rect == Rect2()) {
+ rect = Rect2(Vector2(), obj_styleBox->get_texture()->get_size());
+ }
}
}
@@ -1169,7 +1164,7 @@ TextureRegionEditor::TextureRegionEditor() {
hb_grid->hide();
panner.instantiate();
- panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_scroll_callback), callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback));
+ panner->set_callbacks(callable_mp(this, &TextureRegionEditor::_pan_callback), callable_mp(this, &TextureRegionEditor::_zoom_callback));
edit_draw = memnew(Panel);
vb->add_child(edit_draw);
@@ -1229,7 +1224,7 @@ void EditorInspectorPluginTextureRegion::_region_edit(Object *p_object) {
texture_region_editor->edit(p_object);
}
-bool EditorInspectorPluginTextureRegion::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginTextureRegion::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
if ((p_type == Variant::RECT2 || p_type == Variant::RECT2I)) {
if (((Object::cast_to<Sprite2D>(p_object) || Object::cast_to<Sprite3D>(p_object) || Object::cast_to<NinePatchRect>(p_object) || Object::cast_to<StyleBoxTexture>(p_object)) && p_path == "region_rect") || (Object::cast_to<AtlasTexture>(p_object) && p_path == "region")) {
Button *button = EditorInspector::create_inspector_action_button(TTR("Edit Region"));
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index 0325700d25..c303cec3f5 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -103,9 +103,8 @@ class TextureRegionEditor : public AcceptDialog {
bool request_center = false;
Ref<ViewPanner> panner;
- void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
- void _pan_callback(Vector2 p_scroll_vec);
- void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
+ void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
void _set_snap_mode(int p_mode);
void _set_snap_off_x(float p_val);
@@ -157,7 +156,7 @@ class EditorInspectorPluginTextureRegion : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) override;
EditorInspectorPluginTextureRegion();
};
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 40aac77a99..2519928ea3 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -3223,6 +3223,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) {
return;
}
+ ERR_FAIL_COND_MSG(edited_theme.is_null(), "Leading stylebox does not have an edited theme to update");
// Prevent changes from immediately being reported while the operation is still ongoing.
edited_theme->_freeze_change_propagation();
@@ -3335,8 +3336,10 @@ void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
}
edited_theme = p_theme;
- edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
- _update_type_list();
+ if (edited_theme.is_valid()) {
+ edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced));
+ _update_type_list();
+ }
add_type_dialog->set_edited_theme(edited_theme);
}
@@ -3496,7 +3499,9 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) {
preview_tab->set_preview_theme(p_theme);
}
- theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
+ if (theme.is_valid()) {
+ theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
+ }
}
Ref<Theme> ThemeEditor::get_edited_theme() {
@@ -3701,82 +3706,17 @@ ThemeEditor::ThemeEditor() {
void ThemeEditorPlugin::edit(Object *p_node) {
if (Object::cast_to<Theme>(p_node)) {
theme_editor->edit(Object::cast_to<Theme>(p_node));
- } else if (Object::cast_to<Font>(p_node) || Object::cast_to<StyleBox>(p_node) || Object::cast_to<Texture2D>(p_node)) {
- // Do nothing, keep editing the existing theme.
} else {
- theme_editor->edit(Ref<Theme>());
+ // We intentionally keep a reference to the last used theme to work around
+ // the the editor being hidden while base resources are edited. Uncomment
+ // the following line again and remove this comment once that bug has been
+ // fixed (scheduled for Godot 4.1 in PR 73098):
+ // theme_editor->edit(Ref<Theme>());
}
}
bool ThemeEditorPlugin::handles(Object *p_node) const {
- if (Object::cast_to<Theme>(p_node)) {
- return true;
- }
-
- Ref<Theme> edited_theme = theme_editor->get_edited_theme();
- if (edited_theme.is_null()) {
- return false;
- }
-
- // If we are editing a theme already and this particular resource happens to belong to it,
- // then we just keep editing it, despite not being able to directly handle it.
- // This only goes one layer deep, but if required this can be extended to support, say, Font inside of Font.
- bool belongs_to_theme = false;
-
- if (Object::cast_to<Font>(p_node)) {
- Ref<Font> font_item = Object::cast_to<Font>(p_node);
- List<StringName> types;
- List<StringName> names;
-
- edited_theme->get_font_type_list(&types);
- for (const StringName &E : types) {
- names.clear();
- edited_theme->get_font_list(E, &names);
-
- for (const StringName &F : names) {
- if (font_item == edited_theme->get_font(F, E)) {
- belongs_to_theme = true;
- break;
- }
- }
- }
- } else if (Object::cast_to<StyleBox>(p_node)) {
- Ref<StyleBox> stylebox_item = Object::cast_to<StyleBox>(p_node);
- List<StringName> types;
- List<StringName> names;
-
- edited_theme->get_stylebox_type_list(&types);
- for (const StringName &E : types) {
- names.clear();
- edited_theme->get_stylebox_list(E, &names);
-
- for (const StringName &F : names) {
- if (stylebox_item == edited_theme->get_stylebox(F, E)) {
- belongs_to_theme = true;
- break;
- }
- }
- }
- } else if (Object::cast_to<Texture2D>(p_node)) {
- Ref<Texture2D> icon_item = Object::cast_to<Texture2D>(p_node);
- List<StringName> types;
- List<StringName> names;
-
- edited_theme->get_icon_type_list(&types);
- for (const StringName &E : types) {
- names.clear();
- edited_theme->get_icon_list(E, &names);
-
- for (const StringName &F : names) {
- if (icon_item == edited_theme->get_icon(F, E)) {
- belongs_to_theme = true;
- break;
- }
- }
- }
- }
-
- return belongs_to_theme;
+ return Object::cast_to<Theme>(p_node) != nullptr;
}
void ThemeEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 0ac375407c..43c6d1a48b 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -47,18 +47,14 @@ void TileAtlasView::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void TileAtlasView::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
- _pan_callback(-p_scroll_vec * 32);
-}
-
-void TileAtlasView::_pan_callback(Vector2 p_scroll_vec) {
+void TileAtlasView::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
panning += p_scroll_vec;
_update_zoom_and_panning(true);
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
}
-void TileAtlasView::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- zoom_widget->set_zoom_by_increments(-p_scroll_vec.y * 2);
+void TileAtlasView::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
+ zoom_widget->set_zoom(zoom_widget->get_zoom() * p_zoom_factor);
_update_zoom_and_panning(true);
emit_signal(SNAME("transform_changed"), zoom_widget->get_zoom(), panning);
}
@@ -251,7 +247,7 @@ void TileAtlasView::_draw_base_tiles() {
for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) {
// Update the y to max value.
Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame);
- Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(atlas_coords, 0);
+ Vector2i offset_pos = base_frame_rect.get_center() + tile_set_atlas_source->get_tile_data(atlas_coords, 0)->get_texture_origin();
// Draw the tile.
TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame);
@@ -326,18 +322,19 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
Vector2i tile_shape_size = tile_set->get_tile_size();
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);
-
- 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;
+ Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_data(tile_id, 0)->get_texture_origin();
+ if (tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, -tile_shape_size / 2) && tile_set_atlas_source->is_position_in_tile_texture_region(tile_id, 0, tile_shape_size / 2 - Vector2(1, 1))) {
+ 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, frame);
+ 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);
}
- 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);
}
}
}
@@ -376,10 +373,10 @@ void TileAtlasView::_draw_alternatives() {
// Update the y to max value.
Vector2i offset_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));
+ offset_pos = (current_pos + Vector2(texture_region_size.y, texture_region_size.x) / 2 + tile_data->get_texture_origin());
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));
+ offset_pos = (current_pos + texture_region_size / 2 + tile_data->get_texture_origin());
y_increment = MAX(y_increment, texture_region_size.y);
}
@@ -407,13 +404,16 @@ void TileAtlasView::_draw_background_right() {
}
void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
- ERR_FAIL_COND(!p_tile_set);
- ERR_FAIL_COND(!p_tile_set_atlas_source);
+ tile_set = p_tile_set;
+ tile_set_atlas_source = p_tile_set_atlas_source;
+
+ if (!tile_set) {
+ return;
+ }
+
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
- tile_set = p_tile_set;
- tile_set_atlas_source = p_tile_set_atlas_source;
source_id = p_source_id;
// Show or hide the view.
@@ -583,7 +583,7 @@ TileAtlasView::TileAtlasView() {
add_child(button_center_view);
panner.instantiate();
- panner->set_callbacks(callable_mp(this, &TileAtlasView::_scroll_callback), callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback));
+ panner->set_callbacks(callable_mp(this, &TileAtlasView::_pan_callback), callable_mp(this, &TileAtlasView::_zoom_callback));
panner->set_enable_rmb(true);
center_container = memnew(CenterContainer);
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index f719bee704..4a7547f34b 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -65,9 +65,8 @@ private:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
Ref<ViewPanner> panner;
- void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
- void _pan_callback(Vector2 p_scroll_vec);
- void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
+ void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
HashMap<Vector2, HashMap<int, Rect2i>> alternative_tiles_rect_cache;
void _update_alternative_tiles_rect_cache();
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 1a4223e9e6..3dd0c84ee7 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -1122,14 +1122,15 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
return;
}
+ Vector2 texture_origin = tile_data->get_texture_origin();
if (value.get_type() == Variant::BOOL) {
Ref<Texture2D> texture = (bool)value ? tile_bool_checked : tile_bool_unchecked;
int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3;
- Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size)));
+ Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2) - texture_origin, Vector2(size, size)));
p_canvas_item->draw_texture_rect(texture, rect);
} else if (value.get_type() == Variant::COLOR) {
int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3;
- Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size)));
+ Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2) - texture_origin, Vector2(size, size)));
p_canvas_item->draw_rect(rect, value);
} else {
Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
@@ -1166,8 +1167,8 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
}
Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
- p_canvas_item->draw_string_outline(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1));
- p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
+ p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
}
}
@@ -1241,20 +1242,38 @@ TileDataDefaultEditor::~TileDataDefaultEditor() {
memdelete(dummy_object);
}
-void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
+void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
Vector2i tile_set_tile_size = tile_set->get_tile_size();
- Color color = Color(1.0, 0.0, 0.0);
+ Color color = Color(1.0, 1.0, 1.0);
if (p_selected) {
Color grid_color = EDITOR_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;
}
- Transform2D tile_xform;
- tile_xform.set_scale(tile_set_tile_size);
- tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color);
+
+ TileSetSource *source = *(tile_set->get_source(p_cell.source_id));
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, -tile_set_tile_size / 2) && atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, tile_set_tile_size / 2 - Vector2(1, 1))) {
+ Transform2D tile_xform;
+ tile_xform.set_scale(tile_set_tile_size);
+ tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color);
+ }
+
+ if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2())) {
+ Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons"));
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2()) - (position_icon->get_size() / 2), color);
+ } else {
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
+ Vector2 texture_origin = tile_data->get_texture_origin();
+ String text = vformat("%s", texture_origin);
+ Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
+ p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
+ }
}
void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
@@ -1288,8 +1307,21 @@ void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D
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;
}
- Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons"));
- p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color);
+ Vector2 texture_origin = tile_data->get_texture_origin();
+ TileSetSource *source = *(tile_set->get_source(p_cell.source_id));
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source->is_position_in_tile_texture_region(p_cell.get_atlas_coords(), p_cell.alternative_tile, Vector2(0, tile_data->get_y_sort_origin()))) {
+ Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons"));
+ p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color);
+ } else {
+ Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int font_size = TileSetEditor::get_singleton()->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
+ String text = vformat("%s", tile_data->get_y_sort_origin());
+
+ Vector2 string_size = font->get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
+ p_canvas_item->draw_string_outline(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, 1, Color(0, 0, 0, 1));
+ p_canvas_item->draw_string(font, p_transform.xform(-texture_origin) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HORIZONTAL_ALIGNMENT_CENTER, string_size.x, font_size, color);
+ }
}
void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
@@ -1333,7 +1365,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile
if (occluder_polygon.is_valid()) {
polygon_editor->add_polygon(occluder_polygon->get_polygon());
}
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
@@ -1342,7 +1374,7 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl
Ref<OccluderPolygon2D> occluder_polygon = p_value;
tile_data->set_occluder(occlusion_layer, occluder_polygon);
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
@@ -1489,7 +1521,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_
E.value->update_property();
}
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
@@ -1508,7 +1540,7 @@ void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_so
tile_data->set_collision_polygon_one_way_margin(physics_layer, i, polygon_dict["one_way_margin"]);
}
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
@@ -1741,7 +1773,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
TileData *tile_data = 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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) {
// Draw hovered bit.
@@ -1792,7 +1824,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Color color = Color(1, 1, 1);
String text;
@@ -1885,7 +1917,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
Vector2i coords = E.get_atlas_coords();
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = texture_region.get_center() + 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_data(coords, 0)->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
for (int j = 0; j < polygon.size(); j++) {
@@ -1930,7 +1962,7 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
TileData *tile_data = 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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
if (terrain_set == int(dummy_object->get("terrain_set"))) {
// Draw hovered bit.
@@ -1984,7 +2016,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Color color = Color(1, 1, 1);
String text;
@@ -2069,7 +2101,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
@@ -2103,7 +2135,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
TileData *tile_data = 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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
@@ -2218,7 +2250,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
@@ -2365,7 +2397,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(coords, 0);
Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords);
- Vector2i position = texture_region.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
for (int j = 0; j < polygon.size(); j++) {
@@ -2465,7 +2497,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(tile_data->get_terrain_set());
if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) {
@@ -2501,7 +2533,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
TileData *tile_data = 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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
dummy_object->set("terrain_set", terrain_set);
dummy_object->set("terrain", -1);
@@ -2591,7 +2623,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.get_center() + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2i position = texture_region.get_center() + tile_data->get_texture_origin();
Vector<Vector2> polygon = tile_set->get_terrain_polygon(terrain_set);
if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) {
@@ -2741,7 +2773,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set
polygon_editor->add_polygon(nav_polygon->get_outline(i));
}
}
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
@@ -2750,7 +2782,7 @@ void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_s
Ref<NavigationPolygon> nav_polygon = p_value;
tile_data->set_navigation_polygon(navigation_layer, nav_polygon);
- polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index 02d4584428..1ebf30aecd 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -242,8 +242,8 @@ public:
~TileDataDefaultEditor();
};
-class TileDataTextureOffsetEditor : public TileDataDefaultEditor {
- GDCLASS(TileDataTextureOffsetEditor, TileDataDefaultEditor);
+class TileDataTextureOriginEditor : public TileDataDefaultEditor {
+ GDCLASS(TileDataTextureOriginEditor, TileDataDefaultEditor);
public:
virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 2394130ad6..4d9e2db682 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -266,7 +266,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven
}
Ref<TileSet> tile_set = tile_map->get_tileset();
- if (!tile_set.is_valid()) {
+ if (!tile_set.is_valid() || EditorNode::get_singleton()->is_resource_read_only(tile_set)) {
return;
}
@@ -571,14 +571,14 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
case DRAG_TYPE_PAINT: {
HashMap<Vector2i, TileMapCell> to_draw = _draw_line(drag_start_mouse_pos, drag_last_mouse_pos, mpos, drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
- continue;
- }
Vector2i coords = E.key;
if (!drag_modified.has(coords)) {
drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
_fix_invalid_tiles_in_tile_map_selection();
} break;
@@ -588,14 +588,14 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
- continue;
- }
Vector2i coords = E.key;
if (!drag_modified.has(coords)) {
drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
}
}
@@ -684,14 +684,14 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_modified.has(line[i])) {
HashMap<Vector2i, TileMapCell> to_draw = _draw_bucket_fill(line[i], bucket_contiguous_checkbox->is_pressed(), drag_erasing);
for (const KeyValue<Vector2i, TileMapCell> &E : to_draw) {
- if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
- continue;
- }
Vector2i coords = E.key;
if (!drag_modified.has(coords)) {
drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
+ if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
+ continue;
+ }
+ tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
}
}
@@ -897,7 +897,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Compute the offset
Rect2i source_rect = atlas_source->get_tile_texture_region(E.value.get_atlas_coords());
- Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(E.value.get_atlas_coords(), E.value.alternative_tile);
+ Vector2i tile_offset = tile_data->get_texture_origin();
// Compute the destination rectangle in the CanvasItem.
Rect2 dest_rect;
@@ -1277,13 +1277,15 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile);
}
- // Creating a pattern in the pattern list.
- select_last_pattern = true;
- int new_pattern_index = tile_set->get_patterns_count();
- undo_redo->create_action(TTR("Add TileSet pattern"));
- undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index);
- undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
- undo_redo->commit_action();
+ if (!EditorNode::get_singleton()->is_resource_read_only(tile_set)) {
+ // Creating a pattern in the pattern list.
+ select_last_pattern = true;
+ int new_pattern_index = tile_set->get_patterns_count();
+ undo_redo->create_action(TTR("Add TileSet pattern"));
+ undo_redo->add_do_method(*tile_set, "add_pattern", selection_pattern, new_pattern_index);
+ undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
+ undo_redo->commit_action();
+ }
} else {
// Get the top-left cell.
Vector2i top_left;
@@ -1989,6 +1991,15 @@ TypedArray<Vector2i> TileMapEditorTilesPlugin::_get_tile_map_selection() const {
void TileMapEditorTilesPlugin::edit(ObjectID p_tile_map_id, int p_tile_map_layer) {
_stop_dragging(); // Avoids staying in a wrong drag state.
+ // Disable sort button if the tileset is read-only
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (tile_map) {
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (tile_set.is_valid()) {
+ source_sort_button->set_disabled(EditorNode::get_singleton()->is_resource_read_only(tile_set));
+ }
+ }
+
if (tile_map_id != p_tile_map_id) {
tile_map_id = p_tile_map_id;
@@ -2044,7 +2055,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
select_tool_button->set_flat(true);
select_tool_button->set_toggle_mode(true);
select_tool_button->set_button_group(tool_buttons_group);
- select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", "Selection", Key::S));
+ select_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/selection_tool", TTR("Selection"), Key::S));
select_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(select_tool_button);
@@ -2052,7 +2063,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_flat(true);
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", Key::D));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D));
paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -2061,7 +2072,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
line_tool_button->set_flat(true);
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", Key::L));
+ // TRANSLATORS: This refers to the line tool in the tilemap editor.
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line", "Tool"), Key::L));
line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
@@ -2069,7 +2081,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
rect_tool_button->set_flat(true);
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", Key::R));
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R));
rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
@@ -2077,7 +2089,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
bucket_tool_button->set_flat(true);
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", Key::B));
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B));
bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
toolbar->add_child(tilemap_tiles_tools_buttons);
@@ -2093,7 +2105,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
picker_button->set_tooltip_text(TTR("Alternatively hold Ctrl with other tools to pick tile."));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -2102,7 +2114,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
erase_button = memnew(Button);
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E));
erase_button->set_tooltip_text(TTR("Alternatively use RMB to erase tiles."));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -2130,7 +2142,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scatter_controls_container = memnew(HBoxContainer);
scatter_label = memnew(Label);
- scatter_label->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_label->set_tooltip_text(TTR("Modifies the chance of painting nothing instead of a randomly selected tile."));
scatter_label->set_text(TTR("Scattering:"));
scatter_controls_container->add_child(scatter_label);
@@ -2138,7 +2150,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scatter_spinbox->set_min(0.0);
scatter_spinbox->set_max(1000);
scatter_spinbox->set_step(0.001);
- scatter_spinbox->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_spinbox->set_tooltip_text(TTR("Modifies the chance of painting nothing instead of a randomly selected tile."));
scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4);
scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed));
scatter_controls_container->add_child(scatter_spinbox);
@@ -3169,7 +3181,7 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() {
terrain_set_tree_item->set_icon(0, main_vbox_container->get_theme_icon(SNAME("TerrainMatchSides"), SNAME("EditorIcons")));
matches = String(TTR("Matches Sides Only"));
}
- terrain_set_tree_item->set_text(0, vformat("Terrain Set %d (%s)", terrain_set_index, matches));
+ terrain_set_tree_item->set_text(0, vformat(TTR("Terrain Set %d (%s)"), terrain_set_index, matches));
terrain_set_tree_item->set_selectable(0, false);
for (int terrain_index = 0; terrain_index < tile_set->get_terrains_count(terrain_set_index); terrain_index++) {
@@ -3318,7 +3330,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
main_vbox_container = memnew(VBoxContainer);
main_vbox_container->connect("tree_entered", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
main_vbox_container->connect("theme_changed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_theme));
- main_vbox_container->set_name("Terrains");
+ main_vbox_container->set_name(TTR("Terrains"));
HSplitContainer *tilemap_tab_terrains = memnew(HSplitContainer);
tilemap_tab_terrains->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -3354,7 +3366,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::D));
+ paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -3362,7 +3374,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
line_tool_button->set_flat(true);
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", "Line", Key::L));
+ line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line"), Key::L));
line_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
@@ -3370,7 +3382,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
rect_tool_button->set_flat(true);
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", "Rect", Key::R));
+ rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R));
rect_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
@@ -3378,7 +3390,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
bucket_tool_button->set_flat(true);
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", Key::B));
+ bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B));
bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
@@ -3395,7 +3407,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
picker_button = memnew(Button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
+ picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -3403,7 +3415,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() {
erase_button = memnew(Button);
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
+ erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -3986,7 +3998,7 @@ TileMapEditor::TileMapEditor() {
tabs_bar->connect("tab_changed", callable_mp(this, &TileMapEditor::_tab_changed));
// --- TileMap toolbar ---
- tile_map_toolbar = memnew(HBoxContainer);
+ tile_map_toolbar = memnew(HFlowContainer);
tile_map_toolbar->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(tile_map_toolbar);
@@ -4001,8 +4013,11 @@ TileMapEditor::TileMapEditor() {
}
}
- // Wide empty separation control.
- tile_map_toolbar->add_spacer();
+ // Wide empty separation control. (like BoxContainer::add_spacer())
+ Control *c = memnew(Control);
+ c->set_mouse_filter(MOUSE_FILTER_PASS);
+ c->set_h_size_flags(SIZE_EXPAND_FILL);
+ tile_map_toolbar->add_child(c);
// Layer selector.
layers_selection_button = memnew(OptionButton);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index fb9c2f3689..1cab1d1500 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -38,6 +38,7 @@
#include "scene/2d/tile_map.h"
#include "scene/gui/box_container.h"
#include "scene/gui/check_box.h"
+#include "scene/gui/flow_container.h"
#include "scene/gui/item_list.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
@@ -323,7 +324,7 @@ private:
Vector<TileMapEditorPlugin *> tile_map_editor_plugins;
// Toolbar.
- HBoxContainer *tile_map_toolbar = nullptr;
+ HFlowContainer *tile_map_toolbar = nullptr;
OptionButton *layers_selection_button = nullptr;
Button *toggle_highlight_selected_layer_button = nullptr;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 32421daa92..fcefbb7d06 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_inspector.h"
#include "editor/editor_node.h"
+#include "editor/editor_property_name_processor.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
@@ -106,13 +107,13 @@ bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringN
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, TTR("Atlas"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- p_list->push_back(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1"));
- p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, ""));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("id"), PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::STRING, PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("texture"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("margins"), PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("separation")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("texture_region_size"), PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("use_texture_padding")));
}
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
@@ -120,10 +121,9 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
}
void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
- ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set_atlas_source);
ERR_FAIL_COND(p_source_id < 0);
- ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
+ ERR_FAIL_COND(p_tile_set.is_valid() && p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == source_id) {
return;
@@ -393,11 +393,11 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
if (tiles.size() == 1) {
if (tiles.front()->get().alternative == 0) {
p_list->push_back(PropertyInfo(Variant::NIL, TTR("Base Tile"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("atlas_coords")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("size_in_atlas")));
} else {
p_list->push_back(PropertyInfo(Variant::NIL, TTR("Alternative Tile"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
- p_list->push_back(PropertyInfo(Variant::INT, "alternative_id"));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("alternative_id")));
}
} else {
p_list->push_back(PropertyInfo(Variant::NIL, TTR("Tiles"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
@@ -414,17 +414,17 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
}
if (all_alternatve_id_zero) {
- 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_"));
+ p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Animation", "animation_"), PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_columns")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("animation_separation")));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("animation_speed")));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_frames_count"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
// Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
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, "suffix:s", 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, "suffix:s"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/%s", i, PNAME("duration")), PROPERTY_HINT_NONE, "suffix:s"));
}
}
}
@@ -585,6 +585,7 @@ void TileSetAtlasSourceEditor::_update_atlas_source_inspector() {
// Update visibility.
bool inspector_visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button;
atlas_source_inspector->set_visible(inspector_visible);
+ atlas_source_inspector->set_read_only(read_only);
}
void TileSetAtlasSourceEditor::_update_tile_inspector() {
@@ -599,6 +600,7 @@ void TileSetAtlasSourceEditor::_update_tile_inspector() {
tile_inspector->hide();
tile_inspector_no_tile_selected_label->hide();
}
+ tile_inspector->set_read_only(read_only);
}
void TileSetAtlasSourceEditor::_update_tile_data_editors() {
@@ -609,6 +611,10 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors_tree->clear();
+ if (tile_set.is_null()) {
+ return;
+ }
+
TreeItem *root = tile_data_editors_tree->create_item();
TreeItem *group;
@@ -636,19 +642,19 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
// List of editors.
// --- Rendering ---
- ADD_TILE_DATA_EDITOR_GROUP("Rendering");
+ ADD_TILE_DATA_EDITOR_GROUP(TTR("Rendering"));
- ADD_TILE_DATA_EDITOR(group, "Texture Offset", "texture_offset");
- if (!tile_data_editors.has("texture_offset")) {
- TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
- tile_data_texture_offset_editor->hide();
- tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset");
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
- tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
- tile_data_editors["texture_offset"] = tile_data_texture_offset_editor;
+ ADD_TILE_DATA_EDITOR(group, TTR("Texture Origin"), "texture_origin");
+ if (!tile_data_editors.has("texture_origin")) {
+ TileDataTextureOriginEditor *tile_data_texture_origin_editor = memnew(TileDataTextureOriginEditor);
+ tile_data_texture_origin_editor->hide();
+ tile_data_texture_origin_editor->setup_property_editor(Variant::VECTOR2, "texture_origin");
+ tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
+ tile_data_texture_origin_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
+ tile_data_editors["texture_origin"] = tile_data_texture_origin_editor;
}
- ADD_TILE_DATA_EDITOR(group, "Modulate", "modulate");
+ ADD_TILE_DATA_EDITOR(group, TTR("Modulate"), "modulate");
if (!tile_data_editors.has("modulate")) {
TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor());
tile_data_modulate_editor->hide();
@@ -658,7 +664,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors["modulate"] = tile_data_modulate_editor;
}
- ADD_TILE_DATA_EDITOR(group, "Z Index", "z_index");
+ ADD_TILE_DATA_EDITOR(group, TTR("Z Index"), "z_index");
if (!tile_data_editors.has("z_index")) {
TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor());
tile_data_z_index_editor->hide();
@@ -668,7 +674,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
tile_data_editors["z_index"] = tile_data_z_index_editor;
}
- ADD_TILE_DATA_EDITOR(group, "Y Sort Origin", "y_sort_origin");
+ ADD_TILE_DATA_EDITOR(group, TTR("Y Sort Origin"), "y_sort_origin");
if (!tile_data_editors.has("y_sort_origin")) {
TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
tile_data_y_sort_editor->hide();
@@ -679,7 +685,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
- ADD_TILE_DATA_EDITOR(group, vformat("Occlusion Layer %d", i), vformat("occlusion_layer_%d", i));
+ ADD_TILE_DATA_EDITOR(group, vformat(TTR("Occlusion Layer %d"), i), vformat("occlusion_layer_%d", i));
if (!tile_data_editors.has(vformat("occlusion_layer_%d", i))) {
TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor());
tile_data_occlusion_shape_editor->hide();
@@ -695,7 +701,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// --- Rendering ---
- ADD_TILE_DATA_EDITOR(root, "Terrains", "terrain_set");
+ ADD_TILE_DATA_EDITOR(root, TTR("Terrains"), "terrain_set");
if (!tile_data_editors.has("terrain_set")) {
TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
tile_data_terrains_editor->hide();
@@ -705,7 +711,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// --- Miscellaneous ---
- ADD_TILE_DATA_EDITOR(root, "Probability", "probability");
+ ADD_TILE_DATA_EDITOR(root, TTR("Probability"), "probability");
if (!tile_data_editors.has("probability")) {
TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor());
tile_data_probability_editor->hide();
@@ -716,9 +722,9 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// --- Physics ---
- ADD_TILE_DATA_EDITOR_GROUP("Physics");
+ ADD_TILE_DATA_EDITOR_GROUP(TTR("Physics"));
for (int i = 0; i < tile_set->get_physics_layers_count(); i++) {
- ADD_TILE_DATA_EDITOR(group, vformat("Physics Layer %d", i), vformat("physics_layer_%d", i));
+ ADD_TILE_DATA_EDITOR(group, vformat(TTR("Physics Layer %d"), i), vformat("physics_layer_%d", i));
if (!tile_data_editors.has(vformat("physics_layer_%d", i))) {
TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor());
tile_data_collision_editor->hide();
@@ -734,9 +740,9 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// --- Navigation ---
- ADD_TILE_DATA_EDITOR_GROUP("Navigation");
+ ADD_TILE_DATA_EDITOR_GROUP(TTR("Navigation"));
for (int i = 0; i < tile_set->get_navigation_layers_count(); i++) {
- ADD_TILE_DATA_EDITOR(group, vformat("Navigation Layer %d", i), vformat("navigation_layer_%d", i));
+ ADD_TILE_DATA_EDITOR(group, vformat(TTR("Navigation Layer %d"), i), vformat("navigation_layer_%d", i));
if (!tile_data_editors.has(vformat("navigation_layer_%d", i))) {
TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor());
tile_data_navigation_editor->hide();
@@ -752,14 +758,14 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
// --- Custom Data ---
- ADD_TILE_DATA_EDITOR_GROUP("Custom Data");
+ ADD_TILE_DATA_EDITOR_GROUP(TTR("Custom Data"));
for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) {
String editor_name = vformat("custom_data_%d", i);
String prop_name = tile_set->get_custom_data_layer_name(i);
Variant::Type prop_type = tile_set->get_custom_data_layer_type(i);
if (prop_name.is_empty()) {
- ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), editor_name);
+ ADD_TILE_DATA_EDITOR(group, vformat(TTR("Custom Data %d"), i), editor_name);
} else {
ADD_TILE_DATA_EDITOR(group, prop_name, editor_name);
}
@@ -917,6 +923,10 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
alternative_tiles_control->get_child(i)->queue_free();
}
+ if (tile_set.is_null()) {
+ return;
+ }
+
Vector2i pos;
Vector2 texture_region_base_size = tile_set_atlas_source->get_texture_region_size();
int texture_region_base_size_min = MIN(texture_region_base_size.x, texture_region_base_size.y);
@@ -970,19 +980,19 @@ void TileSetAtlasSourceEditor::_update_toolbar() {
current_tile_data_editor_toolbar->hide();
}
tools_settings_erase_button->show();
- tool_advanced_menu_buttom->show();
+ tool_advanced_menu_button->show();
} else if (tools_button_group->get_pressed_button() == tool_select_button) {
if (current_tile_data_editor_toolbar) {
current_tile_data_editor_toolbar->hide();
}
tools_settings_erase_button->hide();
- tool_advanced_menu_buttom->hide();
+ tool_advanced_menu_button->hide();
} else if (tools_button_group->get_pressed_button() == tool_paint_button) {
if (current_tile_data_editor_toolbar) {
current_tile_data_editor_toolbar->show();
}
tools_settings_erase_button->hide();
- tool_advanced_menu_buttom->hide();
+ tool_advanced_menu_button->hide();
}
}
@@ -1862,7 +1872,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.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
+ Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_data(coords, 0)->get_texture_origin();
Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
xform.translate_local(position);
@@ -1885,7 +1895,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
continue;
}
Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E.tile);
- Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E.tile, 0);
+ Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_data(E.tile, 0)->get_texture_origin();
Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
xform.translate_local(position);
@@ -2037,7 +2047,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_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile);
+ Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_data(coords, alternative_tile)->get_texture_origin();
Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
xform.translate_local(position);
@@ -2061,7 +2071,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
continue;
}
Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E.tile, E.alternative);
- Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E.tile, E.alternative);
+ Vector2 position = rect.get_center() + tile_set_atlas_source->get_tile_data(E.tile, E.alternative)->get_texture_origin();
Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
xform.translate_local(position);
@@ -2188,7 +2198,12 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
- if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id) {
+ bool new_read_only_state = false;
+ if (p_tile_set.is_valid()) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set);
+ }
+
+ if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id && new_read_only_state == read_only) {
return;
}
@@ -2205,11 +2220,23 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource
tile_set_atlas_source = p_tile_set_atlas_source;
tile_set_atlas_source_id = p_source_id;
- // Add the listener again.
+ // Read-only is off by default.
+ read_only = new_read_only_state;
+
if (tile_set.is_valid()) {
tile_set->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
}
+ if (read_only && tools_button_group->get_pressed_button() == tool_paint_button) {
+ tool_paint_button->set_pressed(false);
+ tool_setup_atlas_source_button->set_pressed(true);
+ }
+
+ // Disable buttons in read-only mode.
+ tool_paint_button->set_disabled(read_only);
+ tools_settings_erase_button->set_disabled(read_only);
+ tool_advanced_menu_button->set_disabled(read_only);
+
// Update everything.
_update_source_inspector();
@@ -2344,7 +2371,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
tools_settings_erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
- tool_advanced_menu_buttom->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ tool_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
resize_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons"));
@@ -2352,6 +2379,18 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_set_changed_needs_update) {
+ // Read-only is off by default
+ read_only = false;
+ // Add the listener again and check for read-only status.
+ if (tile_set.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set);
+ }
+
+ // Disable buttons in read-only mode.
+ tool_paint_button->set_disabled(read_only);
+ tools_settings_erase_button->set_disabled(read_only);
+ tool_advanced_menu_button->set_disabled(read_only);
+
// Update everything.
_update_source_inspector();
@@ -2376,6 +2415,14 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
}
}
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) {
+ EditorPropertyNameProcessor::Style style = EditorPropertyNameProcessor::get_singleton()->get_settings_style();
+ atlas_source_inspector->set_property_name_style(style);
+ tile_inspector->set_property_name_style(style);
+ }
+ } break;
}
}
@@ -2445,6 +2492,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_inspector->edit(tile_proxy_object);
tile_inspector->set_use_folding(true);
tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected));
+ tile_inspector->set_property_name_style(EditorPropertyNameProcessor::get_singleton()->get_settings_style());
middle_vbox_container->add_child(tile_inspector);
tile_inspector_no_tile_selected_label = memnew(Label);
@@ -2496,6 +2544,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
atlas_source_inspector->set_v_size_flags(SIZE_EXPAND_FILL);
atlas_source_inspector->set_show_categories(true);
atlas_source_inspector->edit(atlas_source_proxy_object);
+ atlas_source_inspector->set_property_name_style(EditorPropertyNameProcessor::get_singleton()->get_settings_style());
middle_vbox_container->add_child(atlas_source_inspector);
// -- Right side --
@@ -2516,12 +2565,12 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tools_settings_erase_button->set_shortcut_context(this);
tool_settings->add_child(tools_settings_erase_button);
- tool_advanced_menu_buttom = memnew(MenuButton);
- tool_advanced_menu_buttom->set_flat(true);
- tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
- tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
- tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
- tool_settings->add_child(tool_advanced_menu_buttom);
+ tool_advanced_menu_button = memnew(MenuButton);
+ tool_advanced_menu_button->set_flat(true);
+ tool_advanced_menu_button->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
+ tool_advanced_menu_button->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
+ tool_advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
+ tool_settings->add_child(tool_advanced_menu_button);
_update_toolbar();
@@ -2673,7 +2722,7 @@ void EditorPropertyTilePolygon::update_property() {
Vector2i coords = atlas_tile_proxy_object->get_edited_tiles().front()->get().tile;
int alternative = atlas_tile_proxy_object->get_edited_tiles().front()->get().alternative;
TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
- generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
+ generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_data->get_texture_origin(), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
// Reset the polygons.
generic_tile_polygon_editor->clear_polygons();
@@ -2742,7 +2791,7 @@ bool EditorInspectorPluginTileData::can_handle(Object *p_object) {
return Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(p_object) != nullptr;
}
-bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
Vector<String> components = String(p_path).split("/", true, 2);
if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
// Occlusion layers.
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index bcab1296ad..5141824f79 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -113,6 +113,8 @@ public:
};
private:
+ bool read_only = false;
+
Ref<TileSet> tile_set;
TileSetAtlasSource *tile_set_atlas_source = nullptr;
int tile_set_atlas_source_id = TileSet::INVALID_SOURCE;
@@ -209,7 +211,7 @@ private:
HBoxContainer *tool_settings = nullptr;
HBoxContainer *tool_settings_tile_data_toolbar_container = nullptr;
Button *tools_settings_erase_button = nullptr;
- MenuButton *tool_advanced_menu_buttom = nullptr;
+ MenuButton *tool_advanced_menu_button = nullptr;
// Selection.
RBSet<TileSelection> selection;
@@ -310,7 +312,7 @@ class EditorInspectorPluginTileData : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
#endif // TILE_SET_ATLAS_SOURCE_EDITOR_H
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 53c2d4de51..358cc47977 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -89,6 +89,10 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data,
bool TileSetEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
ERR_FAIL_COND_V(!tile_set.is_valid(), false);
+ if (read_only) {
+ return false;
+ }
+
if (p_from == sources_list) {
Dictionary d = p_data;
@@ -223,7 +227,7 @@ void TileSetEditor::_source_selected(int p_source_index) {
ERR_FAIL_COND(!tile_set.is_valid());
// Update the selected source.
- sources_delete_button->set_disabled(p_source_index < 0);
+ sources_delete_button->set_disabled(p_source_index < 0 || read_only);
if (p_source_index >= 0) {
int source_id = sources_list->get_item_metadata(p_source_index);
@@ -356,8 +360,19 @@ void TileSetEditor::_notification(int p_what) {
if (tile_set.is_valid()) {
tile_set->set_edited(true);
}
+
+ read_only = false;
+ if (tile_set.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set);
+ }
+
_update_sources_list();
_update_patterns_list();
+
+ sources_add_button->set_disabled(read_only);
+ sources_advanced_menu_button->set_disabled(read_only);
+ source_sort_button->set_disabled(read_only);
+
tile_set_changed_needs_update = false;
}
} break;
@@ -367,6 +382,10 @@ void TileSetEditor::_notification(int p_what) {
void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(!tile_set.is_valid());
+ if (EditorNode::get_singleton()->is_resource_read_only(tile_set)) {
+ return;
+ }
+
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
Vector<int> selected = patterns_item_list->get_selected_items();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
@@ -667,7 +686,12 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
}
void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
- if (p_tile_set == tile_set) {
+ bool new_read_only_state = false;
+ if (p_tile_set.is_valid()) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set);
+ }
+
+ if (p_tile_set == tile_set && new_read_only_state == read_only) {
return;
}
@@ -679,8 +703,15 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
// Change the edited object.
tile_set = p_tile_set;
- // Add the listener again.
+ // Read-only status is false by default
+ read_only = new_read_only_state;
+
+ // Add the listener again and check for read-only status.
if (tile_set.is_valid()) {
+ sources_add_button->set_disabled(read_only);
+ sources_advanced_menu_button->set_disabled(read_only);
+ source_sort_button->set_disabled(read_only);
+
tile_set->connect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
if (first_edit) {
first_edit = false;
@@ -690,10 +721,6 @@ void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
}
_update_patterns_list();
}
-
- tile_set_atlas_source_editor->hide();
- tile_set_scenes_collection_source_editor->hide();
- no_source_selected_label->show();
}
TileSetEditor::TileSetEditor() {
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index e3dff11277..d36d3bde41 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -45,6 +45,8 @@ class TileSetEditor : public VBoxContainer {
static TileSetEditor *singleton;
private:
+ bool read_only = false;
+
Ref<TileSet> tile_set;
bool tile_set_changed_needs_update = false;
HSplitContainer *split_container = nullptr;
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index 6251cd18f7..101ec5f66c 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
+#include "editor/editor_property_name_processor.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -284,7 +285,7 @@ void TileSetScenesCollectionSourceEditor::_update_tile_inspector() {
void TileSetScenesCollectionSourceEditor::_update_action_buttons() {
Vector<int> selected_indices = scene_tiles_list->get_selected_items();
- scene_tile_delete_button->set_disabled(selected_indices.size() <= 0);
+ scene_tile_delete_button->set_disabled(selected_indices.size() <= 0 || read_only);
}
void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
@@ -342,6 +343,12 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
if (tile_set_scenes_collection_source_changed_needs_update) {
+ read_only = false;
+ // Add the listener again and check for read-only status.
+ if (tile_set.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(tile_set);
+ }
+
// Update everything.
_update_source_inspector();
_update_scenes_list();
@@ -356,6 +363,14 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
_update_scenes_list();
_update_action_buttons();
} break;
+
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/localize_settings")) {
+ EditorPropertyNameProcessor::Style style = EditorPropertyNameProcessor::get_singleton()->get_settings_style();
+ scenes_collection_source_inspector->set_property_name_style(style);
+ tile_inspector->set_property_name_style(style);
+ }
+ } break;
}
}
@@ -365,7 +380,12 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
- if (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id) {
+ bool new_read_only_state = false;
+ if (p_tile_set.is_valid()) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_tile_set);
+ }
+
+ if (p_tile_set == tile_set && p_tile_set_scenes_collection_source == tile_set_scenes_collection_source && p_source_id == tile_set_source_id && new_read_only_state == read_only) {
return;
}
@@ -379,6 +399,16 @@ void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetS
tile_set_scenes_collection_source = p_tile_set_scenes_collection_source;
tile_set_source_id = p_source_id;
+ // Read-only status is false by default
+ read_only = new_read_only_state;
+
+ if (tile_set.is_valid()) {
+ scenes_collection_source_inspector->set_read_only(read_only);
+ tile_inspector->set_read_only(read_only);
+
+ scene_tile_add_button->set_disabled(read_only);
+ }
+
// Add the listener again.
if (tile_set_scenes_collection_source) {
tile_set_scenes_collection_source->connect("changed", callable_mp(this, &TileSetScenesCollectionSourceEditor::_tile_set_scenes_collection_source_changed));
@@ -482,6 +512,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scenes_collection_source_inspector = memnew(EditorInspector);
scenes_collection_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
scenes_collection_source_inspector->edit(scenes_collection_source_proxy_object);
+ scenes_collection_source_inspector->set_property_name_style(EditorPropertyNameProcessor::get_singleton()->get_settings_style());
middle_vbox_container->add_child(scenes_collection_source_inspector);
// Tile inspector.
@@ -498,6 +529,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
tile_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
tile_inspector->edit(tile_proxy_object);
tile_inspector->set_use_folding(true);
+ tile_inspector->set_property_name_style(EditorPropertyNameProcessor::get_singleton()->get_settings_style());
middle_vbox_container->add_child(tile_inspector);
// Scenes list.
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
index 0901205a29..2a0e8595c4 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -91,6 +91,8 @@ private:
};
private:
+ bool read_only = false;
+
Ref<TileSet> tile_set;
TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
int tile_set_source_id = -1;
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 19ee0ae98d..78522dfa73 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -101,12 +101,12 @@ void TilesEditorPlugin::_thread() {
encompassing_rect.expand_to(world_pos);
// Texture.
- Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(tile_map->get_cell_source_id(0, cell));
+ Ref<TileSetAtlasSource> atlas_source = item.tile_set->get_source(tile_map->get_cell_source_id(0, cell));
if (atlas_source.is_valid()) {
Vector2i coords = tile_map->get_cell_atlas_coords(0, cell);
int alternative = tile_map->get_cell_alternative_tile(0, cell);
- Vector2 center = world_pos - atlas_source->get_tile_effective_texture_offset(coords, alternative);
+ Vector2 center = world_pos - atlas_source->get_tile_data(coords, alternative)->get_texture_origin();
encompassing_rect.expand_to(center - atlas_source->get_tile_texture_region(coords).size / 2);
encompassing_rect.expand_to(center + atlas_source->get_tile_texture_region(coords).size / 2);
}
@@ -117,7 +117,7 @@ void TilesEditorPlugin::_thread() {
tile_map->set_position(-(scale * encompassing_rect.get_center()) + thumbnail_size2 / 2);
// Add the viewport at the last moment to avoid rendering too early.
- EditorNode::get_singleton()->add_child(viewport);
+ EditorNode::get_singleton()->call_deferred("add_child", viewport);
RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Object::CONNECT_ONE_SHOT);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 96b1ad7ee0..af761a2cea 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/filesystem_dock.h"
#include "editor/inspector_dock.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/shader_editor_plugin.h"
@@ -127,7 +128,7 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio
connections = p_connections;
}
-void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) {
+void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
Link &link = links[p_node_id];
@@ -161,7 +162,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
vbox->add_child(offset);
VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
- port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id);
+ port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id, p_is_valid);
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
vbox->add_child(port_preview);
link.preview_visible = true;
@@ -350,6 +351,29 @@ void VisualShaderGraphPlugin::update_theme() {
vector_expanded_color[3] = editor->get_theme_color(SNAME("axis_w_color"), SNAME("Editor")); // alpha
}
+bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const {
+ bool result = false;
+
+ Ref<VisualShaderNodeParameter> parameter_node = Object::cast_to<VisualShaderNodeParameter>(visual_shader->get_node_unchecked(p_type, p_node).ptr());
+ if (parameter_node.is_valid()) {
+ if (parameter_node->get_qualifier() == VisualShaderNodeParameter::QUAL_INSTANCE) {
+ return true;
+ }
+ }
+
+ LocalVector<int> prev_connected_nodes;
+ visual_shader->get_prev_connected_nodes(p_type, p_node, prev_connected_nodes);
+
+ for (const int &E : prev_connected_nodes) {
+ result = is_node_has_parameter_instances_relatively(p_type, E);
+ if (result) {
+ break;
+ }
+ }
+
+ return result;
+}
+
void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update) {
if (!visual_shader.is_valid() || p_type != visual_shader->get_shader_type()) {
return;
@@ -968,8 +992,10 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
}
}
+ bool has_relative_parameter_instances = false;
if (vsnode->get_output_port_for_preview() >= 0) {
- show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview());
+ has_relative_parameter_instances = is_node_has_parameter_instances_relatively(p_type, p_id);
+ show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview(), !has_relative_parameter_instances);
} else {
offset = memnew(Control);
offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
@@ -977,6 +1003,9 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
}
String error = vsnode->get_warning(mode, p_type);
+ if (has_relative_parameter_instances) {
+ error += "\n" + TTR("The 2D preview cannot correctly show the result retrieved from instance parameter.");
+ }
if (!error.is_empty()) {
Label *error_label = memnew(Label);
error_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("error_color"), SNAME("Editor")));
@@ -1271,18 +1300,55 @@ Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom>
return dict;
}
-void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
- Ref<Script> scr = Ref<Script>(p_resource.ptr());
- if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {
+void VisualShaderEditor::_get_current_mode_limits(int &r_begin_type, int &r_end_type) const {
+ switch (visual_shader->get_mode()) {
+ case Shader::MODE_CANVAS_ITEM:
+ case Shader::MODE_SPATIAL: {
+ r_begin_type = 0;
+ r_end_type = 3;
+ } break;
+ case Shader::MODE_PARTICLES: {
+ r_begin_type = 3;
+ r_end_type = 5 + r_begin_type;
+ } break;
+ case Shader::MODE_SKY: {
+ r_begin_type = 8;
+ r_end_type = 1 + r_begin_type;
+ } break;
+ case Shader::MODE_FOG: {
+ r_begin_type = 9;
+ r_end_type = 1 + r_begin_type;
+ } break;
+ default: {
+ } break;
+ }
+}
+
+void VisualShaderEditor::_script_created(const Ref<Script> &p_script) {
+ if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {
+ return;
+ }
+ Ref<VisualShaderNodeCustom> ref;
+ ref.instantiate();
+ ref->set_script(p_script);
+
+ Dictionary dict = get_custom_node_data(ref);
+ add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
+
+ _update_options_menu();
+}
+
+void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {
+ if (p_script.is_null() || p_script->get_instance_base_type() != "VisualShaderNodeCustom") {
return;
}
Ref<VisualShaderNodeCustom> ref;
ref.instantiate();
- ref->set_script(scr);
+ ref->set_script(p_script);
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
for (int i = 0; i < add_options.size(); i++) {
- if (add_options[i].is_custom && add_options[i].script == scr) {
+ if (add_options[i].is_custom && add_options[i].script == p_script) {
add_options.remove_at(i);
_update_options_menu();
// TODO: Make indication for the existed custom nodes with that script on graph to be disabled.
@@ -1296,8 +1362,8 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
bool found_type = false;
bool need_rebuild = false;
- for (int i = 0; i < add_options.size(); i++) {
- if (add_options[i].is_custom && add_options[i].script == scr) {
+ for (int i = custom_node_option_idx; i < add_options.size(); i++) {
+ if (add_options[i].script == p_script) {
found_type = true;
add_options.write[i].name = dict["name"];
@@ -1306,31 +1372,11 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
add_options.write[i].category = dict["category"];
add_options.write[i].highend = dict["highend"];
- int max_type = 0;
- int type_offset = 0;
- switch (visual_shader->get_mode()) {
- case Shader::MODE_CANVAS_ITEM:
- case Shader::MODE_SPATIAL: {
- max_type = 3;
- } break;
- case Shader::MODE_PARTICLES: {
- max_type = 5;
- type_offset = 3;
- } break;
- case Shader::MODE_SKY: {
- max_type = 1;
- type_offset = 8;
- } break;
- case Shader::MODE_FOG: {
- max_type = 1;
- type_offset = 9;
- } break;
- default: {
- } break;
- }
- max_type = type_offset + max_type;
+ int begin_type = 0;
+ int end_type = 0;
+ _get_current_mode_limits(begin_type, end_type);
- for (int t = type_offset; t < max_type; t++) {
+ for (int t = begin_type; t < end_type; t++) {
VisualShader::Type type = (VisualShader::Type)t;
Vector<int> nodes = visual_shader->get_node_list(type);
@@ -1339,28 +1385,27 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
List<VisualShader::Connection> custom_node_input_connections;
List<VisualShader::Connection> custom_node_output_connections;
+
for (const VisualShader::Connection &E : node_connections) {
int from = E.from_node;
- int from_idx = E.from_port;
+ int from_port = E.from_port;
int to = E.to_node;
- int to_idx = E.to_port;
+ int to_port = E.to_port;
- if (graph_plugin->get_node_script(from) == scr) {
- custom_node_output_connections.push_back({ from, from_idx, to, to_idx });
- } else if (graph_plugin->get_node_script(to) == scr) {
- custom_node_input_connections.push_back({ from, from_idx, to, to_idx });
+ if (graph_plugin->get_node_script(from) == p_script) {
+ custom_node_output_connections.push_back({ from, from_port, to, to_port });
+ } else if (graph_plugin->get_node_script(to) == p_script) {
+ custom_node_input_connections.push_back({ from, from_port, to, to_port });
}
}
- for (int j = 0; j < nodes.size(); j++) {
- int node_id = nodes[j];
-
+ for (int node_id : nodes) {
Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
if (vsnode.is_null()) {
continue;
}
Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr());
- if (custom_node.is_null() || custom_node->get_script() != scr) {
+ if (custom_node.is_null() || custom_node->get_script() != p_script) {
continue;
}
need_rebuild = true;
@@ -1429,6 +1474,89 @@ void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) {
}
}
+void VisualShaderEditor::_resource_saved(const Ref<Resource> &p_resource) {
+ _update_custom_script(Ref<Script>(p_resource.ptr()));
+}
+
+void VisualShaderEditor::_resources_removed() {
+ bool has_any_instance = false;
+
+ for (const Ref<Script> &scr : custom_scripts_to_delete) {
+ for (int i = custom_node_option_idx; i < add_options.size(); i++) {
+ if (add_options[i].script == scr) {
+ add_options.remove_at(i);
+
+ // Removes all node instances using that script from the graph.
+ {
+ int begin_type = 0;
+ int end_type = 0;
+ _get_current_mode_limits(begin_type, end_type);
+
+ for (int t = begin_type; t < end_type; t++) {
+ VisualShader::Type type = (VisualShader::Type)t;
+
+ List<VisualShader::Connection> node_connections;
+ visual_shader->get_node_connections(type, &node_connections);
+
+ for (const VisualShader::Connection &E : node_connections) {
+ int from = E.from_node;
+ int from_port = E.from_port;
+ int to = E.to_node;
+ int to_port = E.to_port;
+
+ if (graph_plugin->get_node_script(from) == scr || graph_plugin->get_node_script(to) == scr) {
+ visual_shader->disconnect_nodes(type, from, from_port, to, to_port);
+ graph_plugin->disconnect_nodes(type, from, from_port, to, to_port);
+ }
+ }
+
+ Vector<int> nodes = visual_shader->get_node_list(type);
+ for (int node_id : nodes) {
+ Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id);
+ if (vsnode.is_null()) {
+ continue;
+ }
+ Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr());
+ if (custom_node.is_null() || custom_node->get_script() != scr) {
+ continue;
+ }
+ visual_shader->remove_node(type, node_id);
+ graph_plugin->remove_node(type, node_id, false);
+
+ has_any_instance = true;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ if (has_any_instance) {
+ EditorUndoRedoManager::get_singleton()->clear_history(); // Need to clear undo history, otherwise it may lead to hard-detected errors and crashes (since the script was removed).
+ ResourceSaver::save(visual_shader, visual_shader->get_path());
+ }
+ _update_options_menu();
+
+ custom_scripts_to_delete.clear();
+ pending_custom_scripts_to_delete = false;
+}
+
+void VisualShaderEditor::_resource_removed(const Ref<Resource> &p_resource) {
+ Ref<Script> scr = Ref<Script>(p_resource.ptr());
+ if (scr.is_null() || scr->get_instance_base_type() != "VisualShaderNodeCustom") {
+ return;
+ }
+
+ custom_scripts_to_delete.push_back(scr);
+
+ if (!pending_custom_scripts_to_delete) {
+ pending_custom_scripts_to_delete = true;
+
+ call_deferred("_resources_removed");
+ }
+}
+
void VisualShaderEditor::_update_options_menu_deferred() {
_update_options_menu();
@@ -4870,6 +4998,29 @@ void VisualShaderEditor::_update_preview() {
}
}
+void VisualShaderEditor::_update_next_previews(int p_node_id) {
+ VisualShader::Type type = get_current_shader_type();
+
+ LocalVector<int> nodes;
+ _get_next_nodes_recursively(type, p_node_id, nodes);
+
+ for (int node_id : nodes) {
+ if (graph_plugin->is_preview_visible(node_id)) {
+ graph_plugin->update_node_deferred(type, node_id);
+ }
+ }
+}
+
+void VisualShaderEditor::_get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const {
+ LocalVector<int> next_connections;
+ visual_shader->get_next_connected_nodes(p_type, p_node_id, next_connections);
+
+ for (int node_id : next_connections) {
+ r_nodes.push_back(node_id);
+ _get_next_nodes_recursively(p_type, node_id, r_nodes);
+ }
+}
+
void VisualShaderEditor::_visibility_changed() {
if (!is_visible()) {
if (preview_window->is_visible()) {
@@ -4901,13 +5052,17 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port);
ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
+ ClassDB::bind_method("_resources_removed", &VisualShaderEditor::_resources_removed);
+ ClassDB::bind_method("_update_next_previews", &VisualShaderEditor::_update_next_previews);
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
VisualShaderEditor::VisualShaderEditor() {
ShaderLanguage::get_keyword_list(&keyword_list);
- EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::update_custom_type));
+ EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved));
+ FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created));
+ FileSystemDock::get_singleton()->connect("resource_removed", callable_mp(this, &VisualShaderEditor::_resource_removed));
graph = memnew(GraphEdit);
graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -5186,7 +5341,7 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog->set_ok_button_text(TTR("Create"));
members_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
members_dialog->get_ok_button()->set_disabled(true);
- members_dialog->connect("cancelled", callable_mp(this, &VisualShaderEditor::_member_cancel));
+ members_dialog->connect("canceled", callable_mp(this, &VisualShaderEditor::_member_cancel));
add_child(members_dialog);
// add varyings dialog
@@ -5433,6 +5588,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("EyeOffset", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
@@ -5451,6 +5607,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("EyeOffset", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "eye_offset", "EYE_OFFSET"), { "eye_offset" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -5544,7 +5701,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("WorldPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "world_position", "WORLD_POSITION"), { "world_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
add_options.push_back(AddOption("ObjectPosition", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "object_position", "OBJECT_POSITION"), { "object_position" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
add_options.push_back(AddOption("UVW", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "uvw", "UVW"), { "uvw" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
- add_options.push_back(AddOption("Extents", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "extents", "EXTENTS"), { "extents" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
+ add_options.push_back(AddOption("Size", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "size", "SIZE"), { "size" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FOG, Shader::MODE_FOG));
add_options.push_back(AddOption("SDF", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "sdf", "SDF"), { "sdf" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
add_options.push_back(AddOption("Time", "Input/Fog", "VisualShaderNodeInput", vformat(input_param_for_fog_shader_mode, "time", "TIME"), { "time" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FOG, Shader::MODE_FOG));
@@ -6187,6 +6344,8 @@ public:
if (p_property != "constant") {
VisualShaderGraphPlugin *graph_plugin = editor->get_graph_plugin();
if (graph_plugin) {
+ undo_redo->add_do_method(editor, "_update_next_previews", node_id);
+ undo_redo->add_undo_method(editor, "_update_next_previews", node_id);
undo_redo->add_do_method(graph_plugin, "update_node_deferred", shader_type, node_id);
undo_redo->add_undo_method(graph_plugin, "update_node_deferred", shader_type, node_id);
}
@@ -6465,7 +6624,7 @@ bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {
return true; // Can handle everything.
}
-bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {
EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);
Vector<String> options = p_hint_text.split(",");
@@ -6481,7 +6640,7 @@ bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, con
//////////////////////////////////
void VisualShaderNodePortPreview::_shader_changed() {
- if (shader.is_null()) {
+ if (!is_valid || shader.is_null()) {
return;
}
@@ -6528,12 +6687,13 @@ void VisualShaderNodePortPreview::_shader_changed() {
set_material(mat);
}
-void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port) {
+void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid) {
shader = p_shader;
- shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed));
+ shader->connect("changed", callable_mp(this, &VisualShaderNodePortPreview::_shader_changed), CONNECT_DEFERRED);
type = p_type;
port = p_port;
node = p_node;
+ is_valid = p_is_valid;
queue_redraw();
_shader_changed();
}
@@ -6560,14 +6720,24 @@ void VisualShaderNodePortPreview::_notification(int p_what) {
Vector2(0, 1)
};
- Vector<Color> colors = {
- Color(1, 1, 1, 1),
- Color(1, 1, 1, 1),
- Color(1, 1, 1, 1),
- Color(1, 1, 1, 1)
- };
+ if (is_valid) {
+ Vector<Color> colors = {
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1),
+ Color(1, 1, 1, 1)
+ };
+ draw_primitive(points, colors, uvs);
+ } else {
+ Vector<Color> colors = {
+ Color(0, 0, 0, 1),
+ Color(0, 0, 0, 1),
+ Color(0, 0, 0, 1),
+ Color(0, 0, 0, 1)
+ };
+ draw_primitive(points, colors, uvs);
+ }
- draw_primitive(points, colors, uvs);
} break;
}
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index c4f6b4952c..21139fbddd 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -120,7 +120,7 @@ public:
void remove_node(VisualShader::Type p_type, int p_id, bool p_just_update);
void connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
void disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
- void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id);
+ void show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid);
void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
void refresh_node_ports(VisualShader::Type p_type, int p_node);
void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
@@ -133,6 +133,7 @@ public:
Ref<Script> get_node_script(int p_node_id) const;
void update_node_size(int p_node_id);
void update_theme();
+ bool is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const;
VisualShader::Type get_shader_type() const;
VisualShaderGraphPlugin();
@@ -188,6 +189,9 @@ class VisualShaderEditor : public VBoxContainer {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
+ bool pending_custom_scripts_to_delete = false;
+ List<Ref<Script>> custom_scripts_to_delete;
+
bool _block_update_options_menu = false;
bool _block_rebuild_shader = false;
@@ -351,6 +355,8 @@ class VisualShaderEditor : public VBoxContainer {
void _preview_close_requested();
void _preview_size_changed();
void _update_preview();
+ void _update_next_previews(int p_node_id);
+ void _get_next_nodes_recursively(VisualShader::Type p_type, int p_node_id, LocalVector<int> &r_nodes) const;
String _get_description(int p_idx);
struct DragOp {
@@ -503,6 +509,13 @@ class VisualShaderEditor : public VBoxContainer {
void _visibility_changed();
+ void _get_current_mode_limits(int &r_begin_type, int &r_end_type) const;
+ void _update_custom_script(const Ref<Script> &p_script);
+ void _script_created(const Ref<Script> &p_script);
+ void _resource_saved(const Ref<Resource> &p_resource);
+ void _resource_removed(const Ref<Resource> &p_resource);
+ void _resources_removed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -517,7 +530,6 @@ public:
void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend);
Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node);
- void update_custom_type(const Ref<Resource> &p_resource);
virtual Size2 get_minimum_size() const override;
void edit(VisualShader *p_visual_shader);
@@ -552,7 +564,7 @@ class EditorInspectorVisualShaderModePlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
+ virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override;
};
class VisualShaderNodePortPreview : public Control {
@@ -561,6 +573,7 @@ class VisualShaderNodePortPreview : public Control {
VisualShader::Type type = VisualShader::Type::TYPE_MAX;
int node = 0;
int port = 0;
+ bool is_valid = false;
void _shader_changed(); //must regen
protected:
void _notification(int p_what);
@@ -568,7 +581,7 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
- void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port);
+ void setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port, bool p_is_valid);
};
class VisualShaderConversionPlugin : public EditorResourceConversionPlugin {
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index a3ccf392e6..1087a50df6 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -35,7 +35,9 @@
void VoxelGIEditorPlugin::_bake() {
if (voxel_gi) {
- if (voxel_gi->get_probe_data().is_null()) {
+ Ref<VoxelGIData> voxel_gi_data = voxel_gi->get_probe_data();
+
+ if (voxel_gi_data.is_null()) {
String path = get_tree()->get_edited_scene_root()->get_scene_file_path();
if (path.is_empty()) {
path = "res://" + voxel_gi->get_name() + "_data.res";
@@ -46,7 +48,32 @@ void VoxelGIEditorPlugin::_bake() {
probe_file->set_current_path(path);
probe_file->popup_file_dialog();
return;
+ } else {
+ String path = voxel_gi_data->get_path();
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is not local to the scene."));
+ return;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is part of an imported resource."));
+ return;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Voxel GI data is an imported resource."));
+ return;
+ }
+ }
}
+
voxel_gi->bake();
}
}
@@ -74,12 +101,12 @@ void VoxelGIEditorPlugin::_notification(int p_what) {
// Set information tooltip on the Bake button. This information is useful
// to optimize performance (video RAM size) and reduce light leaking (individual cell size).
- const Vector3i size = voxel_gi->get_estimated_cell_size();
+ const Vector3i cell_size = voxel_gi->get_estimated_cell_size();
- const Vector3 extents = voxel_gi->get_extents();
+ const Vector3 half_size = voxel_gi->get_size() / 2;
const int data_size = 4;
- const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0);
+ const double size_mb = cell_size.x * cell_size.y * cell_size.z * data_size / (1024.0 * 1024.0);
// Add a qualitative measurement to help the user assess whether a VoxelGI node is using a lot of VRAM.
String size_quality;
if (size_mb < 16.0) {
@@ -91,8 +118,8 @@ void VoxelGIEditorPlugin::_notification(int p_what) {
}
String text;
- text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z)) + "\n";
- text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), extents.x / size.x, extents.y / size.y, extents.z / size.z)) + "\n";
+ text += vformat(TTR("Subdivisions: %s"), vformat(String::utf8("%d × %d × %d"), cell_size.x, cell_size.y, cell_size.z)) + "\n";
+ text += vformat(TTR("Cell size: %s"), vformat(String::utf8("%.3f × %.3f × %.3f"), half_size.x / cell_size.x, half_size.y / cell_size.y, half_size.z / cell_size.z)) + "\n";
text += vformat(TTR("Video RAM size: %s MB (%s)"), String::num(size_mb, 2), size_quality);
// Only update the tooltip when needed to avoid constant redrawing.