diff options
| -rw-r--r-- | editor/create_dialog.cpp | 55 | ||||
| -rw-r--r-- | editor/editor_node.cpp | 64 | ||||
| -rw-r--r-- | editor/editor_node.h | 9 | ||||
| -rw-r--r-- | editor/editor_themes.cpp | 47 | ||||
| -rw-r--r-- | editor/export_template_manager.cpp | 135 | ||||
| -rw-r--r-- | editor/export_template_manager.h | 2 | ||||
| -rw-r--r-- | editor/import/resource_importer_wav.cpp | 4 | ||||
| -rw-r--r-- | editor/plugins/spatial_editor_plugin.cpp | 4 | ||||
| -rw-r--r-- | editor/project_export.cpp | 1 | ||||
| -rw-r--r-- | editor/project_manager.cpp | 2 | ||||
| -rw-r--r-- | editor/project_settings_editor.cpp | 1 | ||||
| -rw-r--r-- | modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj | 5 | ||||
| -rw-r--r-- | modules/mono/mono_gd/gd_mono.cpp | 7 | ||||
| -rw-r--r-- | platform/android/SCsub | 22 | ||||
| -rw-r--r-- | platform/android/export/export.cpp | 9 | ||||
| -rw-r--r-- | scene/gui/spin_box.cpp | 20 | ||||
| -rw-r--r-- | scene/gui/tab_container.cpp | 14 | ||||
| -rw-r--r-- | scene/gui/tab_container.h | 3 | 
18 files changed, 259 insertions, 145 deletions
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 8a8d52c6f1..d5f0dc01ee 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -191,34 +191,41 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p  		item->set_custom_color(0, get_color("disabled_font_color", "Editor"));  		item->set_selectable(0, false);  	} else if (!(*to_select && (*to_select)->get_text(0) == search_box->get_text())) { -		bool current_type_prefered = _is_type_prefered(p_type); -		bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false; -  		String search_term = search_box->get_text().to_lower(); -		bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type); -		bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0; -		bool is_substring_of_selected = false; -		bool is_subsequence_of_selected = false; -		bool is_selected_equal = false; - -		if (*to_select) { -			String name = (*to_select)->get_text(0).split(" ")[0].to_lower(); -			is_substring_of_selected = name.find(search_term) >= 0; -			is_subsequence_of_selected = search_term.is_subsequence_of(name); -			is_selected_equal = name == search_term; -		} -		if (is_subsequence_of_type && !is_selected_equal) { -			if (is_substring_of_type) { -				if (!is_substring_of_selected || (current_type_prefered && !selected_type_prefered)) { -					*to_select = item; -				} -			} else { -				// substring results weigh more than subsequences, so let's make sure we don't override them -				if (!is_substring_of_selected) { -					if (!is_subsequence_of_selected || (current_type_prefered && !selected_type_prefered)) { +		// if the node name matches exactly as the search, the node should be selected. +		// this also fixes when the user clicks on recent nodes. +		if (p_type.to_lower() == search_term) { +			*to_select = item; +		} else { +			bool current_type_prefered = _is_type_prefered(p_type); +			bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false; + +			bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type); +			bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0; +			bool is_substring_of_selected = false; +			bool is_subsequence_of_selected = false; +			bool is_selected_equal = false; + +			if (*to_select) { +				String name = (*to_select)->get_text(0).split(" ")[0].to_lower(); +				is_substring_of_selected = name.find(search_term) >= 0; +				is_subsequence_of_selected = search_term.is_subsequence_of(name); +				is_selected_equal = name == search_term; +			} + +			if (is_subsequence_of_type && !is_selected_equal) { +				if (is_substring_of_type) { +					if (!is_substring_of_selected || (current_type_prefered && !selected_type_prefered)) {  						*to_select = item;  					} +				} else { +					// substring results weigh more than subsequences, so let's make sure we don't override them +					if (!is_substring_of_selected) { +						if (!is_subsequence_of_selected || (current_type_prefered && !selected_type_prefered)) { +							*to_select = item; +						} +					}  				}  			}  		} diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 635f6d4fc7..8ed6cec779 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2632,11 +2632,8 @@ void EditorNode::_exit_editor() {  	resource_preview->stop(); //stop early to avoid crashes  	_save_docks(); -	// Dim the editor window while it's quitting to make it clearer that it's busy. -	// No transition is applied, as the effect needs to be visible immediately -	float c = 0.4f; -	Color dim_color = Color(c, c, c); -	gui_base->set_modulate(dim_color); +	// Dim the editor window while it's quitting to make it clearer that it's busy +	dim_editor(true, true);  	get_tree()->quit();  } @@ -5133,46 +5130,12 @@ void EditorNode::_open_imported() {  	load_scene(open_import_request, true, false, true, true);  } -void EditorNode::dim_editor(bool p_dimming) { -	static int dim_count = 0; -	bool dim_ui = EditorSettings::get_singleton()->get("interface/editor/dim_editor_on_dialog_popup"); -	if (p_dimming) { -		if (dim_ui && dim_count == 0) { -			_start_dimming(true); -		} -		dim_count++; -	} else { -		if (dim_count == 1) { -			_start_dimming(false); -		} -		if (dim_count > 0) { -			dim_count--; -		} else { -			ERR_PRINT("Undimmed before dimming!"); -		} -	} -} - -void EditorNode::_start_dimming(bool p_dimming) { -	_dimming = p_dimming; -	_dim_time = 0.0f; -	_dim_timer->start(); -} - -void EditorNode::_dim_timeout() { - -	_dim_time += _dim_timer->get_wait_time(); -	float wait_time = 0.08f; -	float c = 0.4f; - -	Color base = _dimming ? Color(1, 1, 1) : Color(c, c, c); -	Color final = _dimming ? Color(c, c, c) : Color(1, 1, 1); - -	if (_dim_time + _dim_timer->get_wait_time() >= wait_time) { -		gui_base->set_modulate(final); -		_dim_timer->stop(); +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) { +		gui_base->set_modulate(Color(0.5, 0.5, 0.5));  	} else { -		gui_base->set_modulate(base.linear_interpolate(final, _dim_time / wait_time)); +		gui_base->set_modulate(Color(1, 1, 1));  	}  } @@ -5356,7 +5319,6 @@ void EditorNode::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_open_imported"), &EditorNode::_open_imported);  	ClassDB::bind_method(D_METHOD("_inherit_imported"), &EditorNode::_inherit_imported); -	ClassDB::bind_method(D_METHOD("_dim_timeout"), &EditorNode::_dim_timeout);  	ClassDB::bind_method("_copy_warning", &EditorNode::_copy_warning); @@ -5818,6 +5780,7 @@ EditorNode::EditorNode() {  		dock_slot[i]->set_drag_to_rearrange_enabled(true);  		dock_slot[i]->set_tabs_rearrange_group(1);  		dock_slot[i]->connect("tab_changed", this, "_dock_tab_changed"); +		dock_slot[i]->set_use_hidden_tabs_for_min_size(true);  	}  	dock_drag_timer = memnew(Timer); @@ -6411,13 +6374,13 @@ EditorNode::EditorNode() {  	gui_base->add_child(custom_build_manage_templates);  	install_android_build_template = memnew(ConfirmationDialog); -	install_android_build_template->set_text(TTR("This will install the Android project for custom builds.\nNote that, in order to use it, it needs to be enabled per export preset.")); +	install_android_build_template->set_text(TTR("This will set up your project for custom Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote that in order to make custom builds instead of using pre-built APKs, the \"Use Custom Build\" option should be enabled in the Android export preset."));  	install_android_build_template->get_ok()->set_text(TTR("Install"));  	install_android_build_template->connect("confirmed", this, "_menu_confirm_current");  	gui_base->add_child(install_android_build_template);  	remove_android_build_template = memnew(ConfirmationDialog); -	remove_android_build_template->set_text(TTR("Android build template is already installed and it won't be overwritten.\nRemove the \"build\" directory manually before attempting this operation again.")); +	remove_android_build_template->set_text(TTR("The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"res://android/build\" directory manually before attempting this operation again."));  	remove_android_build_template->get_ok()->set_text(TTR("Show in File Manager"));  	remove_android_build_template->connect("confirmed", this, "_menu_option", varray(FILE_EXPLORE_ANDROID_BUILD_TEMPLATES));  	gui_base->add_child(remove_android_build_template); @@ -6687,13 +6650,6 @@ EditorNode::EditorNode() {  	waiting_for_first_scan = true; -	_dimming = false; -	_dim_time = 0.0f; -	_dim_timer = memnew(Timer); -	_dim_timer->set_wait_time(0.01666f); -	_dim_timer->connect("timeout", this, "_dim_timeout"); -	add_child(_dim_timer); -  	print_handler.printfunc = _print_handler;  	print_handler.userdata = this;  	add_print_handler(&print_handler); diff --git a/editor/editor_node.h b/editor/editor_node.h index 61bbb7b86d..54bcf14c1b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -633,13 +633,6 @@ private:  	static int build_callback_count;  	static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; -	bool _dimming; -	float _dim_time; -	Timer *_dim_timer; - -	void _start_dimming(bool p_dimming); -	void _dim_timeout(); -  	void _license_tree_selected();  	void _update_update_spinner(); @@ -849,7 +842,7 @@ public:  	void save_scene_list(Vector<String> p_scene_filenames);  	void restart_editor(); -	void dim_editor(bool p_dimming); +	void dim_editor(bool p_dimming, bool p_force_dim = false);  	void edit_current() { _edit_current(); }; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 56eed96e31..c15d24719f 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -108,16 +108,17 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =  #ifdef SVG_ENABLED  	Dictionary dark_icon_color_dictionary;  	if (!p_dark_theme) { -		//convert color:                              FROM       TO -		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#4f4f4f"); // common icon color -		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#000000"); // white -		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#000000"); // script darker color +		// convert color:                             FROM       TO +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // common icon color +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // white +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b4b4b4", "#363636"); // script darker color +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // scrollbar grabber highlight color  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cea4f1", "#a85de9"); // animation  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc9c9c", "#cd3838"); // spatial  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5b7f3", "#3d64dd"); // 2d  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#708cea", "#1a3eac"); // 2d dark -		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5efac", "#2aa235"); // control +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a5efac", "#2fa139"); // control  		// rainbow  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff7070", "#ff2929"); // red @@ -145,9 +146,14 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea9568", "#bd5e2c"); // 3D Transform track  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#66f376", "#16a827"); // Call Method track  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5792f6", "#236be6"); // Bezier Curve track -		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae668", "#aea923"); // Audio Playback track +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae668", "#9f9722"); // Audio Playback track  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b76ef0", "#9853ce"); // Animation Playback track +		// TileSet editor icons +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce844", "#aa8d24"); // New Single Tile +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4490fc", "#0350bd"); // New Autotile +		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c9cfd4", "#828f9b"); // New Atlas +  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#69ecbd", "#25e3a0"); // VS variant  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da6f0", "#6d8eeb"); // VS bool  		ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#7dc6ef", "#4fb2e9"); // VS int @@ -339,6 +345,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	const Color color_disabled = mono_color.inverted().linear_interpolate(base_color, 0.7);  	const Color color_disabled_bg = mono_color.inverted().linear_interpolate(base_color, 0.9); +	Color icon_color_hover = Color(1, 1, 1) * (dark_theme ? 1.15 : 1.45); +	icon_color_hover.a = 1.0; +	// Make the pressed icon color overbright because icons are not completely white on a dark theme. +	// On a light theme, icons are dark, so we need to modulate them with an even brighter color. +	Color icon_color_pressed = accent_color * (dark_theme ? 1.15 : 3.5); +	icon_color_pressed.a = 1.0; +  	const Color separator_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.1);  	const Color highlight_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.2); @@ -565,9 +578,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	theme->set_color("font_color_hover", "Button", font_color_hl);  	theme->set_color("font_color_pressed", "Button", accent_color);  	theme->set_color("font_color_disabled", "Button", font_color_disabled); -	theme->set_color("icon_color_hover", "Button", font_color_hl); -	// make icon color value bigger because icon image is not complete white -	theme->set_color("icon_color_pressed", "Button", Color(accent_color.r * 1.15, accent_color.g * 1.15, accent_color.b * 1.15, accent_color.a)); +	theme->set_color("icon_color_hover", "Button", icon_color_hover); +	theme->set_color("icon_color_pressed", "Button", icon_color_pressed);  	// OptionButton  	theme->set_stylebox("normal", "OptionButton", style_widget); @@ -580,7 +592,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	theme->set_color("font_color_hover", "OptionButton", font_color_hl);  	theme->set_color("font_color_pressed", "OptionButton", accent_color);  	theme->set_color("font_color_disabled", "OptionButton", font_color_disabled); -	theme->set_color("icon_color_hover", "OptionButton", font_color_hl); +	theme->set_color("icon_color_hover", "OptionButton", icon_color_hover);  	theme->set_icon("arrow", "OptionButton", theme->get_icon("GuiOptionArrow", "EditorIcons"));  	theme->set_constant("arrow_margin", "OptionButton", default_margin_size * EDSCALE);  	theme->set_constant("modulate_arrow", "OptionButton", true); @@ -601,7 +613,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	theme->set_color("font_color_hover", "CheckButton", font_color_hl);  	theme->set_color("font_color_pressed", "CheckButton", accent_color);  	theme->set_color("font_color_disabled", "CheckButton", font_color_disabled); -	theme->set_color("icon_color_hover", "CheckButton", font_color_hl); +	theme->set_color("icon_color_hover", "CheckButton", icon_color_hover);  	theme->set_constant("hseparation", "CheckButton", 4 * EDSCALE);  	theme->set_constant("check_vadjust", "CheckButton", 0 * EDSCALE); @@ -626,7 +638,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	theme->set_color("font_color_hover", "CheckBox", font_color_hl);  	theme->set_color("font_color_pressed", "CheckBox", accent_color);  	theme->set_color("font_color_disabled", "CheckBox", font_color_disabled); -	theme->set_color("icon_color_hover", "CheckBox", font_color_hl); +	theme->set_color("icon_color_hover", "CheckBox", icon_color_hover);  	theme->set_constant("hseparation", "CheckBox", 4 * EDSCALE);  	theme->set_constant("check_vadjust", "CheckBox", 0 * EDSCALE); @@ -983,8 +995,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	// GraphEdit  	theme->set_stylebox("bg", "GraphEdit", style_tree_bg); -	theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15)); -	theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07)); +	if (dark_theme) { +		theme->set_color("grid_major", "GraphEdit", Color(1.0, 1.0, 1.0, 0.15)); +		theme->set_color("grid_minor", "GraphEdit", Color(1.0, 1.0, 1.0, 0.07)); +	} else { +		theme->set_color("grid_major", "GraphEdit", Color(0.0, 0.0, 0.0, 0.15)); +		theme->set_color("grid_minor", "GraphEdit", Color(0.0, 0.0, 0.0, 0.07)); +	}  	theme->set_color("activity", "GraphEdit", accent_color);  	theme->set_icon("minus", "GraphEdit", theme->get_icon("ZoomLess", "EditorIcons"));  	theme->set_icon("more", "GraphEdit", theme->get_icon("ZoomMore", "EditorIcons")); @@ -1068,7 +1085,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {  	theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));  	// Use a different color for folder icons to make them easier to distinguish from files.  	// On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color. -	theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(5, 5, 5)).linear_interpolate(accent_color, 0.7)); +	theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).linear_interpolate(accent_color, 0.7));  	theme->set_color("files_disabled", "FileDialog", font_color_disabled);  	// color picker diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 1447a143d4..536cfaa1dd 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -542,7 +542,6 @@ void ExportTemplateManager::_notification(int p_what) {  		template_list_state->set_text(status);  		if (errored) {  			set_process(false); -			;  		}  	} @@ -555,25 +554,33 @@ void ExportTemplateManager::_notification(int p_what) {  bool ExportTemplateManager::can_install_android_template() { -	return FileAccess::exists(EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG).plus_file("android_source.zip")); +	const String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); +	return FileAccess::exists(templates_dir.plus_file("android_source.zip")) && +		   FileAccess::exists(templates_dir.plus_file("android_release.apk")) && +		   FileAccess::exists(templates_dir.plus_file("android_debug.apk"));  }  Error ExportTemplateManager::install_android_template() { +	// To support custom Android builds, we install various things to the project's res://android folder. +	// First is the Java source code and buildsystem from android_source.zip. +	// Then we extract the Godot Android libraries from pre-build android_release.apk +	// and android_debug.apk, to place them in the libs folder. +  	DirAccessRef da = DirAccess::open("res://");  	ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); -	//make android dir (if it does not exist) +	// Make res://android dir (if it does not exist).  	da->make_dir("android");  	{ -		//add an empty .gdignore file to avoid scan +		// Add an empty .gdignore file to avoid scan.  		FileAccessRef f = FileAccess::open("res://android/.gdignore", FileAccess::WRITE);  		ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);  		f->store_line("");  		f->close();  	}  	{ -		//add version, to ensure building won't work if template and Godot version don't match +		// Add version, to ensure building won't work if template and Godot version don't match.  		FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::WRITE);  		ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);  		f->store_line(VERSION_FULL_CONFIG); @@ -583,7 +590,10 @@ Error ExportTemplateManager::install_android_template() {  	Error err = da->make_dir_recursive("android/build");  	ERR_FAIL_COND_V(err != OK, err); -	String source_zip = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG).plus_file("android_source.zip"); +	// Uncompress source template. + +	const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); +	const String &source_zip = templates_path.plus_file("android_source.zip");  	ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN);  	FileAccess *src_f = NULL; @@ -593,37 +603,33 @@ Error ExportTemplateManager::install_android_template() {  	ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in ZIP format.");  	int ret = unzGoToFirstFile(pkg); -  	int total_files = 0; -	//count files +	// Count files to unzip.  	while (ret == UNZ_OK) {  		total_files++;  		ret = unzGoToNextFile(pkg);  	} -  	ret = unzGoToFirstFile(pkg); -	//decompress files -	ProgressDialog::get_singleton()->add_task("uncompress", TTR("Uncompressing Android Build Sources"), total_files); -	Set<String> dirs_tested; +	ProgressDialog::get_singleton()->add_task("uncompress_src", TTR("Uncompressing Android Build Sources"), total_files); +	Set<String> dirs_tested;  	int idx = 0;  	while (ret == UNZ_OK) { -		//get filename +		// Get file path.  		unz_file_info info; -		char fname[16384]; -		ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); - -		String name = fname; +		char fpath[16384]; +		ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0); -		String base_dir = name.get_base_dir(); +		String path = fpath; +		String base_dir = path.get_base_dir(); -		if (!name.ends_with("/")) { +		if (!path.ends_with("/")) {  			Vector<uint8_t> data;  			data.resize(info.uncompressed_size); -			//read +			// Read.  			unzOpenCurrentFile(pkg);  			unzReadCurrentFile(pkg, data.ptrw(), data.size());  			unzCloseCurrentFile(pkg); @@ -633,7 +639,7 @@ Error ExportTemplateManager::install_android_template() {  				dirs_tested.insert(base_dir);  			} -			String to_write = String("res://android/build").plus_file(name); +			String to_write = String("res://android/build").plus_file(path);  			FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE);  			if (f) {  				f->store_buffer(data.ptr(), data.size()); @@ -646,13 +652,96 @@ Error ExportTemplateManager::install_android_template() {  			}  		} -		ProgressDialog::get_singleton()->task_step("uncompress", name, idx); +		ProgressDialog::get_singleton()->task_step("uncompress_src", path, idx); + +		idx++; +		ret = unzGoToNextFile(pkg); +	} + +	ProgressDialog::get_singleton()->end_task("uncompress_src"); +	unzClose(pkg); + +	// Extract libs from pre-built APKs. +	err = _extract_libs_from_apk("release"); +	ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_release.apk."); +	err = _extract_libs_from_apk("debug"); +	ERR_FAIL_COND_V_MSG(err != OK, err, "Can't extract Android libs from android_debug.apk."); + +	return OK; +} + +Error ExportTemplateManager::_extract_libs_from_apk(const String &p_target_name) { + +	const String &templates_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG); +	const String &apk_file = templates_path.plus_file("android_" + p_target_name + ".apk"); +	ERR_FAIL_COND_V(!FileAccess::exists(apk_file), ERR_CANT_OPEN); + +	FileAccess *src_f = NULL; +	zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + +	unzFile pkg = unzOpen2(apk_file.utf8().get_data(), &io); +	ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android APK can't be extracted."); + +	DirAccessRef da = DirAccess::open("res://"); +	ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + +	// 8 steps because 4 arches, 2 libs per arch. +	ProgressDialog::get_singleton()->add_task("extract_libs_from_apk", TTR("Extracting Android Libraries From APKs"), 8); + +	int ret = unzGoToFirstFile(pkg); +	Set<String> dirs_tested; +	int idx = 0; +	while (ret == UNZ_OK) { +		// Get file path. +		unz_file_info info; +		char fpath[16384]; +		ret = unzGetCurrentFileInfo(pkg, &info, fpath, 16384, NULL, 0, NULL, 0); + +		String path = fpath; +		String base_dir = path.get_base_dir(); +		String file = path.get_file(); + +		if (!base_dir.begins_with("lib") || path.ends_with("/")) { +			ret = unzGoToNextFile(pkg); +			continue; +		} + +		Vector<uint8_t> data; +		data.resize(info.uncompressed_size); + +		// Read. +		unzOpenCurrentFile(pkg); +		unzReadCurrentFile(pkg, data.ptrw(), data.size()); +		unzCloseCurrentFile(pkg); + +		// We have a "lib" folder in the APK, but it should be "libs/{release,debug}" in the source dir. +		String target_base_dir = base_dir.replace_first("lib", String("libs").plus_file(p_target_name)); + +		if (!dirs_tested.has(base_dir)) { +			da->make_dir_recursive(String("android/build").plus_file(target_base_dir)); +			dirs_tested.insert(base_dir); +		} + +		String to_write = String("res://android/build").plus_file(target_base_dir.plus_file(path.get_file())); +		FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE); +		if (f) { +			f->store_buffer(data.ptr(), data.size()); +			memdelete(f); +#ifndef WINDOWS_ENABLED +			// We can't retrieve Unix permissions from the APK it seems, so simply set 0755 as should be. +			FileAccess::set_unix_permissions(to_write, 0755); +#endif +		} else { +			ERR_PRINTS("Can't uncompress file: " + to_write); +		} + +		ProgressDialog::get_singleton()->task_step("extract_libs_from_apk", path, idx);  		idx++;  		ret = unzGoToNextFile(pkg);  	} -	ProgressDialog::get_singleton()->end_task("uncompress"); +	ProgressDialog::get_singleton()->end_task("extract_libs_from_apk");  	unzClose(pkg);  	return OK; diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index ad3ab507b3..ecb8e85b21 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -72,6 +72,8 @@ class ExportTemplateManager : public ConfirmationDialog {  	virtual void ok_pressed();  	bool _install_from_file(const String &p_file, bool p_use_progress = true); +	Error _extract_libs_from_apk(const String &p_target_name); +  	void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data);  	void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 4fd4ab2f2e..f1de71e25e 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -83,8 +83,8 @@ void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int  	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/mono"), false));  	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/max_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));  	r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "force/max_rate_hz", PROPERTY_HINT_EXP_RANGE, "11025,192000,1"), 44100)); -	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), true)); -	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), true)); +	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false)); +	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false));  	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false));  	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Disabled,RAM (Ima-ADPCM)"), 0));  } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 2eb3ce1ec3..85ddcb8b9d 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -5298,6 +5298,10 @@ void SpatialEditor::_notification(int p_what) {  		tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));  		tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));  		tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); +		tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons")); +		tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons")); +		tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons")); +		tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));  		tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));  		tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons")); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 956da92c35..c54103f6f7 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1116,6 +1116,7 @@ ProjectExportDialog::ProjectExportDialog() {  	sections = memnew(TabContainer);  	sections->set_tab_align(TabContainer::ALIGN_LEFT); +	sections->set_use_hidden_tabs_for_min_size(true);  	settings_vb->add_child(sections);  	sections->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 98335c8367..c6e3dc1e32 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1754,7 +1754,7 @@ void ProjectManager::_dim_window() {  	// Dim the project manager window while it's quitting to make it clearer that it's busy.  	// No transition is applied, as the effect needs to be visible immediately -	float c = 0.4f; +	float c = 0.5f;  	Color dim_color = Color(c, c, c);  	gui_base->set_modulate(dim_color);  } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 1c588a45f1..a0d2332ffc 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1674,6 +1674,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {  	tab_container = memnew(TabContainer);  	tab_container->set_tab_align(TabContainer::ALIGN_LEFT); +	tab_container->set_use_hidden_tabs_for_min_size(true);  	add_child(tab_container);  	VBoxContainer *props_base = memnew(VBoxContainer); diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj index c745fe321b..ab3a5d1aea 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj @@ -37,9 +37,8 @@        entire solution. $(SolutionDir) is not defined in that case, so we need to workaround that.        We make SCons restore the NuGet packages in the project directory instead in this case.        --> -      <HintPath Condition=" '$(SolutionDir)' != '' ">$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> -      <HintPath>$(ProjectDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> -      <HintPath>packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> <!-- Are you happy CI? --> +      <HintPath Condition=" '$(SolutionDir)' != '' And Exists('$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll') ">$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath> +      <HintPath Condition=" '$(SolutionDir)' == '' Or !Exists('$(SolutionDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll') ">$(ProjectDir)\packages\DotNet.Glob.2.1.1\lib\net45\DotNet.Glob.dll</HintPath>      </Reference>    </ItemGroup>    <ItemGroup> diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index aa69803a58..cd111abd4d 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -317,6 +317,13 @@ void GDMono::initialize() {  		return;  #endif +#if !defined(WINDOWS_ENABLED) && !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND) +	// FIXME: Temporary workaround. See: https://github.com/godotengine/godot/issues/29812 +	if (!OS::get_singleton()->has_environment("MONO_THREADS_SUSPEND")) { +		OS::get_singleton()->set_environment("MONO_THREADS_SUSPEND", "preemptive"); +	} +#endif +  	root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");  	ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime."); diff --git a/platform/android/SCsub b/platform/android/SCsub index d2f27817c6..1bd8161fa7 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -55,3 +55,25 @@ if lib_arch_dir != '':      stl_lib_path = str(env['ANDROID_NDK_ROOT']) + '/sources/cxx-stl/llvm-libc++/libs/' + lib_arch_dir + '/libc++_shared.so'      env_android.Command(out_dir + '/libc++_shared.so', stl_lib_path, Copy("$TARGET", "$SOURCE")) + +# Zip android/java folder for the source export template. +print("Archiving platform/android/java as bin/android_source.zip...") +import os +import zipfile +# Change dir to avoid have zipped paths start from the android/java folder. +olddir = os.getcwd() +os.chdir(Dir('#platform/android/java').abspath) +bindir = Dir('#bin').abspath +# Make 'bin' dir if missing, can happen on fresh clone. +if not os.path.exists(bindir): +    os.makedirs(bindir) +zipf = zipfile.ZipFile(os.path.join(bindir, 'android_source.zip'), 'w', zipfile.ZIP_DEFLATED) +exclude_dirs = ['.gradle', 'build', 'libs', 'patches'] +for root, dirs, files in os.walk('.', topdown=True): +    # Change 'dirs' in place to exclude folders we don't want. +    # https://stackoverflow.com/a/19859907 +    dirs[:] = [d for d in dirs if d not in exclude_dirs] +    for f in files: +        zipf.write(os.path.join(root, f)) +zipf.close() +os.chdir(olddir) diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 16e49e8a38..441fa38bff 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1610,19 +1610,16 @@ public:  				valid = false;  			} else {  				Error errn; -				DirAccess *da = DirAccess::open(sdk_path.plus_file("tools"), &errn); +				DirAccessRef da = DirAccess::open(sdk_path.plus_file("tools"), &errn);  				if (errn != OK) {  					err += TTR("Invalid Android SDK path for custom build in Editor Settings.") + "\n";  					valid = false;  				} -				if (da) { -					memdelete(da); -				}  			}  			if (!FileAccess::exists("res://android/build/build.gradle")) { -				err += TTR("Android project is not installed for compiling. Install from Editor menu.") + "\n"; +				err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n";  				valid = false;  			}  		} @@ -2513,7 +2510,7 @@ void register_android_exporter() {  	EDITOR_DEF("export/android/debug_keystore_pass", "android");  	EDITOR_DEF("export/android/force_system_user", false);  	EDITOR_DEF("export/android/custom_build_sdk_path", ""); -	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR, "*.keystore")); +	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/custom_build_sdk_path", PROPERTY_HINT_GLOBAL_DIR));  	EDITOR_DEF("export/android/timestamping_authority_url", "");  	EDITOR_DEF("export/android/shutdown_adb_on_exit", true); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 6ada0cba97..3c63f6b2c7 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -29,6 +29,7 @@  /*************************************************************************/  #include "spin_box.h" +#include "core/math/expression.h"  #include "core/os/input.h"  Size2 SpinBox::get_minimum_size() const { @@ -50,15 +51,18 @@ void SpinBox::_value_changed(double) {  void SpinBox::_text_entered(const String &p_string) { -	/* -	if (!p_string.is_numeric()) +	Ref<Expression> expr; +	expr.instance(); +	Error err = expr->parse(p_string); +	if (err != OK) {  		return; -	*/ -	String value = p_string; -	if (prefix != "" && p_string.begins_with(prefix)) -		value = p_string.substr(prefix.length(), p_string.length() - prefix.length()); -	set_value(value.to_double()); -	_value_changed(0); +	} + +	Variant value = expr->execute(Array(), NULL, false); +	if (value.get_type() != Variant::NIL) { +		set_value(value); +		_value_changed(0); +	}  }  LineEdit *SpinBox::get_line_edit() { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index be8f1cf36e..292d80be9d 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -840,7 +840,7 @@ Size2 TabContainer::get_minimum_size() const {  		Control *c = tabs[i]; -		if (!c->is_visible_in_tree()) +		if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size)  			continue;  		Size2 cms = c->get_combined_minimum_size(); @@ -887,6 +887,13 @@ int TabContainer::get_tabs_rearrange_group() const {  	return tabs_rearrange_group;  } +void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { +	use_hidden_tabs_for_min_size = p_use_hidden_tabs; +} + +bool TabContainer::get_use_hidden_tabs_for_min_size() const { +	return use_hidden_tabs_for_min_size; +}  void TabContainer::_bind_methods() {  	ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input); @@ -913,6 +920,9 @@ void TabContainer::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group);  	ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group); +	ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size); +	ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size); +  	ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback);  	ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);  	ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); @@ -925,6 +935,7 @@ void TabContainer::_bind_methods() {  	ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); +	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");  	BIND_ENUM_CONSTANT(ALIGN_LEFT);  	BIND_ENUM_CONSTANT(ALIGN_CENTER); @@ -945,4 +956,5 @@ TabContainer::TabContainer() {  	popup = NULL;  	drag_to_rearrange_enabled = false;  	tabs_rearrange_group = -1; +	use_hidden_tabs_for_min_size = false;  } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index f7a9fb64fd..0314f86837 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -59,6 +59,7 @@ private:  	int _get_top_margin() const;  	Popup *popup;  	bool drag_to_rearrange_enabled; +	bool use_hidden_tabs_for_min_size;  	int tabs_rearrange_group;  	Vector<Control *> _get_tabs() const; @@ -118,6 +119,8 @@ public:  	bool get_drag_to_rearrange_enabled() const;  	void set_tabs_rearrange_group(int p_group_id);  	int get_tabs_rearrange_group() const; +	void set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs); +	bool get_use_hidden_tabs_for_min_size() const;  	TabContainer();  };  |