Merge pull request #43456 from akien-mga/3.2-cherrypicks

Cherry-picks for the 3.2 branch (future 3.2.4) - 7th batch
This commit is contained in:
Rémi Verschelde 2020-11-11 22:33:31 +01:00 committed by GitHub
commit adf2dabbde
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 644 additions and 252 deletions

1
.gitignore vendored
View file

@ -21,6 +21,7 @@ project.properties
platform/android/java/app/libs/*
platform/android/java/libs/*
platform/android/java/lib/.cxx/
platform/android/java/nativeSrcsConfigs/.cxx/
# General c++ generated files
*.lib

View file

@ -117,6 +117,11 @@ void Array::push_back(const Variant &p_value) {
_p->array.push_back(p_value);
}
void Array::append_array(const Array &p_array) {
_p->array.append_array(p_array._p->array);
}
Error Array::resize(int p_new_size) {
return _p->array.resize(p_new_size);

View file

@ -64,6 +64,7 @@ public:
void push_back(const Variant &p_value);
_FORCE_INLINE_ void append(const Variant &p_value) { push_back(p_value); } //for python compatibility
void append_array(const Array &p_array);
Error resize(int p_new_size);
void insert(int p_pos, const Variant &p_value);

View file

@ -2335,6 +2335,7 @@ ImageMemLoadFunc Image::_png_mem_loader_func = NULL;
ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL;
ImageMemLoadFunc Image::_webp_mem_loader_func = NULL;
ImageMemLoadFunc Image::_tga_mem_loader_func = NULL;
ImageMemLoadFunc Image::_bmp_mem_loader_func = NULL;
void (*Image::_image_compress_bc_func)(Image *, float, Image::CompressSource) = NULL;
void (*Image::_image_compress_bptc_func)(Image *, float, Image::CompressSource) = NULL;
@ -2784,6 +2785,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
@ -3104,6 +3106,14 @@ Error Image::load_tga_from_buffer(const PoolVector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _tga_mem_loader_func);
}
Error Image::load_bmp_from_buffer(const PoolVector<uint8_t> &p_array) {
ERR_FAIL_NULL_V_MSG(
_bmp_mem_loader_func,
ERR_UNAVAILABLE,
"The BMP module isn't enabled. Recompile the Godot editor or export template binary with the `module_bmp_enabled=yes` SCons option.");
return _load_from_buffer(p_array, _bmp_mem_loader_func);
}
Error Image::_load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader) {
int buffer_size = p_array.size();

View file

@ -132,6 +132,7 @@ public:
static ImageMemLoadFunc _jpg_mem_loader_func;
static ImageMemLoadFunc _webp_mem_loader_func;
static ImageMemLoadFunc _tga_mem_loader_func;
static ImageMemLoadFunc _bmp_mem_loader_func;
static void (*_image_compress_bc_func)(Image *, float, CompressSource p_source);
static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, CompressSource p_source);
@ -333,6 +334,7 @@ public:
Error load_jpg_from_buffer(const PoolVector<uint8_t> &p_array);
Error load_webp_from_buffer(const PoolVector<uint8_t> &p_array);
Error load_tga_from_buffer(const PoolVector<uint8_t> &p_array);
Error load_bmp_from_buffer(const PoolVector<uint8_t> &p_array);
Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
Image(const char **p_xpm);

View file

@ -749,7 +749,8 @@ HTTPClient::HTTPClient() {
ssl = false;
blocking = false;
handshaking = false;
read_chunk_size = 4096;
// 64 KiB by default (favors fast download speeds at the cost of memory usage).
read_chunk_size = 65536;
}
HTTPClient::~HTTPClient() {

View file

@ -35,7 +35,6 @@ RandomNumberGenerator::RandomNumberGenerator() {}
void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &RandomNumberGenerator::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &RandomNumberGenerator::get_seed);
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi);
ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf);
@ -43,4 +42,8 @@ void RandomNumberGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
// Default value is non-deterministic, override it for doc generation purposes.
ADD_PROPERTY_DEFAULT("seed", 0);
}

View file

@ -257,7 +257,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t
real_t dot = v1.dot(v2);
dot = (dot < -1.0) ? -1.0 : ((dot > 1.0) ? 1.0 : dot); //clamp dot to [-1,1]
dot = CLAMP(dot, -1.0, 1.0);
Vector2 v;

View file

@ -534,6 +534,7 @@ struct _VariantCall {
VCALL_LOCALMEM0R(Array, pop_back);
VCALL_LOCALMEM0R(Array, pop_front);
VCALL_LOCALMEM1(Array, append);
VCALL_LOCALMEM1(Array, append_array);
VCALL_LOCALMEM1(Array, resize);
VCALL_LOCALMEM2(Array, insert);
VCALL_LOCALMEM1(Array, remove);
@ -1799,6 +1800,7 @@ void register_variant_methods() {
ADDFUNC1NC(ARRAY, NIL, Array, push_back, NIL, "value", varray());
ADDFUNC1NC(ARRAY, NIL, Array, push_front, NIL, "value", varray());
ADDFUNC1NC(ARRAY, NIL, Array, append, NIL, "value", varray());
ADDFUNC1NC(ARRAY, NIL, Array, append_array, ARRAY, "array", varray());
ADDFUNC1NC(ARRAY, NIL, Array, resize, INT, "size", varray());
ADDFUNC2NC(ARRAY, NIL, Array, insert, INT, "position", NIL, "value", varray());
ADDFUNC1NC(ARRAY, NIL, Array, remove, INT, "position", varray());

View file

@ -1174,10 +1174,10 @@
[codeblock]
var err = method_that_returns_error()
if err != OK:
print("Failure!)
print("Failure!")
# Or, equivalent:
if err:
print("Still failing!)
print("Still failing!")
[/codeblock]
</constant>
<constant name="FAILED" value="1" enum="Error">

View file

@ -20,6 +20,7 @@
var array2 = [3, "Four"]
print(array1 + array2) # ["One", 2, 3, "Four"]
[/codeblock]
Note that concatenating with [code]+=[/code] operator will create a new array. If you want to append another array to an existing array, [method append_array] is more efficient.
[b]Note:[/b] Arrays are always passed by reference. To get a copy of an array which can be modified independently of the original array, use [method duplicate].
</description>
<tutorials>
@ -95,6 +96,19 @@
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<argument index="0" name="array" type="Array">
</argument>
<description>
Appends another array at the end of this array.
[codeblock]
var array1 = [1, 2, 3]
var array2 = [4, 5, 6]
array1.append_array(array2)
print(array1) # Prints [1, 2, 3, 4, 5, 6].
[/codeblock]
</description>
</method>
<method name="back">
<return type="Variant">
</return>

View file

@ -594,7 +594,7 @@
</signal>
<signal name="item_rect_changed">
<description>
Emitted when the item rect has changed.
Emitted when the item's [Rect2] boundaries (position or size) have changed, or when an action is taking place that may have impacted these boundaries (e.g. changing [member Sprite.texture]).
</description>
</signal>
<signal name="visibility_changed">

View file

@ -58,25 +58,26 @@
</description>
</method>
<method name="_make_custom_tooltip" qualifiers="virtual">
<return type="Object">
<return type="Control">
</return>
<argument index="0" name="for_text" type="String">
</argument>
<description>
Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. Use [code]for_text[/code] parameter to determine what text the tooltip should contain (likely the contents of [member hint_tooltip]).
The returned node must be of type [Control] or Control-derieved. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance, not e.g. a node from scene. When [code]null[/code] or non-Control node is returned, the default tooltip will be used instead.
Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. The [code]for_text[/code] includes the contents of the [member hint_tooltip] property.
The returned node must be of type [Control] or Control-derived. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance (if you want to use a pre-existing node from your scene tree, you can duplicate it and pass the duplicated instance).When [code]null[/code] or a non-Control node is returned, the default tooltip will be used instead.
The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member hint_tooltip] for an example).
[b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member rect_min_size] to some non-zero value.
Example of usage with custom-constructed node:
Example of usage with a custom-constructed node:
[codeblock]
func _make_custom_tooltip(for_text):
var label = Label.new()
label.text = for_text
return label
[/codeblock]
Example of usage with custom scene instance:
Example of usage with a custom scene instance:
[codeblock]
func _make_custom_tooltip(for_text):
var tooltip = preload("SomeTooltipScene.tscn").instance()
var tooltip = preload("res://SomeTooltipScene.tscn").instance()
tooltip.get_node("Label").text = for_text
return tooltip
[/codeblock]
@ -846,6 +847,15 @@
</member>
<member name="hint_tooltip" type="String" setter="set_tooltip" getter="_get_tooltip" default="&quot;&quot;">
Changes the tooltip text. The tooltip appears when the user's mouse cursor stays idle over this control for a few moments, provided that the [member mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. You can change the time required for the tooltip to appear with [code]gui/timers/tooltip_delay_sec[/code] option in Project Settings.
The tooltip popup will use either a default implementation, or a custom one that you can provide by overriding [method _make_custom_tooltip]. The default tooltip includes a [PopupPanel] and [Label] whose theme properties can be customized using [Theme] methods with the [code]"TooltipPanel"[/code] and [code]"TooltipLabel"[/code] respectively. For example:
[codeblock]
var style_box = StyleBoxFlat.new()
style_box.set_bg_color(Color(1, 1, 0))
style_box.set_border_width_all(2)
# We assume here that the `theme` property has been assigned a custom Theme beforehand.
theme.set_stylebox("panel", "TooltipPanel", style_box)
theme.set_color("font_color", "TooltipLabel", Color(0, 1, 1))
[/codeblock]
</member>
<member name="margin_bottom" type="float" setter="set_margin" getter="get_margin" default="0.0">
Distance between the node's bottom edge and its parent control, based on [member anchor_bottom].

View file

@ -192,6 +192,19 @@
<argument index="0" name="overlay" type="Control">
</argument>
<description>
Called by the engine when the 2D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblock]
func forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64)
func forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
# Redraw viewport when cursor is moved.
update_overlays()
return true
return false
[/codeblock]
</description>
</method>
<method name="forward_canvas_force_draw_over_viewport" qualifiers="virtual">
@ -200,6 +213,8 @@
<argument index="0" name="overlay" type="Control">
</argument>
<description>
This method is the same as [method forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
</description>
</method>
<method name="forward_canvas_gui_input" qualifiers="virtual">
@ -226,6 +241,37 @@
[/codeblock]
</description>
</method>
<method name="forward_spatial_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
</argument>
<description>
Called by the engine when the 3D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblock]
func forward_spatial_draw_over_viewport(overlay):
# Draw a circle at cursor position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64)
func forward_spatial_gui_input(camera, event):
if event is InputEventMouseMotion:
# Redraw viewport when cursor is moved.
update_overlays()
return true
return false
[/codeblock]
</description>
</method>
<method name="forward_spatial_force_draw_over_viewport" qualifiers="virtual">
<return type="void">
</return>
<argument index="0" name="overlay" type="Control">
</argument>
<description>
This method is the same as [method forward_spatial_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
</description>
</method>
<method name="forward_spatial_gui_input" qualifiers="virtual">
<return type="bool">
</return>
@ -475,6 +521,7 @@
<return type="void">
</return>
<description>
Enables calling of [method forward_canvas_force_draw_over_viewport] for the 2D editor and [method forward_spatial_force_draw_over_viewport] for the 3D editor when their viewports are updated. You need to call this method only once and it will work permanently for this plugin.
</description>
</method>
<method name="set_input_event_forwarding_always_enabled">
@ -506,7 +553,7 @@
<return type="int">
</return>
<description>
Updates the overlays of the editor (2D/3D) viewport.
Updates the overlays of the 2D and 3D editor viewport. Causes methods [method forward_canvas_draw_over_viewport], [method forward_canvas_force_draw_over_viewport], [method forward_spatial_draw_over_viewport] and [method forward_spatial_force_draw_over_viewport] to be called.
</description>
</method>
</methods>

View file

@ -9,6 +9,7 @@
A [HTTPClient] should be reused between multiple requests or to connect to different hosts instead of creating one client per request. Supports SSL and SSL server certificate verification. HTTP status codes in the 2xx range indicate success, 3xx redirection (i.e. "try again, but over here"), 4xx something was wrong with the request, and 5xx something went wrong on the server's side.
For more information on HTTP, see https://developer.mozilla.org/en-US/docs/Web/HTTP (or read RFC 2616 to get it straight from the source: https://tools.ietf.org/html/rfc2616).
[b]Note:[/b] When performing HTTP requests from a project exported to HTML5, keep in mind the remote server may not allow requests from foreign origins due to [url=https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS]CORS[/url]. If you host the server in question, you should modify its backend to allow requests from foreign origins by adding the [code]Access-Control-Allow-Origin: *[/code] HTTP header.
[b]Note:[/b] SSL/TLS support is currently limited to TLS 1.0, TLS 1.1, and TLS 1.2. Attempting to connect to a TLS 1.3-only server will return an error.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/3.2/tutorials/networking/http_client_class.html</link>
@ -180,7 +181,7 @@
<member name="connection" type="StreamPeer" setter="set_connection" getter="get_connection">
The connection to use for this client.
</member>
<member name="read_chunk_size" type="int" setter="set_read_chunk_size" getter="get_read_chunk_size" default="4096">
<member name="read_chunk_size" type="int" setter="set_read_chunk_size" getter="get_read_chunk_size" default="65536">
The size of the buffer used and maximum bytes to read per iteration. See [method read_response_body_chunk].
</member>
</members>

View file

@ -23,7 +23,7 @@
# Note: Don't make simultaneous requests using a single HTTPRequest node.
# The snippet below is provided for reference only.
var body = {"name": "Godette"}
var error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body)
error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body)
if error != OK:
push_error("An error occurred in the HTTP request.")
@ -65,6 +65,7 @@
texture_rect.texture = texture
[/codeblock]
[b]Note:[/b] When performing HTTP requests from a project exported to HTML5, keep in mind the remote server may not allow requests from foreign origins due to [url=https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS]CORS[/url]. If you host the server in question, you should modify its backend to allow requests from foreign origins by adding the [code]Access-Control-Allow-Origin: *[/code] HTTP header.
[b]Note:[/b] SSL/TLS support is currently limited to TLS 1.0, TLS 1.1, and TLS 1.2. Attempting to connect to a TLS 1.3-only server will return an error.
</description>
<tutorials>
<link>https://docs.godotengine.org/en/3.2/tutorials/networking/http_request_class.html</link>
@ -124,9 +125,9 @@
<member name="body_size_limit" type="int" setter="set_body_size_limit" getter="get_body_size_limit" default="-1">
Maximum allowed size for response bodies.
</member>
<member name="download_chunk_size" type="int" setter="set_download_chunk_size" getter="get_download_chunk_size" default="4096">
<member name="download_chunk_size" type="int" setter="set_download_chunk_size" getter="get_download_chunk_size" default="65536">
The size of the buffer used and maximum bytes to read per iteration. See [member HTTPClient.read_chunk_size].
Set this to a higher value (e.g. 65536 for 64 KiB) when downloading large files to achieve better speeds at the cost of memory.
Set this to a lower value (e.g. 4096 for 4 KiB) when downloading small files to decrease memory usage at the cost of download speeds.
</member>
<member name="download_file" type="String" setter="set_download_file" getter="get_download_file" default="&quot;&quot;">
The file to download into. Will output any received file into it.

View file

@ -333,6 +333,16 @@
Loads an image from file [code]path[/code]. See [url=https://docs.godotengine.org/en/3.2/getting_started/workflow/assets/importing_images.html#supported-image-formats]Supported image formats[/url] for a list of supported image formats and limitations.
</description>
</method>
<method name="load_bmp_from_buffer">
<return type="int" enum="Error">
</return>
<argument index="0" name="buffer" type="PoolByteArray">
</argument>
<description>
Loads an image from the binary contents of a BMP file.
[b]Note:[/b] Godot's BMP module doesn't support 16-bit per pixel images. Only 1-bit, 4-bit, 8-bit, 24-bit, and 32-bit per pixel images are supported.
</description>
</method>
<method name="load_jpg_from_buffer">
<return type="int" enum="Error">
</return>

View file

@ -76,6 +76,13 @@
Returns the [PopupMenu] of this [LineEdit]. By default, this menu is displayed when right-clicking on the [LineEdit].
</description>
</method>
<method name="get_scroll_offset" qualifiers="const">
<return type="int">
</return>
<description>
Returns the scroll offset due to [member caret_position], as a number of characters.
</description>
</method>
<method name="menu_option">
<return type="void">
</return>

View file

@ -32,10 +32,10 @@
</methods>
<members>
<member name="axis_stretch_horizontal" type="int" setter="set_h_axis_stretch_mode" getter="get_h_axis_stretch_mode" enum="NinePatchRect.AxisStretchMode" default="0">
Doesn't do anything at the time of writing.
The stretch mode to use for horizontal stretching/tiling. See [enum NinePatchRect.AxisStretchMode] for possible values.
</member>
<member name="axis_stretch_vertical" type="int" setter="set_v_axis_stretch_mode" getter="get_v_axis_stretch_mode" enum="NinePatchRect.AxisStretchMode" default="0">
Doesn't do anything at the time of writing.
The stretch mode to use for vertical stretching/tiling. See [enum NinePatchRect.AxisStretchMode] for possible values.
</member>
<member name="draw_center" type="bool" setter="set_draw_center" getter="is_draw_center_enabled" default="true">
If [code]true[/code], draw the panel's center. Else, only draw the 9-slice's borders.
@ -69,13 +69,15 @@
</signals>
<constants>
<constant name="AXIS_STRETCH_MODE_STRETCH" value="0" enum="AxisStretchMode">
Doesn't do anything at the time of writing.
Stretches the center texture across the NinePatchRect. This may cause the texture to be distorted.
</constant>
<constant name="AXIS_STRETCH_MODE_TILE" value="1" enum="AxisStretchMode">
Doesn't do anything at the time of writing.
Repeats the center texture across the NinePatchRect. This won't cause any visible distortion. The texture must be seamless for this to work without displaying artifacts between edges.
[b]Note:[/b] Only supported when using the GLES3 renderer. When using the GLES2 renderer, this will behave like [constant AXIS_STRETCH_MODE_STRETCH].
</constant>
<constant name="AXIS_STRETCH_MODE_TILE_FIT" value="2" enum="AxisStretchMode">
Doesn't do anything at the time of writing.
Repeats the center texture across the NinePatchRect, but will also stretch the texture to make sure each tile is visible in full. This may cause the texture to be distorted, but less than [constant AXIS_STRETCH_MODE_STRETCH]. The texture must be seamless for this to work without displaying artifacts between edges.
[b]Note:[/b] Only supported when using the GLES3 renderer. When using the GLES2 renderer, this will behave like [constant AXIS_STRETCH_MODE_STRETCH].
</constant>
</constants>
</class>

View file

@ -25,7 +25,7 @@
</argument>
<description>
Calling this method connects this UDP peer to the given [code]host[/code]/[code]port[/code] pair. UDP is in reality connectionless, so this option only means that incoming packets from different addresses are automatically discarded, and that outgoing packets are always sent to the connected address (future calls to [method set_dest_address] are not allowed). This method does not send any data to the remote peer, to do that, use [method PacketPeer.put_var] or [method PacketPeer.put_packet] as usual. See also [UDPServer].
Note: Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
[b]Note:[/b] Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
</description>
</method>
<method name="get_packet_ip" qualifiers="const">
@ -123,6 +123,18 @@
</return>
<description>
Waits for a packet to arrive on the listening port. See [method listen].
[b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this:
[codeblock]
# Server
socket.set_dest_address("127.0.0.1", 789)
socket.put_packet("Time to stop".to_ascii())
# Client
while socket.wait() == OK:
var data = socket.get_packet().get_string_from_ascii()
if data == "Time to stop":
return
[/codeblock]
</description>
</method>
</methods>

View file

@ -447,19 +447,24 @@
Sets the window background to transparent when it starts.
</member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Force the window to be always on top.
Forces the main window to be always on top.
[b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
</member>
<member name="display/window/size/borderless" type="bool" setter="" getter="" default="false">
Force the window to be borderless.
Forces the main window to be borderless.
[b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
</member>
<member name="display/window/size/fullscreen" type="bool" setter="" getter="" default="false">
Sets the window to full screen when it starts.
Sets the main window to full screen when the project starts. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=https://docs.godotengine.org/en/latest/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
[b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
</member>
<member name="display/window/size/height" type="int" setter="" getter="" default="600">
Sets the game's main viewport height. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
Allows the window to be resizable by default.
[b]Note:[/b] This setting is ignored on iOS and Android.
</member>
<member name="display/window/size/test_height" type="int" setter="" getter="" default="0">
If greater than zero, overrides the window height when running the game. Useful for testing stretch modes.
@ -830,6 +835,8 @@
<member name="logging/file_logging/max_log_files" type="int" setter="" getter="" default="5">
Specifies the maximum amount of log files allowed (used for rotation).
</member>
<member name="memory/limits/command_queue/multithreading_queue_size_kb" type="int" setter="" getter="" default="256">
</member>
<member name="memory/limits/message_queue/max_size_kb" type="int" setter="" getter="" default="4096">
Godot uses a message queue to defer some function calls. If you run out of space on it (you will see an error), you can increase the size here.
</member>
@ -1069,6 +1076,14 @@
<member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="" default="3600">
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
</member>
<member name="rendering/options/api_usage_batching/flag_stream" type="bool" setter="" getter="" default="false">
</member>
<member name="rendering/options/api_usage_batching/send_null" type="bool" setter="" getter="" default="true">
</member>
<member name="rendering/options/api_usage_legacy/flag_stream" type="bool" setter="" getter="" default="false">
</member>
<member name="rendering/options/api_usage_legacy/orphan_buffers" type="bool" setter="" getter="" default="true">
</member>
<member name="rendering/quality/2d/ninepatch_mode" type="int" setter="" getter="" default="0">
Choose between default mode where corner scalings are preserved matching the artwork, and scaling mode.
Not available in GLES3 when [member rendering/batching/options/use_batching] is off.

View file

@ -74,9 +74,10 @@
</method>
</methods>
<members>
<member name="seed" type="int" setter="set_seed" getter="get_seed" default="-6398989897141750821">
<member name="seed" type="int" setter="set_seed" getter="get_seed" default="0">
The seed used by the random number generator. A given seed will give a reproducible sequence of pseudo-random numbers.
[b]Note:[/b] The RNG does not have an avalanche effect, and can output similar random streams given similar seeds. Consider using a hash function to improve your seed quality if they're sourced externally.
[b]Note:[/b] The default value of this property is pseudo-random, and changes when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed.
</member>
</members>
<constants>

View file

@ -4,7 +4,7 @@
Tabs control.
</brief_description>
<description>
Simple tabs control, similar to [TabContainer] but is only in charge of drawing tabs, not interact with children.
Simple tabs control, similar to [TabContainer] but is only in charge of drawing tabs, not interacting with children.
</description>
<tutorials>
</tutorials>

View file

@ -1480,9 +1480,9 @@ void EditorInspector::update_tree() {
String group_base;
VBoxContainer *category_vbox = NULL;
List<PropertyInfo>
plist;
List<PropertyInfo> plist;
object->get_property_list(&plist, true);
_update_script_class_properties(*object, plist);
HashMap<String, VBoxContainer *> item_path;
Map<VBoxContainer *, EditorInspectorSection *> section_map;
@ -1538,7 +1538,28 @@ void EditorInspector::update_tree() {
category_vbox = NULL; //reset
String type = p.name;
category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
Ref<Script> s = ResourceLoader::load(p.hint_string, "Script");
String base_type;
if (s.is_valid()) {
base_type = s->get_instance_base_type();
}
while (s.is_valid()) {
StringName name = EditorNode::get_editor_data().script_class_get_name(s->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
if (name != StringName() && icon_path.length()) {
category->icon = ResourceLoader::load(icon_path, "Texture");
break;
}
s = s->get_base_script();
}
if (category->icon.is_null() && has_icon(base_type, "EditorIcons")) {
category->icon = get_icon(base_type, "EditorIcons");
}
}
if (category->icon.is_null()) {
category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
}
category->label = type;
category->bg_color = get_color("prop_category", "Editor");
@ -2312,6 +2333,83 @@ void EditorInspector::_feature_profile_changed() {
update_tree();
}
void EditorInspector::_update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const {
Ref<Script> script = p_object.get_script();
if (script.is_null()) {
return;
}
List<StringName> classes;
Map<StringName, String> paths;
// NodeC -> NodeB -> NodeA
while (script.is_valid()) {
String n = EditorNode::get_editor_data().script_class_get_name(script->get_path());
if (n.length()) {
classes.push_front(n);
} else {
n = script->get_path().get_file();
classes.push_front(n);
}
paths[n] = script->get_path();
script = script->get_base_script();
}
if (classes.empty()) {
return;
}
// Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
List<PropertyInfo>::Element *script_variables = NULL;
List<PropertyInfo>::Element *bottom = NULL;
List<PropertyInfo>::Element *insert_here = NULL;
for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
PropertyInfo &pi = E->get();
if (pi.name != "Script Variables") {
continue;
}
script_variables = E;
bottom = r_list.insert_after(script_variables, PropertyInfo());
insert_here = bottom;
break;
}
Set<StringName> added;
for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
StringName name = E->get();
String path = paths[name];
Ref<Script> s = ResourceLoader::load(path, "Script");
List<PropertyInfo> props;
s->get_script_property_list(&props);
// Script Variables -> NodeA -> bottom (insert_here)
List<PropertyInfo>::Element *category = r_list.insert_before(insert_here, PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY));
// Script Variables -> NodeA -> A props... -> bottom (insert_here)
for (List<PropertyInfo>::Element *P = props.front(); P; P = P->next()) {
PropertyInfo &pi = P->get();
if (added.has(pi.name)) {
continue;
}
added.insert(pi.name);
r_list.insert_before(insert_here, pi);
}
// Script Variables -> NodeA (insert_here) -> A props... -> bottom
insert_here = category;
}
// NodeC -> C props... -> NodeB..C..
r_list.erase(script_variables);
List<PropertyInfo>::Element *to_delete = bottom->next();
while (to_delete && !(to_delete->get().usage & PROPERTY_USAGE_CATEGORY)) {
r_list.erase(to_delete);
to_delete = bottom->next();
}
r_list.erase(bottom);
}
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed, DEFVAL(""), DEFVAL(false));

View file

@ -325,6 +325,7 @@ class EditorInspector : public ScrollContainer {
void _vscroll_changed(double);
void _feature_profile_changed();
void _update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const;
bool _is_property_disabled_by_feature_profile(const StringName &p_property);

View file

@ -3952,8 +3952,6 @@ Ref<Texture> EditorNode::get_class_icon(const String &p_class, const String &p_f
if (icon.is_null()) {
icon = gui_base->get_icon(ScriptServer::get_global_class_base(name), "EditorIcons");
}
return icon;
}
const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();

View file

@ -904,6 +904,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "get_plugin_icon"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen"));

View file

@ -2547,7 +2547,8 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
editor = p_editor;
path = "res://";
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_C);
// `KEY_MASK_CMD | KEY_C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C);
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), KEY_DELETE);
ED_SHORTCUT("filesystem_dock/rename", TTR("Rename"));

View file

@ -209,7 +209,7 @@ void Polygon2DEditor::_uv_edit_mode_select(int p_mode) {
uv_button[UV_MODE_CREATE]->hide();
uv_button[UV_MODE_CREATE_INTERNAL]->hide();
uv_button[UV_MODE_REMOVE_INTERNAL]->hide();
for (int i = UV_MODE_MOVE; i <= UV_MODE_SCALE; i++) {
for (int i = UV_MODE_EDIT_POINT; i <= UV_MODE_SCALE; i++) {
uv_button[i]->show();
}
uv_button[UV_MODE_ADD_POLYGON]->hide();

View file

@ -661,9 +661,15 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era
return PoolVector<Vector2>();
}
// Check if the tile variation is the same
Vector2 prev_position = node->get_cell_autotile_coord(p_start.x, p_start.y);
if (ids.size() == 1 && ids[0] == prev_id) {
// Same ID, nothing to change
return PoolVector<Vector2>();
int current = manual_palette->get_current();
Vector2 position = manual_palette->get_item_metadata(current);
if (prev_position == position) {
// Same ID and variation, nothing to change
return PoolVector<Vector2>();
}
}
Rect2i r = node->get_used_rect();

View file

@ -1368,7 +1368,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: END");
GLOBAL_DEF("application/config/icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon", PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.webp"));
ProjectSettings::get_singleton()->set_custom_property_info("application/config/icon",
PropertyInfo(Variant::STRING, "application/config/icon",
PROPERTY_HINT_FILE, "*.png,*.webp,*.svg,*.svgz"));
GLOBAL_DEF("application/config/macos_native_icon", String());
ProjectSettings::get_singleton()->set_custom_property_info("application/config/macos_native_icon", PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"));

View file

@ -30,6 +30,8 @@
#include "image_loader_bmp.h"
#include "core/io/file_access_memory.h"
Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
const uint8_t *p_buffer,
const uint8_t *p_color_buffer,
@ -294,10 +296,21 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
return err;
}
void ImageLoaderBMP::get_recognized_extensions(
List<String> *p_extensions) const {
void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("bmp");
}
ImageLoaderBMP::ImageLoaderBMP() {}
static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) {
FileAccessMemory memfile;
Error open_memfile_error = memfile.open_custom(p_bmp, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer.");
Ref<Image> img;
img.instance();
Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image.");
return img;
}
ImageLoaderBMP::ImageLoaderBMP() {
Image::_bmp_mem_loader_func = _bmp_mem_loader_func;
}

View file

@ -4,3 +4,13 @@ def can_build(env, platform):
def configure(env):
pass
def get_doc_classes():
return [
"EditorSceneImporterFBX",
]
def get_doc_path():
return "doc_classes"

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorSceneImporterAssimp" inherits="EditorSceneImporter" version="3.2">
<class name="EditorSceneImporterFBX" inherits="EditorSceneImporter" version="3.2">
<brief_description>
FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url].
FBX 3D asset importer.
</brief_description>
<description>
This is an FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url]. It currently has many known limitations and works best with static meshes. Most animated meshes won't import correctly.
This is an FBX 3D asset importer with full support for most FBX features.
If exporting a FBX scene from Autodesk Maya, use these FBX export settings:
[codeblock]
- Smoothing Groups

View file

@ -94,14 +94,15 @@
<argument index="1" name="message" type="String" default="&quot;&quot;">
</argument>
<description>
Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development.
Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method push_error] for reporting errors to project developers or add-on users.
[b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
[codeblock]
# Imagine we always want speed to be between 0 and 20
speed = -10
# Imagine we always want speed to be between 0 and 20.
var speed = -10
assert(speed &lt; 20) # True, the program will continue
assert(speed &gt;= 0) # False, the program will stop
assert(speed &gt;= 0 &amp;&amp; speed &lt; 20) # You can also combine the two conditional statements in one check
assert(speed &gt;= 0 and speed &lt; 20) # You can also combine the two conditional statements in one check
assert(speed &lt; 20, "speed = %f, but the speed limit is 20" % speed) # Show a message with clarifying details
[/codeblock]
</description>

View file

@ -1120,6 +1120,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
}
} else if (methodstr == "call_recursive" && basestr == "TreeItem") {
if (argc >= 1) {
methodstr = String(*argptrs[0]) + " (via TreeItem.call_recursive)";
if (err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
err.argument += 1;
}
}
}
err_text = _get_call_error(err, "function '" + methodstr + "' in base '" + basestr + "'", (const Variant **)argptrs);
OPCODE_BREAK;

View file

@ -293,7 +293,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
r_ret = i < 0 ? -1 : (i > 0 ? +1 : 0);
} else if (p_args[0]->get_type() == Variant::REAL) {
real_t r = *p_args[0];
double r = *p_args[0];
r_ret = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
} else {
@ -520,8 +520,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
real_t a = *p_args[0];
real_t b = *p_args[1];
double a = *p_args[0];
double b = *p_args[1];
r_ret = MAX(a, b);
}
@ -538,8 +538,8 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
real_t a = *p_args[0];
real_t b = *p_args[1];
double a = *p_args[0];
double b = *p_args[1];
r_ret = MIN(a, b);
}
@ -557,9 +557,9 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
real_t a = *p_args[0];
real_t b = *p_args[1];
real_t c = *p_args[2];
double a = *p_args[0];
double b = *p_args[1];
double c = *p_args[2];
r_ret = CLAMP(a, b, c);
}

View file

@ -81,6 +81,11 @@ namespace Godot.Collections
return godot_icall_Array_Resize(GetPtr(), newSize);
}
public void Shuffle()
{
godot_icall_Array_Shuffle(GetPtr());
}
public static Array operator +(Array left, Array right)
{
return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr()));
@ -219,6 +224,9 @@ namespace Godot.Collections
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static Error godot_icall_Array_Shuffle(IntPtr ptr);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
@ -295,6 +303,11 @@ namespace Godot.Collections
return objectArray.Resize(newSize);
}
public void Shuffle()
{
objectArray.Shuffle();
}
public static Array<T> operator +(Array<T> left, Array<T> right)
{
return new Array<T>(left.objectArray + right.objectArray);

View file

@ -221,8 +221,7 @@ namespace Godot
real_t dot = v1.Dot(v2);
// Clamp dot to [-1, 1]
dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot);
dot = Mathf.Clamp(dot, -1.0f, 1.0f);
Vector2 v;

View file

@ -161,6 +161,10 @@ Error godot_icall_Array_Resize(Array *ptr, int new_size) {
return ptr->resize(new_size);
}
void godot_icall_Array_Shuffle(Array *ptr) {
ptr->shuffle();
}
void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
MonoType *elem_type = mono_reflection_type_get_type(refltype);
@ -321,6 +325,7 @@ void godot_register_collections_icalls() {
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", (void *)godot_icall_Array_Resize);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", (void *)godot_icall_Array_Shuffle);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", (void *)godot_icall_Array_Generic_GetElementTypeInfo);
mono_add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", (void *)godot_icall_Array_ToString);

View file

@ -316,9 +316,9 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("tga");
}
static Ref<Image> _tga_mem_loader_func(const uint8_t *p_png, int p_size) {
static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) {
FileAccessMemory memfile;
Error open_memfile_error = memfile.open_custom(p_png, p_size);
Error open_memfile_error = memfile.open_custom(p_tga, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer.");
Ref<Image> img;
img.instance();

View file

@ -82,8 +82,8 @@ android {
buildToolsVersion versions.buildTools
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
sourceCompatibility versions.javaVersion
targetCompatibility versions.javaVersion
}
defaultConfig {

View file

@ -1,12 +1,13 @@
ext.versions = [
androidGradlePlugin: '3.5.3',
androidGradlePlugin: '4.1.0',
compileSdk : 29,
minSdk : 18,
targetSdk : 29,
buildTools : '29.0.3',
buildTools : '30.0.1',
supportCoreUtils : '1.0.0',
kotlinVersion : '1.3.61',
v4Support : '1.0.0'
kotlinVersion : '1.4.10',
v4Support : '1.0.0',
javaVersion : 1.8
]

View file

@ -18,3 +18,5 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
org.gradle.warning.mode=all

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

View file

@ -18,6 +18,11 @@ android {
targetSdkVersion versions.targetSdk
}
compileOptions {
sourceCompatibility versions.javaVersion
targetCompatibility versions.javaVersion
}
lintOptions {
abortOnError false
disable 'MissingTranslation', 'UnusedResources'
@ -50,15 +55,6 @@ android {
def buildType = variant.buildType.name.capitalize()
def taskPrefix = ""
if (project.path != ":") {
taskPrefix = project.path + ":"
}
// Disable the externalNativeBuild* task as it would cause build failures since the cmake build
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
def releaseTarget = buildType.toLowerCase()
if (releaseTarget == null || releaseTarget == "") {
throw new GradleException("Invalid build type: " + buildType)
@ -78,10 +74,4 @@ android {
// Schedule the tasks so the generated libs are present before the aar file is packaged.
tasks["merge${buildType}JniLibFolders"].dependsOn taskName
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="org.godotengine.godot" />

View file

@ -1,3 +1,4 @@
# Non functional cmake build file used to provide Android Studio editor support to the project.
cmake_minimum_required(VERSION 3.6)
project(godot)

View file

@ -0,0 +1,4 @@
## Native sources configs
This is a non functional Android library used to provide Android Studio editor support to the Godot project native files.
Nothing else should be added to this library.

View file

@ -0,0 +1,54 @@
// Non functional android library used to provide Android Studio editor support to the project.
plugins {
id 'com.android.library'
}
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
}
compileOptions {
sourceCompatibility versions.javaVersion
targetCompatibility versions.javaVersion
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
// Should be uncommented for development purpose within Android Studio
// doNotStrip '**/*.so'
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
libraryVariants.all { variant ->
def buildType = variant.buildType.name.capitalize()
def taskPrefix = ""
if (project.path != ":") {
taskPrefix = project.path + ":"
}
// Disable the externalNativeBuild* task as it would cause build failures since the cmake build
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
}
}
dependencies {}

