diff options
-rw-r--r-- | doc/classes/ButtonGroup.xml | 4 | ||||
-rw-r--r-- | doc/classes/RichTextLabel.xml | 8 | ||||
-rw-r--r-- | editor/editor_inspector.cpp | 4 | ||||
-rw-r--r-- | editor/editor_log.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 41 | ||||
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 10 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd | 4 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out | 2 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd | 9 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out | 2 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 29 | ||||
-rw-r--r-- | scene/gui/base_button.cpp | 12 | ||||
-rw-r--r-- | scene/gui/base_button.h | 2 | ||||
-rw-r--r-- | scene/gui/rich_text_label.cpp | 20 | ||||
-rw-r--r-- | scene/gui/rich_text_label.h | 2 | ||||
-rw-r--r-- | scene/resources/navigation_mesh.cpp | 26 |
16 files changed, 90 insertions, 87 deletions
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml index 277bda2836..8195669b10 100644 --- a/doc/classes/ButtonGroup.xml +++ b/doc/classes/ButtonGroup.xml @@ -4,8 +4,8 @@ Group of Buttons. </brief_description> <description> - Group of [Button]. All direct and indirect children buttons become radios. Only one allows being pressed. - [member BaseButton.toggle_mode] should be [code]true[/code]. + Group of [BaseButton]. The members of this group are treated like radio buttons in the sense that only one button can be pressed at the same time. + Every member of the ButtonGroup should have [member BaseButton.toggle_mode] set to [code]true[/code]. </description> <tutorials> </tutorials> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index e4bc2db104..dd291a425d 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -378,12 +378,12 @@ Adds a [code][u][/code] tag to the tag stack. </description> </method> - <method name="remove_line"> + <method name="remove_paragraph"> <return type="bool" /> - <param index="0" name="line" type="int" /> + <param index="0" name="paragraph" type="int" /> <description> - Removes a line of content from the label. Returns [code]true[/code] if the line exists. - The [param line] argument is the index of the line to remove, it can take values in the interval [code][0, get_line_count() - 1][/code]. + Removes a paragraph of content from the label. Returns [code]true[/code] if the paragraph exists. + The [param paragraph] argument is the index of the paragraph to remove, it can take values in the interval [code][0, get_paragraph_count() - 1][/code]. </description> </method> <method name="scroll_to_line"> diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index e2ed264645..88a1bbb4a9 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -3856,10 +3856,6 @@ void EditorInspector::_notification(int p_what) { _update_inspector_bg(); } break; - case NOTIFICATION_THEME_CHANGED: { - update_tree(); - } break; - case NOTIFICATION_ENTER_TREE: { if (!sub_inspector) { get_tree()->connect("node_removed", callable_mp(this, &EditorInspector::_node_removed)); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 84284a7f31..a232c83783 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -286,7 +286,7 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool 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 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_paragraph_count() - 2); + log->remove_paragraph(log->get_paragraph_count() - 2); } switch (p_message.type) { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 0aea2b9c16..5102c54785 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -901,18 +901,19 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, member.signal->set_datatype(resolving_datatype); + // This is the _only_ way to declare a signal. Therefore, we can generate its + // MethodInfo inline so it's a tiny bit more efficient. + MethodInfo mi = MethodInfo(member.signal->identifier->name); + for (int j = 0; j < member.signal->parameters.size(); j++) { - GDScriptParser::DataType signal_type = resolve_datatype(member.signal->parameters[j]->datatype_specifier); - signal_type.is_meta_type = false; - member.signal->parameters[j]->set_datatype(signal_type); + GDScriptParser::ParameterNode *param = member.signal->parameters[j]; + GDScriptParser::DataType param_type = resolve_datatype(param->datatype_specifier); + param_type.is_meta_type = false; + param->set_datatype(param_type); + mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name)); + // TODO: add signal parameter default values } - // TODO: Make MethodInfo from signal. - GDScriptParser::DataType signal_type; - signal_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - signal_type.kind = GDScriptParser::DataType::BUILTIN; - signal_type.builtin_type = Variant::SIGNAL; - - member.signal->set_datatype(signal_type); + member.signal->set_datatype(make_signal_type(mi)); // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { @@ -1747,6 +1748,12 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable type = p_variable->initializer->get_datatype(); +#ifdef DEBUG_ENABLED + if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); + } +#endif + if (p_variable->infer_datatype) { type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; @@ -1760,11 +1767,6 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable } else { type.type_source = GDScriptParser::DataType::INFERRED; } -#ifdef DEBUG_ENABLED - if (p_variable->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { - parser->push_warning(p_variable->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_variable->initializer)->function_name); - } -#endif } if (p_variable->datatype_specifier != nullptr) { @@ -1843,7 +1845,7 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant type = p_constant->initializer->get_datatype(); #ifdef DEBUG_ENABLED - if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { + if (p_constant->initializer->type == GDScriptParser::Node::CALL && type.is_hard_type() && type.kind == GDScriptParser::DataType::BUILTIN && type.builtin_type == Variant::NIL) { parser->push_warning(p_constant->initializer, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_constant->initializer)->function_name); } #endif @@ -2331,7 +2333,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig } #ifdef DEBUG_ENABLED - if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { + if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.is_hard_type() && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name); } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) { parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION); @@ -3970,10 +3972,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va result.builtin_type = p_value.get_type(); result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type. - if (p_value.get_type() == Variant::NIL) { - // A null value is a variant, not void. - result.kind = GDScriptParser::DataType::VARIANT; - } else if (p_value.get_type() == Variant::OBJECT) { + if (p_value.get_type() == Variant::OBJECT) { // Object is treated as a native type, not a builtin type. result.kind = GDScriptParser::DataType::NATIVE; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 79387d1bf6..d84af0c63c 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2848,16 +2848,6 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c break; } - GDScriptParser::CompletionContext c = completion_context; - c.current_function = nullptr; - c.current_suite = nullptr; - c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : nullptr; - if (base.type.kind == GDScriptParser::DataType::CLASS) { - c.current_class = base.type.class_type; - } else { - c.current_class = nullptr; - } - _find_identifiers_in_base(base, false, options, 0); } break; case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: { diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd new file mode 100644 index 0000000000..0e1f7256f8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.gd @@ -0,0 +1,4 @@ +signal your_base +signal my_base +func test(): + your_base = my_base diff --git a/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out new file mode 100644 index 0000000000..5275183da2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/assign_signal.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a new value to a constant. diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd new file mode 100644 index 0000000000..39ced354df --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.gd @@ -0,0 +1,9 @@ +# https://github.com/godotengine/godot/issues/61159 + +func get_param(): + return null + +func test(): + var v = get_param() + v = get_param() + print(v) diff --git a/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out new file mode 100644 index 0000000000..f0c83a69b3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/inferred_return_type.out @@ -0,0 +1,2 @@ +GDTEST_OK +<null> diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index cc6fadd9b2..b76e49b86f 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1072,25 +1072,34 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { accum_pass++; bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process. + if (p_delta != 0) { c.seeked = false; } - _animation_process_data(c.current, p_delta, 1.0f, seeked, p_started); + float blend = 1.0; // First animation we play at 100% blend - List<Blend>::Element *prev = nullptr; - for (List<Blend>::Element *E = c.blend.back(); E; E = prev) { + List<Blend>::Element *next = NULL; + for (List<Blend>::Element *E = c.blend.front(); E; E = next) { Blend &b = E->get(); - float blend = b.blend_left / b.blend_time; + // Note: There may be issues if an animation event triggers an animation change while this blend is active, + // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations. + _animation_process_data(b.data, p_delta, blend, false, false); + blend = 1.0 - b.blend_left / b.blend_time; // This is how much to blend the NEXT animation b.blend_left -= Math::absf(speed_scale * p_delta); - prev = E->prev(); + next = E->next(); if (b.blend_left < 0) { - c.blend.erase(E); + // If the blend of this has finished, we need to remove ALL the previous blends + List<Blend>::Element *prev; + while (E) { + prev = E->prev(); + c.blend.erase(E); + E = prev; + } } - // The effect of animation changes during blending is unknown... - // In that case, we recommends to use method call mode "deferred", not "immediate". - _animation_process_data(b.data, p_delta, blend, false, false); } + + _animation_process_data(c.current, p_delta, blend, seeked, p_started); } void AnimationPlayer::_animation_update_transforms() { @@ -1643,6 +1652,8 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa b.data = c.current; b.blend_time = b.blend_left = blend_time; c.blend.push_back(b); + } else { + c.blend.clear(); } } diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ac9034c6fd..9da1fbda1b 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -300,6 +300,7 @@ void BaseButton::set_toggle_mode(bool p_on) { } toggle_mode = p_on; + update_configuration_warnings(); } bool BaseButton::is_toggle_mode() const { @@ -381,6 +382,7 @@ void BaseButton::set_button_group(const Ref<ButtonGroup> &p_group) { } queue_redraw(); //checkbox changes to radio if set a buttongroup + update_configuration_warnings(); } Ref<ButtonGroup> BaseButton::get_button_group() const { @@ -399,6 +401,16 @@ bool BaseButton::is_shortcut_feedback() const { return shortcut_feedback; } +PackedStringArray BaseButton::get_configuration_warnings() const { + PackedStringArray warnings = Control::get_configuration_warnings(); + + if (get_button_group().is_valid() && !is_toggle_mode()) { + warnings.push_back(RTR("ButtonGroup is intended to be used only with buttons that have toggle_mode set to true.")); + } + + return warnings; +} + void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed); ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 3acf535f54..5018aea120 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -136,6 +136,8 @@ public: void set_shortcut_feedback(bool p_feedback); bool is_shortcut_feedback() const; + PackedStringArray get_configuration_warnings() const override; + BaseButton(); ~BaseButton(); }; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index a0f2096009..d5c4fd3f07 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -3071,18 +3071,18 @@ void RichTextLabel::add_newline() { queue_redraw(); } -bool RichTextLabel::remove_line(const int p_line) { +bool RichTextLabel::remove_paragraph(const int p_paragraph) { _stop_thread(); MutexLock data_lock(data_mutex); - if (p_line >= (int)current_frame->lines.size() || p_line < 0) { + if (p_paragraph >= (int)current_frame->lines.size() || p_paragraph < 0) { return false; } // Remove all subitems with the same line as that provided. Vector<int> subitem_indices_to_remove; for (int i = 0; i < current->subitems.size(); i++) { - if (current->subitems[i]->line == p_line) { + if (current->subitems[i]->line == p_paragraph) { subitem_indices_to_remove.push_back(i); } } @@ -3092,17 +3092,17 @@ bool RichTextLabel::remove_line(const int p_line) { for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) { int subitem_idx = subitem_indices_to_remove[i]; had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE; - _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line); + _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_paragraph); } if (!had_newline) { - current_frame->lines.remove_at(p_line); + current_frame->lines.remove_at(p_paragraph); if (current_frame->lines.size() == 0) { current_frame->lines.resize(1); } } - if (p_line == 0 && current->subitems.size() > 0) { + if (p_paragraph == 0 && current->subitems.size() > 0) { main->lines[0].from = main; } @@ -3182,7 +3182,8 @@ void RichTextLabel::push_normal() { void RichTextLabel::push_bold() { ERR_FAIL_COND(theme_cache.bold_font.is_null()); - _push_def_font(BOLD_FONT); + ItemFont *item_font = _find_font(current); + _push_def_font((item_font && item_font->def_font == ITALICS_FONT) ? BOLD_ITALICS_FONT : BOLD_FONT); } void RichTextLabel::push_bold_italics() { @@ -3194,7 +3195,8 @@ void RichTextLabel::push_bold_italics() { void RichTextLabel::push_italics() { ERR_FAIL_COND(theme_cache.italics_font.is_null()); - _push_def_font(ITALICS_FONT); + ItemFont *item_font = _find_font(current); + _push_def_font((item_font && item_font->def_font == BOLD_FONT) ? BOLD_ITALICS_FONT : ITALICS_FONT); } void RichTextLabel::push_mono() { @@ -5313,7 +5315,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0))); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); - ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); + ClassDB::bind_method(D_METHOD("remove_paragraph", "paragraph"), &RichTextLabel::remove_paragraph); ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font); ClassDB::bind_method(D_METHOD("push_font_size", "font_size"), &RichTextLabel::push_font_size); ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 7aa6e6fa2a..a4bc1c8e03 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -573,7 +573,7 @@ public: void add_text(const String &p_text); void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0)); void add_newline(); - bool remove_line(const int p_line); + bool remove_paragraph(const int p_paragraph); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); void _push_def_font(DefaultFont p_def_font); void _push_def_font_var(DefaultFont p_def_font, const Ref<Font> &p_font, int p_size = -1); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 5d9adccaac..bf4291869f 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -590,19 +590,6 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const { #ifndef DISABLE_DEPRECATED bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) { - String prop_name = p_name; - if (prop_name.find("/") != -1) { - // Compatibility with pre-3.5 "category/path" property names. - prop_name = prop_name.replace("/", "_"); - if (prop_name == "sample_partition_type_sample_partition_type") { - set_sample_partition_type((NavigationMesh::SamplePartitionType)p_value.operator int()); - } else if (prop_name == "filter_filter_walkable_low_height_spans") { - set_filter_walkable_low_height_spans(p_value); - } else { - set(prop_name, p_value); - } - return true; - } if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9. set_vertices_per_polygon(p_value); return true; @@ -611,19 +598,6 @@ bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) { } bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const { - String prop_name = p_name; - if (prop_name.find("/") != -1) { - // Compatibility with pre-3.5 "category/path" property names. - prop_name = prop_name.replace("/", "_"); - if (prop_name == "sample_partition_type_sample_partition_type") { - r_ret = get_sample_partition_type(); - } else if (prop_name == "filter_filter_walkable_low_height_spans") { - r_ret = get_filter_walkable_low_height_spans(); - } else { - r_ret = get(prop_name); - } - return true; - } if (p_name == "polygon_verts_per_poly") { // Renamed in 4.0 beta 9. r_ret = get_vertices_per_polygon(); return true; |