diff options
30 files changed, 505 insertions, 85 deletions
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 779a28be66..972bccc0ac 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -98,6 +98,11 @@ real_t Vector2::cross(const Vector2 &p_other) const { return x * p_other.y - y * p_other.x; } +Vector2 Vector2::sign() const { + + return Vector2(SGN(x), SGN(y)); +} + Vector2 Vector2::floor() const { return Vector2(Math::floor(x), Math::floor(y)); @@ -121,6 +126,14 @@ Vector2 Vector2::rotated(real_t p_by) const { return v; } +Vector2 Vector2::posmod(const real_t p_mod) const { + return Vector2(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod)); +} + +Vector2 Vector2::posmodv(const Vector2 &p_modv) const { + return Vector2(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y)); +} + Vector2 Vector2::project(const Vector2 &p_b) const { return p_b * (dot(p_b) / p_b.length_squared()); } diff --git a/core/math/vector2.h b/core/math/vector2.h index 78a1641c1e..1a73831891 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -38,6 +38,11 @@ struct Vector2i; struct Vector2 { + enum Axis { + AXIS_X, + AXIS_Y, + }; + union { real_t x; real_t width; @@ -69,6 +74,8 @@ struct Vector2 { real_t dot(const Vector2 &p_other) const; real_t cross(const Vector2 &p_other) const; + Vector2 posmod(const real_t p_mod) const; + Vector2 posmodv(const Vector2 &p_modv) const; Vector2 project(const Vector2 &p_b) const; Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; @@ -107,8 +114,10 @@ struct Vector2 { bool operator==(const Vector2 &p_vec2) const; bool operator!=(const Vector2 &p_vec2) const; - bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); } + bool operator<(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator>(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y <= p_vec2.y) : (x < p_vec2.x); } + bool operator>=(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y >= p_vec2.y) : (x > p_vec2.x); } real_t angle() const; @@ -129,6 +138,7 @@ struct Vector2 { return Vector2(y, -x); } + Vector2 sign() const; Vector2 floor() const; Vector2 ceil() const; Vector2 round() const; @@ -141,10 +151,7 @@ struct Vector2 { x = p_x; y = p_y; } - _FORCE_INLINE_ Vector2() { - x = 0; - y = 0; - } + _FORCE_INLINE_ Vector2() { x = y = 0; } }; _FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { @@ -262,6 +269,11 @@ typedef Vector2 Point2; struct Vector2i { + enum Axis { + AXIS_X, + AXIS_Y, + }; + union { int x; int width; diff --git a/core/math/vector3.h b/core/math/vector3.h index 45bdfee487..597d3c22a8 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -31,9 +31,7 @@ #ifndef VECTOR3_H #define VECTOR3_H -#include "core/math/math_defs.h" #include "core/math/math_funcs.h" -#include "core/typedefs.h" #include "core/ustring.h" class Basis; @@ -110,6 +108,8 @@ struct Vector3 { _FORCE_INLINE_ real_t distance_to(const Vector3 &p_b) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_b) const; + _FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const; + _FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const; _FORCE_INLINE_ Vector3 project(const Vector3 &p_b) const; _FORCE_INLINE_ real_t angle_to(const Vector3 &p_b) const; @@ -141,15 +141,17 @@ struct Vector3 { _FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const; _FORCE_INLINE_ bool operator<(const Vector3 &p_v) const; _FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator>(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const; operator String() const; - _FORCE_INLINE_ Vector3() { x = y = z = 0; } _FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) { x = p_x; y = p_y; z = p_z; } + _FORCE_INLINE_ Vector3() { x = y = z = 0; } }; // Should be included after class definition, otherwise we get circular refs @@ -233,6 +235,14 @@ real_t Vector3::distance_squared_to(const Vector3 &p_b) const { return (p_b - *this).length_squared(); } +Vector3 Vector3::posmod(const real_t p_mod) const { + return Vector3(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod)); +} + +Vector3 Vector3::posmodv(const Vector3 &p_modv) const { + return Vector3(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z)); +} + Vector3 Vector3::project(const Vector3 &p_b) const { return p_b * (dot(p_b) / p_b.length_squared()); } @@ -357,6 +367,18 @@ bool Vector3::operator<(const Vector3 &p_v) const { } } +bool Vector3::operator>(const Vector3 &p_v) const { + + if (x == p_v.x) { + if (y == p_v.y) + return z > p_v.z; + else + return y > p_v.y; + } else { + return x > p_v.x; + } +} + bool Vector3::operator<=(const Vector3 &p_v) const { if (Math::is_equal_approx(x, p_v.x)) { @@ -369,6 +391,18 @@ bool Vector3::operator<=(const Vector3 &p_v) const { } } +bool Vector3::operator>=(const Vector3 &p_v) const { + + if (x == p_v.x) { + if (y == p_v.y) + return z >= p_v.z; + else + return y > p_v.y; + } else { + return x > p_v.x; + } +} + _FORCE_INLINE_ Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) { return p_a.cross(p_b); diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 0a673fb638..eb88143db3 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -1019,6 +1019,9 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("editor/search_in_file_extensions", extensions); custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::POOL_STRING_ARRAY, "editor/search_in_file_extensions"); + GLOBAL_DEF("editor/script_templates_search_path", "res://script_templates"); + custom_prop_info["editor/script_templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script_templates_search_path", PROPERTY_HINT_DIR); + action = Dictionary(); action["deadzone"] = Variant(0.5f); events = Array(); diff --git a/core/ustring.cpp b/core/ustring.cpp index 4e9ab7be6b..21696e2a55 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -40,6 +40,7 @@ #include "core/variant.h" #include <wchar.h> +#include <cstdint> #ifndef NO_USE_STDLIB #include <stdio.h> @@ -1668,6 +1669,7 @@ int String::hex_to_int(bool p_with_prefix) const { return 0; } + ERR_FAIL_COND_V_MSG(hex > INT32_MAX / 16, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + *this + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); hex *= 16; hex += n; s++; @@ -1709,6 +1711,7 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { return 0; } + ERR_FAIL_COND_V_MSG(hex > INT64_MAX / 16, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); hex *= 16; hex += n; s++; @@ -1748,6 +1751,7 @@ int64_t String::bin_to_int64(bool p_with_prefix) const { return 0; } + ERR_FAIL_COND_V_MSG(binary > INT64_MAX / 2, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); binary *= 2; binary += n; s++; @@ -1771,6 +1775,7 @@ int String::to_int() const { CharType c = operator[](i); if (c >= '0' && c <= '9') { + ERR_FAIL_COND_V_MSG(integer > INT32_MAX / 10, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + *this + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); integer *= 10; integer += c - '0'; @@ -1798,6 +1803,7 @@ int64_t String::to_int64() const { CharType c = operator[](i); if (c >= '0' && c <= '9') { + ERR_FAIL_COND_V_MSG(integer > INT64_MAX / 10, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small.")); integer *= 10; integer += c - '0'; @@ -1828,6 +1834,7 @@ int String::to_int(const char *p_str, int p_len) { char c = p_str[i]; if (c >= '0' && c <= '9') { + ERR_FAIL_COND_V_MSG(integer > INT32_MAX / 10, sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); integer *= 10; integer += c - '0'; @@ -2140,6 +2147,14 @@ int64_t String::to_int(const CharType *p_str, int p_len) { if (c >= '0' && c <= '9') { + if (integer > INT32_MAX / 10) { + String number(""); + str = p_str; + while (str != limit) { + number += *(str++); + } + ERR_FAIL_V_MSG(sign == 1 ? INT32_MAX : INT32_MIN, "Cannot represent " + number + " as integer, provided value is " + (sign == 1 ? "too big." : "too small.")); + } integer *= 10; integer += c - '0'; } else { diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 3ab1386b13..05ef51cecd 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -347,6 +347,8 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector2, is_normalized); VCALL_LOCALMEM1R(Vector2, distance_to); VCALL_LOCALMEM1R(Vector2, distance_squared_to); + VCALL_LOCALMEM1R(Vector2, posmod); + VCALL_LOCALMEM1R(Vector2, posmodv); VCALL_LOCALMEM1R(Vector2, project); VCALL_LOCALMEM1R(Vector2, angle_to); VCALL_LOCALMEM1R(Vector2, angle_to_point); @@ -370,6 +372,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Vector2, cross); VCALL_LOCALMEM0R(Vector2, abs); VCALL_LOCALMEM1R(Vector2, clamped); + VCALL_LOCALMEM0R(Vector2, sign); VCALL_LOCALMEM0R(Rect2, get_area); VCALL_LOCALMEM1R(Rect2, intersects); @@ -407,12 +410,15 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector3, round); VCALL_LOCALMEM1R(Vector3, distance_to); VCALL_LOCALMEM1R(Vector3, distance_squared_to); + VCALL_LOCALMEM1R(Vector3, posmod); + VCALL_LOCALMEM1R(Vector3, posmodv); VCALL_LOCALMEM1R(Vector3, project); VCALL_LOCALMEM1R(Vector3, angle_to); VCALL_LOCALMEM1R(Vector3, direction_to); VCALL_LOCALMEM1R(Vector3, slide); VCALL_LOCALMEM1R(Vector3, bounce); VCALL_LOCALMEM1R(Vector3, reflect); + VCALL_LOCALMEM0R(Vector3, sign); VCALL_LOCALMEM0R(Plane, normalized); VCALL_LOCALMEM0R(Plane, center); @@ -1587,6 +1593,8 @@ void register_variant_methods() { ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmod, REAL, "mod", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmodv, VECTOR2, "modv", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); @@ -1608,6 +1616,7 @@ void register_variant_methods() { ADDFUNC1R(VECTOR2, REAL, Vector2, cross, VECTOR2, "with", varray()); ADDFUNC0R(VECTOR2, VECTOR2, Vector2, abs, varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray()); ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray()); ADDFUNC1R(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray()); @@ -1646,11 +1655,14 @@ void register_variant_methods() { ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmod, REAL, "mod", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmodv, VECTOR3, "modv", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, sign, varray()); ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray()); @@ -1943,6 +1955,9 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); + _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF)); diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 237b596fad..66c4849358 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -203,6 +203,24 @@ Returns the vector scaled to unit length. Equivalent to [code]v / v.length()[/code]. </description> </method> + <method name="posmod"> + <return type="Vector2"> + </return> + <argument index="0" name="mod" type="float"> + </argument> + <description> + Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]mod[/code]. + </description> + </method> + <method name="posmodv"> + <return type="Vector2"> + </return> + <argument index="0" name="mod" type="float"> + </argument> + <description> + Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]modv[/code]'s components. + </description> + </method> <method name="project"> <return type="Vector2"> </return> @@ -237,6 +255,13 @@ Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero. </description> </method> + <method name="sign"> + <return type="Vector2"> + </return> + <description> + Returns the vector with each component set to one or negative one, depending on the signs of the components. + </description> + </method> <method name="slerp"> <return type="Vector2"> </return> @@ -284,6 +309,12 @@ </member> </members> <constants> + <constant name="AXIS_X" value="0"> + Enumerated value for the X axis. Returned by [method max_axis] and [method min_axis]. + </constant> + <constant name="AXIS_Y" value="1"> + Enumerated value for the Y axis. + </constant> <constant name="ZERO" value="Vector2( 0, 0 )"> Zero vector. </constant> @@ -291,7 +322,7 @@ One vector. </constant> <constant name="INF" value="Vector2( inf, inf )"> - Infinite vector. + Infinity vector. </constant> <constant name="LEFT" value="Vector2( -1, 0 )"> Left unit vector. diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 3e1083ab69..4631eb7300 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="Vector3" category="Built-In Types" version="3.2"> <brief_description> - Vector class, which performs basic 3D vector math operations. + Vector used for 3D math. </brief_description> <description> - Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vector math operations. + 3-element structure that can be used to represent positions in 3D space or any other pair of numeric values. </description> <tutorials> <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link> @@ -202,6 +202,24 @@ Returns the outer product with [code]b[/code]. </description> </method> + <method name="posmod"> + <return type="Vector3"> + </return> + <argument index="0" name="mod" type="float"> + </argument> + <description> + Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]mod[/code]. + </description> + </method> + <method name="posmodv"> + <return type="Vector3"> + </return> + <argument index="0" name="mod" type="float"> + </argument> + <description> + Returns a vector composed of the [code]fposmod[/code] of this vector's components and [code]modv[/code]'s components. + </description> + </method> <method name="project"> <return type="Vector3"> </return> @@ -238,6 +256,13 @@ Returns the vector with all components rounded to the nearest integer, with halfway cases rounded away from zero. </description> </method> + <method name="sign"> + <return type="Vector3"> + </return> + <description> + Returns the vector with each component set to one or negative one, depending on the signs of the components. + </description> + </method> <method name="slerp"> <return type="Vector3"> </return> @@ -304,7 +329,7 @@ One vector. </constant> <constant name="INF" value="Vector3( inf, inf, inf )"> - Infinite vector. + Infinity vector. </constant> <constant name="LEFT" value="Vector3( -1, 0, 0 )"> Left unit vector. diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 555a7f99c8..f44e1b7b14 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -439,11 +439,11 @@ void EditorAutoloadSettings::update_autoload() { } if (info.in_editor) { ERR_CONTINUE(!info.node); - get_tree()->get_root()->remove_child(info.node); + get_tree()->get_root()->call_deferred("remove_child", info.node); } if (info.node) { - memdelete(info.node); + info.node->queue_delete(); info.node = NULL; } } diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index e2a750cf08..e58c7c992a 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -148,6 +148,12 @@ String EditorExportPreset::get_include_filter() const { void EditorExportPreset::set_export_path(const String &p_path) { export_path = p_path; + /* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path, + * this should be removed. */ + if (export_path.is_abs_path()) { + String res_path = OS::get_singleton()->get_resource_dir(); + export_path = res_path.path_to_file(export_path); + } EditorExport::singleton->save_presets(); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 385b6924df..2e8f8ec646 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -164,6 +164,17 @@ void EditorHelp::_class_desc_select(const String &p_select) { void EditorHelp::_class_desc_input(const Ref<InputEvent> &p_input) { } +void EditorHelp::_class_desc_resized() { + // Add extra horizontal margins for better readability. + // The margins increase as the width of the editor help container increases. + const int display_margin = MAX(30 * EDSCALE, get_parent_anchorable_rect().size.width - 900 * EDSCALE) * 0.5; + + Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_stylebox("normal", "RichTextLabel")->duplicate(); + class_desc_stylebox->set_default_margin(MARGIN_LEFT, display_margin); + class_desc_stylebox->set_default_margin(MARGIN_RIGHT, display_margin); + class_desc->add_style_override("normal", class_desc_stylebox); +} + void EditorHelp::_add_type(const String &p_type, const String &p_enum) { String t = p_type; @@ -1488,6 +1499,7 @@ void EditorHelp::_bind_methods() { ClassDB::bind_method("_class_list_select", &EditorHelp::_class_list_select); ClassDB::bind_method("_class_desc_select", &EditorHelp::_class_desc_select); ClassDB::bind_method("_class_desc_input", &EditorHelp::_class_desc_input); + ClassDB::bind_method("_class_desc_resized", &EditorHelp::_class_desc_resized); ClassDB::bind_method("_request_help", &EditorHelp::_request_help); ClassDB::bind_method("_unhandled_key_input", &EditorHelp::_unhandled_key_input); ClassDB::bind_method("_search", &EditorHelp::_search); @@ -1506,8 +1518,11 @@ EditorHelp::EditorHelp() { add_child(class_desc); class_desc->set_v_size_flags(SIZE_EXPAND_FILL); class_desc->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4)); + class_desc->connect("meta_clicked", this, "_class_desc_select"); class_desc->connect("gui_input", this, "_class_desc_input"); + class_desc->connect("resized", this, "_class_desc_resized"); + _class_desc_resized(); // Added second so it opens at the bottom so it won't offset the entire widget. find_bar = memnew(FindBar); diff --git a/editor/editor_help.h b/editor/editor_help.h index 3824ba231e..1019cafffc 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -151,6 +151,7 @@ class EditorHelp : public VBoxContainer { void _class_list_select(const String &p_select); void _class_desc_select(const String &p_select); void _class_desc_input(const Ref<InputEvent> &p_input); + void _class_desc_resized(); Error _goto_desc(const String &p_class, int p_vscr = -1); //void _update_history_buttons(); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 12510e27de..23d28261d1 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -78,6 +78,9 @@ void EditorPath::_about_to_show() { } void EditorPath::update_path() { + set_text(""); + set_tooltip(""); + set_icon(NULL); for (int i = 0; i < history->get_path_size(); i++) { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 20ba07c102..378dd34e39 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -209,13 +209,7 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() { void EditorPropertyPath::_path_selected(const String &p_path) { - String final_path = p_path; - if (final_path.is_abs_path()) { - String res_path = OS::get_singleton()->get_resource_dir() + "/"; - final_path = res_path.path_to_file(final_path); - } - - emit_changed(get_edited_property(), final_path); + emit_changed(get_edited_property(), p_path); update_property(); } void EditorPropertyPath::_path_pressed() { @@ -228,13 +222,6 @@ void EditorPropertyPath::_path_pressed() { } String full_path = get_edited_object()->get(get_edited_property()); - if (full_path.is_rel_path()) { - - if (!DirAccess::exists(full_path.get_base_dir())) { - DirAccessRef da(DirAccess::create(DirAccess::ACCESS_FILESYSTEM)); - da->make_dir_recursive(full_path.get_base_dir()); - } - } dialog->clear_filters(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index ef5a067d01..ea6361665c 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1209,6 +1209,11 @@ String EditorSettings::get_script_templates_dir() const { return get_settings_dir().plus_file("script_templates"); } +String EditorSettings::get_project_script_templates_dir() const { + + return ProjectSettings::get_singleton()->get("editor/script_templates_search_path"); +} + // Cache directory String EditorSettings::get_cache_dir() const { @@ -1429,10 +1434,14 @@ bool EditorSettings::is_default_text_editor_theme() { return _is_default_text_editor_theme(p_file.get_file().to_lower()); } -Vector<String> EditorSettings::get_script_templates(const String &p_extension) { +Vector<String> EditorSettings::get_script_templates(const String &p_extension, const String &p_custom_path) { Vector<String> templates; - DirAccess *d = DirAccess::open(get_script_templates_dir()); + String template_dir = get_script_templates_dir(); + if (!p_custom_path.empty()) { + template_dir = p_custom_path; + } + DirAccess *d = DirAccess::open(template_dir); if (d) { d->list_dir_begin(); String file = d->get_next(); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 890850629e..0738185e95 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -166,6 +166,7 @@ public: String get_project_settings_dir() const; String get_text_editor_themes_dir() const; String get_script_templates_dir() const; + String get_project_script_templates_dir() const; String get_cache_dir() const; String get_feature_profiles_dir() const; @@ -187,7 +188,7 @@ public: bool save_text_editor_theme_as(String p_file); bool is_default_text_editor_theme(); - Vector<String> get_script_templates(const String &p_extension); + Vector<String> get_script_templates(const String &p_extension, const String &p_custom_path = String()); String get_editor_layouts_config() const; void add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcut); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index c78a81dbe0..956da92c35 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -931,17 +931,8 @@ void ProjectExportDialog::_export_project() { export_project->add_filter("*." + extension_list[i] + " ; " + platform->get_name() + " Export"); } - String current_preset_export_path = current->get_export_path(); - - if (current_preset_export_path != "") { - - if (!DirAccess::exists(current_preset_export_path.get_base_dir())) { - - DirAccessRef da(DirAccess::create(DirAccess::ACCESS_FILESYSTEM)); - da->make_dir_recursive(current_preset_export_path.get_base_dir()); - } - - export_project->set_current_path(current_preset_export_path); + if (current->get_export_path() != "") { + export_project->set_current_path(current->get_export_path()); } else { if (extension_list.size() >= 1) { export_project->set_current_file(default_filename + "." + extension_list[0]); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index b88b2b38a0..5709bdc3fa 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1255,19 +1255,22 @@ void ProjectList::create_project_item_control(int p_index) { TextureRect *tf = memnew(TextureRect); tf->set_texture(get_icon("DefaultProjectIcon", "EditorIcons")); + if (item.missing) { + tf->set_modulate(Color(1, 1, 1, 0.5)); + } hb->add_child(tf); hb->icon = tf; VBoxContainer *vb = memnew(VBoxContainer); if (item.grayed) - vb->set_modulate(Color(0.5, 0.5, 0.5)); + vb->set_modulate(Color(1, 1, 1, 0.5)); vb->set_h_size_flags(SIZE_EXPAND_FILL); hb->add_child(vb); Control *ec = memnew(Control); ec->set_custom_minimum_size(Size2(0, 1)); ec->set_mouse_filter(MOUSE_FILTER_PASS); vb->add_child(ec); - Label *title = memnew(Label(item.project_name)); + Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project"))); title->add_font_override("font", get_font("title", "EditorFonts")); title->add_color_override("font_color", font_color); title->set_clip_text(true); @@ -1278,12 +1281,21 @@ void ProjectList::create_project_item_control(int p_index) { vb->add_child(path_hb); Button *show = memnew(Button); - show->set_icon(get_icon("Load", "EditorIcons")); // Folder icon + // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't + show->set_icon(get_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons")); show->set_flat(true); - show->set_modulate(Color(1, 1, 1, 0.5)); + if (!item.grayed) { + // Don't make the icon less prominent if the parent is already grayed out + show->set_modulate(Color(1, 1, 1, 0.5)); + } path_hb->add_child(show); - show->connect("pressed", this, "_show_project", varray(item.path)); - show->set_tooltip(TTR("Show in File Manager")); + + if (!item.missing) { + show->connect("pressed", this, "_show_project", varray(item.path)); + show->set_tooltip(TTR("Show in File Manager")); + } else { + show->set_tooltip(TTR("Error: Project is missing on the filesystem.")); + } Label *fpath = memnew(Label(item.path)); path_hb->add_child(fpath); @@ -1737,10 +1749,18 @@ void ProjectManager::_update_project_buttons() { Vector<ProjectList::Item> selected_projects = _project_list->get_selected_projects(); bool empty_selection = selected_projects.empty(); + bool is_missing_project_selected = false; + for (int i = 0; i < selected_projects.size(); ++i) { + if (selected_projects[i].missing) { + is_missing_project_selected = true; + break; + } + } + erase_btn->set_disabled(empty_selection); - open_btn->set_disabled(empty_selection); - rename_btn->set_disabled(empty_selection); - run_btn->set_disabled(empty_selection); + open_btn->set_disabled(empty_selection || is_missing_project_selected); + rename_btn->set_disabled(empty_selection || is_missing_project_selected); + run_btn->set_disabled(empty_selection || is_missing_project_selected); erase_missing_btn->set_visible(_project_list->is_any_project_missing()); } @@ -1928,6 +1948,9 @@ void ProjectManager::_open_selected_projects_ask() { } ProjectList::Item project = _project_list->get_selected_projects()[0]; + if (project.missing) { + return; + } // Update the project settings or don't open String conf = project.path.plus_file("project.godot"); @@ -2110,7 +2133,7 @@ void ProjectManager::_erase_project() { void ProjectManager::_erase_missing_projects() { - erase_missing_ask->set_text(TTR("Remove all missing projects from the list? The project folders' contents won't be modified.")); + erase_missing_ask->set_text(TTR("Remove all missing projects from the list?\nThe project folders' contents won't be modified.")); erase_missing_ask->popup_centered_minsize(); } diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 7d0f40fe91..ffb3f5feab 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -34,6 +34,7 @@ #include "core/os/file_access.h" #include "core/project_settings.h" #include "core/script_language.h" +#include "core/string_builder.h" #include "editor/create_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -238,16 +239,22 @@ void ScriptCreateDialog::_parent_name_changed(const String &p_parent) { void ScriptCreateDialog::_template_changed(int p_template) { - String selected_template = p_template == 0 ? "" : template_menu->get_item_text(template_menu->get_selected()); + String selected_template = p_template == 0 ? "" : template_menu->get_item_text(p_template); EditorSettings::get_singleton()->set_project_metadata("script_setup", "last_selected_template", selected_template); if (p_template == 0) { //default script_template = ""; return; } - String ext = ScriptServer::get_language(language_menu->get_selected())->get_extension(); - String name = template_list[p_template - 1] + "." + ext; - script_template = EditorSettings::get_singleton()->get_script_templates_dir().plus_file(name); + int selected_id = template_menu->get_selected_id(); + + for (int i = 0; i < template_list.size(); i++) { + const ScriptTemplateInfo &sinfo = template_list[i]; + if (sinfo.id == selected_id) { + script_template = sinfo.dir.plus_file(sinfo.name + "." + sinfo.extension); + break; + } + } } void ScriptCreateDialog::ok_pressed() { @@ -368,23 +375,77 @@ void ScriptCreateDialog::_lang_changed(int l) { bool use_templates = language->is_using_templates(); template_menu->set_disabled(!use_templates); template_menu->clear(); - if (use_templates) { - template_list = EditorSettings::get_singleton()->get_script_templates(language->get_extension()); + if (use_templates) { + _update_script_templates(language->get_extension()); String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); String last_template = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_template", ""); template_menu->add_item(TTR("Default")); + + ScriptTemplateInfo *templates = template_list.ptrw(); + + Vector<String> origin_names; + origin_names.push_back(TTR("Project")); + origin_names.push_back(TTR("Editor")); + int cur_origin = -1; + + // Populate script template items previously sorted and now grouped by origin for (int i = 0; i < template_list.size(); i++) { - String s = template_list[i].capitalize(); - template_menu->add_item(s); - if (language_menu->get_item_text(language_menu->get_selected()) == last_lang && last_template == s) { - template_menu->select(i + 1); + + if (int(templates[i].origin) != cur_origin) { + template_menu->add_separator(); + + String origin_name = origin_names[templates[i].origin]; + + int last_index = template_menu->get_item_count() - 1; + template_menu->set_item_text(last_index, origin_name); + + cur_origin = templates[i].origin; } + String item_name = templates[i].name.capitalize(); + template_menu->add_item(item_name); + + int new_id = template_menu->get_item_count() - 1; + templates[i].id = new_id; } - } else { + // Disable overridden + for (Map<String, Vector<int> >::Element *E = template_overrides.front(); E; E = E->next()) { + const Vector<int> &overrides = E->get(); + + if (overrides.size() == 1) { + continue; // doesn't override anything + } + const ScriptTemplateInfo &extended = template_list[overrides[0]]; + + StringBuilder override_info; + override_info += TTR("Overrides"); + override_info += ": "; + + for (int i = 1; i < overrides.size(); i++) { + const ScriptTemplateInfo &overridden = template_list[overrides[i]]; + + int disable_index = template_menu->get_item_index(overridden.id); + template_menu->set_item_disabled(disable_index, true); + override_info += origin_names[overridden.origin]; + if (i < overrides.size() - 1) { + override_info += ", "; + } + } + template_menu->set_item_icon(extended.id, get_icon("Override", "EditorIcons")); + template_menu->get_popup()->set_item_tooltip(extended.id, override_info.as_string()); + } + // Reselect last selected template + for (int i = 0; i < template_menu->get_item_count(); i++) { + const String &ti = template_menu->get_item_text(i); + if (language_menu->get_item_text(language_menu->get_selected()) == last_lang && last_template == ti) { + template_menu->select(i); + break; + } + } + } else { template_menu->add_item(TTR("N/A")); script_template = ""; } @@ -396,6 +457,41 @@ void ScriptCreateDialog::_lang_changed(int l) { _update_dialog(); } +void ScriptCreateDialog::_update_script_templates(const String &p_extension) { + + template_list.clear(); + template_overrides.clear(); + + Vector<String> dirs; + + // Ordered from local to global for correct override mechanism + dirs.push_back(EditorSettings::get_singleton()->get_project_script_templates_dir()); + dirs.push_back(EditorSettings::get_singleton()->get_script_templates_dir()); + + for (int i = 0; i < dirs.size(); i++) { + + Vector<String> list = EditorSettings::get_singleton()->get_script_templates(p_extension, dirs[i]); + + for (int j = 0; j < list.size(); j++) { + ScriptTemplateInfo sinfo; + sinfo.origin = ScriptOrigin(i); + sinfo.dir = dirs[i]; + sinfo.name = list[j]; + sinfo.extension = p_extension; + template_list.push_back(sinfo); + + if (!template_overrides.has(sinfo.name)) { + Vector<int> overrides; + overrides.push_back(template_list.size() - 1); // first one + template_overrides.insert(sinfo.name, overrides); + } else { + Vector<int> &overrides = template_overrides[sinfo.name]; + overrides.push_back(template_list.size() - 1); + } + } + } +} + void ScriptCreateDialog::_built_in_pressed() { if (internal->is_pressed()) { diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 202846fd3c..31cf2478cf 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -78,8 +78,25 @@ class ScriptCreateDialog : public ConfirmationDialog { int current_language; int default_language; bool re_check_path; + + enum ScriptOrigin { + SCRIPT_ORIGIN_PROJECT, + SCRIPT_ORIGIN_EDITOR, + }; + struct ScriptTemplateInfo { + int id; + ScriptOrigin origin; + String dir; + String name; + String extension; + }; + String script_template; - Vector<String> template_list; + Vector<ScriptTemplateInfo> template_list; + Map<String, Vector<int> > template_overrides; // name : indices + + void _update_script_templates(const String &p_extension); + String base_type; void _path_hbox_sorted(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index f7ff754a0b..fc5aecdbe9 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1376,7 +1376,7 @@ void ScriptEditorDebugger::stop() { profiler->set_enabled(true); inspect_scene_tree->clear(); - inspector->edit(NULL); + EditorNode::get_singleton()->edit_current(); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs index b1c1dae3c2..0daa94057e 100644 --- a/modules/mono/glue/Managed/Files/Vector2.cs +++ b/modules/mono/glue/Managed/Files/Vector2.cs @@ -14,10 +14,19 @@ using real_t = System.Single; namespace Godot { + /// <summary> + /// 2-element structure that can be used to represent positions in 2D space or any other pair of numeric values. + /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector2 : IEquatable<Vector2> { + public enum Axis + { + X = 0, + Y + } + public real_t x; public real_t y; @@ -202,6 +211,22 @@ namespace Godot return v; } + public Vector2 PosMod(real_t mod) + { + Vector2 v; + v.x = Mathf.PosMod(x, mod); + v.y = Mathf.PosMod(y, mod); + return v; + } + + public Vector2 PosMod(Vector2 modv) + { + Vector2 v; + v.x = Mathf.PosMod(x, modv.x); + v.y = Mathf.PosMod(y, modv.y); + return v; + } + public Vector2 Project(Vector2 onNormal) { return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); @@ -236,6 +261,14 @@ namespace Godot y = v.y; } + public Vector2 Sign() + { + Vector2 v; + v.x = Mathf.Sign(x); + v.y = Mathf.Sign(y); + return v; + } + public Vector2 Slerp(Vector2 b, real_t t) { real_t theta = AngleTo(b); @@ -265,7 +298,7 @@ namespace Godot private static readonly Vector2 _up = new Vector2(0, -1); private static readonly Vector2 _down = new Vector2(0, 1); - private static readonly Vector2 _right = new Vector2(1, 0); + private static readonly Vector2 _right = new Vector2(1, 0); private static readonly Vector2 _left = new Vector2(-1, 0); public static Vector2 Zero { get { return _zero; } } @@ -346,6 +379,20 @@ namespace Godot return left; } + public static Vector2 operator %(Vector2 vec, real_t divisor) + { + vec.x %= divisor; + vec.y %= divisor; + return vec; + } + + public static Vector2 operator %(Vector2 vec, Vector2 divisorv) + { + vec.x %= divisorv.x; + vec.y %= divisorv.y; + return vec; + } + public static bool operator ==(Vector2 left, Vector2 right) { return left.Equals(right); diff --git a/modules/mono/glue/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs index c2da7b8bb1..9076dbd3b0 100644 --- a/modules/mono/glue/Managed/Files/Vector3.cs +++ b/modules/mono/glue/Managed/Files/Vector3.cs @@ -14,6 +14,9 @@ using real_t = System.Single; namespace Godot { + /// <summary> + /// 3-element structure that can be used to represent positions in 3D space or any other pair of numeric values. + /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Vector3 : IEquatable<Vector3> @@ -225,6 +228,24 @@ namespace Godot ); } + public Vector3 PosMod(real_t mod) + { + Vector3 v; + v.x = Mathf.PosMod(x, mod); + v.y = Mathf.PosMod(y, mod); + v.z = Mathf.PosMod(z, mod); + return v; + } + + public Vector3 PosMod(Vector3 modv) + { + Vector3 v; + v.x = Mathf.PosMod(x, modv.x); + v.y = Mathf.PosMod(y, modv.y); + v.z = Mathf.PosMod(z, modv.z); + return v; + } + public Vector3 Project(Vector3 onNormal) { return onNormal * (Dot(onNormal) / onNormal.LengthSquared()); @@ -264,6 +285,15 @@ namespace Godot z = v.z; } + public Vector3 Sign() + { + Vector3 v; + v.x = Mathf.Sign(x); + v.y = Mathf.Sign(y); + v.z = Mathf.Sign(z); + return v; + } + public Vector3 Slerp(Vector3 b, real_t t) { real_t theta = AngleTo(b); @@ -397,6 +427,22 @@ namespace Godot return left; } + public static Vector3 operator %(Vector3 vec, real_t divisor) + { + vec.x %= divisor; + vec.y %= divisor; + vec.z %= divisor; + return vec; + } + + public static Vector3 operator %(Vector3 vec, Vector3 divisorv) + { + vec.x %= divisorv.x; + vec.y %= divisorv.y; + vec.z %= divisorv.z; + return vec; + } + public static bool operator ==(Vector3 left, Vector3 right) { return left.Equals(right); diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index fc18661f62..68e3bc64fc 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -39,6 +39,10 @@ - (void)didReceiveMemoryWarning; +- (void)viewDidLoad; + +- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures; + - (BOOL)prefersStatusBarHidden; @end diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index 0358abf9e2..e52ad92bf2 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -83,6 +83,18 @@ int add_cmdline(int p_argc, char **p_args) { printf("*********** did receive memory warning!\n"); }; +- (void)viewDidLoad { + [super viewDidLoad]; + + if (@available(iOS 11.0, *)) { + [self setNeedsUpdateOfScreenEdgesDeferringSystemGestures]; + } +} + +- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures { + return UIRectEdgeAll; +} + - (BOOL)shouldAutorotate { switch (OS::get_singleton()->get_screen_orientation()) { case OS::SCREEN_SENSOR: diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 0d9df3dae9..7cc937a64a 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1266,7 +1266,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const //all is a wall on_wall = true; } else { - if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor + if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; on_floor_body = collision.collider_rid; @@ -1281,7 +1281,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const } } - } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling + } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 19d5f1dd3c..ebac968cb4 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1192,7 +1192,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve //all is a wall on_wall = true; } else { - if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor + if (Math::acos(collision.normal.dot(p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; on_floor_body = collision.collider_rid; @@ -1209,7 +1209,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve is_on_slope = true; - } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling + } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index b197971b61..1d529f4e72 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -247,15 +247,19 @@ void ColorPicker::_update_color(bool p_update_sliders) { } void ColorPicker::_update_presets() { + presets_per_row = 10; Size2 size = bt_add_preset->get_size(); - Size2 preset_size = Size2(size.width * presets.size(), size.height); + Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row))); preset->set_custom_minimum_size(preset_size); - - preset->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), Rect2(Point2(), preset_size), true); + preset_container->set_custom_minimum_size(preset_size); + preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0)); for (int i = 0; i < presets.size(); i++) { - preset->draw_rect(Rect2(Point2(size.width * i, 0), size), presets[i]); + int x = (i % presets_per_row) * size.width; + int y = (Math::floor((float)i / presets_per_row)) * size.height; + preset->draw_rect(Rect2(Point2(x, y), size), presets[i]); } + _notification(NOTIFICATION_VISIBILITY_CHANGED); } void ColorPicker::_text_type_toggled() { @@ -288,8 +292,6 @@ void ColorPicker::add_preset(const Color &p_color) { presets.push_back(p_color); } preset->update(); - if (presets.size() == 10) - bt_add_preset->hide(); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -533,14 +535,20 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; if (bev.is_valid()) { - + int index = 0; if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { - int index = bev->get_position().x / (preset->get_size().x / presets.size()); + for (int i = 0; i < presets.size(); i++) { + int x = (i % presets_per_row) * bt_add_preset->get_size().x; + int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y; + if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) { + index = i; + } + } set_pick_color(presets[index]); _update_color(); emit_signal("color_changed", color); } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) { - int index = bev->get_position().x / (preset->get_size().x / presets.size()); + index = bev->get_position().x / (preset->get_size().x / presets.size()); Color clicked_preset = presets[index]; erase_preset(clicked_preset); emit_signal("preset_removed", clicked_preset); @@ -841,6 +849,7 @@ ColorPicker::ColorPicker() : add_child(preset_separator); preset_container = memnew(HBoxContainer); + preset_container->set_h_size_flags(SIZE_EXPAND_FILL); add_child(preset_container); preset = memnew(TextureRect); @@ -848,8 +857,11 @@ ColorPicker::ColorPicker() : preset->connect("gui_input", this, "_preset_input"); preset->connect("draw", this, "_update_presets"); + preset_container2 = memnew(HBoxContainer); + preset_container2->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(preset_container2); bt_add_preset = memnew(Button); - preset_container->add_child(bt_add_preset); + preset_container2->add_child(bt_add_preset); bt_add_preset->set_tooltip(TTR("Add current color as a preset.")); bt_add_preset->connect("pressed", this, "_add_preset_pressed"); } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 3af27a9856..167f7b33b3 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -54,6 +54,7 @@ private: TextureRect *sample; TextureRect *preset; HBoxContainer *preset_container; + HBoxContainer *preset_container2; HSeparator *preset_separator; Button *bt_add_preset; List<Color> presets; @@ -68,6 +69,7 @@ private: bool edit_alpha; Size2i ms; bool text_is_constructor; + int presets_per_row; Color color; bool raw_mode_enabled; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 9b9fc863dd..b655feecbe 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2925,10 +2925,10 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input")); ADD_GROUP("Anchor", "anchor_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.01,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM); ADD_GROUP("Margin", "margin_"); ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT); |