View file

@ -3,3 +3,4 @@ rootProject.name = "Godot"
include ':app'
include ':lib'
include ':nativeSrcsConfigs'

View file

@ -17,5 +17,5 @@ files = [
prog = env.add_program("#bin/godot", files)
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
if env["debug_symbols"] == "yes" and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_osx_builders.make_debug_osx))

View file

@ -25,7 +25,7 @@ def get_opts():
return [
("osxcross_sdk", "OSXCross SDK version", "darwin14"),
("MACOS_SDK_PATH", "Path to the macOS SDK", ""),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
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),
@ -50,8 +50,6 @@ def configure(env):
env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "release_debug":
@ -64,8 +62,6 @@ def configure(env):
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "debug":

View file

@ -38,7 +38,7 @@ def get_opts():
BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
]
@ -60,8 +60,6 @@ def configure(env):
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "release_debug":
@ -72,8 +70,6 @@ def configure(env):
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "debug":

View file

@ -31,5 +31,5 @@ if env["vsproj"]:
env.vs_srcs += ["platform/windows/" + str(x)]
if not os.getenv("VCINSTALLDIR"):
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
if env["debug_symbols"] == "yes" and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_windows_builders.make_debug_mingw))

View file

@ -64,7 +64,7 @@ def get_opts():
# XP support dropped after EOL due to missing API for IPv6 and other issues
# Vista support dropped after EOL due to GH-10243
("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None),
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
@ -202,7 +202,7 @@ def configure_msvc(env, manual_msvc_config):
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
env.Append(LINKFLAGS=["/DEBUG"])
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
if env["debug_symbols"] == "yes":
env.AppendUnique(CCFLAGS=["/Z7"])
env.AppendUnique(LINKFLAGS=["/DEBUG"])
@ -309,16 +309,12 @@ def configure_mingw(env):
env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "release_debug":
env.Append(CCFLAGS=["-O2"])
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["-O2"])

