diff options
Diffstat (limited to 'editor')
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 = ¶ms[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.") |