diff options
Diffstat (limited to 'editor')
42 files changed, 816 insertions, 300 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 87ac16fdcf..97ba5d7a5f 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -302,7 +302,7 @@ void FindReplaceBar::_replace_all() { matches_label->add_theme_color_override("font_color", rc > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor")); matches_label->set_text(vformat(TTR("%d replaced."), rc)); - text_editor->call_deferred("connect", "text_changed", Callable(this, "_editor_text_changed")); + text_editor->call_deferred("connect", "text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed)); results_count = -1; } diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 466ca70130..4317760379 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -173,6 +173,9 @@ void EditorAudioBus::_notification(int p_what) { bypass->set_icon(get_theme_icon("AudioBusBypass", "EditorIcons")); bus_options->set_icon(get_theme_icon("GuiTabMenuHl", "EditorIcons")); + + audio_value_preview_box->add_theme_color_override("font_color", get_theme_color("font_color", "TooltipLabel")); + audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel")); } break; case NOTIFICATION_MOUSE_EXIT: case NOTIFICATION_DRAG_END: { @@ -379,15 +382,24 @@ void EditorAudioBus::_show_value(float slider_value) { db = _normalized_volume_to_scaled_db(slider_value); } - String text = vformat("%10.1f dB", db); + String text; + if (Math::is_zero_approx(Math::snapped(db, 0.1))) { + // Prevent displaying `-0.0 dB` and show ` 0.0 dB` instead. + // The leading space makes the text visually line up with its positive/negative counterparts. + text = " 0.0 dB"; + } else { + // Show an explicit `+` sign if positive. + text = vformat("%+.1f dB", db); + } + // Also set the preview text as a standard Control tooltip. + // This way, it can be seen when the slider is merely hovered (instead of dragged). slider->set_tooltip(text); audio_value_preview_label->set_text(text); - Vector2 slider_size = slider->get_size(); - Vector2 slider_position = slider->get_global_position(); - float left_padding = 5.0f; - float vert_padding = 10.0f; - Vector2 box_position = Vector2(slider_size.x + left_padding, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding); + const Vector2 slider_size = slider->get_size(); + const Vector2 slider_position = slider->get_global_position(); + const float vert_padding = 10.0f; + const Vector2 box_position = Vector2(slider_size.x, (slider_size.y - vert_padding) * (1.0f - slider->get_value()) - vert_padding); audio_value_preview_box->set_position(slider_position + box_position); audio_value_preview_box->set_size(audio_value_preview_label->get_size()); if (slider->has_focus() && !audio_value_preview_box->is_visible()) { @@ -830,14 +842,13 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { audio_value_preview_label->set_v_size_flags(SIZE_EXPAND_FILL); audio_value_preview_label->set_h_size_flags(SIZE_EXPAND_FILL); audio_value_preview_label->set_mouse_filter(MOUSE_FILTER_PASS); + audio_value_preview_box->add_theme_color_override("font_color", get_theme_color("font_color", "TooltipLabel")); audioprev_hbc->add_child(audio_value_preview_label); slider->add_child(audio_value_preview_box); audio_value_preview_box->set_as_top_level(true); - Ref<StyleBoxFlat> panel_style = memnew(StyleBoxFlat); - panel_style->set_bg_color(Color(0.0f, 0.0f, 0.0f, 0.8f)); - audio_value_preview_box->add_theme_style_override("panel", panel_style); + audio_value_preview_box->add_theme_style_override("panel", get_theme_stylebox("panel", "TooltipPanel")); audio_value_preview_box->set_mouse_filter(MOUSE_FILTER_PASS); audio_value_preview_box->hide(); @@ -925,7 +936,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { bus_options->set_shortcut_context(this); bus_options->set_h_size_flags(SIZE_SHRINK_END); bus_options->set_anchor(SIDE_RIGHT, 0.0); - bus_options->set_tooltip(TTR("Bus options")); + bus_options->set_tooltip(TTR("Bus Options")); hbc->add_child(bus_options); bus_popup = bus_options->get_popup(); @@ -1400,7 +1411,7 @@ void EditorAudioMeterNotches::_bind_methods() { void EditorAudioMeterNotches::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0); + notch_color = get_theme_color("font_color", "Editor"); } break; case NOTIFICATION_DRAW: { _draw_audio_notches(); @@ -1416,13 +1427,13 @@ void EditorAudioMeterNotches::_draw_audio_notches() { for (int i = 0; i < notches.size(); i++) { AudioNotch n = notches[i]; draw_line(Vector2(0, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), - Vector2(line_length, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), + Vector2(line_length * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + top_padding), notch_color, - 1); + Math::round(EDSCALE)); if (n.render_db_value) { draw_string(font, - Vector2(line_length + label_space, + Vector2((line_length + label_space) * EDSCALE, (1.0f - n.relative_position) * (get_size().y - btm_padding - top_padding) + (font_height / 4) + top_padding), String::num(Math::abs(n.db_value)) + "dB", HALIGN_LEFT, -1, font_size, @@ -1432,5 +1443,5 @@ void EditorAudioMeterNotches::_draw_audio_notches() { } EditorAudioMeterNotches::EditorAudioMeterNotches() { - notch_color = EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(0, 0, 0); + notch_color = get_theme_color("font_color", "Editor"); } diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h index 8dfc2137ef..0fbda8ece9 100644 --- a/editor/editor_audio_buses.h +++ b/editor/editor_audio_buses.h @@ -243,10 +243,10 @@ private: List<AudioNotch> notches; public: - float line_length = 5.0f; - float label_space = 2.0f; - float btm_padding = 9.0f; - float top_padding = 5.0f; + const float line_length = 5.0f; + const float label_space = 2.0f; + const float btm_padding = 9.0f; + const float top_padding = 5.0f; Color notch_color; void add_notch(float p_normalized_offset, float p_db_value, bool p_render_value = false); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index b3755bef80..40313fbeff 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -1065,7 +1065,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } } else { // Use default text server data. - String icu_data_file = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_icu_data"); + String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data"); TS->save_support_data(icu_data_file); Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); @@ -1078,7 +1078,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String config_file = "project.binary"; - String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); + String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); @@ -1100,9 +1100,9 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c // Create the temporary export directory if it doesn't exist. DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - da->make_dir_recursive(EditorSettings::get_singleton()->get_cache_dir()); + da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir()); - String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp"); + String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp"); FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE); ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'."); @@ -1984,7 +1984,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con if (!convert) { return; } - String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpfile.res"); + String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res"); Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path); if (err != OK) { DirAccess::remove_file_or_error(tmp_path); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index bd00d86ec8..d232153206 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -46,6 +46,16 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = { TTRC("Import Dock"), }; +const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = { + TTRC("Allows to view and edit 3D scenes."), + TTRC("Allows to edit scripts using the integrated script editor."), + TTRC("Provides built-in access to the Asset Library."), + TTRC("Allows editing the node hierarchy in the Scene dock."), + TTRC("Allows to work with signals and groups of the node selected in the Scene dock."), + TTRC("Allows to browse the local file system via a dedicated dock."), + TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."), +}; + const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = { "3d", "script", @@ -118,6 +128,18 @@ bool EditorFeatureProfile::has_class_properties_disabled(const StringName &p_cla return disabled_properties.has(p_class); } +void EditorFeatureProfile::set_item_collapsed(const StringName &p_class, bool p_collapsed) { + if (p_collapsed) { + collapsed_classes.insert(p_class); + } else { + collapsed_classes.erase(p_class); + } +} + +bool EditorFeatureProfile::is_item_collapsed(const StringName &p_class) const { + return collapsed_classes.has(p_class); +} + void EditorFeatureProfile::set_disable_feature(Feature p_feature, bool p_disable) { ERR_FAIL_INDEX(p_feature, FEATURE_MAX); features_disabled[p_feature] = p_disable; @@ -133,6 +155,11 @@ String EditorFeatureProfile::get_feature_name(Feature p_feature) { return feature_names[p_feature]; } +String EditorFeatureProfile::get_feature_description(Feature p_feature) { + ERR_FAIL_INDEX_V(p_feature, FEATURE_MAX, String()); + return feature_descriptions[p_feature]; +} + Error EditorFeatureProfile::save_to_file(const String &p_path) { Dictionary json; json["type"] = "feature_profile"; @@ -406,7 +433,7 @@ void EditorFeatureProfileManager::_profile_action(int p_action) { export_profile->set_current_file(_get_selected_profile() + ".profile"); } break; case PROFILE_NEW: { - new_profile_dialog->popup_centered(); + new_profile_dialog->popup_centered(Size2(240, 60) * EDSCALE); new_profile_name->clear(); new_profile_name->grab_focus(); } break; @@ -414,8 +441,8 @@ void EditorFeatureProfileManager::_profile_action(int p_action) { String selected = _get_selected_profile(); ERR_FAIL_COND(selected == String()); - erase_profile_dialog->set_text(vformat(TTR("Erase profile '%s'? (no undo)"), selected)); - erase_profile_dialog->popup_centered(); + erase_profile_dialog->set_text(vformat(TTR("Remove currently selected profile, '%s'? Cannot be undone."), selected)); + erase_profile_dialog->popup_centered(Size2(240, 60) * EDSCALE); } break; } } @@ -484,6 +511,9 @@ void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const S class_item->set_selectable(0, true); class_item->set_metadata(0, p_class); + bool collapsed = edited->is_item_collapsed(p_class); + class_item->set_collapsed(collapsed); + if (p_class == p_selected) { class_item->select(0); } @@ -520,12 +550,28 @@ void EditorFeatureProfileManager::_class_list_item_selected() { } Variant md = item->get_metadata(0); - if (md.get_type() != Variant::STRING && md.get_type() != Variant::STRING_NAME) { + if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) { + String class_name = md; + String class_description; + + DocTools *dd = EditorHelp::get_doc_data(); + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_name); + if (E) { + class_description = DTR(E->get().brief_description); + } + + description_bit->set_text(class_description); + } else if (md.get_type() == Variant::INT) { + int feature_id = md; + String feature_description = EditorFeatureProfile::get_feature_description(EditorFeatureProfile::Feature(feature_id)); + + description_bit->set_text(feature_description); + return; + } else { return; } String class_name = md; - if (edited->is_class_disabled(class_name)) { return; } @@ -545,27 +591,28 @@ void EditorFeatureProfileManager::_class_list_item_selected() { option->set_metadata(0, CLASS_OPTION_DISABLE_EDITOR); } - TreeItem *properties = property_list->create_item(root); - properties->set_text(0, TTR("Enabled Properties:")); - List<PropertyInfo> props; - ClassDB::get_property_list(class_name, &props, true); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String name = E->get().name; - if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) { - continue; + if (props.size() > 0) { + TreeItem *properties = property_list->create_item(root); + properties->set_text(0, TTR("Class Properties:")); + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + String name = E->get().name; + if (!(E->get().usage & PROPERTY_USAGE_EDITOR)) { + continue; + } + TreeItem *property = property_list->create_item(properties); + property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); + property->set_editable(0, true); + property->set_selectable(0, true); + property->set_checked(0, !edited->is_class_property_disabled(class_name, name)); + property->set_text(0, name.capitalize()); + property->set_metadata(0, name); + String icon_type = Variant::get_type_name(E->get().type); + property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type)); } - TreeItem *property = property_list->create_item(properties); - property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - property->set_editable(0, true); - property->set_selectable(0, true); - property->set_checked(0, !edited->is_class_property_disabled(class_name, name)); - property->set_text(0, name.capitalize()); - property->set_metadata(0, name); - String icon_type = Variant::get_type_name(E->get().type); - property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type)); } updating_features = false; @@ -596,6 +643,26 @@ void EditorFeatureProfileManager::_class_list_item_edited() { } } +void EditorFeatureProfileManager::_class_list_item_collapsed(Object *p_item) { + if (updating_features) { + return; + } + + TreeItem *item = Object::cast_to<TreeItem>(p_item); + if (!item) { + return; + } + + Variant md = item->get_metadata(0); + if (md.get_type() != Variant::STRING && md.get_type() != Variant::STRING_NAME) { + return; + } + + String class_name = md; + bool collapsed = item->is_collapsed(); + edited->set_item_collapsed(class_name, collapsed); +} + void EditorFeatureProfileManager::_property_item_edited() { if (updating_features) { return; @@ -675,7 +742,7 @@ void EditorFeatureProfileManager::_update_selected_profile() { TreeItem *features = class_list->create_item(root); TreeItem *last_feature; - features->set_text(0, TTR("Enabled Features:")); + features->set_text(0, TTR("Main Features") + ":"); for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) { TreeItem *feature; if (i == EditorFeatureProfile::FEATURE_IMPORT_DOCK) { @@ -699,7 +766,7 @@ void EditorFeatureProfileManager::_update_selected_profile() { } TreeItem *classes = class_list->create_item(root); - classes->set_text(0, TTR("Enabled Classes:")); + classes->set_text(0, TTR("Nodes and Classes") + ":"); _fill_classes_from(classes, "Node", class_selected); _fill_classes_from(classes, "Resource", class_selected); @@ -797,47 +864,51 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { current_profile_name->set_text(TTR("(none)")); current_profile_name->set_editable(false); current_profile_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); - profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Unset"))); + profile_actions[PROFILE_CLEAR] = memnew(Button(TTR("Reset to Default"))); name_hbc->add_child(profile_actions[PROFILE_CLEAR]); profile_actions[PROFILE_CLEAR]->set_disabled(true); profile_actions[PROFILE_CLEAR]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_CLEAR)); main_vbc->add_margin_child(TTR("Current Profile:"), name_hbc); + main_vbc->add_child(memnew(HSeparator)); + HBoxContainer *profiles_hbc = memnew(HBoxContainer); profile_list = memnew(OptionButton); profile_list->set_h_size_flags(Control::SIZE_EXPAND_FILL); profiles_hbc->add_child(profile_list); profile_list->connect("item_selected", callable_mp(this, &EditorFeatureProfileManager::_profile_selected)); - profile_actions[PROFILE_SET] = memnew(Button(TTR("Make Current"))); - profiles_hbc->add_child(profile_actions[PROFILE_SET]); - profile_actions[PROFILE_SET]->set_disabled(true); - profile_actions[PROFILE_SET]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_SET)); + profile_actions[PROFILE_NEW] = memnew(Button(TTR("Create Profile"))); + profiles_hbc->add_child(profile_actions[PROFILE_NEW]); + profile_actions[PROFILE_NEW]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_NEW)); - profile_actions[PROFILE_ERASE] = memnew(Button(TTR("Remove"))); + profile_actions[PROFILE_ERASE] = memnew(Button(TTR("Remove Profile"))); profiles_hbc->add_child(profile_actions[PROFILE_ERASE]); profile_actions[PROFILE_ERASE]->set_disabled(true); profile_actions[PROFILE_ERASE]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_ERASE)); - profiles_hbc->add_child(memnew(VSeparator)); + main_vbc->add_margin_child(TTR("Available Profiles:"), profiles_hbc); - profile_actions[PROFILE_NEW] = memnew(Button(TTR("New"))); - profiles_hbc->add_child(profile_actions[PROFILE_NEW]); - profile_actions[PROFILE_NEW]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_NEW)); + HBoxContainer *current_profile_hbc = memnew(HBoxContainer); - profiles_hbc->add_child(memnew(VSeparator)); + profile_actions[PROFILE_SET] = memnew(Button(TTR("Make Current"))); + current_profile_hbc->add_child(profile_actions[PROFILE_SET]); + profile_actions[PROFILE_SET]->set_disabled(true); + profile_actions[PROFILE_SET]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_SET)); + + current_profile_hbc->add_child(memnew(VSeparator)); profile_actions[PROFILE_IMPORT] = memnew(Button(TTR("Import"))); - profiles_hbc->add_child(profile_actions[PROFILE_IMPORT]); + current_profile_hbc->add_child(profile_actions[PROFILE_IMPORT]); profile_actions[PROFILE_IMPORT]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_IMPORT)); profile_actions[PROFILE_EXPORT] = memnew(Button(TTR("Export"))); - profiles_hbc->add_child(profile_actions[PROFILE_EXPORT]); + current_profile_hbc->add_child(profile_actions[PROFILE_EXPORT]); profile_actions[PROFILE_EXPORT]->set_disabled(true); profile_actions[PROFILE_EXPORT]->connect("pressed", callable_mp(this, &EditorFeatureProfileManager::_profile_action), varray(PROFILE_EXPORT)); - main_vbc->add_margin_child(TTR("Available Profiles:"), profiles_hbc); + main_vbc->add_child(current_profile_hbc); h_split = memnew(HSplitContainer); h_split->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -848,11 +919,12 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { class_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); class_list = memnew(Tree); - class_list_vbc->add_margin_child(TTR("Enabled Classes:"), class_list, true); + class_list_vbc->add_margin_child(TTR("Configure Selected Profile") + ":", class_list, true); class_list->set_hide_root(true); class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); class_list->connect("cell_selected", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_selected)); class_list->connect("item_edited", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_edited), varray(), CONNECT_DEFERRED); + class_list->connect("item_collapsed", callable_mp(this, &EditorFeatureProfileManager::_class_list_item_collapsed)); // It will be displayed once the user creates or chooses a profile. class_list_vbc->hide(); @@ -860,8 +932,12 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { h_split->add_child(property_list_vbc); property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + description_bit = memnew(EditorHelpBit); + property_list_vbc->add_margin_child(TTR("Description") + ":", description_bit, false); + description_bit->set_custom_minimum_size(Size2(0, 80) * EDSCALE); + property_list = memnew(Tree); - property_list_vbc->add_margin_child(TTR("Class Options:"), property_list, true); + property_list_vbc->add_margin_child(TTR("Extra Options") + ":", property_list, true); property_list->set_hide_root(true); property_list->set_hide_folding(true); property_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); @@ -879,9 +955,14 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { h_split->add_child(no_profile_selected_help); new_profile_dialog = memnew(ConfirmationDialog); - new_profile_dialog->set_title(TTR("New profile name:")); + new_profile_dialog->set_title(TTR("Create Profile")); + VBoxContainer *new_profile_vb = memnew(VBoxContainer); + new_profile_dialog->add_child(new_profile_vb); + Label *new_profile_label = memnew(Label); + new_profile_label->set_text(TTR("New profile name") + ":"); + new_profile_vb->add_child(new_profile_label); new_profile_name = memnew(LineEdit); - new_profile_dialog->add_child(new_profile_name); + new_profile_vb->add_child(new_profile_name); new_profile_name->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); add_child(new_profile_dialog); new_profile_dialog->connect("confirmed", callable_mp(this, &EditorFeatureProfileManager::_create_new_profile)); @@ -890,7 +971,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { erase_profile_dialog = memnew(ConfirmationDialog); add_child(erase_profile_dialog); - erase_profile_dialog->set_title(TTR("Erase Profile")); + erase_profile_dialog->set_title(TTR("Remove Profile")); erase_profile_dialog->connect("confirmed", callable_mp(this, &EditorFeatureProfileManager::_erase_selected_profile)); import_profiles = memnew(EditorFileDialog); diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h index 01e6a6a142..e118b5f287 100644 --- a/editor/editor_feature_profile.h +++ b/editor/editor_feature_profile.h @@ -34,6 +34,7 @@ #include "core/object/reference.h" #include "core/os/file_access.h" #include "editor/editor_file_dialog.h" +#include "editor_help.h" #include "scene/gui/dialogs.h" #include "scene/gui/option_button.h" #include "scene/gui/separator.h" @@ -60,8 +61,11 @@ private: Set<StringName> disabled_editors; Map<StringName, Set<StringName>> disabled_properties; + Set<StringName> collapsed_classes; + bool features_disabled[FEATURE_MAX]; static const char *feature_names[FEATURE_MAX]; + static const char *feature_descriptions[FEATURE_MAX]; static const char *feature_identifiers[FEATURE_MAX]; String _get_feature_name(Feature p_feature) { return get_feature_name(p_feature); } @@ -80,6 +84,9 @@ public: bool is_class_property_disabled(const StringName &p_class, const StringName &p_property) const; bool has_class_properties_disabled(const StringName &p_class) const; + void set_item_collapsed(const StringName &p_class, bool p_collapsed); + bool is_item_collapsed(const StringName &p_class) const; + void set_disable_feature(Feature p_feature, bool p_disable); bool is_feature_disabled(Feature p_feature) const; @@ -87,6 +94,7 @@ public: Error load_from_file(const String &p_path); static String get_feature_name(Feature p_feature); + static String get_feature_description(Feature p_feature); EditorFeatureProfile(); }; @@ -124,6 +132,7 @@ class EditorFeatureProfileManager : public AcceptDialog { Tree *class_list; VBoxContainer *property_list_vbc; Tree *property_list; + EditorHelpBit *description_bit; Label *no_profile_selected_help; EditorFileDialog *import_profiles; @@ -151,6 +160,7 @@ class EditorFeatureProfileManager : public AcceptDialog { void _class_list_item_selected(); void _class_list_item_edited(); + void _class_list_item_collapsed(Object *p_item); void _property_item_edited(); void _save_and_update(); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 0616ab07bd..f869031446 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1626,7 +1626,7 @@ void EditorInspector::update_tree() { bool draw_red = false; - { + if (is_inside_tree()) { Node *nod = Object::cast_to<Node>(object); Node *es = EditorNode::get_singleton()->get_edited_scene(); if (nod && es != nod && nod->get_owner() != es) { diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 622b3fe355..35d8021394 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -234,10 +234,9 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { if (p_replace_previous) { // Remove last line if replacing, as it will be replace by the next added line. - // Why - 2? RichTextLabel is weird. When you add a line, it also adds a NEW line, which is null, + // Why "- 2"? RichTextLabel is weird. When you add a line with add_newline(), it also adds an element to the list of lines which is null/blank, // but it still counts as a line. So if you remove the last line (count - 1) you are actually removing nothing... - log->remove_line(log->get_line_count() - 2); - log->increment_line_count(); + log->remove_line(log->get_paragraph_count() - 2); } switch (p_message.type) { @@ -271,13 +270,14 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { } log->add_text(p_message.text); - log->add_newline(); // Need to use pop() to exit out of the RichTextLabels current "push" stack. // We only "push" in the above switch when message type != STD, so only pop when that is the case. if (p_message.type != MSG_TYPE_STD) { log->pop(); } + + log->add_newline(); } void EditorLog::_set_filter_active(bool p_active, MessageType p_message_type) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 72963012d6..aa632b90ad 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -80,6 +80,7 @@ #include "editor/editor_inspector.h" #include "editor/editor_layouts_dialog.h" #include "editor/editor_log.h" +#include "editor/editor_paths.h" #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/editor_resource_picker.h" @@ -1457,7 +1458,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { img->convert(Image::FORMAT_RGB8); //save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5 - String temp_path = EditorSettings::get_singleton()->get_cache_dir(); + String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); @@ -2745,10 +2746,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { settings_config_dialog->popup_edit_settings(); } break; case SETTINGS_EDITOR_DATA_FOLDER: { - OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_data_dir()); + OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_data_dir()); } break; case SETTINGS_EDITOR_CONFIG_FOLDER: { - OS::get_singleton()->shell_open(String("file://") + EditorSettings::get_singleton()->get_settings_dir()); + OS::get_singleton()->shell_open(String("file://") + EditorPaths::get_singleton()->get_settings_dir()); } break; case SETTINGS_MANAGE_EXPORT_TEMPLATES: { export_template_manager->popup_manager(); @@ -2892,7 +2893,7 @@ void EditorNode::_exit_editor() { _save_docks(); // Dim the editor window while it's quitting to make it clearer that it's busy - dim_editor(true, true); + dim_editor(true); get_tree()->quit(); } @@ -3727,10 +3728,15 @@ bool EditorNode::is_scene_in_use(const String &p_path) { return false; } +void EditorNode::register_editor_paths(bool p_for_project_manager) { + EditorPaths::create(p_for_project_manager); +} + void EditorNode::register_editor_types() { ResourceLoader::set_timestamp_on_load(true); ResourceSaver::set_timestamp_on_save(true); + ClassDB::register_class<EditorPaths>(); ClassDB::register_class<EditorPlugin>(); ClassDB::register_class<EditorTranslationParserPlugin>(); ClassDB::register_class<EditorImportPlugin>(); @@ -3774,6 +3780,9 @@ void EditorNode::register_editor_types() { void EditorNode::unregister_editor_types() { _init_callbacks.clear(); + if (EditorPaths::get_singleton()) { + EditorPaths::free(); + } } void EditorNode::stop_child_process(OS::ProcessID p_pid) { @@ -5396,15 +5405,9 @@ void EditorNode::_open_imported() { load_scene(open_import_request, true, false, true, true); } -void EditorNode::dim_editor(bool p_dimming, bool p_force_dim) { - // Dimming can be forced regardless of the editor setting, which is useful when quitting the editor. - if ((p_force_dim || EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup")) && p_dimming) { - dimmed = true; - gui_base->set_modulate(Color(0.5, 0.5, 0.5)); - } else { - dimmed = false; - gui_base->set_modulate(Color(1, 1, 1)); - } +void EditorNode::dim_editor(bool p_dimming) { + dimmed = p_dimming; + gui_base->set_modulate(p_dimming ? Color(0.5, 0.5, 0.5) : Color(1, 1, 1)); } bool EditorNode::is_editor_dimmed() const { diff --git a/editor/editor_node.h b/editor/editor_node.h index 9824702d7b..9625b318e0 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -798,6 +798,7 @@ public: Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only); + static void register_editor_paths(bool p_for_project_manager); static void register_editor_types(); static void unregister_editor_types(); @@ -855,7 +856,7 @@ public: void notify_settings_changed(); - void dim_editor(bool p_dimming, bool p_force_dim = false); + void dim_editor(bool p_dimming); bool is_editor_dimmed() const; void edit_current() { _edit_current(); }; diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp new file mode 100644 index 0000000000..96469d3143 --- /dev/null +++ b/editor/editor_paths.cpp @@ -0,0 +1,156 @@ +/*************************************************************************/ +/* editor_paths.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_paths.h" +#include "core/os/dir_access.h" +#include "core/os/os.h" + +EditorPaths *EditorPaths::singleton = nullptr; + +bool EditorPaths::are_paths_valid() const { + return paths_valid; +} + +String EditorPaths::get_settings_dir() const { + return settings_dir; +} +String EditorPaths::get_data_dir() const { + return data_dir; +} +String EditorPaths::get_config_dir() const { + return config_dir; +} +String EditorPaths::get_cache_dir() const { + return cache_dir; +} +bool EditorPaths::is_self_contained() const { + return self_contained; +} +String EditorPaths::get_self_contained_file() const { + return self_contained_file; +} + +void EditorPaths::create(bool p_for_project_manager) { + ERR_FAIL_COND(singleton != nullptr); + memnew(EditorPaths(p_for_project_manager)); +} +void EditorPaths::free() { + ERR_FAIL_COND(singleton == nullptr); + memdelete(singleton); +} + +void EditorPaths::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorPaths::get_settings_dir); + ClassDB::bind_method(D_METHOD("get_data_dir"), &EditorPaths::get_data_dir); + ClassDB::bind_method(D_METHOD("get_config_dir"), &EditorPaths::get_config_dir); + ClassDB::bind_method(D_METHOD("get_cache_dir"), &EditorPaths::get_cache_dir); + ClassDB::bind_method(D_METHOD("is_self_contained"), &EditorPaths::is_self_contained); + ClassDB::bind_method(D_METHOD("get_self_contained_file"), &EditorPaths::get_self_contained_file); +} + +EditorPaths::EditorPaths(bool p_for_project_mamanger) { + singleton = this; + + String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); + { + DirAccessRef d = DirAccess::create_for_path(exe_path); + + if (d->file_exists(exe_path + "/._sc_")) { + self_contained = true; + self_contained_file = exe_path + "/._sc_"; + } else if (d->file_exists(exe_path + "/_sc_")) { + self_contained = true; + self_contained_file = exe_path + "/_sc_"; + } + } + + String data_path; + String config_path; + String cache_path; + + if (self_contained) { + // editor is self contained, all in same folder + data_path = exe_path; + data_dir = data_path.plus_file("editor_data"); + config_path = exe_path; + config_dir = data_dir; + cache_path = exe_path; + cache_dir = data_dir.plus_file("cache"); + } else { + // Typically XDG_DATA_HOME or %APPDATA% + data_path = OS::get_singleton()->get_data_path(); + data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from data_path e.g. on Linux or macOS + config_path = OS::get_singleton()->get_config_path(); + config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + // Can be different from above paths, otherwise a subfolder of data_dir + cache_path = OS::get_singleton()->get_cache_path(); + if (cache_path == data_path) { + cache_dir = data_dir.plus_file("cache"); + } else { + cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name()); + } + } + + paths_valid = (data_path != "" && config_path != "" && cache_path != ""); + + if (paths_valid) { + DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (dir->change_dir(data_dir) != OK) { + dir->make_dir_recursive(data_dir); + if (dir->change_dir(data_dir) != OK) { + ERR_PRINT("Cannot create data directory!"); + paths_valid = false; + } + } + + // Validate/create cache dir + + if (dir->change_dir(EditorPaths::get_singleton()->get_cache_dir()) != OK) { + dir->make_dir_recursive(cache_dir); + if (dir->change_dir(cache_dir) != OK) { + ERR_PRINT("Cannot create cache directory!"); + } + } + + if (p_for_project_mamanger) { + Engine::get_singleton()->set_shader_cache_path(get_data_dir()); + } else { + DirAccessRef dir2 = DirAccess::open("res://"); + if (dir2->change_dir(".godot") != OK) { //ensure the .godot subdir exists + if (dir2->make_dir(".godot") != OK) { + ERR_PRINT("Cannot create res://.godot directory!"); + } + } + + Engine::get_singleton()->set_shader_cache_path("res://.godot"); + } + } +} diff --git a/editor/editor_paths.h b/editor/editor_paths.h new file mode 100644 index 0000000000..096174943d --- /dev/null +++ b/editor/editor_paths.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* editor_paths.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITORPATHS_H +#define EDITORPATHS_H + +#include "core/config/engine.h" + +class EditorPaths : public Object { + GDCLASS(EditorPaths, Object) + + bool paths_valid = false; + String settings_dir; + String data_dir; //editor data dir + String config_dir; //editor config dir + String cache_dir; //editor cache dir + bool self_contained = false; //true if running self contained + String self_contained_file; //self contained file with configuration + + static EditorPaths *singleton; + +protected: + static void _bind_methods(); + +public: + bool are_paths_valid() const; + + String get_settings_dir() const; + String get_data_dir() const; + String get_config_dir() const; + String get_cache_dir() const; + bool is_self_contained() const; + String get_self_contained_file() const; + + static EditorPaths *get_singleton() { + return singleton; + } + + static void create(bool p_for_project_manager); + static void free(); + + EditorPaths(bool p_for_project_mamanger = false); +}; + +#endif // EDITORPATHS_H diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 6b96cb0f5c..c5097a17a5 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_export.h" #include "editor/editor_node.h" +#include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "editor/filesystem_dock.h" #include "editor/project_settings_editor.h" @@ -257,6 +258,9 @@ EditorSelection *EditorInterface::get_selection() { Ref<EditorSettings> EditorInterface::get_editor_settings() { return EditorSettings::get_singleton(); } +EditorPaths *EditorInterface::get_editor_paths() { + return EditorPaths::get_singleton(); +} EditorResourcePreview *EditorInterface::get_resource_previewer() { return EditorResourcePreview::get_singleton(); @@ -335,6 +339,7 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_selected_path"), &EditorInterface::get_selected_path); ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path); ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock); + ClassDB::bind_method(D_METHOD("get_editor_paths"), &EditorInterface::get_editor_paths); ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled); ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 37412e5ebe..3f72e468b2 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -54,6 +54,7 @@ class EditorNode3DGizmoPlugin; class EditorResourcePreview; class EditorFileSystem; class EditorToolAddons; +class EditorPaths; class FileSystemDock; class ScriptEditor; @@ -95,6 +96,7 @@ public: EditorSelection *get_selection(); //EditorImportExport *get_import_export(); Ref<EditorSettings> get_editor_settings(); + EditorPaths *get_editor_paths(); EditorResourcePreview *get_resource_previewer(); EditorFileSystem *get_resource_file_system(); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 086afde07c..d1a0bfeded 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -224,6 +224,13 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { valid_extensions.insert(E->get()); } + if (!file_dialog) { + file_dialog = memnew(EditorFileDialog); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + add_child(file_dialog); + file_dialog->connect("file_selected", callable_mp(this, &EditorResourcePicker::_file_selected)); + } + file_dialog->clear_filters(); for (Set<String>::Element *E = valid_extensions.front(); E; E = E->next()) { file_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper()); @@ -781,10 +788,11 @@ EditorResourcePicker::EditorResourcePicker() { assign_button->set_flat(true); assign_button->set_h_size_flags(SIZE_EXPAND_FILL); assign_button->set_clip_text(true); - assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected)); assign_button->set_drag_forwarding(this); - assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw)); add_child(assign_button); + assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected)); + assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw)); + assign_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input)); preview_rect = memnew(TextureRect); preview_rect->set_expand(true); @@ -793,23 +801,17 @@ EditorResourcePicker::EditorResourcePicker() { preview_rect->set_offset(SIDE_BOTTOM, -1); preview_rect->set_offset(SIDE_RIGHT, -1); assign_button->add_child(preview_rect); - assign_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input)); - edit_menu = memnew(PopupMenu); - add_child(edit_menu); edit_button = memnew(Button); edit_button->set_flat(true); edit_button->set_toggle_mode(true); - edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); - edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed), varray(false)); edit_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_update_menu)); add_child(edit_button); edit_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input)); - - file_dialog = memnew(EditorFileDialog); - file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); - add_child(file_dialog); - file_dialog->connect("file_selected", callable_mp(this, &EditorResourcePicker::_file_selected)); + edit_menu = memnew(PopupMenu); + add_child(edit_menu); + edit_menu->connect("id_pressed", callable_mp(this, &EditorResourcePicker::_edit_menu_cbk)); + edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed), varray(false)); } void EditorScriptPicker::set_create_options(Object *p_menu_node) { diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 20fafe1780..9a4b945bc7 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -51,7 +51,7 @@ class EditorResourcePicker : public HBoxContainer { Button *assign_button; TextureRect *preview_rect; Button *edit_button; - EditorFileDialog *file_dialog; + EditorFileDialog *file_dialog = nullptr; enum MenuOption { OBJ_MENU_LOAD, diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 138830cdc6..35cf08b4d7 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -241,7 +241,7 @@ void EditorResourcePreview::_thread() { _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata); } else { - String temp_path = EditorSettings::get_singleton()->get_cache_dir(); + String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index c4e796dcf1..ffeb22162e 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -101,7 +101,8 @@ protected: public: static EditorResourcePreview *get_singleton(); - //callback function is callback(String p_path,Ref<Texture2D> preview,Variant udata) preview null if could not load + // p_receiver_func callback has signature (String p_path, Ref<Texture2D> p_preview, Ref<Texture2D> p_preview_small, Variant p_userdata) + // p_preview will be null if there was an error void queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata); void queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 0868c31c45..1255526a4a 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -419,7 +419,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/code_font", ""); hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/editor/dim_editor_on_dialog_popup", true); _initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS @@ -503,12 +502,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { /* Text editor */ // Theme - _initial_set("text_editor/theme/color_theme", "Adaptive"); - hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Adaptive,Default,Custom"); + _initial_set("text_editor/theme/color_theme", "Default"); + hints["text_editor/theme/color_theme"] = PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, "Default,Godot 2,Custom"); _initial_set("text_editor/theme/line_spacing", 6); hints["text_editor/theme/line_spacing"] = PropertyInfo(Variant::INT, "text_editor/theme/line_spacing", PROPERTY_HINT_RANGE, "0,50,1"); - _load_default_text_editor_theme(); + _load_godot2_text_editor_theme(); // Highlighting _initial_set("text_editor/highlighting/highlight_all_occurrences", true); @@ -704,6 +703,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/2d/scroll_to_pan", false); _initial_set("editors/2d/pan_speed", 20); + // Tiles editor + _initial_set("editors/tiles_editor/display_grid", true); + _initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5)); + // Polygon editor _initial_set("editors/poly_editor/point_grab_radius", 8); _initial_set("editors/poly_editor/show_previous_outline", true); @@ -782,9 +785,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { }; } -void EditorSettings::_load_default_text_editor_theme() { - bool dark_theme = is_dark_theme(); - +void EditorSettings::_load_godot2_text_editor_theme() { + // Godot 2 is only a dark theme; it doesn't have a light theme counterpart. _initial_set("text_editor/highlighting/symbol_color", Color(0.73, 0.87, 1.0)); _initial_set("text_editor/highlighting/keyword_color", Color(1.0, 1.0, 0.7)); _initial_set("text_editor/highlighting/control_flow_keyword_color", Color(1.0, 0.85, 0.7)); @@ -793,7 +795,7 @@ void EditorSettings::_load_default_text_editor_theme() { _initial_set("text_editor/highlighting/user_type_color", Color(0.42, 0.67, 0.93)); _initial_set("text_editor/highlighting/comment_color", Color(0.4, 0.4, 0.4)); _initial_set("text_editor/highlighting/string_color", Color(0.94, 0.43, 0.75)); - _initial_set("text_editor/highlighting/background_color", dark_theme ? Color(0.0, 0.0, 0.0, 0.23) : Color(0.2, 0.23, 0.31)); + _initial_set("text_editor/highlighting/background_color", Color(0.13, 0.12, 0.15)); _initial_set("text_editor/highlighting/completion_background_color", Color(0.17, 0.16, 0.2)); _initial_set("text_editor/highlighting/completion_selected_color", Color(0.26, 0.26, 0.27)); _initial_set("text_editor/highlighting/completion_existing_color", Color(0.13, 0.87, 0.87, 0.87)); @@ -843,7 +845,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { } bool EditorSettings::_is_default_text_editor_theme(String p_theme_name) { - return p_theme_name == "default" || p_theme_name == "adaptive" || p_theme_name == "custom"; + return p_theme_name == "default" || p_theme_name == "godot 2" || p_theme_name == "custom"; } static Dictionary _get_builtin_script_templates() { @@ -898,67 +900,26 @@ void EditorSettings::create() { return; //pointless } - DirAccess *dir = nullptr; - - String data_path; - String data_dir; - String config_path; - String config_dir; - String cache_path; - String cache_dir; - Ref<ConfigFile> extra_config = memnew(ConfigFile); - String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); - DirAccess *d = DirAccess::create_for_path(exe_path); - bool self_contained = false; - - if (d->file_exists(exe_path + "/._sc_")) { - self_contained = true; - Error err = extra_config->load(exe_path + "/._sc_"); + if (EditorPaths::get_singleton()->is_self_contained()) { + Error err = extra_config->load(EditorPaths::get_singleton()->get_self_contained_file()); if (err != OK) { - ERR_PRINT("Can't load config from path '" + exe_path + "/._sc_'."); - } - } else if (d->file_exists(exe_path + "/_sc_")) { - self_contained = true; - Error err = extra_config->load(exe_path + "/_sc_"); - if (err != OK) { - ERR_PRINT("Can't load config from path '" + exe_path + "/_sc_'."); + ERR_PRINT("Can't load extra config from path :" + EditorPaths::get_singleton()->get_self_contained_file()); } } - memdelete(d); - if (self_contained) { - // editor is self contained, all in same folder - data_path = exe_path; - data_dir = data_path.plus_file("editor_data"); - config_path = exe_path; - config_dir = data_dir; - cache_path = exe_path; - cache_dir = data_dir.plus_file("cache"); - } else { - // Typically XDG_DATA_HOME or %APPDATA% - data_path = OS::get_singleton()->get_data_path(); - data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); - // Can be different from data_path e.g. on Linux or macOS - config_path = OS::get_singleton()->get_config_path(); - config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); - // Can be different from above paths, otherwise a subfolder of data_dir - cache_path = OS::get_singleton()->get_cache_path(); - if (cache_path == data_path) { - cache_dir = data_dir.plus_file("cache"); - } else { - cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name()); - } - } + DirAccess *dir = nullptr; ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized String config_file_path; - if (data_path != "" && config_path != "" && cache_path != "") { + if (EditorPaths::get_singleton()->are_paths_valid()) { // Validate/create data dir and subdirectories + String data_dir = EditorPaths::get_singleton()->get_data_dir(); + dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (dir->change_dir(data_dir) != OK) { dir->make_dir_recursive(data_dir); @@ -975,22 +936,11 @@ void EditorSettings::create() { dir->change_dir(".."); } - // Validate/create cache dir - - if (dir->change_dir(cache_dir) != OK) { - dir->make_dir_recursive(cache_dir); - if (dir->change_dir(cache_dir) != OK) { - ERR_PRINT("Cannot create cache directory!"); - memdelete(dir); - goto fail; - } - } - // Validate/create config dir and subdirectories - if (dir->change_dir(config_dir) != OK) { - dir->make_dir_recursive(config_dir); - if (dir->change_dir(config_dir) != OK) { + if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) { + dir->make_dir_recursive(EditorPaths::get_singleton()->get_config_dir()); + if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) { ERR_PRINT("Cannot create config directory!"); memdelete(dir); goto fail; @@ -1031,7 +981,7 @@ void EditorSettings::create() { // Validate editor config file String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres"; - config_file_path = config_dir.plus_file(config_file_name); + config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name); if (!dir->file_exists(config_file_name)) { memdelete(dir); goto fail; @@ -1048,9 +998,6 @@ void EditorSettings::create() { singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->settings_dir = config_dir; - singleton->data_dir = data_dir; - singleton->cache_dir = cache_dir; print_verbose("EditorSettings: Load OK!"); @@ -1065,6 +1012,8 @@ void EditorSettings::create() { fail: // patch init projects + String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); + if (extra_config->has_section("init_projects")) { Vector<String> list = extra_config->get_value("init_projects", "list"); for (int i = 0; i < list.size(); i++) { @@ -1076,9 +1025,6 @@ fail: singleton = Ref<EditorSettings>(memnew(EditorSettings)); singleton->save_changed_setting = true; singleton->config_file_path = config_file_path; - singleton->settings_dir = config_dir; - singleton->data_dir = data_dir; - singleton->cache_dir = cache_dir; singleton->_load_defaults(extra_config); singleton->setup_language(); singleton->setup_network(); @@ -1308,30 +1254,22 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { // Data directories -String EditorSettings::get_data_dir() const { - return data_dir; -} - String EditorSettings::get_templates_dir() const { - return get_data_dir().plus_file("templates"); + return EditorPaths::get_singleton()->get_data_dir().plus_file("templates"); } // Config directories -String EditorSettings::get_settings_dir() const { - return settings_dir; -} - String EditorSettings::get_project_settings_dir() const { return EditorSettings::PROJECT_EDITOR_SETTINGS_PATH; } String EditorSettings::get_text_editor_themes_dir() const { - return get_settings_dir().plus_file("text_editor_themes"); + return EditorPaths::get_singleton()->get_settings_dir().plus_file("text_editor_themes"); } String EditorSettings::get_script_templates_dir() const { - return get_settings_dir().plus_file("script_templates"); + return EditorPaths::get_singleton()->get_settings_dir().plus_file("script_templates"); } String EditorSettings::get_project_script_templates_dir() const { @@ -1340,12 +1278,8 @@ String EditorSettings::get_project_script_templates_dir() const { // Cache directory -String EditorSettings::get_cache_dir() const { - return cache_dir; -} - String EditorSettings::get_feature_profiles_dir() const { - return get_settings_dir().plus_file("feature_profiles"); + return EditorPaths::get_singleton()->get_settings_dir().plus_file("feature_profiles"); } // Metadata @@ -1432,7 +1366,7 @@ bool EditorSettings::is_dark_theme() { } void EditorSettings::list_text_editor_themes() { - String themes = "Adaptive,Default,Custom"; + String themes = "Default,Godot 2,Custom"; DirAccess *d = DirAccess::open(get_text_editor_themes_dir()); if (d) { @@ -1460,8 +1394,8 @@ void EditorSettings::load_text_editor_theme() { String p_file = get("text_editor/theme/color_theme"); if (_is_default_text_editor_theme(p_file.get_file().to_lower())) { - if (p_file == "Default") { - _load_default_text_editor_theme(); + if (p_file == "Godot 2") { + _load_godot2_text_editor_theme(); } return; // sorry for "Settings changed" console spam } @@ -1572,7 +1506,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c } String EditorSettings::get_editor_layouts_config() const { - return get_settings_dir().plus_file("editor_layouts.cfg"); + return EditorPaths::get_singleton()->get_settings_dir().plus_file("editor_layouts.cfg"); } // Shortcuts @@ -1774,7 +1708,6 @@ void EditorSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert); ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind); - ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir); ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir); ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index e5f8527faf..4c361403a9 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -36,6 +36,7 @@ #include "core/object/class_db.h" #include "core/os/thread_safe.h" #include "core/string/translation.h" +#include "editor/editor_paths.h" #include "scene/gui/shortcut.h" class EditorPlugin; @@ -87,12 +88,7 @@ private: mutable Map<String, Ref<Shortcut>> shortcuts; Map<String, List<Ref<InputEvent>>> builtin_action_overrides; - String resource_path; - String settings_dir; - String data_dir; - String cache_dir; String config_file_path; - String project_config_dir; Vector<String> favorites; Vector<String> recent_dirs; @@ -108,7 +104,7 @@ private: void _add_property_info_bind(const Dictionary &p_info); void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>()); - void _load_default_text_editor_theme(); + void _load_godot2_text_editor_theme(); bool _save_text_editor_theme(String p_file); bool _is_default_text_editor_theme(String p_theme_name); @@ -153,12 +149,10 @@ public: String get_data_dir() const; String get_templates_dir() const; - String get_settings_dir() const; String get_project_settings_dir() const; String get_text_editor_themes_dir() const; String get_script_templates_dir() const; String get_project_script_templates_dir() const; - String get_cache_dir() const; String get_feature_profiles_dir() const; void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 81f6096abf..7971dfc313 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -329,16 +329,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { preset_contrast = default_contrast; } else if (preset == "Light") { preset_accent_color = Color(0.18, 0.50, 1.00); - preset_base_color = Color(1.00, 1.00, 1.00); - preset_contrast = 0.08; + preset_base_color = Color(0.9, 0.9, 0.9); + // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation". + preset_contrast = -0.08; } else if (preset == "Solarized (Dark)") { preset_accent_color = Color(0.15, 0.55, 0.82); preset_base_color = Color(0.04, 0.23, 0.27); preset_contrast = default_contrast; } else if (preset == "Solarized (Light)") { preset_accent_color = Color(0.15, 0.55, 0.82); - preset_base_color = Color(0.99, 0.96, 0.89); - preset_contrast = 0.08; + preset_base_color = Color(0.89, 0.86, 0.79); + // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation". + preset_contrast = -0.08; } else { // Default preset_accent_color = Color(0.44, 0.73, 0.98); preset_base_color = Color(0.21, 0.24, 0.29); @@ -799,8 +801,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_tree_bg->set_border_color(dark_color_3); theme->set_stylebox("bg", "Tree", style_tree_bg); - const Color guide_color = mono_color * Color(1, 1, 1, 0.05); - Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity); // Tree theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons")); @@ -817,19 +817,33 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "Tree", font_color); theme->set_color("font_selected_color", "Tree", mono_color); theme->set_color("title_button_color", "Tree", font_color); - theme->set_color("guide_color", "Tree", guide_color); - theme->set_color("relationship_line_color", "Tree", relationship_line_color); theme->set_color("drop_position_color", "Tree", accent_color); theme->set_constant("vseparation", "Tree", widget_default_margin.y - EDSCALE); theme->set_constant("hseparation", "Tree", 6 * EDSCALE); theme->set_constant("guide_width", "Tree", border_width); theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE); theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE); - theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01); - theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01); theme->set_constant("scroll_border", "Tree", 40 * EDSCALE); theme->set_constant("scroll_speed", "Tree", 12); + const Color guide_color = mono_color * Color(1, 1, 1, 0.05); + Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity); + + theme->set_constant("draw_guides", "Tree", relationship_line_opacity < 0.01); + theme->set_color("guide_color", "Tree", guide_color); + + int relationship_line_width = 1; + Color parent_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.45, 0.0, 1.0)); + Color children_line_color = mono_color * Color(1, 1, 1, CLAMP(relationship_line_opacity + 0.25, 0.0, 1.0)); + theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01); + theme->set_constant("relationship_line_width", "Tree", relationship_line_width); + theme->set_constant("parent_hl_line_width", "Tree", relationship_line_width * 2); + theme->set_constant("children_hl_line_width", "Tree", relationship_line_width); + theme->set_constant("parent_hl_line_margin", "Tree", relationship_line_width * 3); + theme->set_color("relationship_line_color", "Tree", relationship_line_color); + theme->set_color("parent_hl_line_color", "Tree", parent_line_color); + theme->set_color("children_hl_line_color", "Tree", children_line_color); + Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate(); style_tree_btn->set_bg_color(highlight_color); style_tree_btn->set_border_width_all(0); @@ -1343,7 +1357,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color comment_color = dim_color; const Color string_color = (dark_theme ? Color(1.0, 0.85, 0.26) : Color(1.0, 0.82, 0.09)).lerp(mono_color, dark_theme ? 0.5 : 0.3); - const Color te_background_color = dark_theme ? background_color : base_color; + // Use the brightest background color on a light theme (which generally uses a negative contrast rate). + const Color te_background_color = dark_theme ? background_color : dark_color_3; const Color completion_background_color = dark_theme ? base_color : background_color; const Color completion_selected_color = alpha1; const Color completion_existing_color = alpha2; @@ -1372,7 +1387,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { EditorSettings *setting = EditorSettings::get_singleton(); String text_editor_color_theme = setting->get("text_editor/theme/color_theme"); - if (text_editor_color_theme == "Adaptive") { + if (text_editor_color_theme == "Default") { setting->set_initial_value("text_editor/highlighting/symbol_color", symbol_color, true); setting->set_initial_value("text_editor/highlighting/keyword_color", keyword_color, true); setting->set_initial_value("text_editor/highlighting/control_flow_keyword_color", control_flow_keyword_color, true); @@ -1408,7 +1423,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { setting->set_initial_value("text_editor/highlighting/code_folding_color", code_folding_color, true); setting->set_initial_value("text_editor/highlighting/search_result_color", search_result_color, true); setting->set_initial_value("text_editor/highlighting/search_result_border_color", search_result_border_color, true); - } else if (text_editor_color_theme == "Default") { + } else if (text_editor_color_theme == "Godot 2") { setting->load_text_editor_theme(); } diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 0f5c01be0e..6e0ae403a2 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -444,7 +444,7 @@ void ExportTemplateManager::_begin_template_download(const String &p_url) { } download_data.clear(); - download_templates->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz")); + download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz")); download_templates->set_use_threads(true); Error err = download_templates->request(p_url); diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index b04e518b0b..654915e3e5 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -200,7 +200,7 @@ void EditorFileServer::_subthread_start(void *s) { cd->connection->put_data(buf4, 4); encode_uint32(OK, buf4); cd->connection->put_data(buf4, 4); - encode_uint64(fa->get_len(), buf4); + encode_uint64(fa->get_length(), buf4); cd->connection->put_data(buf4, 8); cd->files[id] = fa; diff --git a/editor/icons/Grid.svg b/editor/icons/Grid.svg index b80a9d6525..3b63bfb051 100644 --- a/editor/icons/Grid.svg +++ b/editor/icons/Grid.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2 10 2h2 12v-2-12h-12zm2 2h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm-8 4h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z" fill="#8da5f3" fill-opacity=".98824"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm1.9999999 2h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2zm-8.0000001 4.0000004h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2zm-8.0000001 3.9999996h2v2h-2zm4 0h2v2h-2zm4.0000001 0h2v2h-2z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/RibbonTrailMesh.svg b/editor/icons/RibbonTrailMesh.svg new file mode 100644 index 0000000000..3f6cf0bfef --- /dev/null +++ b/editor/icons/RibbonTrailMesh.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f" stroke-width=".25" transform="rotate(90)"><path d="m6.5625-14.062499h1.875v13.124999h-1.875z"/><path d="m.9375-11.249999h1.875v7.499999h-1.875z"/><path d="m12.187499-11.249999h1.875v7.5h-1.875z"/></g></svg> diff --git a/editor/icons/TubeTrailMesh.svg b/editor/icons/TubeTrailMesh.svg new file mode 100644 index 0000000000..3ca524226f --- /dev/null +++ b/editor/icons/TubeTrailMesh.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f"><path d="m14.0625 7.5c0-1.6377-.2123-3.12-.5969-4.2737-.1923-.57682-.4237-1.0754-.7508-1.4905-.3271-.41505-.8259-.79834-1.4648-.79834h-7.5c-.6389 0-1.1396.38329-1.4667.79834s-.5585.91366-.7507 1.4905c-.3846 1.1536-.5951 2.6359-.5951 4.2737s.2105 3.12.5951 4.2737c.1922.57682.4236 1.0754.7507 1.4905.3271.41505.8278.79834 1.4667.79834h7.5c.6389 0 1.1377-.38329 1.4648-.79834s.5585-.91366.7508-1.4905c.3846-1.1536.5969-2.6359.5969-4.2737zm-2.8125-4.6875002c.4358 1.0052002 0 0 .4358 1.0052002.2941.88221.5017 2.2134.5017 3.6823s-.2076 2.8-.5017 3.6823c-.1449.4347 0 0-.4358 1.005199l-7.5.000041c-.1212-.15705-.2929-.57092-.4376-1.0052-.2941-.88221-.4999-2.2134-.4999-3.6823s.2058-2.8.4999-3.6823c.1447-.43433.3164-.8482.4376-1.0052"/><path d="m6.5625-11.25h1.875v7.5h-1.875z" stroke-width=".25" transform="rotate(90)"/></g></svg> diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index fa6ce5fc89..c5b2a8dc3a 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -75,7 +75,7 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'."); - uint64_t len = f->get_len(); + uint64_t len = f->get_length(); Vector<uint8_t> data; data.resize(len); diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index f496811e0a..7dda61f0bf 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -214,6 +214,7 @@ PluginConfigDialog::PluginConfigDialog() { desc_edit = memnew(TextEdit); desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE); + desc_edit->set_wrap_enabled(true); grid->add_child(desc_edit); Label *author_lb = memnew(Label); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index a0d9afee74..93bb170128 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -464,7 +464,7 @@ void EditorAssetLibraryItemDownload::_make_request() { retry->hide(); download->cancel_request(); - download->set_download_file(EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); + download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip"); Error err = download->request(host); if (err != OK) { @@ -702,7 +702,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB PackedByteArray image_data = p_data; if (use_cache) { - String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); @@ -781,7 +781,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { if (headers[i].findn("ETag:") == 0) { // Save etag - String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text()); String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges(); FileAccess *file; @@ -829,7 +829,7 @@ void EditorAssetLibrary::_update_image_queue() { List<int> to_delete; for (Map<int, ImageQueue>::Element *E = image_queue.front(); E; E = E->next()) { if (!E->get().active && current_images < max_images) { - String cache_filename_base = EditorSettings::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text()); + String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E->get().image_url.md5_text()); Vector<String> headers; if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 21bff41498..2be586733b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4380,7 +4380,7 @@ void CanvasItemEditor::_update_scrollbars() { // Calculate scrollable area. Rect2 canvas_item_rect = Rect2(Point2(), screen_rect); - if (editor->get_edited_scene()) { + if (editor->is_inside_tree() && editor->get_edited_scene()) { Rect2 content_rect = _get_encompassing_rect(editor->get_edited_scene()); canvas_item_rect.expand_to(content_rect.position); canvas_item_rect.expand_to(content_rect.position + content_rect.size); @@ -5361,8 +5361,10 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); ClassDB::bind_method("_reset_create_position", &CanvasItemEditor::_reset_create_position); + ClassDB::bind_method(D_METHOD("get_state"), &CanvasItemEditor::get_state); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); + ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position); ADD_SIGNAL(MethodInfo("item_lock_status_changed")); ADD_SIGNAL(MethodInfo("item_group_status_changed")); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 18cc5d43fb..2d79e4f3e3 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -265,7 +265,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const RES &p_from, const } Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const { - String temp_path = EditorSettings::get_singleton()->get_cache_dir(); + String temp_path = EditorPaths::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); cache_base = temp_path.plus_file("resthumb-" + cache_base); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 1147267ce0..623e4ea66e 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1504,8 +1504,10 @@ void ScriptEditor::_notification(int p_what) { recent_scripts->set_as_minsize(); - _update_script_colors(); - _update_script_names(); + if (is_inside_tree()) { + _update_script_colors(); + _update_script_names(); + } } break; case NOTIFICATION_READY: { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 72a4bd8243..fe5d830239 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1429,11 +1429,17 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data Array files = d["files"]; String text_to_drop; + bool preload = Input::get_singleton()->is_key_pressed(KEY_CTRL); for (int i = 0; i < files.size(); i++) { if (i > 0) { - text_to_drop += ","; + text_to_drop += ", "; + } + + if (preload) { + text_to_drop += "preload(\"" + String(files[i]).c_escape() + "\")"; + } else { + text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } - text_to_drop += "\"" + String(files[i]).c_escape() + "\""; } te->cursor_set_line(row); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 62ecdb8c32..9526160674 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -937,7 +937,6 @@ void TextureRegionEditor::_edit_region() { if (cache_map.has(texture->get_rid())) { autoslice_cache = cache_map[texture->get_rid()]; autoslice_is_dirty = false; - return; } else { if (is_visible() && snap_mode == SNAP_AUTOSLICE) { _update_autoslice(); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 6e82951d3d..78f181e321 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -39,6 +39,7 @@ #include "scene/gui/texture_rect.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" void TileAtlasView::_gui_input(const Ref<InputEvent> &p_event) { bool ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL); @@ -316,6 +317,7 @@ void TileAtlasView::_draw_base_tiles_dark() { void TileAtlasView::_draw_base_tiles_shape_grid() { // Draw the shapes. + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); Vector2i tile_shape_size = tile_set->get_tile_size(); for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); @@ -324,7 +326,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() { Vector2 origin = texture_region.position + (texture_region.size - tile_shape_size) / 2 + in_tile_base_offset; // Draw only if the tile shape fits in the texture region - tile_set->draw_tile_shape(base_tiles_shape_grid, Rect2(origin, tile_shape_size), Color(1.0, 0.5, 0.2, 0.8)); + tile_set->draw_tile_shape(base_tiles_shape_grid, Rect2(origin, tile_shape_size), grid_color); } } diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 80ba396936..ef13d8ea12 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -56,10 +56,18 @@ void TileMapEditorTilesPlugin::_notification(int p_what) { picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons")); erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons")); + toggle_grid_button->set_icon(get_theme_icon("Grid", "EditorIcons")); + missing_atlas_texture_icon = get_theme_icon("TileSet", "EditorIcons"); + + toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); break; case NOTIFICATION_VISIBILITY_CHANGED: _stop_dragging(); + break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: + toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid")); + break; } } @@ -77,6 +85,10 @@ void TileMapEditorTilesPlugin::_on_scattering_spinbox_changed(double p_value) { scattering = p_value; } +void TileMapEditorTilesPlugin::_on_grid_toggled(bool p_pressed) { + EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed); +} + void TileMapEditorTilesPlugin::_update_toolbar() { // Stop draggig if needed. _stop_dragging(); @@ -604,7 +616,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(KEY_CTRL) && !Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { // Do nothing } else { - tile_map->draw_cells_outline(p_overlay, tile_map_selection, Color(0.0, 0.0, 1.0), xform); + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + tile_map->draw_cells_outline(p_overlay, tile_map_selection, selection_color, xform); } } @@ -703,21 +717,27 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over const int fading = 5; // Draw the lines of the grid behind the preview. - if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) { - drawn_grid_rect = drawn_grid_rect.grow(fading); - for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) { - for (int y = drawn_grid_rect.position.y; y < (drawn_grid_rect.position.y + drawn_grid_rect.size.y); y++) { - Vector2i pos_in_rect = Vector2i(x, y) - drawn_grid_rect.position; - - // Fade out the border of the grid. - float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f); - float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f); - float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f); - float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); - float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); - - Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); - tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 0.5, 0.2, 0.5 * opacity), false); + bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"); + if (display_grid) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) { + drawn_grid_rect = drawn_grid_rect.grow(fading); + for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) { + for (int y = drawn_grid_rect.position.y; y < (drawn_grid_rect.position.y + drawn_grid_rect.size.y); y++) { + Vector2i pos_in_rect = Vector2i(x, y) - drawn_grid_rect.position; + + // Fade out the border of the grid. + float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f); + float right_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.x, (float)(drawn_grid_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f); + float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f); + float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); + float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); + + Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); + Color color = grid_color; + color.a = color.a * opacity; + tile_set->draw_tile_shape(p_overlay, cell_region, color, false); + } } } } @@ -1417,9 +1437,11 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { } // Draw the selection. + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); for (Set<TileMapCell>::Element *E = tile_set_selection.front(); E; E = E->next()) { if (E->get().source_id == source_id && E->get().alternative_tile == 0) { - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords()), Color(0.0, 0.0, 1.0), false); + tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get().get_atlas_coords()), selection_color, false); } } @@ -1445,9 +1467,9 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { } } } - + Color selection_rect_color = selection_color.lightened(0.2); for (Set<Vector2i>::Element *E = to_draw.front(); E; E = E->next()) { - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get()), Color(0.8, 0.8, 1.0), false); + tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E->get()), selection_rect_color, false); } } } @@ -1730,6 +1752,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { // --- Toolbar --- toolbar = memnew(HBoxContainer); + toolbar->set_h_size_flags(SIZE_EXPAND_FILL); HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer); @@ -1774,7 +1797,6 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", "Bucket", KEY_B)); bucket_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar)); tilemap_tiles_tools_buttons->add_child(bucket_tool_button); - toolbar->add_child(tilemap_tiles_tools_buttons); // -- TileMap tool settings -- @@ -1834,6 +1856,18 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { _on_random_tile_checkbox_toggled(false); + // Wide empty separation control. + Control *h_empty_space = memnew(Control); + h_empty_space->set_h_size_flags(SIZE_EXPAND_FILL); + toolbar->add_child(h_empty_space); + + // Grid toggle. + toggle_grid_button = memnew(Button); + toggle_grid_button->set_flat(true); + toggle_grid_button->set_toggle_mode(true); + toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_grid_toggled)); + toolbar->add_child(toggle_grid_button); + // Default tool. paint_tool_button->set_pressed(true); _update_toolbar(); @@ -3426,19 +3460,25 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } // Draw the grid. - for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) { - for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) { - Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position; + bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"); + if (display_grid) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) { + for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) { + Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position; - // Fade out the border of the grid. - float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f); - float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f); - float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f); - float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); - float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); + // Fade out the border of the grid. + float left_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.x), 0.0f, 1.0f); + float right_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.x, (float)(displayed_rect.size.x - fading), (float)pos_in_rect.x), 0.0f, 1.0f); + float top_opacity = CLAMP(Math::inverse_lerp(0.0f, (float)fading, (float)pos_in_rect.y), 0.0f, 1.0f); + float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); + float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); - Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); - tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 0.5, 0.2, 0.5 * opacity), false); + Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); + Color color = grid_color; + color.a = color.a * opacity; + tile_set->draw_tile_shape(p_overlay, cell_region, color, false); + } } } @@ -3500,9 +3540,8 @@ TileMapEditor::TileMapEditor() { // --- TileMap toolbar --- tilemap_toolbar = memnew(HBoxContainer); - //tilemap_toolbar->add_child(memnew(VSeparator)); + tilemap_toolbar->set_h_size_flags(SIZE_EXPAND_FILL); tilemap_toolbar->add_child(tabs); - //tilemap_toolbar->add_child(memnew(VSeparator)); for (int i = 0; i < tile_map_editor_plugins.size(); i++) { tile_map_editor_plugins[i]->get_toolbar()->hide(); tilemap_toolbar->add_child(tile_map_editor_plugins[i]->get_toolbar()); diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index a1fb9af3ef..a6f4ec3021 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -82,6 +82,9 @@ private: void _on_random_tile_checkbox_toggled(bool p_pressed); void _on_scattering_spinbox_changed(double p_value); + Button *toggle_grid_button; + void _on_grid_toggled(bool p_pressed); + void _update_toolbar(); ///// Tilemap editing. ///// diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index b6e1a318cb..8e7d613027 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -1178,6 +1178,10 @@ Array TileSetAtlasSourceEditor::_get_selection_as_array() { } void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { + // Colors. + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + // Draw the selected tile. if (tools_button_group->get_pressed_button() == tool_select_button) { for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) { @@ -1185,7 +1189,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { if (selected.alternative == 0) { // Draw the rect. Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - tile_atlas_control->draw_rect(region, Color(0.2, 0.2, 1.0), false); + tile_atlas_control->draw_rect(region, selection_color, false); } } @@ -1234,7 +1238,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Color color = Color(0.0, 0.0, 0.0); if (drag_type == DRAG_TYPE_RECT_SELECT) { - color = Color(0.5, 0.5, 1.0); + color = selection_color.lightened(0.2); } Set<Vector2i> to_paint; @@ -1393,6 +1397,9 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() { } void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + // Update the hovered alternative tile. if (tools_button_group->get_pressed_button() == tool_select_button) { // Draw hovered tile. @@ -1410,7 +1417,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { if (selected.alternative >= 1) { Rect2i rect = tile_atlas_view->get_alternative_tile_rect(selected.tile, selected.alternative); if (rect != Rect2i()) { - alternative_tiles_control->draw_rect(rect, Color(0.2, 0.2, 1.0), false); + alternative_tiles_control->draw_rect(rect, selection_color, false); } } } diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 971ff15073..fb111efc17 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -202,6 +202,7 @@ TilesEditor::TilesEditor(EditorNode *p_editor) { // Toolbar. HBoxContainer *toolbar = memnew(HBoxContainer); + toolbar->set_h_size_flags(SIZE_EXPAND_FILL); add_child(toolbar); // Switch button. diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 8be55296d9..a0757439c3 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -322,6 +322,12 @@ void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_u links[p_node_id].uniform_name = p_uniform_name; } +void VisualShaderGraphPlugin::update_theme() { + vector_expanded_color[0] = VisualShaderEditor::get_singleton()->get_theme_color("axis_x_color", "Editor"); // red + vector_expanded_color[1] = VisualShaderEditor::get_singleton()->get_theme_color("axis_y_color", "Editor"); // green + vector_expanded_color[2] = VisualShaderEditor::get_singleton()->get_theme_color("axis_z_color", "Editor"); // blue +} + void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (p_type != visual_shader->get_shader_type()) { return; @@ -340,6 +346,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { Color(1.0, 1.0, 0.0), // sampler }; + static const String vector_expanded_name[3] = { + "red", + "green", + "blue" + }; + Ref<VisualShaderNode> vsnode = visual_shader->get_node(p_type, p_id); Ref<VisualShaderNodeResizableBase> resizable_node = Object::cast_to<VisualShaderNodeResizableBase>(vsnode.ptr()); @@ -553,13 +565,32 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { } } - for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { + int output_port_count = 0; + for (int i = 0; i < vsnode->get_output_port_count(); i++) { + if (vsnode->_is_output_port_expanded(i)) { + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + output_port_count += 3; + } + } + output_port_count++; + } + int max_ports = MAX(vsnode->get_input_port_count(), output_port_count); + VisualShaderNode::PortType expanded_type = VisualShaderNode::PORT_TYPE_SCALAR; + int expanded_port_counter = 0; + + for (int i = 0, j = 0; i < max_ports; i++, j++) { + if (expanded_type == VisualShaderNode::PORT_TYPE_VECTOR && expanded_port_counter >= 3) { + expanded_type = VisualShaderNode::PORT_TYPE_SCALAR; + expanded_port_counter = 0; + i -= 3; + } + if (vsnode->is_port_separator(i)) { node->add_child(memnew(HSeparator)); port_offset++; } - bool valid_left = i < vsnode->get_input_port_count(); + bool valid_left = j < vsnode->get_input_port_count(); VisualShaderNode::PortType port_left = VisualShaderNode::PORT_TYPE_SCALAR; bool port_left_used = false; String name_left; @@ -567,18 +598,24 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { name_left = vsnode->get_input_port_name(i); port_left = vsnode->get_input_port_type(i); for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { - if (E->get().to_node == p_id && E->get().to_port == i) { + if (E->get().to_node == p_id && E->get().to_port == j) { port_left_used = true; } } } - bool valid_right = i < vsnode->get_output_port_count(); + bool valid_right = true; VisualShaderNode::PortType port_right = VisualShaderNode::PORT_TYPE_SCALAR; String name_right; - if (valid_right) { - name_right = vsnode->get_output_port_name(i); - port_right = vsnode->get_output_port_type(i); + + if (expanded_type == VisualShaderNode::PORT_TYPE_SCALAR) { + valid_right = i < vsnode->get_output_port_count(); + if (valid_right) { + name_right = vsnode->get_output_port_name(i); + port_right = vsnode->get_output_port_type(i); + } + } else { + name_right = vector_expanded_name[expanded_port_counter++]; } HBoxContainer *hb = memnew(HBoxContainer); @@ -686,17 +723,29 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { } } - if (valid_right && visual_shader->get_shader_type() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { - TextureButton *preview = memnew(TextureButton); - preview->set_toggle_mode(true); - preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); - preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons")); - preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + if (valid_right) { + if (vsnode->is_output_port_expandable(i)) { + TextureButton *expand = memnew(TextureButton); + expand->set_toggle_mode(true); + expand->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowDown", "EditorIcons")); + expand->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiTreeArrowRight", "EditorIcons")); + expand->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + expand->set_pressed(vsnode->_is_output_port_expanded(i)); + expand->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_expand_output_port), varray(p_id, i, !vsnode->_is_output_port_expanded(i)), CONNECT_DEFERRED); + hb->add_child(expand); + } + if (visual_shader->get_shader_type() == VisualShader::TYPE_FRAGMENT && port_right != VisualShaderNode::PORT_TYPE_TRANSFORM && port_right != VisualShaderNode::PORT_TYPE_SAMPLER) { + TextureButton *preview = memnew(TextureButton); + preview->set_toggle_mode(true); + preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); + preview->set_pressed_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityVisible", "EditorIcons")); + preview->set_v_size_flags(Control::SIZE_SHRINK_CENTER); - register_output_port(p_id, i, preview); + register_output_port(p_id, j, preview); - preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, i), CONNECT_DEFERRED); - hb->add_child(preview); + preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, j), CONNECT_DEFERRED); + hb->add_child(preview); + } } if (is_group) { @@ -708,7 +757,40 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { node->add_child(hb); + if (expanded_type != VisualShaderNode::PORT_TYPE_SCALAR) { + continue; + } + node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]); + + if (vsnode->_is_output_port_expanded(i)) { + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + port_offset++; + valid_left = (i + 1) < vsnode->get_input_port_count(); + port_left = VisualShaderNode::PORT_TYPE_SCALAR; + if (valid_left) { + port_left = vsnode->get_input_port_type(i + 1); + } + node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[0]); + port_offset++; + + valid_left = (i + 2) < vsnode->get_input_port_count(); + port_left = VisualShaderNode::PORT_TYPE_SCALAR; + if (valid_left) { + port_left = vsnode->get_input_port_type(i + 2); + } + node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[1]); + port_offset++; + + valid_left = (i + 3) < vsnode->get_input_port_count(); + port_left = VisualShaderNode::PORT_TYPE_SCALAR; + if (valid_left) { + port_left = vsnode->get_input_port_type(i + 3); + } + node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], true, VisualShaderNode::PORT_TYPE_SCALAR, vector_expanded_color[2]); + expanded_type = VisualShaderNode::PORT_TYPE_VECTOR; + } + } } if (vsnode->get_output_port_for_preview() >= 0) { @@ -1293,6 +1375,7 @@ void VisualShaderEditor::_update_graph() { graph_plugin->clear_links(); graph_plugin->make_dirty(true); + graph_plugin->update_theme(); for (int n_i = 0; n_i < nodes.size(); n_i++) { graph_plugin->add_node(type, nodes[n_i]); @@ -1441,6 +1524,92 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object * undo_redo->commit_action(); } +void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expand) { + VisualShader::Type type = get_current_shader_type(); + + Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node); + ERR_FAIL_COND(!node.is_valid()); + + if (p_expand) { + undo_redo->create_action(TTR("Expand Output Port")); + } else { + undo_redo->create_action(TTR("Shrink Output Port")); + } + + undo_redo->add_do_method(node.ptr(), "_set_output_port_expanded", p_port, p_expand); + undo_redo->add_undo_method(node.ptr(), "_set_output_port_expanded", p_port, !p_expand); + + int type_size = 0; + if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_VECTOR) { + type_size = 3; + } + + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + int from_node = E->get().from_node; + int from_port = E->get().from_port; + int to_node = E->get().to_node; + int to_port = E->get().to_port; + + if (from_node == p_node) { + if (p_expand) { + if (from_port > p_port) { // reconnect ports after expanded ports + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port + type_size, to_node, to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port + type_size, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port); + } + } else { + if (from_port > p_port + type_size) { // reconnect ports after expanded ports + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port); + } else if (from_port > p_port) { // disconnect component ports + undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port); + + undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port); + undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port); + } + } + } + } + + int preview_port = node->get_output_port_for_preview(); + if (p_expand) { + if (preview_port > p_port) { + undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port + type_size); + undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port); + } + } else { + if (preview_port > p_port + type_size) { + undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", preview_port - type_size); + undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", preview_port); + } + } + + undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type, p_node); + undo_redo->commit_action(); +} + void VisualShaderEditor::_remove_input_port(int p_node, int p_port) { VisualShader::Type type = get_current_shader_type(); Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node); @@ -3469,6 +3638,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected); ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant); ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform); + ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); @@ -4090,6 +4260,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors."))); add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("GetBillboardMatrix", "Transform", "Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM)); add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2f438cc6c8..b3510aafa1 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -83,6 +83,8 @@ private: List<VisualShader::Connection> connections; bool dirty = false; + Color vector_expanded_color[3]; + protected: static void _bind_methods(); @@ -119,6 +121,7 @@ public: void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression); int get_constant_index(float p_constant) const; void update_node_size(int p_node_id); + void update_theme(); VisualShader::Type get_shader_type() const; VisualShaderGraphPlugin(); @@ -401,6 +404,7 @@ class VisualShaderEditor : public VBoxContainer { void _remove_output_port(int p_node, int p_port); void _change_output_port_type(int p_type, int p_node, int p_port); void _change_output_port_name(const String &p_text, Object *p_line_edit, int p_node, int p_port); + void _expand_output_port(int p_node, int p_port, bool p_expand); void _expression_focus_out(Object *code_edit, int p_node); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 49a6d28dc1..8bde397b5c 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1484,16 +1484,7 @@ Vector<ProjectList::Item> ProjectList::get_selected_projects() const { void ProjectList::ensure_project_visible(int p_index) { const Item &item = _projects[p_index]; - - int item_top = item.control->get_position().y; - int item_bottom = item.control->get_position().y + item.control->get_size().y; - - if (item_top < get_v_scroll()) { - set_v_scroll(item_top); - - } else if (item_bottom > get_v_scroll() + get_size().y) { - set_v_scroll(item_bottom - get_size().y); - } + ensure_control_visible(item.control); } int ProjectList::get_single_selected_index() const { |