diff options
40 files changed, 322 insertions, 275 deletions
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 8bc2c34c6d..bb1754b810 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -5,6 +5,7 @@ </brief_description> <description> An animation player is used for general-purpose playback of [Animation] resources. It contains a dictionary of animations (referenced by name) and custom blend times between their transitions. Additionally, animations can be played and blended in different channels. + [AnimationPlayer] is more suited than [Tween] for animations where you know the final values in advance. For example, fading a screen in and out is more easily done with an [AnimationPlayer] node thanks to the animation tools provided by the editor. That particular example can also be implemented with a [Tween] node, but it requires doing everything by code. Updating the target properties of animations occurs at process time. </description> <tutorials> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 5f100d918e..89ad8e17db 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -322,7 +322,12 @@ <method name="sort"> <description> Sorts the array. - [b]Note:[/b] strings are sorted in alphabetical, not natural order. + [b]Note:[/b] Strings are sorted in alphabetical order (as opposed to natural order). This may lead to unexpected behavior when sorting an array of strings ending with a sequence of numbers. Consider the following example: + [codeblock] + var strings = ["string1", "string2", "string10", "string11"] + strings.sort() + print(strings) # Prints [string1, string10, string11, string2] + [/codeblock] </description> </method> <method name="sort_custom"> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 5ba159880e..b5c7332bc1 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CheckBox" inherits="Button" version="3.2"> <brief_description> - Binary choice user interface widget. + Binary choice user interface widget. See also [CheckButton]. </brief_description> <description> - A checkbox allows the user to make a binary choice (choosing only one of two possible options). + A checkbox allows the user to make a binary choice (choosing only one of two possible options). It's similar to [CheckButton] in functionality, but it has a different apperance. To follow established UX patterns, it's recommended to use CheckBox when toggling it has [b]no[/b] immediate effect on something. For instance, it should be used when toggling it will only do something once a confirmation button is pressed. </description> <tutorials> </tutorials> @@ -18,41 +18,58 @@ </constants> <theme_items> <theme_item name="check_vadjust" type="int" default="0"> - The vertical offset used when rendering the check icons. + The vertical offset used when rendering the check icons (in pixels). </theme_item> <theme_item name="checked" type="Texture"> + The check icon to display when the [CheckBox] is checked. </theme_item> <theme_item name="disabled" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckBox] is disabled. </theme_item> <theme_item name="focus" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckBox] is focused. </theme_item> <theme_item name="font" type="Font"> + The [Font] to use for the [CheckBox] text. </theme_item> <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + The [CheckBox] text's font color. </theme_item> <theme_item name="font_color_disabled" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + The [CheckBox] text's font color when it's disabled. </theme_item> <theme_item name="font_color_hover" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + The [CheckBox] text's font color when it's hovered. </theme_item> <theme_item name="font_color_hover_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + The [CheckBox] text's font color when it's hovered and pressed. </theme_item> <theme_item name="font_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + The [CheckBox] text's font color when it's pressed. </theme_item> <theme_item name="hover" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckBox] is hovered. </theme_item> <theme_item name="hover_pressed" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckBox] is hovered and pressed. </theme_item> <theme_item name="hseparation" type="int" default="4"> + The separation between the check icon and the text (in pixels). </theme_item> <theme_item name="normal" type="StyleBox"> + The [StyleBox] to display as a background. </theme_item> <theme_item name="pressed" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckBox] is pressed. </theme_item> <theme_item name="radio_checked" type="Texture"> + If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is checked. </theme_item> <theme_item name="radio_unchecked" type="Texture"> + If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is unchecked. </theme_item> <theme_item name="unchecked" type="Texture"> + The check icon to display when the [CheckBox] is unchecked. </theme_item> </theme_items> </class> diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml index e6a890b21f..769acb5d16 100644 --- a/doc/classes/CheckButton.xml +++ b/doc/classes/CheckButton.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CheckButton" inherits="Button" version="3.2"> <brief_description> - Checkable button. + Checkable button. See also [CheckBox]. </brief_description> <description> - CheckButton is a toggle button displayed as a check field. + CheckButton is a toggle button displayed as a check field. It's similar to [CheckBox] in functionality, but it has a different apperance. To follow established UX patterns, it's recommended to use CheckButton when toggling it has an [b]immediate[/b] effect on something. For instance, it should be used if toggling it enables/disables a setting without requiring the user to press a confirmation button. </description> <tutorials> </tutorials> @@ -18,41 +18,58 @@ </constants> <theme_items> <theme_item name="check_vadjust" type="int" default="0"> - The vertical offset used when rendering the icons. + The vertical offset used when rendering the toggle icons (in pixels). </theme_item> <theme_item name="disabled" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckButton] is disabled. </theme_item> <theme_item name="focus" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckButton] is focused. </theme_item> <theme_item name="font" type="Font"> + The [Font] to use for the [CheckButton] text. </theme_item> <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + The [CheckButton] text's font color. </theme_item> <theme_item name="font_color_disabled" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + The [CheckButton] text's font color when it's disabled. </theme_item> <theme_item name="font_color_hover" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + The [CheckButton] text's font color when it's hovered. </theme_item> <theme_item name="font_color_hover_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + The [CheckButton] text's font color when it's hovered and pressed. </theme_item> <theme_item name="font_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + The [CheckButton] text's font color when it's pressed. </theme_item> <theme_item name="hover" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckButton] is hovered. </theme_item> <theme_item name="hover_pressed" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckButton] is hovered and pressed. </theme_item> <theme_item name="hseparation" type="int" default="4"> + The separation between the toggle icon and the text (in pixels). </theme_item> <theme_item name="normal" type="StyleBox"> + The [StyleBox] to display as a background. </theme_item> <theme_item name="off" type="Texture"> + The icon to display when the [CheckButton] is unchecked. </theme_item> <theme_item name="off_disabled" type="Texture"> + The icon to display when the [CheckButton] is unchecked and disabled. </theme_item> <theme_item name="on" type="Texture"> + The icon to display when the [CheckButton] is checked. </theme_item> <theme_item name="on_disabled" type="Texture"> + The icon to display when the [CheckButton] is checked and disabled. </theme_item> <theme_item name="pressed" type="StyleBox"> + The [StyleBox] to display as a background when the [CheckButton] is pressed. </theme_item> </theme_items> </class> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 9345cd059a..97d436c707 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -5,6 +5,7 @@ </brief_description> <description> Tweens are useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them. + [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween] node; it would be difficult to do the same thing with an [AnimationPlayer] node. Here is a brief usage example that causes a 2D node to move smoothly between two positions: [codeblock] var tween = get_node("Tween") diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 24b89aedc2..5dec6f2fee 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -80,7 +80,7 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - String id = "m_" + p_id; + String id = "m_" + p_id.replace("__", "_dus_"); return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl } diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index f43943bdff..4e4d896bd7 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -166,7 +166,7 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - String id = "m_" + p_id; + String id = "m_" + p_id.replace("__", "_dus_"); return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl } diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 4f684c7bdc..e05ace53da 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -277,7 +277,8 @@ void FindReplaceBar::_replace_all() { } text_edit->set_v_scroll(vsval); - set_error(vformat(TTR("Replaced %d occurrence(s)."), rc)); + matches_label->add_color_override("font_color", rc > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); + matches_label->set_text(vformat(TTR("%d replaced."), rc)); text_edit->call_deferred("connect", "text_changed", this, "_editor_text_changed"); results_count = -1; diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 46a54969e0..dba8c2ec8c 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -120,6 +120,7 @@ void EditorAutoloadSettings::_autoload_add() { autoload_add_path->get_line_edit()->set_text(""); autoload_add_name->set_text(""); + add_autoload->set_disabled(true); } void EditorAutoloadSettings::_autoload_selected() { @@ -312,7 +313,34 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) { void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { - autoload_add_name->set_text(p_path.get_file().get_basename()); + // Convert the file name to PascalCase, which is the convention for classes in GDScript. + const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", ""); + + // If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name. + // The prefix is subjective, but it provides better UX than leaving the Add button disabled :) + const String prefix = ClassDB::class_exists(class_name) ? "Global" : ""; + + autoload_add_name->set_text(prefix + class_name); + add_autoload->set_disabled(false); +} + +void EditorAutoloadSettings::_autoload_text_entered(const String p_name) { + + if (autoload_add_path->get_line_edit()->get_text() != "" && _autoload_name_is_valid(p_name, NULL)) { + _autoload_add(); + } +} + +void EditorAutoloadSettings::_autoload_path_text_changed(const String p_path) { + + add_autoload->set_disabled( + p_path == "" || !_autoload_name_is_valid(autoload_add_name->get_text(), NULL)); +} + +void EditorAutoloadSettings::_autoload_text_changed(const String p_name) { + + add_autoload->set_disabled( + autoload_add_path->get_line_edit()->get_text() == "" || !_autoload_name_is_valid(p_name, NULL)); } Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { @@ -424,7 +452,7 @@ void EditorAutoloadSettings::update_autoload() { item->set_editable(2, true); item->set_text(2, TTR("Enable")); item->set_checked(2, info.is_singleton); - item->add_button(3, get_icon("FileList", "EditorIcons"), BUTTON_OPEN); + item->add_button(3, get_icon("Load", "EditorIcons"), BUTTON_OPEN); item->add_button(3, get_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP); item->add_button(3, get_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN); item->add_button(3, get_icon("Remove", "EditorIcons"), BUTTON_DELETE); @@ -713,7 +741,9 @@ void EditorAutoloadSettings::_bind_methods() { ClassDB::bind_method("_autoload_edited", &EditorAutoloadSettings::_autoload_edited); ClassDB::bind_method("_autoload_button_pressed", &EditorAutoloadSettings::_autoload_button_pressed); ClassDB::bind_method("_autoload_activated", &EditorAutoloadSettings::_autoload_activated); + ClassDB::bind_method("_autoload_path_text_changed", &EditorAutoloadSettings::_autoload_path_text_changed); ClassDB::bind_method("_autoload_text_entered", &EditorAutoloadSettings::_autoload_text_entered); + ClassDB::bind_method("_autoload_text_changed", &EditorAutoloadSettings::_autoload_text_changed); ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open); ClassDB::bind_method("_autoload_file_callback", &EditorAutoloadSettings::_autoload_file_callback); @@ -806,6 +836,8 @@ EditorAutoloadSettings::EditorAutoloadSettings() { autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL); autoload_add_path->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE); autoload_add_path->get_file_dialog()->connect("file_selected", this, "_autoload_file_callback"); + autoload_add_path->get_line_edit()->connect("text_changed", this, "_autoload_path_text_changed"); + hbc->add_child(autoload_add_path); l = memnew(Label); @@ -815,11 +847,14 @@ EditorAutoloadSettings::EditorAutoloadSettings() { autoload_add_name = memnew(LineEdit); autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); autoload_add_name->connect("text_entered", this, "_autoload_text_entered"); + autoload_add_name->connect("text_changed", this, "_autoload_text_changed"); hbc->add_child(autoload_add_name); - Button *add_autoload = memnew(Button); + add_autoload = memnew(Button); add_autoload->set_text(TTR("Add")); add_autoload->connect("pressed", this, "_autoload_add"); + // The button will be enabled once a valid name is entered (either automatically or manually). + add_autoload->set_disabled(true); hbc->add_child(add_autoload); tree = memnew(Tree); diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index e1a04644aa..653a1b0a78 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -76,6 +76,7 @@ class EditorAutoloadSettings : public VBoxContainer { Tree *tree; EditorLineEditFileChooser *autoload_add_path; LineEdit *autoload_add_name; + Button *add_autoload; bool _autoload_name_is_valid(const String &p_name, String *r_error = NULL); @@ -84,7 +85,9 @@ class EditorAutoloadSettings : public VBoxContainer { void _autoload_edited(); void _autoload_button_pressed(Object *p_item, int p_column, int p_button); void _autoload_activated(); - void _autoload_text_entered(String) { _autoload_add(); } + void _autoload_path_text_changed(const String p_path); + void _autoload_text_entered(const String p_name); + void _autoload_text_changed(const String p_name); void _autoload_open(const String &fpath); void _autoload_file_callback(const String &p_path); Node *_create_autoload(const String &p_path); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 56da7d93fa..7c1e58862e 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1596,7 +1596,7 @@ void EditorInspector::update_tree() { if (capitalize_paths) cat = cat.capitalize(); - if (!filter.is_subsequence_ofi(cat) && !filter.is_subsequence_ofi(name)) + if (!filter.is_subsequence_ofi(cat) && !filter.is_subsequence_ofi(name) && property_prefix.to_lower().find(filter.to_lower()) == -1) continue; } diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp index 4807f8839c..3fdeaff19d 100644 --- a/editor/editor_profiler.cpp +++ b/editor/editor_profiler.cpp @@ -102,26 +102,28 @@ void EditorProfiler::clear() { } static String _get_percent_txt(float p_value, float p_total) { - if (p_total == 0) + if (p_total == 0) { p_total = 0.00001; + } + return String::num((p_value / p_total) * 100, 1) + "%"; } String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_calls) { - int dmode = display_mode->get_selected(); + const int dmode = display_mode->get_selected(); if (dmode == DISPLAY_FRAME_TIME) { - return rtos(p_time); + return rtos(p_time * 1000).pad_decimals(2) + " ms"; } else if (dmode == DISPLAY_AVERAGE_TIME) { - if (p_calls == 0) - return "0"; - else - return rtos(p_time / p_calls); + if (p_calls == 0) { + return "0.00 ms"; + } else { + return rtos((p_time / p_calls) * 1000).pad_decimals(2) + " ms"; + } } else if (dmode == DISPLAY_FRAME_PERCENT) { return _get_percent_txt(p_time, m.frame_time); } else if (dmode == DISPLAY_PHYSICS_FRAME_PERCENT) { - return _get_percent_txt(p_time, m.physics_frame_time); } @@ -729,7 +731,7 @@ EditorProfiler::EditorProfiler() { h_split->set_v_size_flags(SIZE_EXPAND_FILL); variables = memnew(Tree); - variables->set_custom_minimum_size(Size2(300, 0) * EDSCALE); + variables->set_custom_minimum_size(Size2(320, 0) * EDSCALE); variables->set_hide_folding(true); h_split->add_child(variables); variables->set_hide_root(true); @@ -737,10 +739,10 @@ EditorProfiler::EditorProfiler() { variables->set_column_titles_visible(true); variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); - variables->set_column_min_width(0, 60); + variables->set_column_min_width(0, 60 * EDSCALE); variables->set_column_title(1, TTR("Time")); variables->set_column_expand(1, false); - variables->set_column_min_width(1, 60 * EDSCALE); + variables->set_column_min_width(1, 100 * EDSCALE); variables->set_column_title(2, TTR("Calls")); variables->set_column_expand(2, false); variables->set_column_min_width(2, 60 * EDSCALE); @@ -749,7 +751,6 @@ EditorProfiler::EditorProfiler() { graph = memnew(TextureRect); graph->set_expand(true); graph->set_mouse_filter(MOUSE_FILTER_STOP); - //graph->set_ignore_mouse(false); graph->connect("draw", this, "_graph_tex_draw"); graph->connect("gui_input", this, "_graph_tex_input"); graph->connect("mouse_exited", this, "_graph_tex_mouse_exit"); @@ -760,13 +761,10 @@ EditorProfiler::EditorProfiler() { int metric_size = CLAMP(int(EDITOR_DEF("debugger/profiler_frame_history_size", 600)), 60, 1024); frame_metrics.resize(metric_size); last_metric = -1; - //cursor_metric=-1; hover_metric = -1; EDITOR_DEF("debugger/profiler_frame_max_functions", 64); - //display_mode=DISPLAY_FRAME_TIME; - frame_delay = memnew(Timer); frame_delay->set_wait_time(0.1); frame_delay->set_one_shot(true); @@ -784,6 +782,4 @@ EditorProfiler::EditorProfiler() { seeking = false; graph_height = 1; - - //activate->set_disabled(true); } diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 28825b45e1..2090c12c91 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -245,6 +245,9 @@ void SectionedInspector::update_category_list() { if (pi.name.find(":") != -1 || pi.name == "script" || pi.name == "resource_name" || pi.name == "resource_path" || pi.name == "resource_local_to_scene" || pi.name.begins_with("_global_script")) continue; + if (!filter.empty() && !filter.is_subsequence_ofi(pi.name) && !filter.is_subsequence_ofi(pi.name.replace("/", " ").capitalize())) + continue; + int sp = pi.name.find("/"); if (sp == -1) pi.name = "global/" + pi.name; @@ -252,9 +255,6 @@ void SectionedInspector::update_category_list() { Vector<String> sectionarr = pi.name.split("/"); String metasection; - if (!filter.empty() && !filter.is_subsequence_ofi(sectionarr[sectionarr.size() - 1].capitalize())) - continue; - int sc = MIN(2, sectionarr.size() - 1); for (int i = 0; i < sc; i++) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 621f531687..8037045e77 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -89,7 +89,11 @@ Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float // dumb gizmo check bool is_gizmo = String(editor_icons_names[p_index]).begins_with("Gizmo"); - ImageLoaderSVG::create_image_from_string(img, editor_icons_sources[p_index], p_scale, true, p_convert_color); + // Upsample icon generation only if the editor scale isn't an integer multiplier. + // Generating upsampled icons is slower, and the benefit is hardly visible + // with integer editor scales. + const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale); + ImageLoaderSVG::create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_color); if ((p_scale - (float)((int)p_scale)) > 0.0 || is_gizmo || p_force_filter) icon->create_from_image(img); // in this case filter really helps @@ -106,7 +110,15 @@ Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false) { #ifdef SVG_ENABLED + // The default icon theme is designed to be used for a dark theme. + // This dictionary stores color codes to convert to other colors + // for better readability on a light theme. Dictionary dark_icon_color_dictionary; + + // The names of the icons to never convert, even if one of their colors + // are contained in the dictionary above. + Set<StringName> exceptions; + if (!p_dark_theme) { // convert color: FROM TO ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // common icon color @@ -172,9 +184,31 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#69ec9a", "#2ce573"); // VS rid ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#79f3e8", "#12d5c3"); // VS object ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#77edb1", "#57e99f"); // VS dict + + exceptions.insert("EditorPivot"); + exceptions.insert("EditorHandle"); + exceptions.insert("Editor3DHandle"); + exceptions.insert("Godot"); + exceptions.insert("PanoramaSky"); + exceptions.insert("ProceduralSky"); + exceptions.insert("EditorControlAnchor"); + exceptions.insert("DefaultProjectIcon"); + exceptions.insert("GuiCloseCustomizable"); + exceptions.insert("GuiGraphNodePort"); + exceptions.insert("GuiResizer"); + exceptions.insert("ZoomMore"); + exceptions.insert("ZoomLess"); + exceptions.insert("ZoomReset"); + exceptions.insert("LockViewport"); + exceptions.insert("GroupViewport"); + exceptions.insert("StatusError"); + exceptions.insert("StatusSuccess"); + exceptions.insert("StatusWarning"); + exceptions.insert("NodeWarning"); + exceptions.insert("OverbrightIndicator"); } - // these ones should be converted even if we are using a dark theme + // These ones should be converted even if we are using a dark theme. const Color error_color = p_theme->get_color("error_color", "Editor"); const Color success_color = p_theme->get_color("success_color", "Editor"); const Color warning_color = p_theme->get_color("warning_color", "Editor"); @@ -182,65 +216,44 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color; dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color; - List<String> exceptions; - exceptions.push_back("EditorPivot"); - exceptions.push_back("EditorHandle"); - exceptions.push_back("Editor3DHandle"); - exceptions.push_back("Godot"); - exceptions.push_back("PanoramaSky"); - exceptions.push_back("ProceduralSky"); - exceptions.push_back("EditorControlAnchor"); - exceptions.push_back("DefaultProjectIcon"); - exceptions.push_back("GuiCloseCustomizable"); - exceptions.push_back("GuiGraphNodePort"); - exceptions.push_back("GuiResizer"); - exceptions.push_back("ZoomMore"); - exceptions.push_back("ZoomLess"); - exceptions.push_back("ZoomReset"); - exceptions.push_back("LockViewport"); - exceptions.push_back("GroupViewport"); - exceptions.push_back("StatusError"); - exceptions.push_back("StatusSuccess"); - exceptions.push_back("StatusWarning"); - exceptions.push_back("NodeWarning"); - exceptions.push_back("OverbrightIndicator"); - ImageLoaderSVG::set_convert_colors(&dark_icon_color_dictionary); - // generate icons - if (!p_only_thumbs) + // Generate icons. + if (!p_only_thumbs) { for (int i = 0; i < editor_icons_count; i++) { - List<String>::Element *is_exception = exceptions.find(editor_icons_names[i]); - if (is_exception) exceptions.erase(is_exception); - Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception); + const int is_exception = exceptions.has(editor_icons_names[i]); + const Ref<ImageTexture> icon = editor_generate_icon(i, !is_exception); + p_theme->set_icon(editor_icons_names[i], "EditorIcons", icon); } + } - // generate thumb files with the given thumb size - bool force_filter = p_thumb_size != 64 && p_thumb_size != 32; // we don't need filter with original resolution + // Generate thumbnail icons with the given thumbnail size. + // We don't need filtering when generating at one of the default resolutions. + const bool force_filter = p_thumb_size != 64 && p_thumb_size != 32; if (p_thumb_size >= 64) { - float scale = (float)p_thumb_size / 64.0 * EDSCALE; + const float scale = (float)p_thumb_size / 64.0 * EDSCALE; for (int i = 0; i < editor_bg_thumbs_count; i++) { - int index = editor_bg_thumbs_indices[i]; - List<String>::Element *is_exception = exceptions.find(editor_icons_names[index]); - if (is_exception) exceptions.erase(is_exception); - Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter); + const int index = editor_bg_thumbs_indices[i]; + const int is_exception = exceptions.has(editor_icons_names[index]); + const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter); + p_theme->set_icon(editor_icons_names[index], "EditorIcons", icon); } } else { - float scale = (float)p_thumb_size / 32.0 * EDSCALE; + const float scale = (float)p_thumb_size / 32.0 * EDSCALE; for (int i = 0; i < editor_md_thumbs_count; i++) { - int index = editor_md_thumbs_indices[i]; - List<String>::Element *is_exception = exceptions.find(editor_icons_names[index]); - if (is_exception) exceptions.erase(is_exception); - Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter); + const int index = editor_md_thumbs_indices[i]; + const bool is_exception = exceptions.has(editor_icons_names[index]); + const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter); + p_theme->set_icon(editor_icons_names[index], "EditorIcons", icon); } } ImageLoaderSVG::set_convert_colors(NULL); #else - print_line("SVG support disabled, editor icons won't be rendered."); + WARN_PRINT("SVG support disabled, editor icons won't be rendered."); #endif } diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 2be3464d30..b65482cc6b 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -584,6 +584,7 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { add_child(warning); warning->set_text(TTR("Changes may be lost!")); warning->set_icon(get_icon("NodeWarning", "EditorIcons")); + warning->set_clip_text(true); warning->hide(); warning->connect("pressed", this, "_warning_pressed"); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 32fcdab4c6..7586f6eac1 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -109,9 +109,13 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und const int feature_min_height = 160 * EDSCALE; - CheckButton *chk_collapse_features = memnew(CheckButton); - chk_collapse_features->set_text(TTR("Advanced Options")); - vbc->add_child(chk_collapse_features); + cbut_regex = memnew(CheckButton); + cbut_regex->set_text(TTR("Use Regular Expressions")); + vbc->add_child(cbut_regex); + + CheckButton *cbut_collapse_features = memnew(CheckButton); + cbut_collapse_features->set_text(TTR("Advanced Options")); + vbc->add_child(cbut_collapse_features); tabc_features = memnew(TabContainer); tabc_features->set_tab_align(TabContainer::ALIGN_LEFT); @@ -195,7 +199,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und grd_substitute->add_child(but_insert_count); chk_per_level_counter = memnew(CheckBox); - chk_per_level_counter->set_text(TTR("Per Level counter")); + chk_per_level_counter->set_text(TTR("Per-level Counter")); chk_per_level_counter->set_tooltip(TTR("If set the counter restarts for each group of child nodes")); vbc_substitute->add_child(chk_per_level_counter); @@ -233,18 +237,6 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und spn_count_padding->set_step(1); hbc_count_options->add_child(spn_count_padding); - // ---- Tab RegEx - - VBoxContainer *vbc_regex = memnew(VBoxContainer); - vbc_regex->set_h_size_flags(SIZE_EXPAND_FILL); - vbc_regex->set_name(TTR("Regular Expressions")); - vbc_regex->set_custom_minimum_size(Size2(0, feature_min_height)); - tabc_features->add_child(vbc_regex); - - cbut_regex = memnew(CheckBox); - cbut_regex->set_text(TTR("Regular Expressions")); - vbc_regex->add_child(cbut_regex); - // ---- Tab Process VBoxContainer *vbc_process = memnew(VBoxContainer); @@ -268,8 +260,8 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und opt_style = memnew(OptionButton); opt_style->add_item(TTR("Keep")); - opt_style->add_item(TTR("CamelCase to under_scored")); - opt_style->add_item(TTR("under_scored to CamelCase")); + opt_style->add_item(TTR("PascalCase to snake_case")); + opt_style->add_item(TTR("snake_case to PascalCase")); hbc_style->add_child(opt_style); // ------ Case @@ -299,7 +291,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und lbl_preview = memnew(Label); lbl_preview->set_text(""); - lbl_preview->add_color_override("font_color", Color(1, 0.5f, 0, 1)); + lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); vbc->add_child(lbl_preview); // ---- Dialog related @@ -314,7 +306,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und // ---- Connections - chk_collapse_features->connect("toggled", this, "_features_toggled"); + cbut_collapse_features->connect("toggled", this, "_features_toggled"); // Substitite Buttons @@ -414,9 +406,12 @@ void RenameDialog::_update_preview(String new_text) { lbl_preview->set_text(new_name); if (new_name == preview_node->get_name()) { - lbl_preview->add_color_override("font_color", Color(0, 0.5f, 0.25f, 1)); + // New name is identical to the old one. Don't color it as much to avoid distracting the user. + const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_color("accent_color", "Editor"); + const Color text_color = EditorNode::get_singleton()->get_gui_base()->get_color("default_color", "RichTextLabel"); + lbl_preview->add_color_override("font_color", accent_color.linear_interpolate(text_color, 0.5)); } else { - lbl_preview->add_color_override("font_color", Color(0, 1, 0.5f, 1)); + lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("success_color", "Editor")); } } @@ -501,9 +496,9 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char * } self->has_errors = true; - self->lbl_preview_title->set_text(TTR("Error")); - self->lbl_preview->add_color_override("font_color", Color(1, 0.25f, 0, 1)); - self->lbl_preview->set_text(err_str); + self->lbl_preview_title->set_text(TTR("Regular Expression Error")); + self->lbl_preview->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + self->lbl_preview->set_text(vformat(TTR("At character %s"), err_str)); } String RenameDialog::_regex(const String &pattern, const String &subject, const String &replacement) { @@ -520,18 +515,18 @@ String RenameDialog::_postprocess(const String &subject) { String result = subject; if (style_id == 1) { + // PascalCase to snake_case - // CamelCase to Under_Line result = result.camelcase_to_underscore(true); result = _regex("_+", result, "_"); } else if (style_id == 2) { + // snake_case to PascalCase - // Under_Line to CamelCase RegEx pattern("_+(.?)"); Array matches = pattern.search_all(result); - // _ name would become empty. Ignore + // The name `_` would become empty; ignore it. if (matches.size() && result != "_") { String buffer; int start = 0; diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h index 692e56f1a4..2825cb2cd2 100644 --- a/editor/rename_dialog.h +++ b/editor/rename_dialog.h @@ -75,7 +75,7 @@ class RenameDialog : public ConfirmationDialog { TabContainer *tabc_features; CheckBox *cbut_substitute; - CheckBox *cbut_regex; + CheckButton *cbut_regex; CheckBox *cbut_process; CheckBox *chk_per_level_counter; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 35d5fe5f70..a982724d4c 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -644,7 +644,7 @@ void ScriptCreateDialog::_update_dialog() { } if (script_ok) { - _msg_script_valid(true, TTR("Script is valid.")); + _msg_script_valid(true, TTR("Script path/name is valid.")); } // Does script have named classes? diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 71a946b256..ab4501bb8a 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -484,8 +484,10 @@ int ScriptEditorDebugger::_update_scene_tree(TreeItem *parent, const Array &node void ScriptEditorDebugger::_video_mem_request() { - ERR_FAIL_COND(connection.is_null()); - ERR_FAIL_COND(!connection->is_connected_to_host()); + if (connection.is_null() || !connection->is_connected_to_host()) { + // Video RAM usage is only available while a project is being debugged. + return; + } Array msg; msg.push_back("request_video_mem"); @@ -806,25 +808,25 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da p.write[i] = arr[i]; if (i < perf_items.size()) { - float v = p[i]; - String vs = rtos(v); - String tt = vs; + const float value = p[i]; + String label = rtos(value); + String tooltip = label; switch (Performance::MonitorType((int)perf_items[i]->get_metadata(1))) { case Performance::MONITOR_TYPE_MEMORY: { - vs = String::humanize_size(v); - tt = vs; + label = String::humanize_size(value); + tooltip = label; } break; case Performance::MONITOR_TYPE_TIME: { - tt += " seconds"; - vs += " s"; + label = rtos(value * 1000).pad_decimals(2) + " ms"; + tooltip = label; } break; default: { - tt += " " + perf_items[i]->get_text(0); + tooltip += " " + perf_items[i]->get_text(0); } break; } - perf_items[i]->set_text(1, vs); - perf_items[i]->set_tooltip(1, tt); + perf_items[i]->set_text(1, label); + perf_items[i]->set_tooltip(1, tooltip); if (p[i] > perf_max[i]) perf_max.write[i] = p[i]; } @@ -1323,6 +1325,7 @@ void ScriptEditorDebugger::_notification(int p_what) { inspect_scene_tree->clear(); le_set->set_disabled(true); le_clear->set_disabled(false); + vmem_refresh->set_disabled(false); error_tree->clear(); error_count = 0; warning_count = 0; @@ -1523,6 +1526,7 @@ void ScriptEditorDebugger::stop() { le_clear->set_disabled(false); le_set->set_disabled(true); profiler->set_enabled(true); + vmem_refresh->set_disabled(true); inspect_scene_tree->clear(); inspector->edit(NULL); @@ -1622,6 +1626,7 @@ void ScriptEditorDebugger::_output_clear() { void ScriptEditorDebugger::_export_csv() { file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); file_dialog_mode = SAVE_CSV; file_dialog->popup_centered_ratio(); } @@ -2187,6 +2192,13 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) { } } +void ScriptEditorDebugger::_tab_changed(int p_tab) { + if (tabs->get_tab_title(p_tab) == TTR("Video RAM")) { + // "Video RAM" tab was clicked, refresh the data it's dislaying when entering the tab. + _video_mem_request(); + } +} + void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected); @@ -2218,6 +2230,7 @@ void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_error_tree_item_rmb_selected"), &ScriptEditorDebugger::_error_tree_item_rmb_selected); ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &ScriptEditorDebugger::_item_menu_id_pressed); + ClassDB::bind_method(D_METHOD("_tab_changed"), &ScriptEditorDebugger::_tab_changed); ClassDB::bind_method(D_METHOD("_paused"), &ScriptEditorDebugger::_paused); @@ -2258,13 +2271,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles")); tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles")); tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles")); + tabs->connect("tab_changed", this, "_tab_changed"); add_child(tabs); { //debugger VBoxContainer *vbc = memnew(VBoxContainer); vbc->set_name(TTR("Debugger")); - //tabs->add_child(vbc); Control *dbg = vbc; HBoxContainer *hbc = memnew(HBoxContainer); @@ -2522,6 +2535,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { vmem_total->set_custom_minimum_size(Size2(100, 0) * EDSCALE); vmem_hb->add_child(vmem_total); vmem_refresh = memnew(ToolButton); + vmem_refresh->set_disabled(true); vmem_hb->add_child(vmem_refresh); vmem_vb->add_child(vmem_hb); vmem_refresh->connect("pressed", this, "_video_mem_request"); @@ -2534,20 +2548,20 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { vmmc->set_v_size_flags(SIZE_EXPAND_FILL); vmem_vb->add_child(vmmc); - vmem_vb->set_name(TTR("Video Mem")); + vmem_vb->set_name(TTR("Video RAM")); vmem_tree->set_columns(4); vmem_tree->set_column_titles_visible(true); vmem_tree->set_column_title(0, TTR("Resource Path")); vmem_tree->set_column_expand(0, true); vmem_tree->set_column_expand(1, false); vmem_tree->set_column_title(1, TTR("Type")); - vmem_tree->set_column_min_width(1, 100); + vmem_tree->set_column_min_width(1, 100 * EDSCALE); vmem_tree->set_column_expand(2, false); vmem_tree->set_column_title(2, TTR("Format")); - vmem_tree->set_column_min_width(2, 150); + vmem_tree->set_column_min_width(2, 150 * EDSCALE); vmem_tree->set_column_expand(3, false); vmem_tree->set_column_title(3, TTR("Usage")); - vmem_tree->set_column_min_width(3, 80); + vmem_tree->set_column_min_width(3, 80 * EDSCALE); vmem_tree->set_hide_root(true); tabs->add_child(vmem_vb); diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index 7d91e247b6..589a011bff 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -226,6 +226,7 @@ private: void _error_tree_item_rmb_selected(const Vector2 &p_pos); void _item_menu_id_pressed(int p_option); + void _tab_changed(int p_tab); void _export_csv(); diff --git a/main/main.cpp b/main/main.cpp index 88d4dcc1fc..3cc809b813 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1900,6 +1900,8 @@ bool Main::start() { ProgressDialog *progress_dialog = memnew(ProgressDialog); pmanager->add_child(progress_dialog); sml->get_root()->add_child(pmanager); + // Speed up rendering slightly by disabling 3D features while in the project manager. + sml->get_root()->set_usage(Viewport::USAGE_2D_NO_SAMPLING); OS::get_singleton()->set_context(OS::CONTEXT_PROJECTMAN); project_manager = true; } diff --git a/misc/dist/linux/godot.6 b/misc/dist/linux/godot.6 index 80dcfc80b3..00d19c5178 100644 --- a/misc/dist/linux/godot.6 +++ b/misc/dist/linux/godot.6 @@ -1,4 +1,4 @@ -.TH GODOT "6" "January 2020" "godot 3.2" "Games" +.TH GODOT "6" "January 2020" "godot 4.0" "Games" .SH NAME godot \- multi\-platform 2D and 3D game engine with a feature\-rich editor .SH SYNOPSIS diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist index 46d2d4cb6e..46550ba6c7 100755 --- a/misc/dist/osx_tools.app/Contents/Info.plist +++ b/misc/dist/osx_tools.app/Contents/Info.plist @@ -19,11 +19,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>3.2</string> + <string>4.0</string> <key>CFBundleSignature</key> <string>godot</string> <key>CFBundleVersion</key> - <string>3.2</string> + <string>4.0</string> <key>NSMicrophoneUsageDescription</key> <string>Microphone access is required to capture audio.</string> <key>NSCameraUsageDescription</key> diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub index 0cdd585558..a18c75fa27 100644 --- a/modules/gdnative/SCsub +++ b/modules/gdnative/SCsub @@ -30,23 +30,3 @@ _, gensource = env_gdnative.CommandNoCache(['include/gdnative_api_struct.gen.h', env_gdnative.add_source_files(env.modules_sources, [gensource]) env.use_ptrcall = True - - -if ARGUMENTS.get('gdnative_wrapper', False): - gensource, = env_gdnative.CommandNoCache('gdnative_wrapper_code.gen.cpp', 'gdnative_api.json', run_in_subprocess(gdnative_builders.build_gdnative_wrapper_code)) - - gd_wrapper_env = env.Clone() - gd_wrapper_env.Prepend(CPPPATH=['#modules/gdnative/include/']) - - if gd_wrapper_env['use_lto']: - if not env.msvc: - gd_wrapper_env.Append(CCFLAGS=['-fno-lto']) - gd_wrapper_env.Append(LINKFLAGS=['-fno-lto']) - else: - gd_wrapper_env.Append(CCFLAGS=['/GL-']) - gd_wrapper_env.Append(LINKFLAGS=['/LTCG:OFF']) - - if not env.msvc: - gd_wrapper_env.Append(CCFLAGS=['-fPIC']) - - lib = gd_wrapper_env.add_library("#bin/gdnative_wrapper_code", [gensource]) diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py index 20c1a2233c..0d95a65b7e 100644 --- a/modules/gdnative/gdnative_builders.py +++ b/modules/gdnative/gdnative_builders.py @@ -12,30 +12,6 @@ def _spaced(e): def _build_gdnative_api_struct_header(api): - gdnative_api_init_macro = [ - '\textern const godot_gdnative_core_api_struct *_gdnative_wrapper_api_struct;' - ] - - for ext in api['extensions']: - name = ext['name'] - gdnative_api_init_macro.append( - '\textern const godot_gdnative_ext_{0}_api_struct *_gdnative_wrapper_{0}_api_struct;'.format(name)) - - gdnative_api_init_macro.append('\t_gdnative_wrapper_api_struct = options->api_struct;') - gdnative_api_init_macro.append('\tfor (unsigned int i = 0; i < _gdnative_wrapper_api_struct->num_extensions; i++) { ') - gdnative_api_init_macro.append('\t\tswitch (_gdnative_wrapper_api_struct->extensions[i]->type) {') - - for ext in api['extensions']: - name = ext['name'] - gdnative_api_init_macro.append( - '\t\t\tcase GDNATIVE_EXT_%s:' % ext['type']) - gdnative_api_init_macro.append( - '\t\t\t\t_gdnative_wrapper_{0}_api_struct = (godot_gdnative_ext_{0}_api_struct *)' - ' _gdnative_wrapper_api_struct->extensions[i];'.format(name)) - gdnative_api_init_macro.append('\t\t\t\tbreak;') - gdnative_api_init_macro.append('\t\t}') - gdnative_api_init_macro.append('\t}') - out = [ '/* THIS FILE IS GENERATED DO NOT EDIT */', '#ifndef GODOT_GDNATIVE_API_STRUCT_H', @@ -49,8 +25,6 @@ def _build_gdnative_api_struct_header(api): '#include <pluginscript/godot_pluginscript.h>', '#include <videodecoder/godot_videodecoder.h>', '', - '#define GDNATIVE_API_INIT(options) do { \\\n' + ' \\\n'.join(gdnative_api_init_macro) + ' \\\n } while (0)', - '', '#ifdef __cplusplus', 'extern "C" {', '#endif', @@ -238,76 +212,5 @@ def build_gdnative_api_struct(target, source, env): fd.write(_build_gdnative_api_struct_source(api)) -def _build_gdnative_wrapper_code(api): - out = [ - '/* THIS FILE IS GENERATED DO NOT EDIT */', - '', - '#include <gdnative/gdnative.h>', - '#include <nativescript/godot_nativescript.h>', - '#include <pluginscript/godot_pluginscript.h>', - '#include <arvr/godot_arvr.h>', - '#include <videodecoder/godot_videodecoder.h>', - '', - '#include <gdnative_api_struct.gen.h>', - '', - '#ifdef __cplusplus', - 'extern "C" {', - '#endif', - '', - 'godot_gdnative_core_api_struct *_gdnative_wrapper_api_struct = 0;', - ] - - for ext in api['extensions']: - name = ext['name'] - out.append('godot_gdnative_ext_' + name + '_api_struct *_gdnative_wrapper_' + name + '_api_struct = 0;') - - out += [''] - - for funcdef in api['core']['api']: - args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']]) - out.append('%s%s(%s) {' % (_spaced(funcdef['return_type']), funcdef['name'], args)) - - args = ', '.join(['%s' % n for t, n in funcdef['arguments']]) - - return_line = '\treturn ' if funcdef['return_type'] != 'void' else '\t' - return_line += '_gdnative_wrapper_api_struct->' + funcdef['name'] + '(' + args + ');' - - out.append(return_line) - out.append('}') - out.append('') - - for ext in api['extensions']: - name = ext['name'] - for funcdef in ext['api']: - args = ', '.join(['%s%s' % (_spaced(t), n) for t, n in funcdef['arguments']]) - out.append('%s%s(%s) {' % (_spaced(funcdef['return_type']), funcdef['name'], args)) - - args = ', '.join(['%s' % n for t, n in funcdef['arguments']]) - - return_line = '\treturn ' if funcdef['return_type'] != 'void' else '\t' - return_line += '_gdnative_wrapper_' + name + '_api_struct->' + funcdef['name'] + '(' + args + ');' - - out.append(return_line) - out.append('}') - out.append('') - - out += [ - '#ifdef __cplusplus', - '}', - '#endif' - ] - - return '\n'.join(out) - - -def build_gdnative_wrapper_code(target, source, env): - with open(source[0], 'r') as fd: - api = json.load(fd) - - wrapper_file = target[0] - with open(wrapper_file, 'w') as fd: - fd.write(_build_gdnative_wrapper_code(api)) - - if __name__ == '__main__': subprocess_main(globals()) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs index 5023725f17..5d16260f5d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs @@ -9,7 +9,7 @@ namespace Godot public T GetNodeOrNull<T>(NodePath path) where T : class { - return GetNode(path) as T; + return GetNodeOrNull(path) as T; } public T GetChild<T>(int idx) where T : class diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index f4f54901fb..f500925f75 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -117,7 +117,8 @@ Difference in period between [member octaves]. </member> <member name="octaves" type="int" setter="set_octaves" getter="get_octaves" default="3"> - Number of OpenSimplex noise layers that are sampled to get the fractal noise. + Number of OpenSimplex noise layers that are sampled to get the fractal noise. Higher values result in more detailed noise but take more time to generate. + [b]Note:[/b] The maximum allowed value is 9. </member> <member name="period" type="float" setter="set_period" getter="get_period" default="64.0"> Period of the base octave. A lower period results in a higher-frequency noise (more value changes across the same distance). diff --git a/modules/opensimplex/open_simplex_noise.cpp b/modules/opensimplex/open_simplex_noise.cpp index c99588aefa..bd187e6b5b 100644 --- a/modules/opensimplex/open_simplex_noise.cpp +++ b/modules/opensimplex/open_simplex_noise.cpp @@ -47,7 +47,7 @@ OpenSimplexNoise::~OpenSimplexNoise() { } void OpenSimplexNoise::_init_seeds() { - for (int i = 0; i < 6; ++i) { + for (int i = 0; i < MAX_OCTAVES; ++i) { open_simplex_noise(seed + i * 2, &(contexts[i])); } } @@ -71,7 +71,10 @@ int OpenSimplexNoise::get_seed() { void OpenSimplexNoise::set_octaves(int p_octaves) { if (p_octaves == octaves) return; - octaves = CLAMP(p_octaves, 1, 6); + + ERR_FAIL_COND_MSG(p_octaves > MAX_OCTAVES, vformat("The number of OpenSimplexNoise octaves is limited to %d; ignoring the new value.", MAX_OCTAVES)); + + octaves = CLAMP(p_octaves, 1, MAX_OCTAVES); emit_changed(); } @@ -182,7 +185,7 @@ void OpenSimplexNoise::_bind_methods() { ClassDB::bind_method(D_METHOD("get_noise_3dv", "pos"), &OpenSimplexNoise::get_noise_3dv); ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "octaves", PROPERTY_HINT_RANGE, "1,6,1"), "set_octaves", "get_octaves"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "octaves", PROPERTY_HINT_RANGE, vformat("1,%d,1", MAX_OCTAVES)), "set_octaves", "get_octaves"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "period", PROPERTY_HINT_RANGE, "0.1,256.0,0.1"), "set_period", "get_period"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "persistence", PROPERTY_HINT_RANGE, "0.0,1.0,0.001"), "set_persistence", "get_persistence"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "lacunarity", PROPERTY_HINT_RANGE, "0.1,4.0,0.01"), "set_lacunarity", "get_lacunarity"); diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h index 89b12253b9..dce62bc1f9 100644 --- a/modules/opensimplex/open_simplex_noise.h +++ b/modules/opensimplex/open_simplex_noise.h @@ -37,11 +37,16 @@ #include "thirdparty/misc/open-simplex-noise.h" +// The maximum number of octaves allowed. Note that these are statically allocated. +// Higher values become exponentially slower, so this shouldn't be set too high +// to avoid freezing the editor for long periods of time. +#define MAX_OCTAVES 9 + class OpenSimplexNoise : public Resource { GDCLASS(OpenSimplexNoise, Resource); OBJ_SAVE_TYPE(OpenSimplexNoise); - osn_context contexts[6]; + osn_context contexts[MAX_OCTAVES]; int seed; float persistence; // Controls details, value in [0,1]. Higher increases grain, lower increases smoothness. diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 57097aaa06..11ae2f81bf 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -103,15 +103,17 @@ Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const PoolVector<uint8_t ERR_PRINT("SVG Corrupted"); return ERR_FILE_CORRUPT; } - if (convert_colors) + + if (convert_colors) { _convert_colors(svg_image); + } - float upscale = upsample ? 2.0 : 1.0; + const float upscale = upsample ? 2.0 : 1.0; - int w = (int)(svg_image->width * p_scale * upscale); + const int w = (int)(svg_image->width * p_scale * upscale); ERR_FAIL_COND_V_MSG(w > Image::MAX_WIDTH, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max width.", rtos(p_scale))); - int h = (int)(svg_image->height * p_scale * upscale); + const int h = (int)(svg_image->height * p_scale * upscale); ERR_FAIL_COND_V_MSG(h > Image::MAX_HEIGHT, ERR_PARAMETER_RANGE_ERROR, vformat("Can't create image from SVG with scale %s, the resulting image size exceeds max height.", rtos(p_scale))); PoolVector<uint8_t> dst_image; @@ -123,8 +125,9 @@ Error ImageLoaderSVG::_create_image(Ref<Image> p_image, const PoolVector<uint8_t dw.release(); p_image->create(w, h, false, Image::FORMAT_RGBA8, dst_image); - if (upsample) + if (upsample) { p_image->shrink_x2(); + } nsvgDelete(svg_image); diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java index 44998aa6c0..e901b4b36d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java @@ -123,7 +123,7 @@ public class GodotEditText extends EditText { } private void setMaxInputLength(EditText p_edit_text, int p_max_input_length) { - if (p_max_input_length >= 0) { + if (p_max_input_length > 0) { InputFilter[] filters = new InputFilter[1]; filters[0] = new InputFilter.LengthFilter(p_max_input_length); p_edit_text.setFilters(filters); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 7bf3e1bc1d..1766833364 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -131,6 +131,11 @@ def configure(env): env.Append(LINKFLAGS=['-s', 'BINARYEN=1']) + # Only include the JavaScript support code for the web environment + # (i.e. exclude Node.js and other unused environments). + # This makes the JavaScript support code about 4 KB smaller. + env.Append(LINKFLAGS=['-s', 'ENVIRONMENT=web']) + # This needs to be defined for Emscripten using 'fastcomp' (default pre-1.39.0) # and undefined if using 'upstream'. And to make things simple, earlier # Emscripten versions didn't include 'fastcomp' in their path, so we check diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 7882253e7a..fe839199e8 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -27,6 +27,9 @@ def get_opts(): ('MACOS_SDK_PATH', 'Path to the macOS SDK', ''), EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False), + BoolVariable('use_ubsan', 'Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)', False), + BoolVariable('use_asan', 'Use LLVM/GCC compiler address sanitizer (ASAN))', False), + BoolVariable('use_tsan', 'Use LLVM/GCC compiler thread sanitizer (TSAN))', False), ] @@ -122,6 +125,21 @@ def configure(env): env["CC"] = "clang" env["LINK"] = "clang++" + if env['use_ubsan'] or env['use_asan'] or env['use_tsan']: + env.extra_suffix += "s" + + if env['use_ubsan']: + env.Append(CCFLAGS=['-fsanitize=undefined']) + env.Append(LINKFLAGS=['-fsanitize=undefined']) + + if env['use_asan']: + env.Append(CCFLAGS=['-fsanitize=address']) + env.Append(LINKFLAGS=['-fsanitize=address']) + + if env['use_tsan']: + env.Append(CCFLAGS=['-fsanitize=thread']) + env.Append(LINKFLAGS=['-fsanitize=thread']) + ## Dependencies if env['builtin_libtheora']: diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 6a214b8669..53fe11b3bb 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -115,6 +115,20 @@ static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFacto return Vector2(mouse_x, mouse_y); } +static NSCursor *cursorFromSelector(SEL selector, SEL fallback = nil) { + if ([NSCursor respondsToSelector:selector]) { + id object = [NSCursor performSelector:selector]; + if ([object isKindOfClass:[NSCursor class]]) { + return object; + } + } + if (fallback) { + // Fallback should be a reasonable default, no need to check. + return [NSCursor performSelector:fallback]; + } + return [NSCursor arrowCursor]; +} + @interface GodotApplication : NSApplication @end @@ -1813,15 +1827,15 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) { case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break; case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break; case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break; - case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break; - case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break; - case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break; - case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break; - case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break; + case CURSOR_FORBIDDEN: [[NSCursor operationNotAllowedCursor] set]; break; + case CURSOR_VSIZE: [cursorFromSelector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set]; break; + case CURSOR_HSIZE: [cursorFromSelector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set]; break; + case CURSOR_BDIAGSIZE: [cursorFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)) set]; break; + case CURSOR_FDIAGSIZE: [cursorFromSelector(@selector(_windowResizeNorthWestSouthEastCursor)) set]; break; case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break; case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break; case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break; - case CURSOR_HELP: [[NSCursor arrowCursor] set]; break; + case CURSOR_HELP: [cursorFromSelector(@selector(_helpCursor)) set]; break; default: { }; } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 8598a953b4..3f46afa8e8 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -36,7 +36,14 @@ Size2 OptionButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); if (has_icon("arrow")) { - minsize.width += Control::get_icon("arrow")->get_width() + get_constant("hseparation"); + const Size2 padding = get_stylebox("normal")->get_minimum_size(); + const Size2 arrow_size = Control::get_icon("arrow")->get_size(); + + Size2 content_size = minsize - padding; + content_size.width += arrow_size.width + get_constant("hseparation"); + content_size.height = MAX(content_size.height, arrow_size.height); + + minsize = content_size + padding; } return minsize; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index c3ddc41813..b045ff4fe1 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -785,23 +785,25 @@ TabContainer::TabAlign TabContainer::get_tab_align() const { return align; } -void TabContainer::set_tabs_visible(bool p_visibe) { +void TabContainer::set_tabs_visible(bool p_visible) { - if (p_visibe == tabs_visible) + if (p_visible == tabs_visible) return; - tabs_visible = p_visibe; + tabs_visible = p_visible; Vector<Control *> tabs = _get_tabs(); for (int i = 0; i < tabs.size(); i++) { Control *c = tabs[i]; - if (p_visibe) + if (p_visible) c->set_margin(MARGIN_TOP, _get_top_margin()); else c->set_margin(MARGIN_TOP, 0); } + update(); + minimum_size_changed(); } bool TabContainer::are_tabs_visible() const { @@ -936,8 +938,10 @@ Size2 TabContainer::get_minimum_size() const { Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled"); Ref<Font> font = get_font("font"); - ms.y += MAX(MAX(tab_bg->get_minimum_size().y, tab_fg->get_minimum_size().y), tab_disabled->get_minimum_size().y); - ms.y += font->get_height(); + if (tabs_visible) { + ms.y += MAX(MAX(tab_bg->get_minimum_size().y, tab_fg->get_minimum_size().y), tab_disabled->get_minimum_size().y); + ms.y += font->get_height(); + } Ref<StyleBox> sb = get_stylebox("panel"); ms += sb->get_minimum_size(); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index e69c2ae289..c5a9045ca6 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -87,7 +87,7 @@ public: void set_tab_align(TabAlign p_align); TabAlign get_tab_align() const; - void set_tabs_visible(bool p_visibe); + void set_tabs_visible(bool p_visible); bool are_tabs_visible() const; void set_tab_title(int p_tab, const String &p_title); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index a1d8e470f8..4161f743a5 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1910,7 +1910,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, // Canvas Item, Light { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, // Particles, Vertex { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index d3ecdf4e59..14d2f6d086 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -662,6 +662,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { idx++; } + str = str.replace("dus_", "_"); + return _make_token(TK_IDENTIFIER, str); } diff --git a/version.py b/version.py index 47af88c676..2a6a9c0a28 100644 --- a/version.py +++ b/version.py @@ -1,9 +1,9 @@ short_name = "godot" name = "Godot Engine" -major = 3 -minor = 2 +major = 4 +minor = 0 patch = 0 -status = "stable" +status = "dev" module_config = "" year = 2020 website = "https://godotengine.org" |