View file

@ -203,7 +203,7 @@ void JoypadWindows::setup_joypad_object(const DIDEVICEOBJECTINSTANCE *ob, int p_
HRESULT res;
DIPROPRANGE prop_range;
DIPROPDWORD dilong;
DWORD ofs;
LONG ofs;
if (ob->guidType == GUID_XAxis)
ofs = DIJOFS_X;
else if (ob->guidType == GUID_YAxis)
@ -426,7 +426,7 @@ void JoypadWindows::process_joypads() {
// on mingw, these constants are not constants
int count = 8;
unsigned int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, DIJOFS_SLIDER(0), DIJOFS_SLIDER(1) };
LONG axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ, (LONG)DIJOFS_SLIDER(0), (LONG)DIJOFS_SLIDER(1) };
int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz, js.rglSlider[0], js.rglSlider[1] };
for (int j = 0; j < joy->joy_axis.size(); j++) {

View file

@ -78,7 +78,7 @@ private:
DWORD last_pad;
LPDIRECTINPUTDEVICE8 di_joy;
List<DWORD> joy_axis;
List<LONG> joy_axis;
GUID guid;
dinput_gamepad() {

View file

@ -2405,7 +2405,7 @@ void OS_Windows::_update_window_style(bool p_repaint, bool p_maximized) {
Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
String path = p_path;
String path = p_path.replace("/", "\\");
if (!FileAccess::exists(path)) {
//this code exists so gdnative can load .dll files from within the executable path
@ -2884,9 +2884,10 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const {
}
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
String path = p_path.replace("/", "\\");
if (p_blocking && r_pipe) {
String argss = _quote_command_line_argument(p_path);
String argss = _quote_command_line_argument(path);
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
argss += " " + _quote_command_line_argument(E->get());
}
@ -2920,7 +2921,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
return OK;
}
String cmdline = _quote_command_line_argument(p_path);
String cmdline = _quote_command_line_argument(path);
const List<String>::Element *I = p_arguments.front();
while (I) {
cmdline += " " + _quote_command_line_argument(I->get());
@ -2994,7 +2995,7 @@ String OS_Windows::get_executable_path() const {
wchar_t bufname[4096];
GetModuleFileNameW(NULL, bufname, 4096);
String s = bufname;
return s;
return s.replace("\\", "/");
}
void OS_Windows::set_native_icon(const String &p_filename) {

View file

@ -17,5 +17,5 @@ common_x11 = [
prog = env.add_program("#bin/godot", ["godot_x11.cpp"] + common_x11)
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
if env["debug_symbols"] == "yes" and env["separate_debug_symbols"]:
env.AddPostAction(prog, run_in_subprocess(platform_x11_builders.make_debug_x11))

View file

@ -73,7 +73,7 @@ def get_opts():
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", False),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("touch", "Enable touch events", True),
BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
@ -97,8 +97,6 @@ def configure(env):
env.Prepend(CCFLAGS=["-Os"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "release_debug":
@ -111,8 +109,6 @@ def configure(env):
env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
if env["debug_symbols"] == "yes":
env.Prepend(CCFLAGS=["-g1"])
if env["debug_symbols"] == "full":
env.Prepend(CCFLAGS=["-g2"])
elif env["target"] == "debug":

View file

@ -782,13 +782,10 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f
else if (next_pos > len)
next_pos = len;
// fix delta
delta = next_pos - cd.pos;
bool backwards = signbit(delta); // Negative zero means playing backwards too
delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here)
if (&cd == &playback.current) {
bool backwards = delta < 0;
if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) {
//playback finished
end_reached = true;

View file

@ -2960,7 +2960,9 @@ void Control::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
BIND_VMETHOD(MethodInfo(
PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"),
"_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input"));
ADD_GROUP("Anchor", "anchor_");

View file

@ -674,7 +674,7 @@ void LineEdit::_notification(int p_what) {
#endif
case NOTIFICATION_RESIZED: {
window_pos = 0;
scroll_offset = 0;
set_cursor_position(get_cursor_position());
} break;
@ -735,7 +735,7 @@ void LineEdit::_notification(int p_what) {
} break;
case ALIGN_CENTER: {
if (window_pos != 0)
if (scroll_offset != 0)
x_ofs = style->get_offset().x;
else
x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (cached_text_width)) / 2);
@ -747,7 +747,7 @@ void LineEdit::_notification(int p_what) {
}
int ofs_max = width - style->get_margin(MARGIN_RIGHT);
int char_ofs = window_pos;
int char_ofs = scroll_offset;
int y_area = height - style->get_minimum_size().height;
int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2;
@ -779,7 +779,7 @@ void LineEdit::_notification(int p_what) {
r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
if (align == ALIGN_CENTER) {
if (window_pos == 0) {
if (scroll_offset == 0) {
x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
}
} else {
@ -1012,7 +1012,7 @@ void LineEdit::undo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
cached_width = op.cached_width;
window_pos = op.window_pos;
scroll_offset = op.scroll_offset;
set_cursor_position(op.cursor_pos);
if (expand_to_text_length)
@ -1032,7 +1032,7 @@ void LineEdit::redo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
cached_width = op.cached_width;
window_pos = op.window_pos;
scroll_offset = op.scroll_offset;
set_cursor_position(op.cursor_pos);
if (expand_to_text_length)
@ -1059,7 +1059,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
void LineEdit::set_cursor_at_pixel_pos(int p_x) {
Ref<Font> font = get_font("font");
int ofs = window_pos;
int ofs = scroll_offset;
Ref<StyleBox> style = get_stylebox("normal");
int pixel_ofs = 0;
Size2 size = get_size();
@ -1075,7 +1075,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
} break;
case ALIGN_CENTER: {
if (window_pos != 0)
if (scroll_offset != 0)
pixel_ofs = int(style->get_offset().x);
else
pixel_ofs = int(size.width - (cached_width)) / 2;
@ -1113,7 +1113,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
int LineEdit::get_cursor_pixel_pos() {
Ref<Font> font = get_font("font");
int ofs = window_pos;
int ofs = scroll_offset;
Ref<StyleBox> style = get_stylebox("normal");
int pixel_ofs = 0;
Size2 size = get_size();
@ -1129,7 +1129,7 @@ int LineEdit::get_cursor_pixel_pos() {
} break;
case ALIGN_CENTER: {
if (window_pos != 0)
if (scroll_offset != 0)
pixel_ofs = int(style->get_offset().x);
else
pixel_ofs = int(size.width - (cached_width)) / 2;
@ -1215,7 +1215,7 @@ void LineEdit::delete_char() {
set_cursor_position(get_cursor_position() - 1);
if (align == ALIGN_CENTER || align == ALIGN_RIGHT) {
window_pos = CLAMP(window_pos - 1, 0, MAX(text.length() - 1, 0));
scroll_offset = CLAMP(scroll_offset - 1, 0, MAX(text.length() - 1, 0));
}
_text_changed();
@ -1242,13 +1242,13 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
cursor_pos = text.length();
}
if (window_pos > cursor_pos) {
if (scroll_offset > cursor_pos) {
window_pos = cursor_pos;
scroll_offset = cursor_pos;
}
if (align == ALIGN_CENTER || align == ALIGN_RIGHT) {
window_pos = CLAMP(window_pos - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0));
scroll_offset = CLAMP(scroll_offset - (p_to_column - p_from_column), 0, MAX(text.length() - 1, 0));
}
if (!text_changed_dirty) {
@ -1270,7 +1270,7 @@ void LineEdit::set_text(String p_text) {
update();
cursor_pos = 0;
window_pos = 0;
scroll_offset = 0;
}
void LineEdit::clear() {
@ -1319,17 +1319,16 @@ void LineEdit::set_cursor_position(int p_pos) {
cursor_pos = p_pos;
if (!is_inside_tree()) {
window_pos = cursor_pos;
scroll_offset = cursor_pos;
return;
}
Ref<StyleBox> style = get_stylebox("normal");
Ref<Font> font = get_font("font");
if (cursor_pos <= window_pos) {
if (cursor_pos <= scroll_offset) {
// Adjust window if cursor goes too much to the left.
set_window_pos(MAX(0, cursor_pos - 1));
set_scroll_offset(MAX(0, cursor_pos - 1));
} else {
// Adjust window if cursor goes too much to the right.
int window_width = get_size().width - style->get_minimum_size().width;
@ -1341,14 +1340,13 @@ void LineEdit::set_cursor_position(int p_pos) {
if (window_width < 0)
return;
int wp = window_pos;
int wp = scroll_offset;
if (font.is_valid()) {
int accum_width = 0;
for (int i = cursor_pos; i >= window_pos; i--) {
for (int i = cursor_pos; i >= scroll_offset; i--) {
if (i >= text.length()) {
// Do not do this, because if the cursor is at the end, its just fine that it takes no space.
// accum_width = font->get_char_size(' ').width;
@ -1366,8 +1364,9 @@ void LineEdit::set_cursor_position(int p_pos) {
}
}
if (wp != window_pos)
set_window_pos(wp);
if (wp != scroll_offset) {
set_scroll_offset(wp);
}
}
update();
}
@ -1377,10 +1376,15 @@ int LineEdit::get_cursor_position() const {
return cursor_pos;
}
void LineEdit::set_window_pos(int p_pos) {
void LineEdit::set_scroll_offset(int p_pos) {
scroll_offset = p_pos;
if (scroll_offset < 0) {
scroll_offset = 0;
}
}
window_pos = p_pos;
if (window_pos < 0) window_pos = 0;
int LineEdit::get_scroll_offset() const {
return scroll_offset;
}
void LineEdit::append_at_cursor(String p_text) {
@ -1402,7 +1406,7 @@ void LineEdit::clear_internal() {
_clear_undo_stack();
cached_width = 0;
cursor_pos = 0;
window_pos = 0;
scroll_offset = 0;
undo_text = "";
text = "";
update();
@ -1637,7 +1641,7 @@ void LineEdit::set_expand_to_text_length(bool p_enabled) {
expand_to_text_length = p_enabled;
minimum_size_changed();
set_window_pos(0);
set_scroll_offset(0);
}
bool LineEdit::get_expand_to_text_length() const {
@ -1762,7 +1766,7 @@ void LineEdit::_create_undo_state() {
op.text = text;
op.cached_width = cached_width;
op.cursor_pos = cursor_pos;
op.window_pos = window_pos;
op.scroll_offset = scroll_offset;
undo_stack.push_back(op);
}
@ -1808,6 +1812,7 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha);
ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position);
ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position);
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset);
ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length);
ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length);
ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled);
@ -1888,7 +1893,7 @@ LineEdit::LineEdit() {
cached_width = 0;
cached_placeholder_width = 0;
cursor_pos = 0;
window_pos = 0;
scroll_offset = 0;
window_has_focus = true;
max_length = 0;
pass = false;

View file

@ -81,7 +81,7 @@ private:
PopupMenu *menu;
int cursor_pos;
int window_pos;
int scroll_offset;
int max_length; // 0 for no maximum.
int cached_width;
@ -108,7 +108,7 @@ private:
struct TextOperation {
int cursor_pos;
int window_pos;
int scroll_offset;
int cached_width;
String text;
};
@ -145,7 +145,8 @@ private:
void shift_selection_check_post(bool);
void selection_fill_at_cursor();
void set_window_pos(int p_pos);
void set_scroll_offset(int p_pos);
int get_scroll_offset() const;
void set_cursor_at_pixel_pos(int p_x);
int get_cursor_pixel_pos();

View file

@ -286,7 +286,6 @@ void TabContainer::_notification(int p_what) {
Color font_color_bg = get_color("font_color_bg");
Color font_color_disabled = get_color("font_color_disabled");
int side_margin = get_constant("side_margin");
int icon_text_distance = get_constant("hseparation");
// Find out start and width of the header area.
int header_x = side_margin;
@ -350,60 +349,35 @@ void TabContainer::_notification(int p_what) {
break;
}
// Draw the tab area.
panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
// Draw all visible tabs.
// Draw unselected tabs in back
int x = 0;
int x_current = 0;
for (int i = 0; i < tab_widths.size(); i++) {
if (get_tab_hidden(i)) {
continue;
}
Ref<StyleBox> tab_style;
Color font_color;
if (get_tab_disabled(i + first_tab_cache)) {
tab_style = tab_disabled;
font_color = font_color_disabled;
} else if (i + first_tab_cache == current) {
tab_style = tab_fg;
font_color = font_color_fg;
} else {
tab_style = tab_bg;
font_color = font_color_bg;
}
// Draw the tab background.
int tab_width = tab_widths[i];
Rect2 tab_rect(tabs_ofs_cache + x, 0, tab_width, header_height);
tab_style->draw(canvas, tab_rect);
// Draw the tab contents.
Control *control = Object::cast_to<Control>(tabs[i + first_tab_cache]);
String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name()));
int x_content = tab_rect.position.x + tab_style->get_margin(MARGIN_LEFT);
int top_margin = tab_style->get_margin(MARGIN_TOP);
int y_center = top_margin + (tab_rect.size.y - tab_style->get_minimum_size().y) / 2;
// Draw the tab icon.
if (control->has_meta("_tab_icon")) {
Ref<Texture> icon = control->get_meta("_tab_icon");
if (icon.is_valid()) {
int y = y_center - (icon->get_height() / 2);
icon->draw(canvas, Point2i(x_content, y));
if (text != "")
x_content += icon->get_width() + icon_text_distance;
}
if (get_tab_disabled(i + first_tab_cache)) {
_draw_tab(tab_disabled, font_color_disabled, i, tabs_ofs_cache + x);
} else if (i + first_tab_cache == current) {
x_current = x;
} else {
_draw_tab(tab_bg, font_color_bg, i, tabs_ofs_cache + x);
}
// Draw the tab text.
Point2i text_pos(x_content, y_center - (font->get_height() / 2) + font->get_ascent());
font->draw(canvas, text_pos, text, font_color);
x += tab_width;
last_tab_cache = i + first_tab_cache;
}
// Draw the tab area.
panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
// Draw selected tab in front. Need to check tabs.size() in case of no contents at all.
if (tabs.size() > 0) {
_draw_tab(tab_fg, font_color_fg, current, tabs_ofs_cache + x_current);
}
// Draw the popup menu.
x = get_size().width;
if (popup) {
@ -440,6 +414,43 @@ void TabContainer::_notification(int p_what) {
}
}
void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) {
Vector<Control *> tabs = _get_tabs();
RID canvas = get_canvas_item();
Ref<Font> font = get_font("font");
int icon_text_distance = get_constant("icon_separation");
int tab_width = _get_tab_width(p_index);
int header_height = _get_top_margin();
// Draw the tab background.
Rect2 tab_rect(p_x, 0, tab_width, header_height);
p_tab_style->draw(canvas, tab_rect);
// Draw the tab contents.
Control *control = Object::cast_to<Control>(tabs[p_index + first_tab_cache]);
String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name()));
int x_content = tab_rect.position.x + p_tab_style->get_margin(MARGIN_LEFT);
int top_margin = p_tab_style->get_margin(MARGIN_TOP);
int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2;
// Draw the tab icon.
if (control->has_meta("_tab_icon")) {
Ref<Texture> icon = control->get_meta("_tab_icon");
if (icon.is_valid()) {
int y = y_center - (icon->get_height() / 2);
icon->draw(canvas, Point2i(x_content, y));
if (text != "") {
x_content += icon->get_width() + icon_text_distance;
}
}
}
// Draw the tab text.
Point2i text_pos(x_content, y_center - (font->get_height() / 2) + font->get_ascent());
font->draw(canvas, text_pos, text, p_font_color);
}
void TabContainer::_on_theme_changed() {
if (get_tab_count() > 0) {
_repaint();

View file

@ -69,6 +69,7 @@ private:
void _repaint();
void _on_mouse_exited();
void _update_current_tab();
void _draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x);
protected:
void _child_renamed_callback();

View file

@ -169,6 +169,11 @@ ViewportTexture::~ViewportTexture() {
/////////////////////////////////////
// Aliases used to provide custom styles to tooltips in the default
// theme and editor theme.
// TooltipPanel is also used for custom tooltips, while TooltipLabel
// is only relevant for default tooltips.
class TooltipPanel : public PanelContainer {
GDCLASS(TooltipPanel, PanelContainer);
@ -185,6 +190,8 @@ public:
TooltipLabel(){};
};
/////////////////////////////////////
Viewport::GUI::GUI() {
dragging = false;
@ -194,7 +201,7 @@ Viewport::GUI::GUI() {
key_focus = NULL;
mouse_over = NULL;
tooltip = NULL;
tooltip_control = NULL;
tooltip_popup = NULL;
tooltip_label = NULL;
subwindow_visibility_dirty = false;
@ -1528,7 +1535,7 @@ void Viewport::_gui_sort_roots() {
void Viewport::_gui_cancel_tooltip() {
gui.tooltip = NULL;
gui.tooltip_control = NULL;
gui.tooltip_timer = -1;
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
@ -1537,7 +1544,7 @@ void Viewport::_gui_cancel_tooltip() {
}
}
String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) {
String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner) {
Vector2 pos = p_pos;
String tooltip;
@ -1546,19 +1553,25 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
tooltip = p_control->get_tooltip(pos);
if (r_which) {
*r_which = p_control;
if (r_tooltip_owner) {
*r_tooltip_owner = p_control;
}
if (tooltip != String())
// If we found a tooltip, we stop here.
if (!tooltip.empty()) {
break;
pos = p_control->get_transform().xform(pos);
}
// Otherwise, we check parent controls unless some conditions prevent it.
if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
break;
if (p_control->is_set_as_toplevel())
break;
// Transform cursor pos for parent control.
pos = p_control->get_transform().xform(pos);
p_control = p_control->get_parent_control();
}
@ -1567,33 +1580,39 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
void Viewport::_gui_show_tooltip() {
if (!gui.tooltip) {
if (!gui.tooltip_control) {
return;
}
Control *which = NULL;
String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
tooltip = tooltip.strip_edges();
if (tooltip.length() == 0)
return; // bye
// Get the Control under cursor and the relevant tooltip text, if any.
Control *tooltip_owner = NULL;
String tooltip_text = _gui_get_tooltip(
gui.tooltip_control,
gui.tooltip_control->get_global_transform().xform_inv(gui.tooltip_pos),
&tooltip_owner);
tooltip_text.strip_edges();
if (tooltip_text.empty()) {
return; // Nothing to show.
}
// Remove previous popup if we change something.
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
gui.tooltip_popup = NULL;
gui.tooltip_label = NULL;
}
if (!which) {
if (!tooltip_owner) {
return;
}
Control *rp = which;
gui.tooltip_popup = which->make_custom_tooltip(tooltip);
// Controls can implement `make_custom_tooltip` to provide their own tooltip.
// This should be a Control node which will be added as child to the tooltip owner.
gui.tooltip_popup = tooltip_owner->make_custom_tooltip(tooltip_text);
// If no custom tooltip is given, use a default implementation.
if (!gui.tooltip_popup) {
gui.tooltip_popup = memnew(TooltipPanel);
gui.tooltip_label = memnew(TooltipLabel);
gui.tooltip_popup->add_child(gui.tooltip_label);
@ -1603,14 +1622,14 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
gui.tooltip_label->set_text(tooltip);
gui.tooltip_label->set_text(tooltip_text);
}
rp->add_child(gui.tooltip_popup);
tooltip_owner->add_child(gui.tooltip_popup);
gui.tooltip_popup->force_parent_owned();
gui.tooltip_popup->set_as_toplevel(true);
if (gui.tooltip) // Avoids crash when rapidly switching controls.
gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
if (gui.tooltip_control) // Avoids crash when rapidly switching controls.
gui.tooltip_popup->set_scale(gui.tooltip_control->get_global_transform().get_scale());
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
@ -1860,6 +1879,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Control *over = NULL;
Point2 mpos = mb->get_position();
if (mb->is_pressed()) {
@ -2000,8 +2021,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
_gui_cancel_tooltip();
//gui.tooltip_popup->hide();
} else {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
@ -2054,6 +2073,31 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data=Variant(); //always clear
}*/
// In case the mouse was released after for example dragging a scrollbar,
// check whether the current control is different from the stored one. If
// it is different, rather than wait for it to be updated the next time the
// mouse is moved, notify the control so that it can e.g. drop the highlight.
// This code is duplicated from the mm.is_valid()-case further below.
if (gui.mouse_focus) {
over = gui.mouse_focus;
} else {
over = _gui_find_control(mpos);
}
if (gui.mouse_focus_mask == 0 && over != gui.mouse_over) {
if (gui.mouse_over) {
_gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
}
_gui_cancel_tooltip();
if (over) {
_gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
}
}
gui.mouse_over = over;
set_input_as_handled();
}
}
@ -2118,10 +2162,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
// These sections of code are reused in the mb.is_valid() case further up
// for the purpose of notifying controls about potential changes in focus
// when the mousebutton is released.
if (gui.mouse_focus) {
over = gui.mouse_focus;
//recompute focus_inv_xform again here
} else {
over = _gui_find_control(mpos);
@ -2214,8 +2259,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_tooltip_shown = false;
if (gui.tooltip_popup) {
if (can_tooltip && gui.tooltip) {
String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
if (can_tooltip && gui.tooltip_control) {
String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform().xform_inv(mpos));
if (tooltip.length() == 0)
_gui_cancel_tooltip();
@ -2232,14 +2277,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (can_tooltip && !is_tooltip_shown) {
gui.tooltip = over;
gui.tooltip_pos = mpos; //(parent_xform * get_transform()).affine_inverse().xform(pos);
gui.tooltip_control = over;
gui.tooltip_pos = mpos;
gui.tooltip_timer = gui.tooltip_delay;
}
}
//pos = gui.focus_inv_xform.xform(pos);
mm->set_position(pos);
Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
@ -2605,21 +2648,11 @@ void Viewport::_gui_hid_control(Control *p_control) {
_drop_mouse_focus();
}
/* ???
if (data.window==p_control) {
window->drag_data=Variant();
if (window->drag_preview) {
memdelete( window->drag_preview);
window->drag_preview=NULL;
}
}
*/
if (gui.key_focus == p_control)
_gui_remove_focus();
if (gui.mouse_over == p_control)
gui.mouse_over = NULL;
if (gui.tooltip == p_control)
if (gui.tooltip_control == p_control)
_gui_cancel_tooltip();
}
@ -2636,8 +2669,8 @@ void Viewport::_gui_remove_control(Control *p_control) {
gui.key_focus = NULL;
if (gui.mouse_over == p_control)
gui.mouse_over = NULL;
if (gui.tooltip == p_control)
gui.tooltip = NULL;
if (gui.tooltip_control == p_control)
gui.tooltip_control = NULL;
if (gui.tooltip_popup == p_control) {
_gui_cancel_tooltip();
}
@ -3420,14 +3453,13 @@ Viewport::Viewport() {
disable_3d = false;
keep_3d_linear = false;
//window tooltip
// Window tooltip.
gui.tooltip_timer = -1;
//gui.tooltip_timer->force_parent_owned();
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
gui.tooltip = NULL;
gui.tooltip_control = NULL;
gui.tooltip_label = NULL;
gui.drag_preview = NULL;
gui.drag_attempted = false;

View file

@ -299,7 +299,7 @@ private:
int mouse_focus_mask;
Control *key_focus;
Control *mouse_over;
Control *tooltip;
Control *tooltip_control;
Control *tooltip_popup;
Label *tooltip_label;
Point2 tooltip_pos;
@ -360,7 +360,7 @@ private:
void _gui_remove_root_control(List<Control *>::Element *RI);
void _gui_remove_subwindow_control(List<Control *>::Element *SI);
String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL);
String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner = NULL);
void _gui_cancel_tooltip();
void _gui_show_tooltip();

View file

@ -947,6 +947,7 @@ bool AudioServer::is_bus_channel_active(int p_bus, int p_channel) const {
}
void AudioServer::set_global_rate_scale(float p_scale) {
ERR_FAIL_COND(p_scale <= 0);
global_rate_scale = p_scale;
}

View file

@ -314,7 +314,7 @@ Collection of single-file libraries used in Godot components.
* License: Apache 2.0
- `open-simplex-noise.{c,h}`
* Upstream: https://github.com/smcameron/open-simplex-noise-in-c
* Version: git (0d555e7f40527d0870906fe9469a3b1bb4020b7f, 2015) + custom changes
* Version: git (0fef0dbedd76f767da7e3c894822729d0f07e54d, 2020) + custom changes
* License: Unlicense
- `pcg.{cpp,h}`
* Upstream: http://www.pcg-random.org

View file

@ -189,14 +189,15 @@ int open_simplex_noise(int64_t seed, struct osn_context *ctx)
permGradIndex3D = ctx->permGradIndex3D;
// -- GODOT end --
uint64_t seedU = seed;
for (i = 0; i < 256; i++)
source[i] = (int16_t) i;
seed = seed * 6364136223846793005LL + 1442695040888963407LL;
seed = seed * 6364136223846793005LL + 1442695040888963407LL;
seed = seed * 6364136223846793005LL + 1442695040888963407LL;
seedU = seedU * 6364136223846793005ULL + 1442695040888963407ULL;
seedU = seedU * 6364136223846793005ULL + 1442695040888963407ULL;
seedU = seedU * 6364136223846793005ULL + 1442695040888963407ULL;
for (i = 255; i >= 0; i--) {
seed = seed * 6364136223846793005LL + 1442695040888963407LL;
r = (int)((seed + 31) % (i + 1));
seedU = seedU * 6364136223846793005ULL + 1442695040888963407ULL;
r = (int)((seedU + 31) % (i + 1));
if (r < 0)
r += (i + 1);
perm[i] = source[r];