summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/SCsub61
-rw-r--r--editor/animation_editor.cpp73
-rw-r--r--editor/code_editor.cpp50
-rw-r--r--editor/editor_about.cpp4
-rw-r--r--editor/editor_audio_buses.cpp22
-rw-r--r--editor/editor_autoload_settings.cpp4
-rw-r--r--editor/editor_export.cpp29
-rw-r--r--editor/editor_file_system.cpp86
-rw-r--r--editor/editor_fonts.cpp13
-rw-r--r--editor/editor_help.cpp27
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_log.cpp9
-rw-r--r--editor/editor_log.h2
-rw-r--r--editor/editor_node.cpp208
-rw-r--r--editor/editor_node.h18
-rw-r--r--editor/editor_plugin.cpp13
-rw-r--r--editor/editor_settings.cpp18
-rw-r--r--editor/editor_themes.cpp4
-rw-r--r--editor/filesystem_dock.cpp18
-rw-r--r--editor/icons/SCsub5
-rw-r--r--editor/icons/icon_key_selected.svg5
-rw-r--r--editor/icons/icon_key_valid.svg (renamed from editor/icons/icon_key_hover.svg)0
-rw-r--r--editor/import/editor_import_collada.cpp2
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp36
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp7
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp10
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp258
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h7
-rw-r--r--editor/plugins/editor_preview_plugins.cpp2
-rw-r--r--editor/plugins/editor_preview_plugins.h2
-rw-r--r--editor/plugins/item_list_editor_plugin.cpp30
-rw-r--r--editor/plugins/item_list_editor_plugin.h4
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.cpp4
-rw-r--r--editor/plugins/script_editor_plugin.cpp32
-rw-r--r--editor/plugins/script_editor_plugin.h12
-rw-r--r--editor/plugins/script_text_editor.cpp57
-rw-r--r--editor/plugins/script_text_editor.h7
-rw-r--r--editor/plugins/shader_graph_editor_plugin.cpp2
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp40
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp18
-rw-r--r--editor/plugins/theme_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp105
-rw-r--r--editor/plugins/tile_map_editor_plugin.h3
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp56
-rw-r--r--editor/plugins/tile_set_editor_plugin.h3
-rw-r--r--editor/project_export.cpp6
-rw-r--r--editor/project_manager.cpp49
-rw-r--r--editor/project_settings_editor.cpp25
-rw-r--r--editor/scene_tree_dock.cpp148
-rw-r--r--editor/scene_tree_editor.cpp4
-rw-r--r--editor/script_create_dialog.cpp21
-rw-r--r--editor/script_create_dialog.h1
-rw-r--r--editor/script_editor_debugger.cpp10
-rwxr-xr-xeditor/translations/extract.py16
57 files changed, 1203 insertions, 453 deletions
diff --git a/editor/SCsub b/editor/SCsub
index 8f87e12cb9..4ca6b9e3fd 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -4,6 +4,7 @@ Import('env')
env.editor_sources = []
import os
+import os.path
from compat import encode_utf8, byte_to_str, open_utf8, escape_string
@@ -29,6 +30,9 @@ def make_certs_header(target, source, env):
g.write("};\n")
g.write("#endif")
+ g.close()
+ f.close()
+
def make_doc_header(target, source, env):
@@ -41,8 +45,8 @@ def make_doc_header(target, source, env):
src = s.srcnode().abspath
if not src.endswith(".xml"):
continue
- f = open_utf8(src, "r")
- content = f.read()
+ with open_utf8(src, "r") as f:
+ content = f.read()
buf += content
buf = encode_utf8(docbegin + buf + docend)
@@ -62,6 +66,8 @@ def make_doc_header(target, source, env):
g.write("#endif")
+ g.close()
+
def make_fonts_header(target, source, env):
@@ -76,9 +82,8 @@ def make_fonts_header(target, source, env):
# saving uncompressed, since freetype will reference from memory pointer
xl_names = []
for i in range(len(source)):
- f = open(source[i].srcnode().abspath, "rb")
- buf = f.read()
- import os.path
+ with open(source[i].srcnode().abspath, "rb")as f:
+ buf = f.read()
name = os.path.splitext(os.path.basename(source[i].srcnode().abspath))[0]
@@ -91,6 +96,8 @@ def make_fonts_header(target, source, env):
g.write("#endif")
+ g.close()
+
def make_translations_header(target, source, env):
@@ -110,8 +117,8 @@ def make_translations_header(target, source, env):
xl_names = []
for i in range(len(sorted_paths)):
- f = open(sorted_paths[i], "rb")
- buf = f.read()
+ with open(sorted_paths[i], "rb") as f:
+ buf = f.read()
decomp_size = len(buf)
buf = zlib.compress(buf)
name = os.path.splitext(os.path.basename(sorted_paths[i]))[0]
@@ -138,6 +145,9 @@ def make_translations_header(target, source, env):
g.write("#endif")
+ g.close()
+
+
def make_authors_header(target, source, env):
sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"]
@@ -180,6 +190,9 @@ def make_authors_header(target, source, env):
g.write("#endif\n")
+ g.close()
+ f.close()
+
def make_donors_header(target, source, env):
sections = ["Platinum sponsors", "Gold sponsors", "Mini sponsors", "Gold donors", "Silver donors", "Bronze donors"]
@@ -222,6 +235,10 @@ def make_donors_header(target, source, env):
g.write("#endif\n")
+ g.close()
+ f.close()
+
+
def make_license_header(target, source, env):
src_copyright = source[0].srcnode().abspath
@@ -387,17 +404,23 @@ def make_license_header(target, source, env):
g.write("#endif\n")
+ g.close()
+ fc.close()
+ f.close()
+
def _make_doc_data_class_path(to_path):
- g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w")
- g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n")
- g.write("struct _DocDataClassPath { const char* name; const char* path; };\n")
+ g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w")
+ g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n")
+ g.write("struct _DocDataClassPath { const char* name; const char* path; };\n")
+
+ g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n");
+ for c in sorted(env.doc_class_path):
+ g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n")
+ g.write("\t{NULL, NULL}\n")
+ g.write("};\n")
- g.write("static const _DocDataClassPath _doc_data_class_paths[" + str(len(env.doc_class_path) + 1) + "] = {\n");
- for c in sorted(env.doc_class_path):
- g.write("\t{\"" + c + "\", \"" + env.doc_class_path[c] + "\"},\n")
- g.write("\t{NULL, NULL}\n")
- g.write("};\n")
+ g.close()
if env['tools']:
@@ -409,10 +432,9 @@ if env['tools']:
reg_exporters += '\tregister_' + e + '_exporter();\n'
reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
reg_exporters += '}\n'
- f = open_utf8("register_exporters.gen.cpp", "w")
- f.write(reg_exporters_inc)
- f.write(reg_exporters)
- f.close()
+ with open_utf8("register_exporters.gen.cpp", "w") as f:
+ f.write(reg_exporters_inc)
+ f.write(reg_exporters)
# API documentation
docs = []
@@ -466,6 +488,7 @@ if env['tools']:
env.add_source_files(env.editor_sources, "*.cpp")
+ env.add_source_files(env.editor_sources, ["#thirdparty/misc/clipper.cpp"])
SConscript('collada/SCsub')
SConscript('doc/SCsub')
diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp
index 1b97a24968..439ec37e71 100644
--- a/editor/animation_editor.cpp
+++ b/editor/animation_editor.cpp
@@ -1149,14 +1149,12 @@ void AnimationKeyEditor::_track_editor_draw() {
get_icon("KeyCall", "EditorIcons")
};
+ Ref<Texture> valid_icon = get_icon("KeyValid", "EditorIcons");
Ref<Texture> invalid_icon = get_icon("KeyInvalid", "EditorIcons");
- Ref<Texture> invalid_icon_hover = get_icon("KeyInvalidHover", "EditorIcons");
+ const Color modulate_selected = Color(0x84 / 255.0, 0xc2 / 255.0, 0xff / 255.0);
Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons");
- Ref<Texture> type_hover = get_icon("KeyHover", "EditorIcons");
- Ref<Texture> type_selected = get_icon("KeySelected", "EditorIcons");
-
int right_separator_ofs = right_data_size_cache;
int h = font->get_height() + sep;
@@ -1268,8 +1266,21 @@ void AnimationKeyEditor::_track_editor_draw() {
int decimals = 2;
bool step_found = false;
+ const int period_width = font->get_char_size('.').width;
+ int max_digit_width = font->get_char_size('0').width;
+ for (int i = 1; i <= 9; i++) {
+ const int digit_width = font->get_char_size('0' + i).width;
+ max_digit_width = MAX(digit_width, max_digit_width);
+ }
+ const int max_sc = int(Math::ceil(zoomw / scale));
+ const int max_sc_width = String::num(max_sc).length() * max_digit_width;
+
while (!step_found) {
+ min = max_sc_width;
+ if (decimals > 0)
+ min += period_width + max_digit_width * decimals;
+
static const int _multp[3] = { 1, 2, 5 };
for (int i = 0; i < 3; i++) {
@@ -1464,6 +1475,10 @@ void AnimationKeyEditor::_track_editor_draw() {
float x = key_hofs + name_limit + (time - keys_from) * zoom_scale;
Ref<Texture> tex = type_icon[tt];
+ Color modulate = Color(1, 1, 1);
+
+ bool is_hover = false;
+ bool is_selected = false;
SelectedKey sk;
sk.key = i;
@@ -1472,13 +1487,33 @@ void AnimationKeyEditor::_track_editor_draw() {
if (click.click == ClickOver::CLICK_MOVE_KEYS)
continue;
- tex = type_selected;
+ is_selected = true;
}
if (mouse_over.over == MouseOver::OVER_KEY && mouse_over.track == idx && mouse_over.over_key == i)
- tex = type_hover;
+ is_hover = true;
Variant value = animation->track_get_key_value(idx, i);
+
+ if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) {
+
+ tex = invalid_icon;
+ if (is_hover)
+ modulate = Color(1.5, 1.5, 1.5);
+ else
+ modulate = Color(1, 1, 1);
+ } else if (is_selected) {
+
+ tex = valid_icon;
+ modulate = modulate_selected;
+ if (is_hover)
+ modulate = modulate.lightened(0.2);
+ } else if (is_hover) {
+
+ tex = valid_icon;
+ modulate = Color(1, 1, 1);
+ }
+
if (first && i > 0 && value == animation->track_get_key_value(idx, i - 1)) {
te->draw_line(ofs + Vector2(name_limit, y + h / 2), ofs + Point2(x, y + h / 2), color);
@@ -1491,19 +1526,7 @@ void AnimationKeyEditor::_track_editor_draw() {
te->draw_line(ofs + Point2(x_n, y + h / 2), ofs + Point2(x, y + h / 2), color);
}
- if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) {
- te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor());
- }
-
- if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) {
- if (tex == type_hover)
- te->draw_texture(invalid_icon_hover, ofs + Point2(x, y + key_vofs).floor());
- else
- te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor());
- } else {
-
- te->draw_texture(tex, ofs + Point2(x, y + key_vofs).floor());
- }
+ te->draw_texture(tex, ofs + Point2(x, y + key_vofs).floor(), modulate);
first = false;
}
@@ -1539,8 +1562,8 @@ void AnimationKeyEditor::_track_editor_draw() {
continue;
int y = h + i * h + sep;
- float key_vofs = Math::floor((float)(h - type_selected->get_height()) / 2);
- float key_hofs = -Math::floor((float)type_selected->get_height() / 2);
+ float key_vofs = Math::floor((float)(h - valid_icon->get_height()) / 2);
+ float key_hofs = -Math::floor((float)valid_icon->get_height() / 2);
float time = animation->track_get_key_time(idx, E->key().key);
float diff = time - from_t;
@@ -1554,7 +1577,7 @@ void AnimationKeyEditor::_track_editor_draw() {
x += name_limit;
- te->draw_texture(type_selected, ofs + Point2(x + key_hofs, y + key_vofs).floor());
+ te->draw_texture(valid_icon, ofs + Point2(x + key_hofs, y + key_vofs).floor(), modulate_selected);
}
} break;
default: {};
@@ -2930,8 +2953,8 @@ void AnimationKeyEditor::_track_editor_gui_input(const Ref<InputEvent> &p_input)
Ref<InputEventPanGesture> pan_gesture = p_input;
if (pan_gesture.is_valid()) {
- h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * pan_gesture->get_delta().x / 8);
- v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * pan_gesture->get_delta().y / 8);
+ h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8);
+ v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
}
}
@@ -3998,6 +4021,7 @@ AnimationKeyEditor::AnimationKeyEditor() {
//key_edit->ke_dialog=key_edit_dialog;
type_menu = memnew(PopupMenu);
+ type_menu->set_pass_on_modal_close_click(false);
add_child(type_menu);
for (int i = 0; i < Variant::VARIANT_MAX; i++)
type_menu->add_item(Variant::get_type_name(Variant::Type(i)), i);
@@ -4038,6 +4062,7 @@ AnimationKeyEditor::AnimationKeyEditor() {
add_child(track_name);
track_name->connect("text_entered", this, "_track_name_changed");
track_menu = memnew(PopupMenu);
+ track_menu->set_pass_on_modal_close_click(false);
add_child(track_menu);
track_menu->connect("id_pressed", this, "_track_menu_selected");
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 9ae9ab1501..4c7f2f53cc 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -212,35 +212,39 @@ void FindReplaceBar::_replace_all() {
text_edit->begin_complex_operation();
- while (search_next()) {
-
- // replace area
- Point2i match_from(result_line, result_col);
- Point2i match_to(result_line, result_col + search_text_len);
-
- if (match_from < prev_match)
- break; // done
+ if (search_current()) {
+ do {
+ // replace area
+ Point2i match_from(result_line, result_col);
+ Point2i match_to(result_line, result_col + search_text_len);
+
+ if (match_from < prev_match) {
+ break; // done
+ }
- prev_match = Point2i(result_line, result_col + replace_text.length());
+ prev_match = Point2i(result_line, result_col + replace_text.length());
- text_edit->unfold_line(result_line);
- text_edit->select(result_line, result_col, result_line, match_to.y);
+ text_edit->unfold_line(result_line);
+ text_edit->select(result_line, result_col, result_line, match_to.y);
- if (selection_enabled && is_selection_only()) {
+ if (selection_enabled && is_selection_only()) {
+ if (match_from < selection_begin || match_to > selection_end) {
+ continue;
+ }
- if (match_from < selection_begin || match_to > selection_end)
- continue;
+ // replace but adjust selection bounds
+ text_edit->insert_text_at_cursor(replace_text);
+ if (match_to.x == selection_end.x) {
+ selection_end.y += replace_text.length() - search_text_len;
+ }
- // replace but adjust selection bounds
- text_edit->insert_text_at_cursor(replace_text);
- if (match_to.x == selection_end.x)
- selection_end.y += replace_text.length() - search_text_len;
- } else {
- // just replace
- text_edit->insert_text_at_cursor(replace_text);
- }
+ } else {
+ // just replace
+ text_edit->insert_text_at_cursor(replace_text);
+ }
- rc++;
+ rc++;
+ } while (search_next());
}
text_edit->end_complex_operation();
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 9ab539da07..360ed620f6 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -44,9 +44,11 @@ void EditorAbout::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- Ref<Font> font = EditorNode::get_singleton()->get_gui_base()->get_font("source", "EditorFonts");
+ Control *base = EditorNode::get_singleton()->get_gui_base();
+ Ref<Font> font = base->get_font("source", "EditorFonts");
_tpl_text->add_font_override("normal_font", font);
_license_text->add_font_override("normal_font", font);
+ _logo->set_texture(base->get_icon("Logo", "EditorIcons"));
} break;
}
}
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index c57d65d321..ac4402d50b 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -121,6 +121,26 @@ void EditorAudioBus::_notification(int p_what) {
set_process(is_visible_in_tree());
}
+
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+
+ for (int i = 0; i < cc; i++) {
+ channel[i].vu_l->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_l->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
+ channel[i].vu_r->set_under_texture(get_icon("BusVuEmpty", "EditorIcons"));
+ channel[i].vu_r->set_progress_texture(get_icon("BusVuFull", "EditorIcons"));
+ channel[i].prev_active = true;
+ }
+ scale->set_texture(get_icon("BusVuDb", "EditorIcons"));
+
+ disabled_vu = get_icon("BusVuFrozen", "EditorIcons");
+
+ solo->set_icon(get_icon("AudioBusSolo", "EditorIcons"));
+ mute->set_icon(get_icon("AudioBusMute", "EditorIcons"));
+ bypass->set_icon(get_icon("AudioBusBypass", "EditorIcons"));
+
+ bus_options->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons"));
+ }
}
void EditorAudioBus::update_send() {
@@ -719,6 +739,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
effects->set_hide_root(true);
effects->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
effects->set_hide_folding(true);
+ effects->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(effects);
effects->connect("item_edited", this, "_effect_edited");
effects->connect("cell_selected", this, "_effect_selected");
@@ -1151,6 +1172,7 @@ EditorAudioBuses::EditorAudioBuses() {
bus_scroll->set_enable_v_scroll(false);
add_child(bus_scroll);
bus_hb = memnew(HBoxContainer);
+ bus_hb->set_v_size_flags(SIZE_EXPAND_FILL);
bus_scroll->add_child(bus_hb);
save_timer = memnew(Timer);
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 0e9b7b74fd..a2f5c1aa1a 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -643,10 +643,10 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
tree->set_column_title(2, TTR("Singleton"));
tree->set_column_expand(2, false);
- tree->set_column_min_width(2, 80);
+ tree->set_column_min_width(2, 80 * EDSCALE);
tree->set_column_expand(3, false);
- tree->set_column_min_width(3, 120);
+ tree->set_column_min_width(3, 120 * EDSCALE);
tree->connect("cell_selected", this, "_autoload_selected");
tree->connect("item_edited", this, "_autoload_edited");
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index da4bbf9b7a..7456cc902a 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1352,27 +1352,24 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error err = da->copy(template_path, p_path, get_chmod_flags());
- memdelete(da);
-
- if (err != OK) {
- return err;
- }
-
- String pck_path = p_path.get_basename() + ".pck";
+ if (err == OK) {
+ String pck_path = p_path.get_basename() + ".pck";
- Vector<SharedObject> so_files;
+ Vector<SharedObject> so_files;
- err = save_pack(p_preset, pck_path, &so_files);
+ err = save_pack(p_preset, pck_path, &so_files);
- if (err != OK || so_files.empty())
- return err;
- //if shared object files, copy them
- da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- for (int i = 0; i < so_files.size(); i++) {
- da->copy(so_files[i].path, p_path.get_base_dir().plus_file(so_files[i].path.get_file()));
+ if (err == OK && !so_files.empty()) {
+ //if shared object files, copy them
+ da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ for (int i = 0; i < so_files.size() && err == OK; i++) {
+ err = da->copy(so_files[i].path, p_path.get_base_dir().plus_file(so_files[i].path.get_file()));
+ }
+ }
}
+
memdelete(da);
- return OK;
+ return err;
}
void EditorExportPlatformPC::set_extension(const String &p_extension, const String &p_feature_key) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index dca32d7492..d8ae1da72e 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -275,9 +275,13 @@ void EditorFileSystem::_scan_filesystem() {
memdelete(d);
f = FileAccess::open(fscache, FileAccess::WRITE);
- _save_filesystem_cache(new_filesystem, f);
- f->close();
- memdelete(f);
+ if (f == NULL) {
+ ERR_PRINTS("Error writing fscache: " + fscache);
+ } else {
+ _save_filesystem_cache(new_filesystem, f);
+ f->close();
+ memdelete(f);
+ }
scanning = false;
}
@@ -286,9 +290,13 @@ void EditorFileSystem::_save_filesystem_cache() {
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3");
FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE);
- _save_filesystem_cache(filesystem, f);
- f->close();
- memdelete(f);
+ if (f == NULL) {
+ ERR_PRINTS("Error writing fscache: " + fscache);
+ } else {
+ _save_filesystem_cache(filesystem, f);
+ f->close();
+ memdelete(f);
+ }
}
void EditorFileSystem::_thread_func(void *_userdata) {
@@ -321,10 +329,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
List<String> to_check;
- String source_file;
- String source_md5;
+ String source_file = "";
+ String source_md5 = "";
Vector<String> dest_files;
- String dest_md5;
+ String dest_md5 = "";
while (true) {
@@ -334,7 +342,6 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
if (err == ERR_FILE_EOF) {
- memdelete(f);
break;
} else if (err != OK) {
ERR_PRINTS("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text);
@@ -351,12 +358,8 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
to_check.push_back(fa[i]);
}
} else if (!p_only_imported_files) {
- if (assign == "source_md5") {
- source_md5 = value;
- } else if (assign == "source_file") {
+ if (assign == "source_file") {
source_file = value;
- } else if (assign == "dest_md5") {
- dest_md5 = value;
} else if (assign == "dest_files") {
dest_files = value;
}
@@ -369,6 +372,42 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
memdelete(f);
+ // Read the md5's from a separate file (so the import parameters aren't dependant on the file version
+ String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_path);
+ FileAccess *md5s = FileAccess::open(base_path + ".md5", FileAccess::READ, &err);
+ if (!md5s) { // No md5's stored for this resource
+ return true;
+ }
+
+ VariantParser::StreamFile md5_stream;
+ md5_stream.f = md5s;
+
+ while (true) {
+ assign = Variant();
+ next_tag.fields.clear();
+ next_tag.name = String();
+
+ err = VariantParser::parse_tag_assign_eof(&md5_stream, lines, error_text, next_tag, assign, value, NULL, true);
+
+ if (err == ERR_FILE_EOF) {
+ break;
+ } else if (err != OK) {
+ ERR_PRINTS("ResourceFormatImporter::load - " + p_path + ".import.md5:" + itos(lines) + " error: " + error_text);
+ memdelete(md5s);
+ return false; // parse error
+ }
+ if (assign != String()) {
+ if (!p_only_imported_files) {
+ if (assign == "source_md5") {
+ source_md5 = value;
+ } else if (assign == "dest_md5") {
+ dest_md5 = value;
+ }
+ }
+ }
+ }
+ memdelete(md5s);
+
//imported files are gone, reimport
for (List<String>::Element *E = to_check.front(); E; E = E->next()) {
if (!FileAccess::exists(E->get())) {
@@ -1316,6 +1355,9 @@ void EditorFileSystem::update_file(const String &p_file) {
fs->files[cpos]->deps = _get_dependencies(p_file);
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
+ // Update preview
+ EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
+
call_deferred("emit_signal", "filesystem_changed"); //update later
}
@@ -1456,15 +1498,13 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
}
f->store_line("source_file=" + Variant(p_file).get_construct_string());
- f->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\"\n");
if (dest_paths.size()) {
Array dp;
for (int i = 0; i < dest_paths.size(); i++) {
dp.push_back(dest_paths[i]);
}
- f->store_line("dest_files=" + Variant(dp).get_construct_string());
- f->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ f->store_line("dest_files=" + Variant(dp).get_construct_string() + "\n");
}
f->store_line("[params]");
@@ -1483,6 +1523,16 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
f->close();
memdelete(f);
+ // Store the md5's of the various files. These are stored separately so that the .import files can be version controlled.
+ FileAccess *md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE);
+ ERR_FAIL_COND(!md5s);
+ md5s->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\"");
+ if (dest_paths.size()) {
+ md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n");
+ }
+ md5s->close();
+ memdelete(md5s);
+
//update modified times, to avoid reimport
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import");
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index a58257962a..2ec3cdb08f 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -103,9 +103,11 @@ void editor_register_fonts(Ref<Theme> p_theme) {
/* Custom font */
String custom_font = EditorSettings::get_singleton()->get("interface/editor/main_font");
+ DynamicFontData::Hinting font_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/main_font_hinting");
Ref<DynamicFontData> CustomFont;
if (custom_font.length() > 0) {
CustomFont.instance();
+ CustomFont->set_hinting(font_hinting);
CustomFont->set_font_path(custom_font);
CustomFont->set_force_autohinter(true); //just looks better..i think?
}
@@ -113,9 +115,11 @@ void editor_register_fonts(Ref<Theme> p_theme) {
/* Custom source code font */
String custom_font_source = EditorSettings::get_singleton()->get("interface/editor/code_font");
+ DynamicFontData::Hinting font_source_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/code_font_hinting");
Ref<DynamicFontData> CustomFontSource;
if (custom_font_source.length() > 0) {
CustomFontSource.instance();
+ CustomFontSource->set_hinting(font_source_hinting);
CustomFontSource->set_font_path(custom_font_source);
}
@@ -123,38 +127,45 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<DynamicFontData> DefaultFont;
DefaultFont.instance();
+ DefaultFont->set_hinting(font_hinting);
DefaultFont->set_font_ptr(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size);
DefaultFont->set_force_autohinter(true); //just looks better..i think?
Ref<DynamicFontData> FontFallback;
FontFallback.instance();
+ FontFallback->set_hinting(font_hinting);
FontFallback->set_font_ptr(_font_DroidSansFallback, _font_DroidSansFallback_size);
FontFallback->set_force_autohinter(true); //just looks better..i think?
Ref<DynamicFontData> FontJapanese;
FontJapanese.instance();
+ FontJapanese->set_hinting(font_hinting);
FontJapanese->set_font_ptr(_font_DroidSansJapanese, _font_DroidSansJapanese_size);
FontJapanese->set_force_autohinter(true); //just looks better..i think?
Ref<DynamicFontData> FontArabic;
FontArabic.instance();
+ FontArabic->set_hinting(font_hinting);
FontArabic->set_font_ptr(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size);
FontArabic->set_force_autohinter(true); //just looks better..i think?
Ref<DynamicFontData> FontHebrew;
FontHebrew.instance();
+ FontHebrew->set_hinting(font_hinting);
FontHebrew->set_font_ptr(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size);
FontHebrew->set_force_autohinter(true); //just looks better..i think?
Ref<DynamicFontData> FontThai;
FontThai.instance();
+ FontThai->set_hinting(font_hinting);
FontThai->set_font_ptr(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size);
FontThai->set_force_autohinter(true); //just looks better..i think?
- /* Source Code Pro */
+ /* Hack */
Ref<DynamicFontData> dfmono;
dfmono.instance();
+ dfmono->set_hinting(font_source_hinting);
dfmono->set_font_ptr(_font_Hack_Regular, _font_Hack_Regular_size);
//dfd->set_force_autohinter(true); //just looks better..i think?
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 7f76cf1af2..f3be02a8c7 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1172,7 +1172,12 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->push_indent(1);
Vector<DocData::ConstantDoc> enum_list = E->get();
+ Map<String, int> enumValuesContainer;
+ int enumStartingLine = enum_line[E->key()];
+
for (int i = 0; i < enum_list.size(); i++) {
+ if (cd.name == "@GlobalScope")
+ enumValuesContainer[enum_list[i].name] = enumStartingLine;
class_desc->push_font(doc_code_font);
class_desc->push_color(headline_color);
@@ -1200,6 +1205,9 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->add_newline();
}
+ if (cd.name == "@GlobalScope")
+ enum_values_line[E->key()] = enumValuesContainer;
+
class_desc->pop();
class_desc->add_newline();
@@ -1485,21 +1493,32 @@ void EditorHelp::_help_callback(const String &p_topic) {
if (method_line.has(name))
line = method_line[name];
} else if (what == "class_property") {
-
if (property_line.has(name))
line = property_line[name];
} else if (what == "class_enum") {
-
if (enum_line.has(name))
line = enum_line[name];
} else if (what == "class_theme_item") {
-
if (theme_property_line.has(name))
line = theme_property_line[name];
} else if (what == "class_constant") {
-
if (constant_line.has(name))
line = constant_line[name];
+ } else if (what == "class_global") {
+ if (constant_line.has(name))
+ line = constant_line[name];
+ else {
+ Map<String, Map<String, int> >::Element *iter = enum_values_line.front();
+ while (true) {
+ if (iter->value().has(name)) {
+ line = iter->value()[name];
+ break;
+ } else if (iter == enum_values_line.back())
+ break;
+ else
+ iter = iter->next();
+ }
+ }
}
class_desc->call_deferred("scroll_to_line", line);
diff --git a/editor/editor_help.h b/editor/editor_help.h
index aa84aa611f..0f93e1b55b 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -152,6 +152,7 @@ class EditorHelp : public VBoxContainer {
Map<String, int> theme_property_line;
Map<String, int> constant_line;
Map<String, int> enum_line;
+ Map<String, Map<String, int> > enum_values_line;
int description_line;
RichTextLabel *class_desc;
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index e301d12214..158eedfb0f 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -88,6 +88,7 @@ void EditorLog::_notification(int p_what) {
void EditorLog::_clear_request() {
log->clear();
+ tool_button->set_icon(Ref<Texture>());
}
void EditorLog::clear() {
@@ -103,9 +104,7 @@ void EditorLog::add_message(const String &p_msg, bool p_error) {
Ref<Texture> icon = get_icon("Error", "EditorIcons");
log->add_image(icon);
log->add_text(" ");
- //button->set_icon(icon);
- } else {
- //button->set_icon(Ref<Texture>());
+ tool_button->set_icon(icon);
}
log->add_text(p_msg);
@@ -115,6 +114,10 @@ void EditorLog::add_message(const String &p_msg, bool p_error) {
log->pop();
}
+void EditorLog::set_tool_button(ToolButton *p_tool_button) {
+ tool_button = p_tool_button;
+}
+
/*
void EditorLog::_dragged(const Point2& p_ofs) {
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 42137f71cc..f9bc82de7d 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -51,6 +51,7 @@ class EditorLog : public VBoxContainer {
RichTextLabel *log;
HBoxContainer *title_hb;
//PaneDrag *pd;
+ ToolButton *tool_button;
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type);
@@ -68,6 +69,7 @@ protected:
public:
void add_message(const String &p_msg, bool p_error = false);
+ void set_tool_button(ToolButton *p_tool_button);
void deinit();
void clear();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 8132575479..0bca78b493 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -190,6 +190,8 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && !k->is_echo() && !gui_base->get_viewport()->gui_has_modal_stack()) {
+ EditorPlugin *old_editor = editor_plugin_screen;
+
if (ED_IS_SHORTCUT("editor/next_tab", p_event)) {
int next_tab = editor_data.get_edited_scene() + 1;
next_tab %= editor_data.get_edited_scene_count();
@@ -225,6 +227,10 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
_bottom_panel_switch(false, i);
}
}
+
+ if (old_editor != editor_plugin_screen) {
+ get_tree()->set_input_as_handled();
+ }
}
}
@@ -349,14 +355,20 @@ void EditorNode::_notification(int p_what) {
// update_icons
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
- Ref<Texture> icon = singleton->main_editor_buttons[i]->get_icon();
+
+ ToolButton *tb = singleton->main_editor_buttons[i];
+ EditorPlugin *p_editor = singleton->editor_table[i];
+ Ref<Texture> icon = p_editor->get_icon();
if (icon.is_valid()) {
- main_editor_buttons[i]->set_icon(icon);
- } else if (singleton->gui_base->has_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")) {
- main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons"));
+ tb->set_icon(icon);
+ } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) {
+ tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons"));
}
}
+
+ _build_icon_type_cache();
+
play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons"));
@@ -382,6 +394,15 @@ void EditorNode::_notification(int p_what) {
dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons"));
+
+ PopupMenu *p = help_menu->get_popup();
+ p->set_item_icon(p->get_item_index(HELP_CLASSES), gui_base->get_icon("ClassList", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_icon("HelpSearch", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_ISSUES), gui_base->get_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_icon("Instance", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_icon("Godot", "EditorIcons"));
}
if (p_what == Control::NOTIFICATION_RESIZED) {
@@ -449,24 +470,28 @@ void EditorNode::_fs_changed() {
}
if (preset.is_null()) {
String err = "Unknown export preset: " + export_defer.preset;
- ERR_PRINT(err.utf8().get_data());
+ ERR_PRINTS(err);
} else {
Ref<EditorExportPlatform> platform = preset->get_platform();
if (platform.is_null()) {
String err = "Preset \"" + export_defer.preset + "\" doesn't have a platform.";
- ERR_PRINT(err.utf8().get_data());
+ ERR_PRINTS(err);
} else {
// ensures export_project does not loop infinitely, because notifications may
// come during the export
export_defer.preset = "";
+ Error err;
if (!preset->is_runnable() && (export_defer.path.ends_with(".pck") || export_defer.path.ends_with(".zip"))) {
if (export_defer.path.ends_with(".zip")) {
- platform->save_zip(preset, export_defer.path);
+ err = platform->save_zip(preset, export_defer.path);
} else if (export_defer.path.ends_with(".pck")) {
- platform->save_pack(preset, export_defer.path);
+ err = platform->save_pack(preset, export_defer.path);
}
} else {
- platform->export_project(preset, export_defer.debug, export_defer.path, /*p_flags*/ 0);
+ err = platform->export_project(preset, export_defer.debug, export_defer.path, /*p_flags*/ 0);
+ }
+ if (err != OK) {
+ ERR_PRINTS(vformat(TTR("Project export failed with error code %d."), (int)err));
}
}
}
@@ -589,6 +614,7 @@ void EditorNode::open_resource(const String &p_type) {
void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) {
editor_data.apply_changes_in_editors();
+
int flg = 0;
if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources"))
flg |= ResourceSaver::FLAG_COMPRESS;
@@ -597,6 +623,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
if (err != OK) {
+ current_option = -1;
accept->set_text(TTR("Error saving resource!"));
accept->popup_centered_minsize();
return;
@@ -983,6 +1010,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
String file = cache_base + ".png";
+ post_process_preview(img);
img->save_png(file);
}
@@ -1072,7 +1100,8 @@ void EditorNode::_save_scene(String p_file, int idx) {
void EditorNode::_save_all_scenes() {
- for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ int i = _next_unsaved_scene(true, 0);
+ while (i != -1) {
Node *scene = editor_data.get_edited_scene_root(i);
if (scene && scene->get_filename() != "") {
if (i != editor_data.get_edited_scene())
@@ -1080,6 +1109,7 @@ void EditorNode::_save_all_scenes() {
else
_save_scene_with_preview(scene->get_filename());
} // else: ignore new scenes
+ i = _next_unsaved_scene(true, ++i);
}
_save_default_environment();
@@ -1194,6 +1224,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, ml);
if (err) {
+ current_option = -1;
accept->get_ok()->set_text(TTR("I see.."));
accept->set_text(TTR("Error saving MeshLibrary!"));
accept->popup_centered_minsize();
@@ -1228,6 +1259,7 @@ void EditorNode::_dialog_action(String p_file) {
Error err = ResourceSaver::save(p_file, ml);
if (err) {
+ current_option = -1;
accept->get_ok()->set_text(TTR("I see.."));
accept->set_text(TTR("Error saving TileSet!"));
accept->popup_centered_minsize();
@@ -1428,7 +1460,8 @@ void EditorNode::_save_default_environment() {
if (fallback.is_valid() && fallback->get_path().is_resource_file()) {
Map<RES, bool> processed;
_find_and_save_edited_subresources(fallback.ptr(), processed, 0);
- save_resource_in_path(fallback, fallback->get_path());
+ if (fallback->get_last_modified_time() != fallback->get_import_last_modified_time())
+ save_resource_in_path(fallback, fallback->get_path());
}
}
@@ -1574,7 +1607,8 @@ void EditorNode::_edit_current() {
// special case if use of external editor is true
if (main_plugin->get_name() == "Script" && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
- main_plugin->edit(current_obj);
+ if (!changing_scene)
+ main_plugin->edit(current_obj);
}
else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) {
@@ -2097,10 +2131,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
log->add_message("REDO: " + action);
} break;
- case TOOLS_ORPHAN_RESOURCES: {
-
- orphan_resources->show();
- } break;
case EDIT_REVERT: {
@@ -2546,6 +2576,30 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
+void EditorNode::_tool_menu_option(int p_idx) {
+ switch (tool_menu->get_item_id(p_idx)) {
+ case TOOLS_ORPHAN_RESOURCES: {
+ orphan_resources->show();
+ } break;
+ case TOOLS_CUSTOM: {
+ if (tool_menu->get_item_submenu(p_idx) == "") {
+ Array params = tool_menu->get_item_metadata(p_idx);
+
+ Object *handler = ObjectDB::get_instance(params[0]);
+ String callback = params[1];
+ Variant *ud = &params[2];
+ Variant::CallError ce;
+
+ handler->call(callback, (const Variant **)&ud, 1, ce);
+ if (ce.error != Variant::CallError::CALL_OK) {
+ String err = Variant::get_call_error_text(handler, callback, (const Variant **)&ud, 1, ce);
+ ERR_PRINTS("Error calling function from tool menu: " + err);
+ }
+ } // else it's a submenu so don't do anything.
+ } break;
+ }
+}
+
int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
for (int i = p_start; i < editor_data.get_edited_scene_count(); i++) {
@@ -3441,6 +3495,19 @@ Ref<Texture> EditorNode::_file_dialog_get_icon(const String &p_path) {
return singleton->icon_type_cache["Object"];
}
+void EditorNode::_build_icon_type_cache() {
+
+ List<StringName> tl;
+ StringName ei = "EditorIcons";
+ theme_base->get_theme()->get_icon_list(ei, &tl);
+ for (List<StringName>::Element *E = tl.front(); E; E = E->next()) {
+
+ if (!ClassDB::class_exists(E->get()))
+ continue;
+ icon_type_cache[E->get()] = theme_base->get_theme()->get_icon(E->get(), ei);
+ }
+}
+
void EditorNode::_file_dialog_register(FileDialog *p_dialog) {
singleton->file_dialogs.insert(p_dialog);
@@ -4425,6 +4492,45 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *
return drag_data;
}
+void EditorNode::add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud) {
+ ERR_FAIL_NULL(p_handler);
+ int idx = tool_menu->get_item_count();
+ tool_menu->add_item(p_name, TOOLS_CUSTOM);
+
+ Array parameters;
+ parameters.push_back(p_handler->get_instance_id());
+ parameters.push_back(p_callback);
+ parameters.push_back(p_ud);
+
+ tool_menu->set_item_metadata(idx, parameters);
+}
+
+void EditorNode::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
+ ERR_FAIL_NULL(p_submenu);
+ ERR_FAIL_COND(p_submenu->get_parent() != NULL);
+
+ tool_menu->add_child(p_submenu);
+ tool_menu->add_submenu_item(p_name, p_submenu->get_name(), TOOLS_CUSTOM);
+}
+
+void EditorNode::remove_tool_menu_item(const String &p_name) {
+ for (int i = 0; i < tool_menu->get_item_count(); i++) {
+ if (tool_menu->get_item_id(i) != TOOLS_CUSTOM)
+ continue;
+
+ if (tool_menu->get_item_text(i) == p_name) {
+ if (tool_menu->get_item_submenu(i) != "") {
+ Node *n = tool_menu->get_node(tool_menu->get_item_submenu(i));
+ tool_menu->remove_child(n);
+ memdelete(n);
+ }
+ tool_menu->remove_item(i);
+ tool_menu->set_as_minsize();
+ return;
+ }
+ }
+}
+
void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {
String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_current_path());
@@ -4621,6 +4727,7 @@ Vector<Ref<EditorResourceConversionPlugin> > EditorNode::find_resource_conversio
void EditorNode::_bind_methods() {
ClassDB::bind_method("_menu_option", &EditorNode::_menu_option);
+ ClassDB::bind_method("_tool_menu_option", &EditorNode::_tool_menu_option);
ClassDB::bind_method("_menu_confirm_current", &EditorNode::_menu_confirm_current);
ClassDB::bind_method("_dialog_action", &EditorNode::_dialog_action);
ClassDB::bind_method("_resource_selected", &EditorNode::_resource_selected, DEFVAL(""));
@@ -4759,18 +4866,43 @@ EditorNode::EditorNode() {
FileAccess::set_backup_save(EDITOR_GET("filesystem/on_save/safe_save_on_backup_then_rename"));
{
- int dpi_mode = EditorSettings::get_singleton()->get("interface/editor/hidpi_mode");
- if (dpi_mode == 0) {
- const int screen = OS::get_singleton()->get_current_screen();
- editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
- } else if (dpi_mode == 1) {
- editor_set_scale(0.75);
- } else if (dpi_mode == 2) {
- editor_set_scale(1.0);
- } else if (dpi_mode == 3) {
- editor_set_scale(1.5);
- } else if (dpi_mode == 4) {
- editor_set_scale(2.0);
+ int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
+
+ switch (display_scale) {
+ case 0: {
+ // Try applying a suitable display scale automatically
+ const int screen = OS::get_singleton()->get_current_screen();
+ editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+ } break;
+
+ case 1: {
+ editor_set_scale(0.75);
+ } break;
+
+ case 2: {
+ editor_set_scale(1.0);
+ } break;
+
+ case 3: {
+ editor_set_scale(1.25);
+ } break;
+
+ case 4: {
+ editor_set_scale(1.5);
+ } break;
+
+ case 5: {
+ editor_set_scale(1.75);
+ } break;
+
+ case 6: {
+ editor_set_scale(2.0);
+ } break;
+
+ default: {
+ editor_set_scale(custom_display_scale);
+ } break;
}
}
@@ -5132,7 +5264,6 @@ EditorNode::EditorNode() {
gui_base->add_child(export_template_manager);
about = memnew(EditorAbout);
- about->get_logo()->set_texture(gui_base->get_icon("Logo", "EditorIcons"));
gui_base->add_child(about);
warning = memnew(AcceptDialog);
@@ -5195,9 +5326,9 @@ EditorNode::EditorNode() {
p->connect("id_pressed", this, "_menu_option");
p->add_item(TTR("Export"), FILE_EXPORT_PROJECT);
- PopupMenu *tool_menu = memnew(PopupMenu);
+ tool_menu = memnew(PopupMenu);
tool_menu->set_name("Tools");
- tool_menu->connect("id_pressed", this, "_menu_option");
+ tool_menu->connect("index_pressed", this, "_tool_menu_option");
p->add_child(tool_menu);
p->add_submenu_item(TTR("Tools"), "Tools");
tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES);
@@ -5557,7 +5688,8 @@ EditorNode::EditorNode() {
bottom_panel_vb->add_child(bottom_panel_hb);
log = memnew(EditorLog);
- add_bottom_panel_item(TTR("Output"), log);
+ ToolButton *output_button = add_bottom_panel_item(TTR("Output"), log);
+ log->set_tool_button(output_button);
old_split_ofs = 0;
@@ -5797,17 +5929,7 @@ EditorNode::EditorNode() {
EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_fs_changed");
EditorFileSystem::get_singleton()->connect("resources_reimported", this, "_resources_reimported");
- {
- List<StringName> tl;
- StringName ei = "EditorIcons";
- theme_base->get_theme()->get_icon_list(ei, &tl);
- for (List<StringName>::Element *E = tl.front(); E; E = E->next()) {
-
- if (!ClassDB::class_exists(E->get()))
- continue;
- icon_type_cache[E->get()] = theme_base->get_theme()->get_icon(E->get(), ei);
- }
- }
+ _build_icon_type_cache();
Node::set_human_readable_collision_renaming(true);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 6d96c2dea7..90bebffca6 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -141,6 +141,7 @@ private:
EDIT_REDO,
EDIT_REVERT,
TOOLS_ORPHAN_RESOURCES,
+ TOOLS_CUSTOM,
RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
@@ -426,6 +427,7 @@ private:
void _menu_option(int p_option);
void _menu_confirm_current();
void _menu_option_confirm(int p_option, bool p_confirmed);
+ void _tool_menu_option(int p_idx);
void _update_debug_options();
void _property_editor_forward();
@@ -496,6 +498,7 @@ private:
Set<EditorFileDialog *> editor_file_dialogs;
Map<String, Ref<Texture> > icon_type_cache;
+ void _build_icon_type_cache();
bool _initializing_addons;
Map<String, EditorPlugin *> plugin_addons;
@@ -599,21 +602,6 @@ private:
static int build_callback_count;
static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS];
- bool _initializing_tool_menu;
-
- struct ToolMenuItem {
- String name;
- String submenu;
- Variant ud;
- ObjectID handler;
- String callback;
- };
-
- Vector<ToolMenuItem> tool_menu_items;
-
- void _tool_menu_insert_item(const ToolMenuItem &p_item);
- void _rebuild_tool_menu() const;
-
bool _dimming;
float _dim_time;
Timer *_dim_timer;
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 31d0bfa8a9..4f38c0188d 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -429,21 +429,18 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
}
void EditorPlugin::add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud) {
-
- //EditorNode::get_singleton()->add_tool_menu_item(p_name, p_handler, p_callback, p_ud);
+ EditorNode::get_singleton()->add_tool_menu_item(p_name, p_handler, p_callback, p_ud);
}
void EditorPlugin::add_tool_submenu_item(const String &p_name, Object *p_submenu) {
-
ERR_FAIL_NULL(p_submenu);
PopupMenu *submenu = Object::cast_to<PopupMenu>(p_submenu);
ERR_FAIL_NULL(submenu);
- //EditorNode::get_singleton()->add_tool_submenu_item(p_name, submenu);
+ EditorNode::get_singleton()->add_tool_submenu_item(p_name, submenu);
}
void EditorPlugin::remove_tool_menu_item(const String &p_name) {
-
- //EditorNode::get_singleton()->remove_tool_menu_item(p_name);
+ EditorNode::get_singleton()->remove_tool_menu_item(p_name);
}
void EditorPlugin::set_input_event_forwarding_always_enabled() {
@@ -707,9 +704,9 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks);
ClassDB::bind_method(D_METHOD("remove_control_from_bottom_panel", "control"), &EditorPlugin::remove_control_from_bottom_panel);
ClassDB::bind_method(D_METHOD("remove_control_from_container", "container", "control"), &EditorPlugin::remove_control_from_container);
- //ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "handler", "callback", "ud"),&EditorPlugin::add_tool_menu_item,DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "handler", "callback", "ud"), &EditorPlugin::add_tool_menu_item, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("add_tool_submenu_item", "name", "submenu"), &EditorPlugin::add_tool_submenu_item);
- //ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"),&EditorPlugin::remove_tool_menu_item);
+ ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"), &EditorPlugin::remove_tool_menu_item);
ClassDB::bind_method(D_METHOD("add_custom_type", "type", "base", "script", "icon"), &EditorPlugin::add_custom_type);
ClassDB::bind_method(D_METHOD("remove_custom_type", "type"), &EditorPlugin::remove_custom_type);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 29363e29c1..85f6d99c67 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -283,13 +283,19 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/editor/editor_language"] = PropertyInfo(Variant::STRING, "interface/editor/editor_language", PROPERTY_HINT_ENUM, lang_hint, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
}
- _initial_set("interface/editor/hidpi_mode", 0);
- hints["interface/editor/hidpi_mode"] = PropertyInfo(Variant::INT, "interface/editor/hidpi_mode", PROPERTY_HINT_ENUM, "Auto,VeryLoDPI,LoDPI,MidDPI,HiDPI", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ _initial_set("interface/editor/display_scale", 0);
+ hints["interface/editor/display_scale"] = PropertyInfo(Variant::INT, "interface/editor/display_scale", PROPERTY_HINT_ENUM, "Auto,75%,100%,125%,150%,175%,200%,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ _initial_set("interface/editor/custom_display_scale", 1.0f);
+ hints["interface/editor/custom_display_scale"] = PropertyInfo(Variant::REAL, "interface/editor/custom_display_scale", PROPERTY_HINT_RANGE, "0.75,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/scene_tabs/show_script_button", false);
_initial_set("interface/editor/main_font_size", 14);
hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "10,40,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/code_font_size", 14);
hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ _initial_set("interface/editor/main_font_hinting", 2);
+ hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ _initial_set("interface/editor/code_font_hinting", 2);
+ hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/main_font", "");
hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/code_font", "");
@@ -403,6 +409,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// navigation
_initial_set("editors/3d/navigation/navigation_scheme", 0);
+ _initial_set("editors/3d/navigation/invert_y-axis", false);
hints["editors/3d/navigation/navigation_scheme"] = PropertyInfo(Variant::INT, "editors/3d/navigation/navigation_scheme", PROPERTY_HINT_ENUM, "Godot,Maya,Modo");
_initial_set("editors/3d/navigation/zoom_style", 0);
hints["editors/3d/navigation/zoom_style"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_style", PROPERTY_HINT_ENUM, "Vertical, Horizontal");
@@ -959,11 +966,8 @@ void EditorSettings::save() {
Error err = ResourceSaver::save(singleton->config_file_path, singleton);
if (err != OK) {
- ERR_PRINT("Can't Save!");
- return;
- }
-
- if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINTS("Error saving editor settings to " + singleton->config_file_path);
+ } else if (OS::get_singleton()->is_stdout_verbose()) {
print_line("EditorSettings Save OK!");
}
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index b10f785a28..3582379e34 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -626,8 +626,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color_disabled", "PopupMenu", font_color_disabled);
theme->set_icon("checked", "PopupMenu", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "PopupMenu", theme->get_icon("GuiUnchecked", "EditorIcons"));
- theme->set_icon("radio_checked", "PopupMenu", theme->get_icon("GuiChecked", "EditorIcons"));
- theme->set_icon("radio_unchecked", "PopupMenu", theme->get_icon("GuiUnchecked", "EditorIcons"));
+ theme->set_icon("radio_checked", "PopupMenu", theme->get_icon("GuiRadioChecked", "EditorIcons"));
+ theme->set_icon("radio_unchecked", "PopupMenu", theme->get_icon("GuiRadioUnchecked", "EditorIcons"));
theme->set_icon("submenu", "PopupMenu", theme->get_icon("ArrowRight", "EditorIcons"));
theme->set_icon("visibility_hidden", "PopupMenu", theme->get_icon("GuiVisibilityHidden", "EditorIcons"));
theme->set_icon("visibility_visible", "PopupMenu", theme->get_icon("GuiVisibilityVisible", "EditorIcons"));
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 9bfa50148f..d5783c9b1a 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1034,8 +1034,19 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path) {
void FileSystemDock::_file_option(int p_option) {
switch (p_option) {
case FILE_SHOW_IN_EXPLORER: {
- String dir = ProjectSettings::get_singleton()->globalize_path(this->path);
- OS::get_singleton()->shell_open(String("file://") + dir);
+
+ String path = this->path;
+
+ // first try to grab directory from selected file, so that it works for searched files
+ int idx = files->get_current();
+
+ if (idx >= 0 && idx < files->get_item_count()) {
+ path = files->get_item_metadata(idx);
+ path = path.get_base_dir();
+ }
+
+ path = ProjectSettings::get_singleton()->globalize_path(path);
+ OS::get_singleton()->shell_open(String("file://") + path);
} break;
case FILE_OPEN: {
for (int i = 0; i < files->get_item_count(); i++) {
@@ -1660,6 +1671,8 @@ void FileSystemDock::_files_gui_input(Ref<InputEvent> p_event) {
_file_option(FILE_COPY_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
_file_option(FILE_REMOVE);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
+ _file_option(FILE_RENAME);
}
}
}
@@ -1770,6 +1783,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), KEY_DELETE);
+ ED_SHORTCUT("filesystem_dock/rename", TTR("Rename"));
HBoxContainer *toolbar_hbc = memnew(HBoxContainer);
add_child(toolbar_hbc);
diff --git a/editor/icons/SCsub b/editor/icons/SCsub
index 64992a9f90..7f94073e01 100644
--- a/editor/icons/SCsub
+++ b/editor/icons/SCsub
@@ -82,10 +82,9 @@ def make_editor_icons_action(target, source, env):
s.write("#endif\n")
+ with open(dst, "w") as f:
+ f.write(s.getvalue())
- f = open(dst, "w")
- f.write(s.getvalue())
- f.close()
s.close()
icons_string.close()
diff --git a/editor/icons/icon_key_selected.svg b/editor/icons/icon_key_selected.svg
deleted file mode 100644
index c73d31981d..0000000000
--- a/editor/icons/icon_key_selected.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1044.4)">
-<rect transform="rotate(-45)" x="-741.53" y="741.08" width="6.1027" height="6.1027" ry=".76286" fill="#84c2ff"/>
-</g>
-</svg>
diff --git a/editor/icons/icon_key_hover.svg b/editor/icons/icon_key_valid.svg
index 4a3fab4754..4a3fab4754 100644
--- a/editor/icons/icon_key_hover.svg
+++ b/editor/icons/icon_key_valid.svg
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 863b13cbd7..c1e897a04c 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -480,7 +480,7 @@ Error ColladaImport::_create_material(const String &p_target) {
}
}
- float roughness = Math::sqrt(1.0 - ((Math::log(effect.shininess) / Math::log(2.0)) / 8.0)); //not very right..
+ float roughness = (effect.shininess - 1.0) / 510;
material->set_roughness(roughness);
if (effect.double_sided) {
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index 2636839764..af79f9946a 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -762,14 +762,22 @@ PoolVector<Color> EditorSceneImporterGLTF::_decode_accessor_as_color(GLTFState &
PoolVector<Color> ret;
if (attribs.size() == 0)
return ret;
- ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
+ int type = state.accessors[p_accessor].type;
+ ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
+ int components;
+ if (type == TYPE_VEC3) {
+ components = 3;
+ } else { // TYPE_VEC4
+ components = 4;
+ }
+ ERR_FAIL_COND_V(attribs.size() % components != 0, ret);
const double *attribs_ptr = attribs.ptr();
- int ret_size = attribs.size() / 4;
+ int ret_size = attribs.size() / components;
ret.resize(ret_size);
{
PoolVector<Color>::Write w = ret.write();
for (int i = 0; i < ret_size; i++) {
- w[i] = Color(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]);
+ w[i] = Color(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], components == 4 ? attribs_ptr[i * 4 + 3] : 1.0);
}
}
return ret;
@@ -1724,14 +1732,19 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto
for (int i = 0; i < n->joints.size(); i++) {
ERR_FAIL_COND(n->joints[i].skin < 0);
- int bone_index = skeletons[n->joints[i].skin]->get_bone_count();
- skeletons[n->joints[i].skin]->add_bone(n->name);
+ int bone_index = n->joints[i].bone;
+
+ Skeleton *s = skeletons[n->joints[i].skin];
+ while (s->get_bone_count() <= bone_index) {
+ s->add_bone("Bone " + itos(s->get_bone_count()));
+ }
+
if (p_parent_bones.size()) {
- skeletons[n->joints[i].skin]->set_bone_parent(bone_index, p_parent_bones[i]);
+ s->set_bone_parent(bone_index, p_parent_bones[i]);
}
- skeletons[n->joints[i].skin]->set_bone_rest(bone_index, state.skins[n->joints[i].skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
+ s->set_bone_rest(bone_index, state.skins[n->joints[i].skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
- n->godot_nodes.push_back(skeletons[n->joints[i].skin]);
+ n->godot_nodes.push_back(s);
n->joints[i].godot_bone_index = bone_index;
parent_bones.push_back(bone_index);
}
@@ -1875,6 +1888,8 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
animation.instance();
animation->set_name(name);
+ float length = 0;
+
for (Map<int, GLTFAnimation::Track>::Element *E = anim.tracks.front(); E; E = E->next()) {
const GLTFAnimation::Track &track = E->get();
@@ -1893,8 +1908,6 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
node_path = ap->get_parent()->get_path_to(node->godot_nodes[i]);
}
- float length = 0;
-
for (int i = 0; i < track.rotation_track.times.size(); i++) {
length = MAX(length, track.rotation_track.times[i]);
}
@@ -1911,8 +1924,6 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
}
}
- animation->set_length(length);
-
if (track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) {
//make transform track
int track_idx = animation->get_track_count();
@@ -2030,6 +2041,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
}
}
}
+ animation->set_length(length);
ap->add_animation(name, animation);
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index c22e1cd88b..7612f18aff 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -1011,6 +1011,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set) {
player->seek_delta(pos, pos - cpos);
} else {
+ player->stop(true);
player->seek(pos, true);
}
@@ -1678,10 +1679,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay
onion_skinning->get_popup()->add_separator();
onion_skinning->get_popup()->add_item(TTR("Depth"), -1);
onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true);
- onion_skinning->get_popup()->add_check_item(TTR("1 step"), ONION_SKINNING_1_STEP);
+ onion_skinning->get_popup()->add_radio_check_item(TTR("1 step"), ONION_SKINNING_1_STEP);
onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true);
- onion_skinning->get_popup()->add_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS);
- onion_skinning->get_popup()->add_check_item(TTR("3 steps"), ONION_SKINNING_3_STEPS);
+ onion_skinning->get_popup()->add_radio_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS);
+ onion_skinning->get_popup()->add_radio_check_item(TTR("3 steps"), ONION_SKINNING_3_STEPS);
onion_skinning->get_popup()->add_separator();
onion_skinning->get_popup()->add_check_item(TTR("Differences Only"), ONION_SKINNING_DIFFERENCES_ONLY);
onion_skinning->get_popup()->add_check_item(TTR("Force White Modulate"), ONION_SKINNING_FORCE_WHITE_MODULATE);
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index f0e186e4b0..37213c1866 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -756,6 +756,7 @@ void AnimationTreeEditor::_gui_input(Ref<InputEvent> p_event) {
if (rclick_type == CLICK_INPUT_SLOT || rclick_type == CLICK_OUTPUT_SLOT) {
node_popup->clear();
+ node_popup->set_size(Size2(1, 1));
node_popup->add_item(TTR("Disconnect"), NODE_DISCONNECT);
if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) {
node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
@@ -774,6 +775,7 @@ void AnimationTreeEditor::_gui_input(Ref<InputEvent> p_event) {
if (rclick_type == CLICK_NODE) {
node_popup->clear();
+ node_popup->set_size(Size2(1, 1));
node_popup->add_item(TTR("Rename"), NODE_RENAME);
node_popup->add_item(TTR("Remove"), NODE_ERASE);
if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION)
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 4b9e5ae301..c203b4b81e 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -514,6 +514,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() {
download = memnew(HTTPRequest);
add_child(download);
download->connect("request_completed", this, "_http_download_completed");
+ download->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
download_error = memnew(AcceptDialog);
add_child(download_error);
@@ -533,11 +534,9 @@ void EditorAssetLibrary::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
- TextureRect *tf = memnew(TextureRect);
- tf->set_texture(get_icon("Error", "EditorIcons"));
+ error_tr->set_texture(get_icon("Error", "EditorIcons"));
reverse->set_icon(get_icon("Sort", "EditorIcons"));
- error_hb->add_child(tf);
error_label->raise();
} break;
@@ -585,6 +584,8 @@ void EditorAssetLibrary::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree"));
+ error_tr->set_texture(get_icon("Error", "EditorIcons"));
+ reverse->set_icon(get_icon("Sort", "EditorIcons"));
} break;
}
}
@@ -832,6 +833,7 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag
iq.image_index = p_image_index;
iq.image_type = p_type;
iq.request = memnew(HTTPRequest);
+ iq.request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
iq.target = p_for;
iq.queue_id = ++last_queue_id;
@@ -1452,6 +1454,8 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
error_label = memnew(Label);
error_label->add_color_override("color", get_color("error_color", "Editor"));
error_hb->add_child(error_label);
+ error_tr = memnew(TextureRect);
+ error_hb->add_child(error_tr);
description = NULL;
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index b344716c1d..89b79d7cfb 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -194,6 +194,7 @@ class EditorAssetLibrary : public PanelContainer {
Button *search;
ProgressBar *load_status;
HBoxContainer *error_hb;
+ TextureRect *error_tr;
Label *error_label;
MenuButton *support;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3bb9dca95f..b8d0958c99 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -210,6 +210,7 @@ void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap,
Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const CanvasItem *p_canvas_item, unsigned int p_forced_modes) {
bool snapped[2] = { false, false };
+ bool is_snap_active = snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
// Smart snap using the canvas position
Vector2 output = p_target;
@@ -219,7 +220,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
rotation = p_canvas_item->get_global_transform_with_canvas().get_rotation();
// Parent sides and center
- if ((snap_active && snap_node_parent && (p_modes & SNAP_NODE_PARENT)) || (p_forced_modes & SNAP_NODE_PARENT)) {
+ if ((is_snap_active && snap_node_parent && (p_modes & SNAP_NODE_PARENT)) || (p_forced_modes & SNAP_NODE_PARENT)) {
Point2 begin;
Point2 end;
bool can_snap = false;
@@ -241,7 +242,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
// Self anchors
- if ((snap_active && snap_node_anchors && (p_modes & SNAP_NODE_ANCHORS)) || (p_forced_modes & SNAP_NODE_ANCHORS)) {
+ if ((is_snap_active && snap_node_anchors && (p_modes & SNAP_NODE_ANCHORS)) || (p_forced_modes & SNAP_NODE_ANCHORS)) {
if (const Control *c = Object::cast_to<Control>(p_canvas_item)) {
Point2 begin = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP))));
Point2 end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM))));
@@ -251,7 +252,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
// Self sides
- if ((snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) {
+ if ((is_snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) {
Point2 begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position());
Point2 end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size());
_snap_if_closer_point(p_target, begin, output, snapped, rotation);
@@ -259,18 +260,18 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
// Self center
- if ((snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
+ if ((is_snap_active && snap_node_center && (p_modes & SNAP_NODE_CENTER)) || (p_forced_modes & SNAP_NODE_CENTER)) {
Point2 center = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->_edit_get_rect().get_position() + p_canvas_item->_edit_get_rect().get_size() / 2.0);
_snap_if_closer_point(p_target, center, output, snapped, rotation);
}
}
// Other nodes sides
- if ((snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) {
+ if ((is_snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) {
_snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item);
}
- if (((snap_active && snap_guides && (p_modes & SNAP_GUIDES)) || (p_forced_modes & SNAP_GUIDES)) && fmod(rotation, (real_t)360.0) == 0.0) {
+ if (((is_snap_active && snap_guides && (p_modes & SNAP_GUIDES)) || (p_forced_modes & SNAP_GUIDES)) && fmod(rotation, (real_t)360.0) == 0.0) {
// Guides
if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) {
Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_");
@@ -287,7 +288,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
}
- if (((snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && fmod(rotation, (real_t)360.0) == 0.0) {
+ if (((is_snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && fmod(rotation, (real_t)360.0) == 0.0) {
// Grid
Point2 offset = grid_offset;
if (snap_relative) {
@@ -313,7 +314,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const
}
float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
- return (snap_rotation && snap_rotation_step != 0) ? Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset : p_target;
+ return (((snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) && snap_rotation_step != 0) ? Math::stepify(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset : p_target;
}
void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
@@ -855,8 +856,8 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
if (b->get_button_index() == BUTTON_WHEEL_DOWN) {
// Scroll or pan down
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
- v_scroll->set_value(v_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
- _update_scroll(0);
+ view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ _update_scrollbars();
viewport->update();
} else {
_zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position());
@@ -867,8 +868,8 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
if (b->get_button_index() == BUTTON_WHEEL_UP) {
// Scroll or pan up
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
- v_scroll->set_value(v_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
- _update_scroll(0);
+ view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ _update_scrollbars();
viewport->update();
} else {
_zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position());
@@ -879,7 +880,9 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
if (b->get_button_index() == BUTTON_WHEEL_LEFT) {
// Pan left
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
- h_scroll->set_value(h_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
+ view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ _update_scrollbars();
+ viewport->update();
return true;
}
}
@@ -887,7 +890,9 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
if (b->get_button_index() == BUTTON_WHEEL_RIGHT) {
// Pan right
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
- h_scroll->set_value(h_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor());
+ view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
+ _update_scrollbars();
+ viewport->update();
return true;
}
}
@@ -907,9 +912,10 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
} else {
relative = m->get_relative();
}
-
- h_scroll->set_value(h_scroll->get_value() - relative.x / zoom);
- v_scroll->set_value(v_scroll->get_value() - relative.y / zoom);
+ view_offset.x -= relative.x / zoom;
+ view_offset.y -= relative.y / zoom;
+ _update_scrollbars();
+ viewport->update();
return true;
}
}
@@ -926,8 +932,10 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
if (pan_gesture.is_valid()) {
// Pan gesture
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
- h_scroll->set_value(h_scroll->get_value() + delta.x);
- v_scroll->set_value(v_scroll->get_value() + delta.y);
+ view_offset.x += delta.x;
+ view_offset.y += delta.y;
+ _update_scrollbars();
+ viewport->update();
return true;
}
@@ -1227,26 +1235,26 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
switch (drag_type) {
case DRAG_ANCHOR_TOP_LEFT:
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
break;
case DRAG_ANCHOR_TOP_RIGHT:
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, false);
break;
case DRAG_ANCHOR_BOTTOM_RIGHT:
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, false);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
break;
case DRAG_ANCHOR_BOTTOM_LEFT:
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, false);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, false);
break;
case DRAG_ANCHOR_ALL:
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true);
- if (!use_single_axis || (use_single_axis && !use_y)) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_TOP, new_anchor.y, false, true);
- if (!use_single_axis || (use_single_axis && use_y)) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_LEFT, new_anchor.x, false, true);
+ if (!use_single_axis || !use_y) control->set_anchor(MARGIN_RIGHT, new_anchor.x, false, true);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_TOP, new_anchor.y, false, true);
+ if (!use_single_axis || use_y) control->set_anchor(MARGIN_BOTTOM, new_anchor.y, false, true);
break;
default:
break;
@@ -1664,8 +1672,6 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
selection_menu_additive_selection = b->get_shift();
selection_menu->set_global_position(b->get_global_position());
selection_menu->popup();
- selection_menu->call_deferred("grab_click_focus");
- selection_menu->set_invalidate_click_until_motion();
return true;
}
}
@@ -1967,10 +1973,11 @@ void CanvasItemEditor::_draw_rulers() {
Color font_color = get_color("font_color", "Editor");
font_color.a = 0.8;
Ref<Font> font = get_font("rulers", "EditorFonts");
+ bool is_snap_active = snap_active ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL);
// The rule transform
Transform2D ruler_transform = Transform2D();
- if (show_grid || (snap_active && snap_grid)) {
+ if (show_grid || (is_snap_active && snap_grid)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (snap_relative && selection.size() > 0) {
ruler_transform.translate(_get_encompassing_rect_from_list(selection).position);
@@ -2399,26 +2406,34 @@ void CanvasItemEditor::_draw_straight_line(Point2 p_from, Point2 p_to, Color p_c
}
void CanvasItemEditor::_draw_axis() {
- RID ci = viewport->get_canvas_item();
- Color x_axis_color(1.0, 0.4, 0.4, 0.6);
- Color y_axis_color(0.4, 1.0, 0.4, 0.6);
- Color area_axis_color(0.4, 0.4, 1.0, 0.4);
+ if (show_origin) {
+
+ Color x_axis_color(1.0, 0.4, 0.4, 0.6);
+ Color y_axis_color(0.4, 1.0, 0.4, 0.6);
- _draw_straight_line(Point2(), Point2(1, 0), x_axis_color);
- _draw_straight_line(Point2(), Point2(0, 1), y_axis_color);
+ _draw_straight_line(Point2(), Point2(1, 0), x_axis_color);
+ _draw_straight_line(Point2(), Point2(0, 1), y_axis_color);
+ }
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ if (show_viewport) {
- Vector2 screen_endpoints[4] = {
- transform.xform(Vector2(0, 0)),
- transform.xform(Vector2(screen_size.width, 0)),
- transform.xform(Vector2(screen_size.width, screen_size.height)),
- transform.xform(Vector2(0, screen_size.height))
- };
+ RID ci = viewport->get_canvas_item();
+
+ Color area_axis_color(0.4, 0.4, 1.0, 0.4);
+
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
- for (int i = 0; i < 4; i++) {
- VisualServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color);
+ Vector2 screen_endpoints[4] = {
+ transform.xform(Vector2(0, 0)),
+ transform.xform(Vector2(screen_size.width, 0)),
+ transform.xform(Vector2(screen_size.width, screen_size.height)),
+ transform.xform(Vector2(0, screen_size.height))
+ };
+
+ for (int i = 0; i < 4; i++) {
+ VisualServer::get_singleton()->canvas_item_add_line(ci, screen_endpoints[i], screen_endpoints[(i + 1) % 4], area_axis_color);
+ }
}
}
@@ -2544,6 +2559,11 @@ void CanvasItemEditor::_build_bones_list(Node *p_node) {
}
void CanvasItemEditor::_draw_viewport() {
+ // Update the transform
+ transform = Transform2D();
+ transform.scale_basis(Size2(zoom, zoom));
+ transform.elements[2] = -view_offset * zoom;
+ editor->get_scene_root()->set_global_canvas_transform(transform);
// hide/show buttons depending on the selection
bool all_locked = true;
@@ -2574,8 +2594,6 @@ void CanvasItemEditor::_draw_viewport() {
group_button->set_disabled(selection.empty());
ungroup_button->set_visible(all_group);
- _update_scrollbars();
-
_draw_grid();
_draw_selection();
_draw_axis();
@@ -2776,17 +2794,18 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
// Clear the selection
editor_selection->clear(); //_clear_canvas_items();
editor_selection->add_node(p_canvas_item);
- viewport->update();
}
void CanvasItemEditor::_update_scrollbars() {
updating_scroll = true;
+ // Move the zoom buttons
Point2 zoom_hb_begin = Point2(5, 5);
zoom_hb_begin += (show_rulers) ? Point2(RULER_WIDTH, RULER_WIDTH) : Point2();
zoom_hb->set_begin(zoom_hb_begin);
+ // Move and resize the scrollbars
Size2 size = viewport->get_size();
Size2 hmin = h_scroll->get_minimum_size();
Size2 vmin = v_scroll->get_minimum_size();
@@ -2797,8 +2816,8 @@ void CanvasItemEditor::_update_scrollbars() {
h_scroll->set_begin(Point2((show_rulers) ? RULER_WIDTH : 0, size.height - hmin.height));
h_scroll->set_end(Point2(size.width - vmin.width, size.height));
+ // Get the visible frame
Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
-
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
bone_last_frame++;
@@ -2828,48 +2847,56 @@ void CanvasItemEditor::_update_scrollbars() {
canvas_item_rect.size += screen_rect * 2;
canvas_item_rect.position -= screen_rect;
- Point2 ofs;
+ // Constraints the view offset and updates the scrollbars
+ Point2 begin = canvas_item_rect.position;
+ Point2 end = canvas_item_rect.position + canvas_item_rect.size - local_rect.size / zoom;
if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) {
+ if (ABS(begin.y - previous_update_view_offset.y) < ABS(begin.y - view_offset.y)) {
+ view_offset.y = previous_update_view_offset.y;
+ }
+
v_scroll->hide();
- ofs.y = canvas_item_rect.position.y;
} else {
-
- v_scroll->show();
- v_scroll->set_min(canvas_item_rect.position.y);
- v_scroll->set_max(canvas_item_rect.position.y + canvas_item_rect.size.y);
- v_scroll->set_page(local_rect.size.y / zoom);
- if (first_update) {
- //so 0,0 is visible
- v_scroll->set_value(-10);
- h_scroll->set_value(-10);
- first_update = false;
+ if (view_offset.y > end.y && view_offset.y > previous_update_view_offset.y) {
+ view_offset.y = MAX(end.y, previous_update_view_offset.y);
+ }
+ if (view_offset.y < begin.y && view_offset.y < previous_update_view_offset.y) {
+ view_offset.y = MIN(begin.y, previous_update_view_offset.y);
}
- ofs.y = v_scroll->get_value();
+ v_scroll->show();
+ v_scroll->set_min(MIN(view_offset.y, begin.y));
+ v_scroll->set_max(MAX(view_offset.y, end.y) + screen_rect.y);
+ v_scroll->set_page(screen_rect.y);
}
if (canvas_item_rect.size.width <= (local_rect.size.x / zoom)) {
+ if (ABS(begin.x - previous_update_view_offset.x) < ABS(begin.x - view_offset.x)) {
+ view_offset.x = previous_update_view_offset.x;
+ }
h_scroll->hide();
- ofs.x = canvas_item_rect.position.x;
} else {
+ if (view_offset.x > end.x && view_offset.x > previous_update_view_offset.x) {
+ view_offset.x = MAX(end.x, previous_update_view_offset.x);
+ }
+ if (view_offset.x < begin.x && view_offset.x < previous_update_view_offset.x) {
+ view_offset.x = MIN(begin.x, previous_update_view_offset.x);
+ }
h_scroll->show();
- h_scroll->set_min(canvas_item_rect.position.x);
- h_scroll->set_max(canvas_item_rect.position.x + canvas_item_rect.size.x);
- h_scroll->set_page(local_rect.size.x / zoom);
- ofs.x = h_scroll->get_value();
+ h_scroll->set_min(MIN(view_offset.x, begin.x));
+ h_scroll->set_max(MAX(view_offset.x, end.x) + screen_rect.x);
+ h_scroll->set_page(screen_rect.x);
}
- //transform=Matrix32();
- transform.elements[2] = -ofs * zoom;
-
- editor->get_scene_root()->set_global_canvas_transform(transform);
+ // Calculate scrollable area
+ v_scroll->set_value(view_offset.y);
+ h_scroll->set_value(view_offset.x);
+ previous_update_view_offset = view_offset;
updating_scroll = false;
-
- //transform.scale_basis(Vector2(zoom,zoom));
}
void CanvasItemEditor::_update_scroll(float) {
@@ -2877,19 +2904,8 @@ void CanvasItemEditor::_update_scroll(float) {
if (updating_scroll)
return;
- Point2 ofs;
- ofs.x = h_scroll->get_value();
- ofs.y = v_scroll->get_value();
-
- //current_window->set_scroll(-ofs);
-
- transform = Transform2D();
-
- transform.scale_basis(Size2(zoom, zoom));
- transform.elements[2] = -ofs;
-
- editor->get_scene_root()->set_global_canvas_transform(transform);
-
+ view_offset.x = h_scroll->get_value();
+ view_offset.y = v_scroll->get_value();
viewport->update();
}
@@ -2956,10 +2972,10 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
zoom = p_zoom;
Point2 ofs = p_position;
ofs = ofs / prev_zoom - ofs / zoom;
- h_scroll->set_value(Math::round(h_scroll->get_value() + ofs.x));
- v_scroll->set_value(Math::round(v_scroll->get_value() + ofs.y));
+ view_offset.x = Math::round(view_offset.x + ofs.x);
+ view_offset.y = Math::round(view_offset.y + ofs.y);
- _update_scroll(0);
+ _update_scrollbars();
viewport->update();
}
@@ -3002,6 +3018,18 @@ void CanvasItemEditor::_popup_callback(int p_op) {
view_menu->get_popup()->set_item_checked(idx, show_grid);
viewport->update();
} break;
+ case SHOW_ORIGIN: {
+ show_origin = !show_origin;
+ int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
+ view_menu->get_popup()->set_item_checked(idx, show_origin);
+ viewport->update();
+ } break;
+ case SHOW_VIEWPORT: {
+ show_viewport = !show_viewport;
+ int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
+ view_menu->get_popup()->set_item_checked(idx, show_viewport);
+ viewport->update();
+ } break;
case SNAP_USE_NODE_PARENT: {
snap_node_parent = !snap_node_parent;
int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_PARENT);
@@ -3532,8 +3560,10 @@ void CanvasItemEditor::_focus_selection(int p_op) {
center = rect.position + rect.size / 2;
Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
- h_scroll->set_value(h_scroll->get_value() - offset.x / zoom);
- v_scroll->set_value(v_scroll->get_value() - offset.y / zoom);
+ view_offset.x -= offset.x / zoom;
+ view_offset.y -= offset.y / zoom;
+ _update_scrollbars();
+ viewport->update();
} else { // VIEW_FRAME_TO_SELECTION
@@ -3542,7 +3572,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
float scale_y = viewport->get_size().y / rect.size.y;
zoom = scale_x < scale_y ? scale_x : scale_y;
zoom *= 0.90;
- _update_scroll(0);
+ viewport->update();
call_deferred("_popup_callback", VIEW_CENTER_TO_SELECTION);
}
}
@@ -3555,6 +3585,7 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus);
ClassDB::bind_method("_button_toggle_snap", &CanvasItemEditor::_button_toggle_snap);
ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll);
+ ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars);
ClassDB::bind_method("_popup_callback", &CanvasItemEditor::_popup_callback);
ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
ClassDB::bind_method("_button_tool_select", &CanvasItemEditor::_button_tool_select);
@@ -3575,7 +3606,7 @@ Dictionary CanvasItemEditor::get_state() const {
Dictionary state;
state["zoom"] = zoom;
- state["ofs"] = Point2(h_scroll->get_value(), v_scroll->get_value());
+ state["ofs"] = view_offset;
state["grid_offset"] = grid_offset;
state["grid_step"] = grid_step;
state["snap_rotation_offset"] = snap_rotation_offset;
@@ -3589,6 +3620,8 @@ Dictionary CanvasItemEditor::get_state() const {
state["snap_grid"] = snap_grid;
state["snap_guides"] = snap_guides;
state["show_grid"] = show_grid;
+ state["show_origin"] = show_origin;
+ state["show_viewport"] = show_viewport;
state["show_rulers"] = show_rulers;
state["show_guides"] = show_guides;
state["show_helpers"] = show_helpers;
@@ -3607,10 +3640,9 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
}
if (state.has("ofs")) {
- _update_scrollbars(); // i wonder how safe is calling this here..
- Point2 ofs = p_state["ofs"];
- h_scroll->set_value(ofs.x);
- v_scroll->set_value(ofs.y);
+ view_offset = p_state["ofs"];
+ previous_update_view_offset = view_offset;
+ _update_scrollbars();
}
if (state.has("grid_offset")) {
@@ -3682,6 +3714,18 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
view_menu->get_popup()->set_item_checked(idx, show_grid);
}
+ if (state.has("show_origin")) {
+ show_origin = state["show_origin"];
+ int idx = view_menu->get_popup()->get_item_index(SHOW_ORIGIN);
+ view_menu->get_popup()->set_item_checked(idx, show_origin);
+ }
+
+ if (state.has("show_viewport")) {
+ show_viewport = state["show_viewport"];
+ int idx = view_menu->get_popup()->get_item_index(SHOW_VIEWPORT);
+ view_menu->get_popup()->set_item_checked(idx, show_viewport);
+ }
+
if (state.has("show_rulers")) {
show_rulers = state["show_rulers"];
int idx = view_menu->get_popup()->get_item_index(SHOW_RULERS);
@@ -3778,6 +3822,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport_scrollable->set_clip_contents(true);
viewport_scrollable->set_v_size_flags(SIZE_EXPAND_FILL);
viewport_scrollable->set_h_size_flags(SIZE_EXPAND_FILL);
+ viewport_scrollable->connect("draw", this, "_update_scrollbars");
ViewportContainer *scene_tree = memnew(ViewportContainer);
viewport_scrollable->add_child(scene_tree);
@@ -3796,12 +3841,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
- h_scroll->connect("value_changed", this, "_update_scroll", Vector<Variant>(), Object::CONNECT_DEFERRED);
+ h_scroll->connect("value_changed", this, "_update_scroll");
h_scroll->hide();
v_scroll = memnew(VScrollBar);
viewport->add_child(v_scroll);
- v_scroll->connect("value_changed", this, "_update_scroll", Vector<Variant>(), Object::CONNECT_DEFERRED);
+ v_scroll->connect("value_changed", this, "_update_scroll");
v_scroll->hide();
zoom_hb = memnew(HBoxContainer);
@@ -3824,7 +3869,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
zoom_plus->set_focus_mode(FOCUS_NONE);
updating_scroll = false;
- first_update = true;
select_button = memnew(ToolButton);
hb->add_child(select_button);
@@ -3955,6 +3999,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers"), KEY_R), SHOW_RULERS);
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION);
@@ -4040,10 +4086,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_scale = false;
show_grid = false;
+ show_origin = true;
+ show_viewport = true;
show_helpers = false;
show_rulers = true;
show_guides = true;
zoom = 1;
+ view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
+ previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
grid_offset = Point2();
grid_step = Point2(10, 10);
grid_step_multiplier = 0;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index adf203cf3d..da7ce9172a 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -100,6 +100,8 @@ class CanvasItemEditor : public VBoxContainer {
SHOW_HELPERS,
SHOW_RULERS,
SHOW_GUIDES,
+ SHOW_ORIGIN,
+ SHOW_VIEWPORT,
LOCK_SELECTED,
UNLOCK_SELECTED,
GROUP_SELECTED,
@@ -199,7 +201,6 @@ class CanvasItemEditor : public VBoxContainer {
bool selection_menu_additive_selection;
Tool tool;
- bool first_update;
Control *viewport;
Control *viewport_scrollable;
@@ -215,8 +216,12 @@ class CanvasItemEditor : public VBoxContainer {
bool show_grid;
bool show_rulers;
bool show_guides;
+ bool show_origin;
+ bool show_viewport;
bool show_helpers;
float zoom;
+ Point2 view_offset;
+ Point2 previous_update_view_offset;
Point2 grid_offset;
Point2 grid_step;
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 47d730cdf1..8542296bde 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -40,7 +40,7 @@
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
-static void post_process_preview(Ref<Image> p_image) {
+void post_process_preview(Ref<Image> p_image) {
if (p_image->get_format() != Image::FORMAT_RGBA8)
p_image->convert(Image::FORMAT_RGBA8);
diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h
index 2e12515e30..35b5c3a5f0 100644
--- a/editor/plugins/editor_preview_plugins.h
+++ b/editor/plugins/editor_preview_plugins.h
@@ -33,6 +33,8 @@
#include "editor/editor_resource_preview.h"
+void post_process_preview(Ref<Image> p_image);
+
class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator)
public:
diff --git a/editor/plugins/item_list_editor_plugin.cpp b/editor/plugins/item_list_editor_plugin.cpp
index fd5a1f185f..8b44f672b0 100644
--- a/editor/plugins/item_list_editor_plugin.cpp
+++ b/editor/plugins/item_list_editor_plugin.cpp
@@ -42,9 +42,18 @@ bool ItemListPlugin::_set(const StringName &p_name, const Variant &p_value) {
set_item_text(idx, p_value);
else if (what == "icon")
set_item_icon(idx, p_value);
- else if (what == "checkable")
- set_item_checkable(idx, p_value);
- else if (what == "checked")
+ else if (what == "checkable") {
+ // This keeps compatibility to/from versions where this property was a boolean, before radio buttons
+ switch ((int)p_value) {
+ case 0:
+ case 1:
+ set_item_checkable(idx, p_value);
+ break;
+ case 2:
+ set_item_radio_checkable(idx, true);
+ break;
+ }
+ } else if (what == "checked")
set_item_checked(idx, p_value);
else if (what == "id")
set_item_id(idx, p_value);
@@ -68,9 +77,14 @@ bool ItemListPlugin::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_item_text(idx);
else if (what == "icon")
r_ret = get_item_icon(idx);
- else if (what == "checkable")
- r_ret = is_item_checkable(idx);
- else if (what == "checked")
+ else if (what == "checkable") {
+ // This keeps compatibility to/from versions where this property was a boolean, before radio buttons
+ if (!is_item_checkable(idx)) {
+ r_ret = 0;
+ } else {
+ r_ret = is_item_radio_checkable(idx) ? 2 : 1;
+ }
+ } else if (what == "checked")
r_ret = is_item_checked(idx);
else if (what == "id")
r_ret = get_item_id(idx);
@@ -95,7 +109,7 @@ void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const {
int flags = get_flags();
if (flags & FLAG_CHECKABLE) {
- p_list->push_back(PropertyInfo(Variant::BOOL, base + "checkable"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, base + "checkable", PROPERTY_HINT_ENUM, "No,As checkbox,As radio button"));
p_list->push_back(PropertyInfo(Variant::BOOL, base + "checked"));
}
@@ -247,7 +261,7 @@ void ItemListEditor::_node_removed(Node *p_node) {
void ItemListEditor::_notification(int p_notification) {
- if (p_notification == NOTIFICATION_ENTER_TREE) {
+ if (p_notification == NOTIFICATION_ENTER_TREE || p_notification == NOTIFICATION_THEME_CHANGED) {
add_button->set_icon(get_icon("Add", "EditorIcons"));
del_button->set_icon(get_icon("Remove", "EditorIcons"));
diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h
index bd7d3db10d..d6a071b9b9 100644
--- a/editor/plugins/item_list_editor_plugin.h
+++ b/editor/plugins/item_list_editor_plugin.h
@@ -74,7 +74,9 @@ public:
virtual Ref<Texture> get_item_icon(int p_idx) const { return Ref<Texture>(); };
virtual void set_item_checkable(int p_idx, bool p_check) {}
+ virtual void set_item_radio_checkable(int p_idx, bool p_check) {}
virtual bool is_item_checkable(int p_idx) const { return false; };
+ virtual bool is_item_radio_checkable(int p_idx) const { return false; };
virtual void set_item_checked(int p_idx, bool p_checked) {}
virtual bool is_item_checked(int p_idx) const { return false; };
@@ -145,7 +147,9 @@ public:
virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); }
virtual void set_item_checkable(int p_idx, bool p_check) { pp->set_item_as_checkable(p_idx, p_check); }
+ virtual void set_item_radio_checkable(int p_idx, bool p_check) { pp->set_item_as_radio_checkable(p_idx, p_check); }
virtual bool is_item_checkable(int p_idx) const { return pp->is_item_checkable(p_idx); }
+ virtual bool is_item_radio_checkable(int p_idx) const { return pp->is_item_radio_checkable(p_idx); }
virtual void set_item_checked(int p_idx, bool p_checked) { pp->set_item_checked(p_idx, p_checked); }
virtual bool is_item_checked(int p_idx) const { return pp->is_item_checked(p_idx); }
diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp
index cb5f7ba76c..7ea2b27744 100644
--- a/editor/plugins/mesh_instance_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_editor_plugin.cpp
@@ -344,6 +344,10 @@ void MeshInstanceEditor::_create_outline_mesh() {
err_dialog->set_text(TTR("Mesh has not surface to create outlines from!"));
err_dialog->popup_centered_minsize();
return;
+ } else if (mesh->get_surface_count() == 1 && mesh->surface_get_primitive_type(0) != Mesh::PRIMITIVE_TRIANGLES) {
+ err_dialog->set_text(TTR("Mesh primitive type is not PRIMITIVE_TRIANGLES!"));
+ err_dialog->popup_centered_minsize();
+ return;
}
Ref<Mesh> mesho = mesh->create_outline(outline_size->get_value());
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 261bece8f7..2ce36ee8d5 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1778,6 +1778,20 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool
}
ERR_FAIL_COND_V(!se, false);
+ bool highlighter_set = false;
+ for (int i = 0; i < syntax_highlighters_func_count; i++) {
+ SyntaxHighlighter *highlighter = syntax_highlighters_funcs[i]();
+ se->add_syntax_highlighter(highlighter);
+
+ if (!highlighter_set) {
+ List<String> languages = highlighter->get_supported_languages();
+ if (languages.find(p_script->get_language()->get_name())) {
+ se->set_syntax_highlighter(highlighter);
+ highlighter_set = true;
+ }
+ }
+ }
+
tab_container->add_child(se);
se->set_edited_script(p_script);
se->set_tooltip_request_func("_get_debug_tooltip", this);
@@ -2494,6 +2508,14 @@ void ScriptEditor::_open_script_request(const String &p_path) {
}
}
+int ScriptEditor::syntax_highlighters_func_count = 0;
+CreateSyntaxHighlighterFunc ScriptEditor::syntax_highlighters_funcs[ScriptEditor::SYNTAX_HIGHLIGHTER_FUNC_MAX];
+
+void ScriptEditor::register_create_syntax_highlighter_function(CreateSyntaxHighlighterFunc p_func) {
+ ERR_FAIL_COND(syntax_highlighters_func_count == SYNTAX_HIGHLIGHTER_FUNC_MAX);
+ syntax_highlighters_funcs[syntax_highlighters_func_count++] = p_func;
+}
+
int ScriptEditor::script_editor_func_count = 0;
CreateScriptEditorFunc ScriptEditor::script_editor_funcs[ScriptEditor::SCRIPT_EDITOR_FUNC_MAX];
@@ -2577,8 +2599,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
waiting_update_names = false;
pending_auto_reload = false;
auto_reload_running_scripts = false;
- members_overview_enabled = true;
- help_overview_enabled = true;
+ members_overview_enabled = EditorSettings::get_singleton()->get("text_editor/open_scripts/show_members_overview");
+ help_overview_enabled = EditorSettings::get_singleton()->get("text_editor/help/show_help_index");
editor = p_editor;
VBoxContainer *main_container = memnew(VBoxContainer);
@@ -2820,9 +2842,9 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
//debugger_gui->hide();
edit_pass = 0;
- trim_trailing_whitespace_on_save = false;
- convert_indent_on_save = false;
- use_space_indentation = false;
+ trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/files/trim_trailing_whitespace_on_save");
+ convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/indent/convert_indent_on_save");
+ use_space_indentation = EditorSettings::get_singleton()->get("text_editor/indent/type");
ScriptServer::edit_request_func = _open_script_request;
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index bcc604d990..f947351089 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -80,6 +80,9 @@ protected:
static void _bind_methods();
public:
+ virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0;
+ virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0;
+
virtual void apply_code() = 0;
virtual Ref<Script> get_edited_script() const = 0;
virtual Vector<String> get_functions() = 0;
@@ -112,6 +115,7 @@ public:
ScriptEditorBase() {}
};
+typedef SyntaxHighlighter *(*CreateSyntaxHighlighterFunc)();
typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const Ref<Script> &p_script);
class EditorScriptCodeCompletionCache;
@@ -214,12 +218,16 @@ class ScriptEditor : public PanelContainer {
ToolButton *script_forward;
enum {
- SCRIPT_EDITOR_FUNC_MAX = 32
+ SCRIPT_EDITOR_FUNC_MAX = 32,
+ SYNTAX_HIGHLIGHTER_FUNC_MAX = 32
};
static int script_editor_func_count;
static CreateScriptEditorFunc script_editor_funcs[SCRIPT_EDITOR_FUNC_MAX];
+ static int syntax_highlighters_func_count;
+ static CreateSyntaxHighlighterFunc syntax_highlighters_funcs[SYNTAX_HIGHLIGHTER_FUNC_MAX];
+
struct ScriptHistory {
Control *control;
@@ -399,7 +407,9 @@ public:
ScriptEditorDebugger *get_debugger() { return debugger; }
void set_live_auto_reload_running_scripts(bool p_enabled);
+ static void register_create_syntax_highlighter_function(CreateSyntaxHighlighterFunc p_func);
static void register_create_script_editor_function(CreateScriptEditorFunc p_func);
+
ScriptEditor(EditorNode *p_editor);
~ScriptEditor();
};
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index aeba0ff930..711a313902 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -349,7 +349,12 @@ void ScriptTextEditor::_convert_case(CaseStyle p_case) {
int end_col = te->get_selection_to_column();
for (int i = begin; i <= end; i++) {
- String new_line = te->get_line(i);
+ int len = te->get_line(i).length();
+ if (i == end)
+ len -= len - end_col;
+ if (i == begin)
+ len -= begin_col;
+ String new_line = te->get_line(i).substr(i == begin ? begin_col : 0, len);
switch (p_case) {
case UPPER: {
@@ -364,10 +369,10 @@ void ScriptTextEditor::_convert_case(CaseStyle p_case) {
}
if (i == begin) {
- new_line = te->get_line(i).left(begin_col) + new_line.right(begin_col);
+ new_line = te->get_line(i).left(begin_col) + new_line;
}
if (i == end) {
- new_line = new_line.left(end_col) + te->get_line(i).right(end_col);
+ new_line = new_line + te->get_line(i).right(end_col);
}
te->set_line(i, new_line);
}
@@ -568,6 +573,7 @@ void ScriptTextEditor::set_edited_script(const Ref<Script> &p_script) {
ERR_FAIL_COND(!script.is_null());
script = p_script;
+ _set_theme_for_script();
code_editor->get_text_edit()->set_text(script->get_source_code());
code_editor->get_text_edit()->clear_undo_history();
@@ -575,8 +581,6 @@ void ScriptTextEditor::set_edited_script(const Ref<Script> &p_script) {
emit_signal("name_changed");
code_editor->update_line_and_column();
-
- _set_theme_for_script();
}
void ScriptTextEditor::_validate_script() {
@@ -784,6 +788,26 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal("go_to_help", "class_method:" + result.class_name + ":" + result.class_member);
} break;
+ case ScriptLanguage::LookupResult::RESULT_CLASS_ENUM: {
+
+ StringName cname = result.class_name;
+ StringName success;
+ while (true) {
+ success = ClassDB::get_integer_constant_enum(cname, result.class_member, true);
+ if (success != StringName()) {
+ result.class_name = cname;
+ cname = ClassDB::get_parent_class(cname);
+ } else {
+ break;
+ }
+ }
+
+ emit_signal("go_to_help", "class_enum:" + result.class_name + ":" + result.class_member);
+
+ } break;
+ case ScriptLanguage::LookupResult::RESULT_CLASS_TBD_GLOBALSCOPE: {
+ emit_signal("go_to_help", "class_global:" + result.class_name + ":" + result.class_member);
+ } break;
}
}
}
@@ -1240,11 +1264,26 @@ void ScriptTextEditor::_edit_option(int p_op) {
}
}
+void ScriptTextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
+ highlighters[p_highlighter->get_name()] = p_highlighter;
+ highlighter_menu->get_popup()->add_item(p_highlighter->get_name());
+}
+
+void ScriptTextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
+ TextEdit *te = code_editor->get_text_edit();
+ te->_set_syntax_highlighting(p_highlighter);
+}
+
+void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
+ set_syntax_highlighter(highlighters[highlighter_menu->get_popup()->get_item_text(p_idx)]);
+}
+
void ScriptTextEditor::_bind_methods() {
ClassDB::bind_method("_validate_script", &ScriptTextEditor::_validate_script);
ClassDB::bind_method("_load_theme_settings", &ScriptTextEditor::_load_theme_settings);
ClassDB::bind_method("_breakpoint_toggled", &ScriptTextEditor::_breakpoint_toggled);
+ ClassDB::bind_method("_change_syntax_highlighter", &ScriptTextEditor::_change_syntax_highlighter);
ClassDB::bind_method("_edit_option", &ScriptTextEditor::_edit_option);
ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line);
ClassDB::bind_method("_lookup_symbol", &ScriptTextEditor::_lookup_symbol);
@@ -1630,6 +1669,14 @@ ScriptTextEditor::ScriptTextEditor() {
edit_hb->add_child(edit_menu);
+ highlighters["Standard"] = NULL;
+
+ highlighter_menu = memnew(MenuButton);
+ highlighter_menu->set_text(TTR("Syntax Highlighter"));
+ highlighter_menu->get_popup()->add_item("Standard");
+ highlighter_menu->get_popup()->connect("id_pressed", this, "_change_syntax_highlighter");
+ edit_hb->add_child(highlighter_menu);
+
quick_open = memnew(ScriptEditorQuickOpen);
add_child(quick_open);
quick_open->connect("goto_line", this, "_goto_line");
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 22e8fbce25..eb52d2593a 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -49,6 +49,7 @@ class ScriptTextEditor : public ScriptEditorBase {
HBoxContainer *edit_hb;
MenuButton *edit_menu;
+ MenuButton *highlighter_menu;
MenuButton *search_menu;
PopupMenu *context_menu;
@@ -125,6 +126,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ Map<String, SyntaxHighlighter *> highlighters;
+ void _change_syntax_highlighter(int p_idx);
+
void _edit_option(int p_op);
void _make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded);
void _text_edit_gui_input(const Ref<InputEvent> &ev);
@@ -145,6 +149,9 @@ protected:
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
public:
+ virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter);
+ virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter);
+
virtual void apply_code();
virtual Ref<Script> get_edited_script() const;
virtual Vector<String> get_functions();
diff --git a/editor/plugins/shader_graph_editor_plugin.cpp b/editor/plugins/shader_graph_editor_plugin.cpp
index 59085c203f..e1d28cc215 100644
--- a/editor/plugins/shader_graph_editor_plugin.cpp
+++ b/editor/plugins/shader_graph_editor_plugin.cpp
@@ -2769,8 +2769,6 @@ void ShaderGraphEditor::_popup_requested(const Vector2 &p_position)
popup->set_global_position(p_position);
popup->set_size( Size2( 200, 0) );
popup->popup();
- popup->call_deferred("grab_click_focus");
- popup->set_invalidate_click_until_motion();
}
void ShaderGraphEditor::_notification(int p_what) {
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 9e7bfd5787..9d7c582e0e 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -886,8 +886,6 @@ void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
selection_menu->set_global_position(b->get_global_position());
selection_menu->popup();
- selection_menu->call_deferred("grab_click_focus");
- selection_menu->set_invalidate_click_until_motion();
}
}
@@ -1907,8 +1905,13 @@ void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, con
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
- cursor.x_rot += p_relative.y * radians_per_pixel;
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
+ }
cursor.y_rot += p_relative.x * radians_per_pixel;
if (cursor.x_rot > Math_PI / 2.0)
cursor.x_rot = Math_PI / 2.0;
@@ -1925,11 +1928,16 @@ void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, cons
if (!orthogonal) {
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
Transform prev_camera_transform = to_camera_transform(cursor);
- cursor.x_rot += p_relative.y * radians_per_pixel;
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
+ }
cursor.y_rot += p_relative.x * radians_per_pixel;
if (cursor.x_rot > Math_PI / 2.0)
cursor.x_rot = Math_PI / 2.0;
@@ -3343,14 +3351,14 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
- view_menu->get_popup()->add_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
+ view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
+ view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
view_menu->get_popup()->add_separator();
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
- view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
+ view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
view_menu->get_popup()->add_separator();
view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
@@ -5101,12 +5109,12 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
accept = memnew(AcceptDialog);
editor->get_gui_base()->add_child(accept);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index d8d0a6f013..71a3c90795 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -458,8 +458,6 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
List<StringName> anim_names;
- anim_names.sort_custom<StringName::AlphCompare>();
-
frames->get_animation_list(&anim_names);
anim_names.sort_custom<StringName::AlphCompare>();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 6cb4ca1e86..5ba3931689 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -57,8 +57,9 @@ void TextureRegionEditor::_region_draw() {
base_tex = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
base_tex = atlas_tex->get_atlas();
- else if (tile_set.is_valid() && selected_tile != -1)
+ else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile))
base_tex = tile_set->tile_get_texture(selected_tile);
+
if (base_tex.is_null())
return;
@@ -600,6 +601,7 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) {
void TextureRegionEditor::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_READY: {
zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
@@ -688,10 +690,11 @@ void TextureRegionEditor::_edit_region() {
texture = obj_styleBox->get_texture();
else if (atlas_tex.is_valid())
texture = atlas_tex->get_atlas();
- else if (tile_set.is_valid() && selected_tile != -1)
+ else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile))
texture = tile_set->tile_get_texture(selected_tile);
if (texture.is_null()) {
+ edit_draw->update();
return;
}
@@ -780,6 +783,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
tile_set = Ref<TileSet>(NULL);
editor = p_editor;
undo_redo = editor->get_undo_redo();
+ selected_tile = -1;
snap_step = Vector2(10, 10);
snap_separation = Vector2(0, 0);
@@ -801,12 +805,10 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
snap_mode_button->set_text(TTR("<None>"));
PopupMenu *p = snap_mode_button->get_popup();
p->set_hide_on_checkable_item_selection(false);
- p->add_item(TTR("<None>"), 0);
- p->add_item(TTR("Pixel Snap"), 1);
- p->add_item(TTR("Grid Snap"), 2);
- p->add_item(TTR("Auto Slice"), 3);
- for (int i = 0; i < 4; i++)
- p->set_item_as_checkable(i, true);
+ p->add_radio_check_item(TTR("<None>"), 0);
+ p->add_radio_check_item(TTR("Pixel Snap"), 1);
+ p->add_radio_check_item(TTR("Grid Snap"), 2);
+ p->add_radio_check_item(TTR("Auto Slice"), 3);
p->set_item_checked(0, true);
p->connect("id_pressed", this, "_set_snap_mode");
hb_grid = memnew(HBoxContainer);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 295d9439ad..550dfb3ae1 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -692,6 +692,10 @@ ThemeEditor::ThemeEditor() {
test_menu_button->get_popup()->add_check_item(TTR("Check Item"));
test_menu_button->get_popup()->add_check_item(TTR("Checked Item"));
test_menu_button->get_popup()->set_item_checked(2, true);
+ test_menu_button->get_popup()->add_separator();
+ test_menu_button->get_popup()->add_check_item(TTR("Radio Item"));
+ test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item"));
+ test_menu_button->get_popup()->set_item_checked(5, true);
first_vb->add_child(test_menu_button);
OptionButton *test_option_button = memnew(OptionButton);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index c97e949403..14c584fa35 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -48,6 +48,20 @@ void TileMapEditor::_notification(int p_what) {
} break;
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+
+ bool new_show_tile_info = EditorSettings::get_singleton()->get("editors/tile_map/show_tile_info_on_hover");
+ if (new_show_tile_info != show_tile_info) {
+ show_tile_info = new_show_tile_info;
+ tile_info->set_visible(show_tile_info);
+ }
+
+ if (is_visible_in_tree()) {
+ _update_palette();
+ }
+
+ } // fallthrough
+
case NOTIFICATION_ENTER_TREE: {
transp->set_icon(get_icon("Transpose", "EditorIcons"));
@@ -60,19 +74,14 @@ void TileMapEditor::_notification(int p_what) {
search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
- } break;
+ PopupMenu *p = options->get_popup();
+ p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_PICK_TILE), get_icon("ColorPick", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_SELECT), get_icon("ToolSelect", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_MOVE), get_icon("ToolMove", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_DUPLICATE), get_icon("Duplicate", "EditorIcons"));
+ p->set_item_icon(p->get_item_index(OPTION_ERASE_SELECTION), get_icon("Remove", "EditorIcons"));
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
-
- bool new_show_tile_info = EditorSettings::get_singleton()->get("editors/tile_map/show_tile_info_on_hover");
- if (new_show_tile_info != show_tile_info) {
- show_tile_info = new_show_tile_info;
- tile_info->set_visible(show_tile_info);
- }
-
- if (is_visible_in_tree()) {
- _update_palette();
- }
} break;
}
}
@@ -139,6 +148,23 @@ void TileMapEditor::_menu_option(int p_option) {
canvas_item_editor->update();
} break;
+ case OPTION_FIX_INVALID: {
+
+ undo_redo->create_action(TTR("Fix Invalid Tiles"));
+ undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data"));
+ node->fix_invalid_tiles();
+ undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data"));
+ undo_redo->commit_action();
+
+ } break;
+ case OPTION_MOVE: {
+
+ if (selection_active) {
+ _update_copydata();
+ tool = TOOL_MOVING;
+ canvas_item_editor->update();
+ }
+ } break;
}
}
@@ -812,6 +838,29 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
copydata.clear();
canvas_item_editor->update();
+ } else if (tool == TOOL_MOVING) {
+
+ Point2 ofs = over_tile - rectangle.position;
+
+ undo_redo->create_action(TTR("Move"));
+ undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data"));
+ for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
+ for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
+
+ _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false);
+ }
+ }
+ for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) {
+
+ _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose);
+ }
+ undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data"));
+ undo_redo->commit_action();
+
+ copydata.clear();
+ selection_active = false;
+
+ canvas_item_editor->update();
} else if (tool == TOOL_SELECTING) {
@@ -871,6 +920,16 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
+ if (tool == TOOL_MOVING) {
+
+ tool = TOOL_NONE;
+ copydata.clear();
+
+ canvas_item_editor->update();
+
+ return true;
+ }
+
if (tool == TOOL_NONE) {
paint_undo.clear();
@@ -1078,7 +1137,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (k->get_scancode() == KEY_ESCAPE) {
- if (tool == TOOL_DUPLICATING)
+ if (tool == TOOL_DUPLICATING || tool == TOOL_MOVING)
copydata.clear();
else if (tool == TOOL_SELECTING || selection_active)
selection_active = false;
@@ -1133,6 +1192,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
}
+ if (ED_IS_SHORTCUT("tile_map_editor/move_selection", p_event)) {
+ if (selection_active) {
+ _update_copydata();
+ tool = TOOL_MOVING;
+ canvas_item_editor->update();
+ return true;
+ }
+ }
if (ED_IS_SHORTCUT("tile_map_editor/find_tile", p_event)) {
search_box->select_all();
search_box->grab_focus();
@@ -1142,18 +1209,21 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (ED_IS_SHORTCUT("tile_map_editor/mirror_x", p_event)) {
flip_h = !flip_h;
mirror_x->set_pressed(flip_h);
+ _update_transform_buttons();
canvas_item_editor->update();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/mirror_y", p_event)) {
flip_v = !flip_v;
mirror_y->set_pressed(flip_v);
+ _update_transform_buttons();
canvas_item_editor->update();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/transpose", p_event)) {
transpose = !transpose;
transp->set_pressed(transpose);
+ _update_transform_buttons();
canvas_item_editor->update();
return true;
}
@@ -1326,7 +1396,7 @@ void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) {
_draw_cell(id, Point2i(j, i), flip_h, flip_v, transpose, xform);
}
}
- } else if (tool == TOOL_DUPLICATING) {
+ } else if (tool == TOOL_DUPLICATING || tool == TOOL_MOVING) {
if (copydata.empty())
return;
@@ -1511,8 +1581,8 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
bucket_cache_tile = -1;
bucket_cache_visited = 0;
- ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase selection"), KEY_DELETE);
- ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find tile"), KEY_MASK_CMD + KEY_F);
+ ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE);
+ ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F);
ED_SHORTCUT("tile_map_editor/transpose", TTR("Transpose"), KEY_T);
ED_SHORTCUT("tile_map_editor/mirror_x", TTR("Mirror X"), KEY_A);
ED_SHORTCUT("tile_map_editor/mirror_y", TTR("Mirror Y"), KEY_S);
@@ -1573,8 +1643,11 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
p->add_item(TTR("Pick Tile"), OPTION_PICK_TILE, KEY_CONTROL);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("tile_map_editor/select", TTR("Select"), KEY_MASK_CMD + KEY_B), OPTION_SELECT);
+ p->add_shortcut(ED_SHORTCUT("tile_map_editor/move_selection", TTR("Move Selection"), KEY_MASK_CMD + KEY_M), OPTION_MOVE);
p->add_shortcut(ED_SHORTCUT("tile_map_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_CMD + KEY_D), OPTION_DUPLICATE);
p->add_shortcut(ED_GET_SHORTCUT("tile_map_editor/erase_selection"), OPTION_ERASE_SELECTION);
+ p->add_separator();
+ p->add_item(TTR("Fix Invalid Tiles"), OPTION_FIX_INVALID);
p->connect("id_pressed", this, "_menu_option");
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 0a937e200e..3257901c88 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -61,6 +61,7 @@ class TileMapEditor : public VBoxContainer {
TOOL_BUCKET,
TOOL_PICKING,
TOOL_DUPLICATING,
+ TOOL_MOVING
};
enum Options {
@@ -71,6 +72,8 @@ class TileMapEditor : public VBoxContainer {
OPTION_DUPLICATE,
OPTION_ERASE_SELECTION,
OPTION_PAINTING,
+ OPTION_FIX_INVALID,
+ OPTION_MOVE
};
TileMap *node;
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 686ad566fd..2311439728 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -242,6 +242,7 @@ void TileSetEditor::_bind_methods() {
ClassDB::bind_method("_name_dialog_confirm", &TileSetEditor::_name_dialog_confirm);
ClassDB::bind_method("_on_tile_list_selected", &TileSetEditor::_on_tile_list_selected);
ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed);
+ ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw);
ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw);
ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input);
ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked);
@@ -256,7 +257,7 @@ void TileSetEditor::_bind_methods() {
}
void TileSetEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons"));
tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons"));
@@ -519,10 +520,15 @@ void TileSetEditor::initialize_bottom_editor() {
workspace_container = memnew(Control);
scroll->add_child(workspace_container);
+ workspace_overlay = memnew(Control);
+ workspace_overlay->connect("draw", this, "_on_workspace_overlay_draw");
+ workspace_container->add_child(workspace_overlay);
+
workspace = memnew(Control);
workspace->connect("draw", this, "_on_workspace_draw");
workspace->connect("gui_input", this, "_on_workspace_input");
- workspace_container->add_child(workspace);
+ workspace->set_draw_behind_parent(true);
+ workspace_overlay->add_child(workspace);
preview = memnew(Sprite);
workspace->add_child(preview);
@@ -558,6 +564,8 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
add_child(err_dialog);
err_dialog->set_title(TTR("Error"));
+ draw_handles = false;
+
initialize_bottom_editor();
}
@@ -739,9 +747,23 @@ void TileSetEditor::_on_workspace_draw() {
}
}
}
+ workspace_overlay->update();
+}
+
+void TileSetEditor::_on_workspace_overlay_draw() {
+
+ int t_id = get_current_tile();
+ if (t_id < 0 || !draw_handles)
+ return;
+
+ Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
+
+ for (int i = 0; i < current_shape.size(); i++) {
+ workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5);
+ }
}
-#define MIN_DISTANCE_SQUARED 10
+#define MIN_DISTANCE_SQUARED 6
void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (get_current_tile() >= 0 && !tileset.is_null()) {
@@ -1162,15 +1184,18 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
scale /= 2;
workspace->set_scale(Vector2(scale, scale));
workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale);
}
} else if (p_tool == ZOOM_1) {
workspace->set_scale(Vector2(1, 1));
workspace_container->set_custom_minimum_size(preview->get_region_rect().size);
+ workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size);
} else if (p_tool == ZOOM_IN) {
float scale = workspace->get_scale().x;
scale *= 2;
workspace->set_scale(Vector2(scale, scale));
workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale);
+ workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale);
} else if (p_tool == TOOL_SELECT) {
if (creating_shape) {
//Cancel Creation
@@ -1292,6 +1317,8 @@ void TileSetEditor::draw_polygon_shapes() {
if (t_id < 0)
return;
+ draw_handles = false;
+
switch (edit_mode) {
case EDITMODE_COLLISION: {
Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id);
@@ -1339,9 +1366,7 @@ void TileSetEditor::draw_polygon_shapes() {
}
if (shape == edited_collision_shape) {
- for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0, 0.7f));
- }
+ draw_handles = true;
}
}
}
@@ -1367,9 +1392,7 @@ void TileSetEditor::draw_polygon_shapes() {
}
workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1], shape->get_polygon()[0], c_border, 1, true);
if (shape == edited_occlusion_shape) {
- for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
- }
+ draw_handles = true;
}
}
} else {
@@ -1412,9 +1435,7 @@ void TileSetEditor::draw_polygon_shapes() {
}
workspace->draw_line(shape->get_polygon()[shape->get_polygon().size() - 1] + anchor, shape->get_polygon()[0] + anchor, c_border, 1, true);
if (shape == edited_occlusion_shape) {
- for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
- }
+ draw_handles = true;
}
}
}
@@ -1445,9 +1466,7 @@ void TileSetEditor::draw_polygon_shapes() {
workspace->draw_line(vertices[shape->get_polygon(0)[j]], vertices[shape->get_polygon(0)[j + 1]], c_border, 1, true);
}
if (shape == edited_navigation_shape) {
- for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
- }
+ draw_handles = true;
}
}
}
@@ -1494,9 +1513,7 @@ void TileSetEditor::draw_polygon_shapes() {
workspace->draw_line(vertices[shape->get_polygon(0)[j]] + anchor, vertices[shape->get_polygon(0)[j + 1]] + anchor, c_border, 1, true);
}
if (shape == edited_navigation_shape) {
- for (int j = 0; j < current_shape.size(); j++) {
- workspace->draw_circle(current_shape[j], 8 / workspace->get_scale().x, Color(1, 0, 0));
- }
+ draw_handles = true;
}
}
}
@@ -1809,6 +1826,8 @@ bool TileSetEditorHelper::_get(const StringName &p_name, Variant &r_ret) const {
if (selected_tile < 0 || tileset.is_null())
return false;
+ if (!tileset->has_tile(selected_tile))
+ return false;
String name = p_name.operator String();
bool v = false;
@@ -1833,6 +1852,7 @@ void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const {
TileSetEditorHelper::TileSetEditorHelper(TileSetEditor *p_tileset_editor) {
tileset_editor = p_tileset_editor;
+ selected_tile = -1;
}
void TileSetEditorPlugin::edit(Object *p_node) {
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index f57ec9a117..4894d641a3 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -91,6 +91,8 @@ class TileSetEditor : public Control {
Sprite *preview;
ScrollContainer *scroll;
Control *workspace_container;
+ bool draw_handles;
+ Control *workspace_overlay;
Control *workspace;
Button *tool_editmode[EDITMODE_MAX];
HBoxContainer *tool_containers[TOOLBAR_MAX];
@@ -160,6 +162,7 @@ public:
private:
void _on_tile_list_selected(int p_index);
void _on_edit_mode_changed(int p_edit_mode);
+ void _on_workspace_overlay_draw();
void _on_workspace_draw();
void _on_workspace_input(const Ref<InputEvent> &p_ie);
void _on_tool_clicked(int p_tool);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index d15a37a19c..4dbd9d500e 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -56,6 +56,12 @@ void ProjectExportDialog::_notification(int p_what) {
case NOTIFICATION_POPUP_HIDE: {
EditorSettings::get_singleton()->set("interface/dialogs/export_bounds", get_rect());
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
+ Control *panel = custom_feature_display->get_parent_control();
+ if (panel)
+ panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ } break;
}
}
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 5f93e984cc..de98c89db5 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1517,18 +1517,43 @@ ProjectManager::ProjectManager() {
EditorSettings::get_singleton()->set_optimize_save(false); //just write settings as they came
{
- int dpi_mode = EditorSettings::get_singleton()->get("interface/editor/hidpi_mode");
- if (dpi_mode == 0) {
- const int screen = OS::get_singleton()->get_current_screen();
- editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
- } else if (dpi_mode == 1) {
- editor_set_scale(0.75);
- } else if (dpi_mode == 2) {
- editor_set_scale(1.0);
- } else if (dpi_mode == 3) {
- editor_set_scale(1.5);
- } else if (dpi_mode == 4) {
- editor_set_scale(2.0);
+ int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
+
+ switch (display_scale) {
+ case 0: {
+ // Try applying a suitable display scale automatically
+ const int screen = OS::get_singleton()->get_current_screen();
+ editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+ } break;
+
+ case 1: {
+ editor_set_scale(0.75);
+ } break;
+
+ case 2: {
+ editor_set_scale(1.0);
+ } break;
+
+ case 3: {
+ editor_set_scale(1.25);
+ } break;
+
+ case 4: {
+ editor_set_scale(1.5);
+ } break;
+
+ case 5: {
+ editor_set_scale(1.75);
+ } break;
+
+ case 6: {
+ editor_set_scale(2.0);
+ } break;
+
+ default: {
+ editor_set_scale(custom_display_scale);
+ } break;
}
}
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 9625bc19c0..75523cd843 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -110,11 +110,28 @@ void ProjectSettingsEditor::_notification(int p_what) {
EditorSettings::get_singleton()->set("interface/dialogs/project_settings_bounds", get_rect());
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+
+ search_button->set_icon(get_icon("Search", "EditorIcons"));
+ clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ action_add_error->add_color_override("font_color", get_color("error_color", "Editor"));
+ popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons"));
+ popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons"));
+ popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_MOTION), get_icon("JoyAxis", "EditorIcons"));
+ popup_add->set_item_icon(popup_add->get_item_index(INPUT_MOUSE_BUTTON), get_icon("Mouse", "EditorIcons"));
_update_actions();
} break;
}
}
+static bool _validate_action_name(const String &p_name) {
+ const CharType *cstr = p_name.c_str();
+ for (int i = 0; cstr[i]; i++)
+ if (cstr[i] == '/' || cstr[i] == ':' || cstr[i] == '"' ||
+ cstr[i] == '=' || cstr[i] == '\\' || cstr[i] < 32)
+ return false;
+ return true;
+}
+
void ProjectSettingsEditor::_action_selected() {
TreeItem *ti = input_editor->get_selected();
@@ -137,12 +154,12 @@ void ProjectSettingsEditor::_action_edited() {
if (new_name == old_name)
return;
- if (new_name.find("/") != -1 || new_name.find(":") != -1 || new_name == "") {
+ if (new_name == "" || !_validate_action_name(new_name)) {
ti->set_text(0, old_name);
add_at = "input/" + old_name;
- message->set_text(TTR("Invalid action (anything goes but '/' or ':')."));
+ message->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
message->popup_centered(Size2(300, 100) * EDSCALE);
return;
}
@@ -830,9 +847,9 @@ void ProjectSettingsEditor::_action_check(String p_action) {
action_add->set_disabled(true);
} else {
- if (p_action.find("/") != -1 || p_action.find(":") != -1) {
+ if (!_validate_action_name(p_action)) {
- action_add_error->set_text(TTR("Can't contain '/' or ':'"));
+ action_add_error->set_text(TTR("Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or '\"'"));
action_add_error->show();
action_add->set_disabled(true);
return;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 9f0f62592b..b13b238fd7 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -345,17 +345,30 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} break;
case TOOL_CLEAR_SCRIPT: {
- Node *selected = scene_tree->get_selected();
- if (!selected)
- break;
- Ref<Script> existing = selected->get_script();
- if (existing.is_valid()) {
- const RefPtr empty;
- selected->set_script(empty);
- _update_script_button();
+ List<Node *> selection = editor_selection->get_selected_node_list();
+
+ if (selection.empty())
+ return;
+
+ editor_data->get_undo_redo().create_action(TTR("Clear Script"));
+ editor_data->get_undo_redo().add_do_method(editor, "push_item", (Script *)NULL);
+
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
+
+ Ref<Script> existing = E->get()->get_script();
+ if (existing.is_valid()) {
+ const RefPtr empty;
+ editor_data->get_undo_redo().add_do_method(E->get(), "set_script", empty);
+ editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
+ }
}
+ editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+
+ editor_data->get_undo_redo().commit_action();
+
} break;
case TOOL_MOVE_UP:
case TOOL_MOVE_DOWN: {
@@ -903,9 +916,6 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
if (!r_rem_anims)
r_rem_anims = &rem_anims;
- if (!bool(EDITOR_DEF("editors/animation/autorename_animation_tracks", true)))
- return;
-
if (!p_base) {
p_base = edited_scene;
@@ -914,7 +924,54 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP
if (!p_base)
return;
- if (Object::cast_to<AnimationPlayer>(p_base)) {
+ // Renaming node paths used in script instances
+ if (p_base->get_script_instance()) {
+
+ ScriptInstance *si = p_base->get_script_instance();
+
+ if (si) {
+
+ List<PropertyInfo> properties;
+ si->get_property_list(&properties);
+
+ for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+
+ String propertyname = E->get().name;
+ Variant p = p_base->get(propertyname);
+ if (p.get_type() == Variant::NODE_PATH) {
+
+ // Goes through all paths to check if its matching
+ for (List<Pair<NodePath, NodePath> >::Element *E = p_renames->front(); E; E = E->next()) {
+
+ NodePath root_path = p_base->get_path();
+
+ NodePath rel_path_old = root_path.rel_path_to(E->get().first);
+
+ NodePath rel_path_new = E->get().second;
+
+ // if not empty, get new relative path
+ if (E->get().second != NodePath()) {
+ rel_path_new = root_path.rel_path_to(E->get().second);
+ }
+
+ // if old path detected, then it needs to be replaced with the new one
+ if (p == rel_path_old) {
+
+ editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new);
+ editor_data->get_undo_redo().add_undo_property(p_base, propertyname, rel_path_old);
+
+ p_base->set(propertyname, rel_path_new);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ bool autorename_animation_tracks = bool(EDITOR_DEF("editors/animation/autorename_animation_tracks", true));
+
+ if (autorename_animation_tracks && Object::cast_to<AnimationPlayer>(p_base)) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_base);
List<StringName> anims;
@@ -1145,7 +1202,30 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo().add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ String old_name = former_names[ni];
String new_name = new_parent->validate_child_name(node);
+
+ // name was modified, fix the path renames
+ if (old_name.casecmp_to(new_name) != 0) {
+
+ // Fix the to name to have the new name
+ NodePath old_new_name = path_renames[ni].second;
+ NodePath new_path;
+
+ Vector<StringName> unfixed_new_names = old_new_name.get_names();
+ Vector<StringName> fixed_new_names;
+
+ // Get last name and replace with fixed new name
+ for (int a = 0; a < (unfixed_new_names.size() - 1); a++) {
+ fixed_new_names.push_back(unfixed_new_names[a]);
+ }
+ fixed_new_names.push_back(new_name);
+
+ NodePath fixed_node_path = NodePath(fixed_new_names, true);
+
+ path_renames[ni].second = fixed_node_path;
+ }
+
editor_data->get_undo_redo().add_do_method(sed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, -1);
editor_data->get_undo_redo().add_undo_method(sed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)) + "/" + new_name), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
@@ -1208,12 +1288,26 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
void SceneTreeDock::_script_created(Ref<Script> p_script) {
- Node *selected = scene_tree->get_selected();
- if (!selected)
+ List<Node *> selected = editor_selection->get_selected_node_list();
+
+ if (selected.empty())
return;
- selected->set_script(p_script.get_ref_ptr());
- editor->push_item(p_script.operator->());
- _update_script_button();
+
+ editor_data->get_undo_redo().create_action(TTR("Attach Script"));
+ for (List<Node *>::Element *E = selected.front(); E; E = E->next()) {
+
+ Ref<Script> existing = E->get()->get_script();
+ editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script.get_ref_ptr());
+ editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
+ }
+
+ editor_data->get_undo_redo().add_do_method(editor, "push_item", p_script.operator->());
+ editor_data->get_undo_redo().add_undo_method(editor, "push_item", (Script *)NULL);
+
+ editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+
+ editor_data->get_undo_redo().commit_action();
}
void SceneTreeDock::_delete_confirm() {
@@ -1411,6 +1505,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) {
Node *n = p_node;
Node *newnode = p_by_node;
+ Node *default_oldnode = Object::cast_to<Node>(ClassDB::instance(n->get_class()));
List<PropertyInfo> pinfo;
n->get_property_list(&pinfo);
@@ -1419,8 +1514,11 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node) {
continue;
if (E->get().name == "__meta__")
continue;
- newnode->set(E->get().name, n->get(E->get().name));
+ if (default_oldnode->get(E->get().name) != n->get(E->get().name)) {
+ newnode->set(E->get().name, n->get(E->get().name));
+ }
}
+ memdelete(default_oldnode);
editor->push_item(NULL);
@@ -1665,8 +1763,12 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
ERR_FAIL_COND(!scr.is_valid());
Node *n = get_node(p_to);
if (n) {
- n->set_script(scr.get_ref_ptr());
- _update_script_button();
+ editor_data->get_undo_redo().create_action(TTR("Attach Script"));
+ editor_data->get_undo_redo().add_do_method(n, "set_script", scr);
+ editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script());
+ editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo().commit_action();
}
}
@@ -1759,6 +1861,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
subresources.clear();
menu_subresources->clear();
+ menu_subresources->set_size(Size2(1, 1));
_add_children_to_popup(selection.front()->get(), 0);
if (menu->get_item_count() > 0)
menu->add_separator();
@@ -1803,6 +1906,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder);
}
}
+ } else {
+ menu->add_separator();
+ menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
}
menu->add_separator();
menu->add_icon_shortcut(get_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE);
@@ -1921,6 +2028,7 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_focus_node"), &SceneTreeDock::_focus_node);
ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected);
ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected);
+ ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button);
ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 8f3113c816..e38347a653 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -550,6 +550,10 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->disconnect("node_configuration_warning_changed", this, "_warning_changed");
EditorSettings::get_singleton()->disconnect("settings_changed", this, "_editor_settings_changed");
}
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+
+ _update_tree();
+ }
}
TreeItem *SceneTreeEditor::_find(TreeItem *p_node, const NodePath &p_path) {
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index b893b098ac..57a003060e 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -41,10 +41,12 @@
void ScriptCreateDialog::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
path_button->set_icon(get_icon("Folder", "EditorIcons"));
parent_browse_button->set_icon(get_icon("Folder", "EditorIcons"));
- }
+ status_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
+ } break;
}
}
@@ -434,6 +436,13 @@ void ScriptCreateDialog::_path_changed(const String &p_path) {
return;
}
+ String path_error = ScriptServer::get_language(language_menu->get_selected())->validate_path(p);
+ if (path_error != "") {
+ _msg_path_valid(false, path_error);
+ _update_dialog();
+ return;
+ }
+
/* All checks passed */
is_path_valid = true;
@@ -609,10 +618,10 @@ ScriptCreateDialog::ScriptCreateDialog() {
hb->add_child(path_error_label);
vb->add_child(hb);
- PanelContainer *pc = memnew(PanelContainer);
- pc->set_h_size_flags(Control::SIZE_FILL);
- pc->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("bg", "Tree"));
- pc->add_child(vb);
+ status_panel = memnew(PanelContainer);
+ status_panel->set_h_size_flags(Control::SIZE_FILL);
+ status_panel->add_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_stylebox("bg", "Tree"));
+ status_panel->add_child(vb);
/* Margins */
@@ -631,7 +640,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
vb->add_child(empty_h->duplicate());
vb->add_child(gc);
vb->add_child(empty_h->duplicate());
- vb->add_child(pc);
+ vb->add_child(status_panel);
vb->add_child(empty_h->duplicate());
hb = memnew(HBoxContainer);
hb->add_child(empty_v->duplicate());
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index 99e5bc9e6a..1ad4a1b7a1 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -46,6 +46,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
LineEdit *class_name;
Label *error_label;
Label *path_error_label;
+ PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
OptionButton *language_menu;
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 7fa3ed34f0..e9529eb1c0 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -1160,6 +1160,16 @@ void ScriptEditorDebugger::_notification(int p_what) {
inspect_scene_tree->add_color_override("relationship_line_color", rl_color);
} else
inspect_scene_tree->add_constant_override("draw_relationship_lines", 0);
+
+ copy->set_icon(get_icon("ActionCopy", "EditorIcons"));
+ step->set_icon(get_icon("DebugStep", "EditorIcons"));
+ next->set_icon(get_icon("DebugNext", "EditorIcons"));
+ back->set_icon(get_icon("Back", "EditorIcons"));
+ forward->set_icon(get_icon("Forward", "EditorIcons"));
+ dobreak->set_icon(get_icon("Pause", "EditorIcons"));
+ docontinue->set_icon(get_icon("DebugContinue", "EditorIcons"));
+ vmem_refresh->set_icon(get_icon("Reload", "EditorIcons"));
+
} break;
}
}
diff --git a/editor/translations/extract.py b/editor/translations/extract.py
index bbc157788d..4b3f416343 100755
--- a/editor/translations/extract.py
+++ b/editor/translations/extract.py
@@ -52,11 +52,7 @@ msgstr ""
"Content-Transfer-Encoding: 8-bit\\n"
"""
-print("Updating the editor.pot template...")
-
-for fname in matches:
-
- f = open(fname, "rb")
+def process_file(f, fname):
l = f.readline()
lc = 1
@@ -100,12 +96,14 @@ for fname in matches:
l = f.readline()
lc += 1
- f.close()
+print("Updating the editor.pot template...")
+for fname in matches:
+ with open(fname, "rb") as f:
+ process_file(f, fname)
-f = open("editor.pot", "wb")
-f.write(main_po)
-f.close()
+with open("editor.pot", "wb") as f:
+ f.write(main_po)
if (os.name == "posix"):
print("Wrapping template at 79 characters for compatibility with Weblate.")