summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/object/script_language.h11
-rw-r--r--core/object/script_language_extension.cpp5
-rw-r--r--core/object/script_language_extension.h3
-rw-r--r--doc/classes/ScriptLanguageExtension.xml12
-rw-r--r--editor/plugins/script_editor_plugin.cpp7
-rw-r--r--editor/plugins/script_text_editor.cpp3
-rw-r--r--editor/plugins/script_text_editor.h47
-rw-r--r--modules/gdscript/gdscript_editor.cpp139
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.h10
-rw-r--r--platform/android/export/export_plugin.cpp6
-rw-r--r--platform/android/export/gradle_export_util.cpp8
-rw-r--r--platform/android/java/editor/src/main/AndroidManifest.xml9
-rw-r--r--platform/android/java_godot_io_wrapper.cpp3
-rw-r--r--platform/osx/os_osx.mm33
-rw-r--r--scene/2d/touch_screen_button.cpp4
-rw-r--r--scene/resources/text_line.cpp32
-rw-r--r--scene/resources/text_paragraph.cpp32
17 files changed, 291 insertions, 73 deletions
diff --git a/core/object/script_language.h b/core/object/script_language.h
index 6161a0fc0f..af4f276825 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -311,6 +311,13 @@ public:
CODE_COMPLETION_KIND_MAX
};
+ enum CodeCompletionLocation {
+ LOCATION_LOCAL = 0,
+ LOCATION_PARENT_MASK = 1 << 8,
+ LOCATION_OTHER_USER_CODE = 1 << 9,
+ LOCATION_OTHER = 1 << 10,
+ };
+
struct CodeCompletionOption {
CodeCompletionKind kind = CODE_COMPLETION_KIND_PLAIN_TEXT;
String display;
@@ -319,13 +326,15 @@ public:
RES icon;
Variant default_value;
Vector<Pair<int, int>> matches;
+ int location = LOCATION_OTHER;
CodeCompletionOption() {}
- CodeCompletionOption(const String &p_text, CodeCompletionKind p_kind) {
+ CodeCompletionOption(const String &p_text, CodeCompletionKind p_kind, int p_location = LOCATION_OTHER) {
display = p_text;
insert_text = p_text;
kind = p_kind;
+ location = p_location;
}
};
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index bf0966c803..21d7685674 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -161,6 +161,11 @@ void ScriptLanguageExtension::_bind_methods() {
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX);
+ BIND_ENUM_CONSTANT(LOCATION_LOCAL);
+ BIND_ENUM_CONSTANT(LOCATION_PARENT_MASK);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER_USER_CODE);
+ BIND_ENUM_CONSTANT(LOCATION_OTHER);
+
BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_CLASS);
BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_FUNCTION);
BIND_ENUM_CONSTANT(CODE_COMPLETION_KIND_SIGNAL);
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index b9ec79da26..40f18ab30d 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -387,6 +387,8 @@ public:
option.icon = op["icon"];
ERR_CONTINUE(!op.has("default_value"));
option.default_value = op["default_value"];
+ ERR_CONTINUE(!op.has("location"));
+ option.location = op["location"];
if (op.has("matches")) {
PackedInt32Array matches = op["matches"];
ERR_CONTINUE(matches.size() & 1);
@@ -639,6 +641,7 @@ public:
VARIANT_ENUM_CAST(ScriptLanguageExtension::LookupResultType)
VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionKind)
+VARIANT_ENUM_CAST(ScriptLanguageExtension::CodeCompletionLocation)
class ScriptInstanceExtension : public ScriptInstance {
public:
diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml
index 7225d93030..d66bb6a7c7 100644
--- a/doc/classes/ScriptLanguageExtension.xml
+++ b/doc/classes/ScriptLanguageExtension.xml
@@ -378,6 +378,18 @@
</constant>
<constant name="LOOKUP_RESULT_MAX" value="7" enum="LookupResultType">
</constant>
+ <constant name="LOCATION_LOCAL" value="0" enum="CodeCompletionLocation">
+ The option is local to the location of the code completion query - e.g. a local variable.
+ </constant>
+ <constant name="LOCATION_PARENT_MASK" value="256" enum="CodeCompletionLocation">
+ The option is from the containing class or a parent class, relative to the location of the code completion query. Perform a bitwise OR with the class depth (e.g. 0 for the local class, 1 for the parent, 2 for the grandparent, etc) to store the depth of an option in a the class or a parent class.
+ </constant>
+ <constant name="LOCATION_OTHER_USER_CODE" value="512" enum="CodeCompletionLocation">
+ The option is from user code which is not local and not in a derived class (e.g. Autoload Singletons).
+ </constant>
+ <constant name="LOCATION_OTHER" value="1024" enum="CodeCompletionLocation">
+ The option is from other engine code, not covered by the other enum constants - e.g. built-in classes.
+ </constant>
<constant name="CODE_COMPLETION_KIND_CLASS" value="0" enum="CodeCompletionKind">
</constant>
<constant name="CODE_COMPLETION_KIND_FUNCTION" value="1" enum="CodeCompletionKind">
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index bbaf2bef98..677b55bb88 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1232,9 +1232,6 @@ void ScriptEditor::_menu_option(int p_option) {
if (ResourceLoader::get_resource_type(res_path) == "PackedScene") {
if (!EditorNode::get_singleton()->is_scene_open(res_path)) {
EditorNode::get_singleton()->load_scene(res_path);
- script_editor->call_deferred(SNAME("_menu_option"), p_option);
- previous_scripts.push_back(path); //repeat the operation
- return;
}
} else {
EditorNode::get_singleton()->load_resource(res_path);
@@ -1250,7 +1247,6 @@ void ScriptEditor::_menu_option(int p_option) {
edit(scr);
file_dialog_option = -1;
- return;
} else {
Error error;
Ref<TextFile> text_file = _load_text_file(path, &error);
@@ -1261,7 +1257,6 @@ void ScriptEditor::_menu_option(int p_option) {
if (text_file.is_valid()) {
edit(text_file);
file_dialog_option = -1;
- return;
}
}
} break;
@@ -3960,7 +3955,7 @@ void ScriptEditorPlugin::edit(Object *p_object) {
Script *p_script = Object::cast_to<Script>(p_object);
String res_path = p_script->get_path().get_slice("::", 0);
- if (p_script->is_built_in()) {
+ if (p_script->is_built_in() && !res_path.is_empty()) {
if (ResourceLoader::get_resource_type(res_path) == "PackedScene") {
if (!EditorNode::get_singleton()->is_scene_open(res_path)) {
EditorNode::get_singleton()->load_scene(res_path);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index c1b0a32fc7..4626f10b8d 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -699,6 +699,9 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
}
String hint;
Error err = script->get_language()->complete_code(p_code, script->get_path(), base, r_options, r_force, hint);
+
+ r_options->sort_custom_inplace<CodeCompletionOptionCompare>();
+
if (err == OK) {
code_editor->get_text_editor()->set_code_hint(hint);
}
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 5c3a66404e..c1c4b0af54 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -256,4 +256,51 @@ public:
~ScriptTextEditor();
};
+const int KIND_COUNT = 10;
+// The order in which to sort code completion options.
+const ScriptLanguage::CodeCompletionKind KIND_SORT_ORDER[KIND_COUNT] = {
+ ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE,
+ ScriptLanguage::CODE_COMPLETION_KIND_MEMBER,
+ ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION,
+ ScriptLanguage::CODE_COMPLETION_KIND_ENUM,
+ ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL,
+ ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT,
+ ScriptLanguage::CODE_COMPLETION_KIND_CLASS,
+ ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH,
+ ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH,
+ ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT,
+};
+
+// The custom comparer which will sort completion options.
+struct CodeCompletionOptionCompare {
+ _FORCE_INLINE_ bool operator()(const ScriptLanguage::CodeCompletionOption &l, const ScriptLanguage::CodeCompletionOption &r) const {
+ if (l.location == r.location) {
+ // If locations are same, sort on kind
+ if (l.kind == r.kind) {
+ // If kinds are same, sort alphanumeric
+ return l.display < r.display;
+ }
+
+ // Sort kinds based on the const sorting array defined above. Lower index = higher priority.
+ int l_index = -1;
+ int r_index = -1;
+ for (int i = 0; i < KIND_COUNT; i++) {
+ const ScriptLanguage::CodeCompletionKind kind = KIND_SORT_ORDER[i];
+ l_index = kind == l.kind ? i : l_index;
+ r_index = kind == r.kind ? i : r_index;
+
+ if (l_index != -1 && r_index != -1) {
+ return l_index < r_index;
+ }
+ }
+
+ // This return should never be hit unless something goes wrong.
+ // l and r should always have a Kind which is in the sort order array.
+ return l.display < r.display;
+ }
+
+ return l.location < r.location;
+ }
+};
+
#endif // SCRIPT_TEXT_EDITOR_H
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 5ed4054c57..7f0ffb4586 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -485,6 +485,89 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
};
+// LOCATION METHODS
+// These methods are used to populate the `CodeCompletionOption::location` integer.
+// For these methods, the location is based on the depth in the inheritance chain that the property
+// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D
+// will have a "better" (lower) location "score" than a property that is found on CanvasItem.
+
+static int _get_property_location(StringName p_class, StringName p_property) {
+ if (!ClassDB::has_property(p_class, p_property)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_property(class_test, p_property, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_constant_location(StringName p_class, StringName p_constant) {
+ if (!ClassDB::has_integer_constant(p_class, p_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_signal_location(StringName p_class, StringName p_signal) {
+ if (!ClassDB::has_signal(p_class, p_signal)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_method_location(StringName p_class, StringName p_method) {
+ if (!ClassDB::has_method(p_class, p_method)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_method(class_test, p_method, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) {
+ if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+// END LOCATION METHODS
+
static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) {
if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
String enum_name = p_info.class_name;
@@ -721,18 +804,18 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
const GDScriptParser::ClassNode::Member &member = current->members[i];
switch (member.type) {
case GDScriptParser::ClassNode::Member::CLASS: {
- ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
if (!p_inherit_only) {
- ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) {
- ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
@@ -748,7 +831,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
- ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
@@ -759,7 +842,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") {
continue;
}
- ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
}
@@ -768,10 +851,10 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite,
for (int i = 0; i < p_suite->locals.size(); i++) {
ScriptLanguage::CodeCompletionOption option;
if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
- option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, ScriptLanguage::LOCATION_LOCAL);
option.default_value = p_suite->locals[i].constant->initializer->reduced_value;
} else {
- option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, ScriptLanguage::LOCATION_LOCAL);
}
r_result.insert(option.display, option);
}
@@ -788,8 +871,10 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (!p_parent_only) {
bool outer = false;
const GDScriptParser::ClassNode *clss = p_class;
+ int classes_processed = 0;
while (clss) {
for (int i = 0; i < clss->members.size(); i++) {
+ const int location = (classes_processed + p_recursion_depth) | ScriptLanguage::LOCATION_PARENT_MASK;
const GDScriptParser::ClassNode::Member &member = clss->members[i];
ScriptLanguage::CodeCompletionOption option;
switch (member.type) {
@@ -797,7 +882,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions || outer || (p_static)) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
break;
case GDScriptParser::ClassNode::Member::CONSTANT:
if (p_only_functions) {
@@ -806,7 +891,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (r_result.has(member.constant->identifier->name)) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
if (member.constant->initializer) {
option.default_value = member.constant->initializer->reduced_value;
}
@@ -815,25 +900,25 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE:
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
break;
case GDScriptParser::ClassNode::Member::ENUM:
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
break;
case GDScriptParser::ClassNode::Member::FUNCTION:
if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (member.function->parameters.size() > 0) {
option.insert_text += "(";
} else {
@@ -844,7 +929,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions || outer) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
+ option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
break;
case GDScriptParser::ClassNode::Member::UNDEFINED:
break;
@@ -853,6 +938,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
}
outer = true;
clss = clss->outer;
+ classes_processed++;
}
}
@@ -891,21 +977,24 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<PropertyInfo> members;
scr->get_script_property_list(&members);
for (const PropertyInfo &E : members) {
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
Map<StringName, Variant> constants;
scr->get_constants(&constants);
for (const KeyValue<StringName, Variant> &E : constants) {
- ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key);
+ ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (const MethodInfo &E : signals) {
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
+ int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
r_result.insert(option.display, option);
}
}
@@ -916,7 +1005,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.begins_with("@")) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (E.arguments.size()) {
option.insert_text += "(";
} else {
@@ -946,7 +1036,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<String> constants;
ClassDB::get_integer_constant_list(type, &constants);
for (const String &E : constants) {
- ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(type, StringName(E));
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
@@ -960,7 +1051,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.contains("/")) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(type, E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
@@ -973,7 +1065,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.begins_with("_")) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ int location = p_recursion_depth + _get_method_location(type, E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (E.arguments.size()) {
option.insert_text += "(";
} else {
@@ -982,7 +1075,6 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
r_result.insert(option.display, option);
}
}
-
return;
} break;
case GDScriptParser::DataType::BUILTIN: {
@@ -2242,7 +2334,8 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
for (const StringName &E : enum_constants) {
String candidate = class_name + "." + E;
- ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ int location = _get_enum_constant_location(class_name, E);
+ ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
r_result.insert(option.display, option);
}
}
diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h
index 05e8a565f7..9a1b5f5803 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.h
+++ b/modules/gltf/editor/editor_scene_importer_blend.h
@@ -84,11 +84,11 @@ class Label;
class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery {
GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery);
- ConfirmationDialog *configure_blender_dialog;
- LineEdit *blender_path;
- Button *blender_path_browse;
- EditorFileDialog *browse_dialog;
- Label *path_status;
+ ConfirmationDialog *configure_blender_dialog = nullptr;
+ LineEdit *blender_path = nullptr;
+ Button *blender_path_browse = nullptr;
+ EditorFileDialog *browse_dialog = nullptr;
+ Label *path_status = nullptr;
bool confirmed = false;
String auto_detected_path;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index df3693ba61..69ae8ed74c 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -863,6 +863,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
bool classify_as_game = p_preset->get("package/classify_as_game");
bool retain_data_on_uninstall = p_preset->get("package/retain_data_on_uninstall");
bool exclude_from_recents = p_preset->get("package/exclude_from_recents");
+ bool is_resizeable = p_preset->get("screen/is_resizeable");
Vector<String> perms;
// Write permissions into the perms variable.
@@ -980,6 +981,10 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
encode_uint32(exclude_from_recents, &p_manifest.write[iofs + 16]);
}
+ if (tname == "activity" && attrname == "resizeableActivity") {
+ encode_uint32(is_resizeable, &p_manifest.write[iofs + 16]);
+ }
+
if (tname == "supports-screens") {
if (attrname == "smallScreens") {
encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
@@ -1733,6 +1738,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/is_resizeable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index ab915a5f85..c4cf82de6c 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -253,11 +253,13 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));
String manifest_activity_text = vformat(
" <activity android:name=\"com.godot.game.GodotApp\" "
- "tools:replace=\"android:screenOrientation,android:excludeFromRecents\" "
+ "tools:replace=\"android:screenOrientation,android:excludeFromRecents,android:resizeableActivity\" "
"android:excludeFromRecents=\"%s\" "
- "android:screenOrientation=\"%s\">\n",
+ "android:screenOrientation=\"%s\" "
+ "android:resizeableActivity=\"%s\">\n",
bool_to_string(p_preset->get("package/exclude_from_recents")),
- orientation);
+ orientation,
+ bool_to_string(p_preset->get("screen/is_resizeable")));
if (uses_xr) {
manifest_activity_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"true\" />\n";
} else {
diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml
index 0708ffa32f..bae075d929 100644
--- a/platform/android/java/editor/src/main/AndroidManifest.xml
+++ b/platform/android/java/editor/src/main/AndroidManifest.xml
@@ -29,8 +29,7 @@
android:name=".GodotProjectManager"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:launchMode="singleTask"
- android:resizeableActivity="false"
- android:screenOrientation="landscape"
+ android:screenOrientation="userLandscape"
android:exported="true"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
android:process=":GodotProjectManager">
@@ -46,8 +45,7 @@
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:process=":GodotEditor"
android:launchMode="singleTask"
- android:resizeableActivity="false"
- android:screenOrientation="landscape"
+ android:screenOrientation="userLandscape"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
</activity>
@@ -57,8 +55,7 @@
android:label="@string/godot_project_name_string"
android:process=":GodotGame"
android:launchMode="singleTask"
- android:resizeableActivity="false"
- android:screenOrientation="landscape"
+ android:screenOrientation="userLandscape"
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
</activity>
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index d6e3ad90b1..a5698f4efc 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -198,11 +198,14 @@ void GodotIOJavaWrapper::hide_vk() {
}
void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
+ // The Godot Android Editor sets its own orientation via its AndroidManifest
+#ifndef TOOLS_ENABLED
if (_set_screen_orientation) {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND(env == nullptr);
env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
}
+#endif
}
int GodotIOJavaWrapper::get_screen_orientation() {
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 7e0cf9f9cc..afbd338832 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -313,21 +313,22 @@ String OS_OSX::get_executable_path() const {
}
Error OS_OSX::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
- if (@available(macOS 10.15, *)) {
- // Use NSWorkspace if path is an .app bundle.
- NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
- NSBundle *bundle = [NSBundle bundleWithURL:url];
- if (bundle) {
- NSMutableArray *arguments = [[NSMutableArray alloc] init];
- for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
- [arguments addObject:[NSString stringWithUTF8String:E->get().utf8().get_data()]];
- }
+ // Use NSWorkspace if path is an .app bundle.
+ NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
+ NSBundle *bundle = [NSBundle bundleWithURL:url];
+ if (bundle) {
+ NSMutableArray *arguments = [[NSMutableArray alloc] init];
+ for (const String &arg : p_arguments) {
+ [arguments addObject:[NSString stringWithUTF8String:arg.utf8().get_data()]];
+ }
+ if (@available(macOS 10.15, *)) {
NSWorkspaceOpenConfiguration *configuration = [[NSWorkspaceOpenConfiguration alloc] init];
[configuration setArguments:arguments];
[configuration setCreatesNewApplicationInstance:YES];
__block dispatch_semaphore_t lock = dispatch_semaphore_create(0);
__block Error err = ERR_TIMEOUT;
__block pid_t pid = 0;
+
[[NSWorkspace sharedWorkspace] openApplicationAtURL:url
configuration:configuration
completionHandler:^(NSRunningApplication *app, NSError *error) {
@@ -350,7 +351,19 @@ Error OS_OSX::create_process(const String &p_path, const List<String> &p_argumen
return err;
} else {
- return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console);
+ Error err = ERR_TIMEOUT;
+ NSError *error = nullptr;
+ NSRunningApplication *app = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];
+ if (error) {
+ err = ERR_CANT_FORK;
+ NSLog(@"Failed to execute: %@", error.localizedDescription);
+ } else {
+ if (r_child_id) {
+ *r_child_id = (ProcessID)[app processIdentifier];
+ }
+ err = OK;
+ }
+ return err;
}
} else {
return OS_Unix::create_process(p_path, p_arguments, r_child_id, p_open_console);
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 9a68c17269..4a4a2a1da0 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -190,7 +190,7 @@ String TouchScreenButton::get_action() const {
void TouchScreenButton::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!get_tree()) {
+ if (!is_visible_in_tree()) {
return;
}
@@ -198,8 +198,6 @@ void TouchScreenButton::input(const Ref<InputEvent> &p_event) {
return;
}
- ERR_FAIL_COND(!is_visible_in_tree());
-
const InputEventScreenTouch *st = Object::cast_to<InputEventScreenTouch>(*p_event);
if (passby_press) {
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index db5f1338db..337776fd47 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -327,10 +327,18 @@ void TextLine::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) co
case HORIZONTAL_ALIGNMENT_LEFT:
break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += Math::floor((width - length) / 2.0);
- } else {
- ofs.y += Math::floor((width - length) / 2.0);
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
}
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {
@@ -366,10 +374,18 @@ void TextLine::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_si
case HORIZONTAL_ALIGNMENT_LEFT:
break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += Math::floor((width - length) / 2.0);
- } else {
- ofs.y += Math::floor((width - length) / 2.0);
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
}
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index d74d7c88c6..61adaf43dd 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -609,10 +609,18 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
case HORIZONTAL_ALIGNMENT_LEFT:
break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += Math::floor((l_width - line_width) / 2.0);
- } else {
- ofs.y += Math::floor((l_width - line_width) / 2.0);
+ if (line_width <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - line_width) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - line_width) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - line_width;
+ } else {
+ ofs.y += l_width - line_width;
+ }
}
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {
@@ -701,10 +709,18 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
case HORIZONTAL_ALIGNMENT_LEFT:
break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += Math::floor((l_width - length) / 2.0);
- } else {
- ofs.y += Math::floor((l_width - length) / 2.0);
+ if (length <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
}
} break;
case HORIZONTAL_ALIGNMENT_RIGHT: {