Merge pull request #64103 from akien-mga/3.5-cherrypicks

This commit is contained in:
Rémi Verschelde 2022-08-08 16:25:33 +02:00 committed by GitHub
commit 76d3453511
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 243 additions and 143 deletions

View file

@ -315,10 +315,10 @@ uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) con
} else {
read_block--;
at_end = true;
if (i < p_length - 1) {
if (i + 1 < p_length) {
read_eof = true;
}
return i;
return i + 1;
}
}
}

View file

@ -5,6 +5,7 @@
</brief_description>
<description>
A curve that can be saved and re-used for other objects. By default, it ranges between [code]0[/code] and [code]1[/code] on the Y axis and positions points relative to the [code]0.5[/code] Y position.
See also [Gradient] which is designed for color interpolation. See also [Curve2D] and [Curve3D].
</description>
<tutorials>
</tutorials>

View file

@ -4,7 +4,8 @@
A color interpolator resource which can be used to generate colors between user-defined color points.
</brief_description>
<description>
Given a set of colors, this resource will interpolate them in order. This means that if you have color 1, color 2 and color 3, the ramp will interpolate from color 1 to color 2 and from color 2 to color 3. The ramp will initially have 2 colors (black and white), one (black) at ramp lower offset 0 and the other (white) at the ramp higher offset 1.
Given a set of colors, this resource will interpolate them in order. This means that if you have color 1, color 2 and color 3, the gradient will interpolate from color 1 to color 2 and from color 2 to color 3. The gradient will initially have 2 colors (black and white), one (black) at gradient lower offset 0 and the other (white) at the gradient higher offset 1.
See also [Curve] which supports more complex easing methods, but does not support colors.
</description>
<tutorials>
</tutorials>

View file

@ -4,7 +4,8 @@
Low-level hyper-text transfer protocol client.
</brief_description>
<description>
Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for a higher-level alternative.[/b]
Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases.
See the [HTTPRequest] node for a higher-level alternative.
[b]Note:[/b] This client only needs to connect to a host once (see [method connect_to_host]) to send multiple requests. Because of this, methods that take URLs usually take just the part after the host instead of the full URL, as the client is already connected to a host. See [method request] for a full example and to get started.
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).

View file

@ -81,7 +81,7 @@
<argument index="1" name="color" type="Color" />
<description>
Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors.
For the color to take effect, ensure that [member color_format] is non-[code]null[/code] on the [MultiMesh] and [member SpatialMaterial.vertex_color_use_as_albedo] is [code]true[/code] on the material.
For the color to take effect, ensure that [member color_format] is non-[code]null[/code] on the [MultiMesh] and [member SpatialMaterial.vertex_color_use_as_albedo] is [code]true[/code] on the material. If the color doesn't look as expected, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
</description>
</method>
<method name="set_instance_custom_data">

View file

@ -69,7 +69,8 @@
</methods>
<members>
<member name="custom_solver_bias" type="float" setter="set_custom_solver_bias" getter="get_custom_solver_bias" default="0.0">
The shape's custom solver bias.
The shape's custom solver bias. Defines how much bodies react to enforce contact separation when this shape is involved.
When set to [code]0.0[/code], the default value of [code]0.3[/code] is used.
</member>
</members>
<constants>

View file

@ -696,6 +696,7 @@
<description>
Splits the string by a [code]delimiter[/code] string and returns an array of the substrings, starting from right.
The splits in the returned array are sorted in the same order as the original string, from left to right.
If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split].
Example:
[codeblock]
@ -765,6 +766,7 @@
<argument index="2" name="maxsplit" type="int" default="0" />
<description>
Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length.
If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split.
If you need only one element from the array at a specific index, [method get_slice] is a more performant option.
Example:
@ -785,6 +787,7 @@
<description>
Splits the string in floats by using a delimiter string and returns an array of the substrings.
For example, [code]"1,2.5,3"[/code] will return [code][1,2.5,3][/code] if split by [code]","[/code].
If [code]allow_empty[/code] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
</description>
</method>
<method name="strip_edges">

View file

@ -483,6 +483,7 @@ public:
Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { return Transform(); }
void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {}
Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { return Transform2D(); }
uint32_t skeleton_get_revision(RID p_skeleton) const { return 0; }
/* Light API */

View file

@ -3731,6 +3731,7 @@ void RasterizerStorageGLES2::skeleton_bone_set_transform_2d(RID p_skeleton, int
if (!skeleton->update_list.in_list()) {
skeleton_update_list.add(&skeleton->update_list);
}
skeleton->revision++;
}
Transform2D RasterizerStorageGLES2::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
@ -3763,6 +3764,12 @@ void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, cons
skeleton->base_transform_2d = p_base_transform;
}
uint32_t RasterizerStorageGLES2::skeleton_get_revision(RID p_skeleton) const {
const Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND_V(!skeleton, 0);
return skeleton->revision;
}
void RasterizerStorageGLES2::update_dirty_blend_shapes() {
while (blend_shapes_update_list.first()) {
Mesh *mesh = blend_shapes_update_list.first()->self();

View file

@ -890,6 +890,7 @@ public:
bool use_2d;
int size;
uint32_t revision;
// TODO use float textures for storage
@ -905,6 +906,7 @@ public:
Skeleton() :
use_2d(false),
size(0),
revision(1),
tex_id(0),
update_list(this) {
}
@ -924,6 +926,7 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
virtual uint32_t skeleton_get_revision(RID p_skeleton) const;
void _update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size);

View file

@ -5277,6 +5277,8 @@ void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int
if (!skeleton->update_list.in_list()) {
skeleton_update_list.add(&skeleton->update_list);
}
skeleton->revision++;
}
Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
@ -5310,6 +5312,12 @@ void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, cons
skeleton->base_transform_2d = p_base_transform;
}
uint32_t RasterizerStorageGLES3::skeleton_get_revision(RID p_skeleton) const {
const Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND_V(!skeleton, 0);
return skeleton->revision;
}
void RasterizerStorageGLES3::update_dirty_skeletons() {
glActiveTexture(GL_TEXTURE0);

View file

@ -920,6 +920,7 @@ public:
struct Skeleton : RID_Data {
bool use_2d;
int size;
uint32_t revision;
Vector<float> skel_texture;
GLuint texture;
SelfList<Skeleton> update_list;
@ -929,6 +930,7 @@ public:
Skeleton() :
use_2d(false),
size(0),
revision(1),
texture(0),
update_list(this) {
}
@ -948,6 +950,7 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform);
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
virtual uint32_t skeleton_get_revision(RID p_skeleton) const;
/* Light API */

View file

@ -1448,8 +1448,7 @@ void EditorInspector::update_tree() {
String group_base;
VBoxContainer *category_vbox = nullptr;
List<PropertyInfo>
plist;
List<PropertyInfo> plist;
object->get_property_list(&plist, true);
HashMap<String, VBoxContainer *> item_path;

View file

@ -1450,14 +1450,13 @@ void FileSystemDock::_folder_removed(String p_folder) {
void FileSystemDock::_rename_operation_confirm() {
String new_name = rename_dialog_text->get_text().strip_edges();
String old_name = tree->get_selected()->get_text(0);
if (new_name.length() == 0) {
EditorNode::get_singleton()->show_warning(TTR("No name provided."));
return;
} else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) {
EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters."));
return;
} else if (to_rename.is_file && old_name.get_extension() != new_name.get_extension()) {
} else if (to_rename.is_file && to_rename.path.get_extension() != new_name.get_extension()) {
if (!EditorFileSystem::get_singleton()->get_valid_extensions().find(new_name.get_extension())) {
EditorNode::get_singleton()->show_warning(TTR("This file extension is not recognized by the editor.\nIf you want to rename it anyway, use your operating system's file manager.\nAfter renaming to an unknown extension, the file won't be shown in the editor anymore."));
return;

View file

@ -319,9 +319,9 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
} else {
Vector<Vector2> vertices2 = _get_polygon(insert.polygon);
pre_move_edit = vertices2;
edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
vertices2.insert(edited_point.vertex, edited_point.pos);
pre_move_edit = vertices2;
selected_point = edited_point;
edge_point = PosVertex();

View file

@ -46,6 +46,7 @@
#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite.h"
#include "scene/2d/touch_screen_button.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/nine_patch_rect.h"
#include "scene/gui/viewport_container.h"
@ -4401,7 +4402,7 @@ void CanvasItemEditor::_update_context_menu_stylebox() {
context_menu_stylebox->set_border_color(accent_color);
context_menu_stylebox->set_border_width(MARGIN_BOTTOM, Math::round(2 * EDSCALE));
context_menu_stylebox->set_default_margin(MARGIN_BOTTOM, 0);
context_menu_container->add_style_override("panel", context_menu_stylebox);
context_menu_panel->add_style_override("panel", context_menu_stylebox);
}
void CanvasItemEditor::_update_scrollbars() {
@ -5737,11 +5738,11 @@ void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);
hbc_context_menu->add_child(p_control);
context_menu_hbox->add_child(p_control);
}
void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
hbc_context_menu->remove_child(p_control);
context_menu_hbox->remove_child(p_control);
}
void CanvasItemEditor::add_control_to_left_panel(Control *p_control) {
@ -5868,9 +5869,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true));
editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false));
hb = memnew(HBoxContainer);
add_child(hb);
hb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
add_child(main_flow);
// Main toolbars.
HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
main_menu_hbox->set_anchors_and_margins_preset(Control::PRESET_WIDE);
main_flow->add_child(main_menu_hbox);
bottom_split = memnew(VSplitContainer);
add_child(bottom_split);
@ -5968,82 +5974,82 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
updating_scroll = false;
select_button = memnew(ToolButton);
hb->add_child(select_button);
main_menu_hbox->add_child(select_button);
select_button->set_toggle_mode(true);
select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SELECT));
select_button->set_pressed(true);
select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), KEY_Q));
select_button->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("RMB: Add node at position clicked."));
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
move_button = memnew(ToolButton);
hb->add_child(move_button);
main_menu_hbox->add_child(move_button);
move_button->set_toggle_mode(true);
move_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_MOVE));
move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), KEY_W));
move_button->set_tooltip(TTR("Move Mode"));
rotate_button = memnew(ToolButton);
hb->add_child(rotate_button);
main_menu_hbox->add_child(rotate_button);
rotate_button->set_toggle_mode(true);
rotate_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_ROTATE));
rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), KEY_E));
rotate_button->set_tooltip(TTR("Rotate Mode"));
scale_button = memnew(ToolButton);
hb->add_child(scale_button);
main_menu_hbox->add_child(scale_button);
scale_button->set_toggle_mode(true);
scale_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_SCALE));
scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), KEY_S));
scale_button->set_tooltip(TTR("Shift: Scale proportionally."));
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
list_select_button = memnew(ToolButton);
hb->add_child(list_select_button);
main_menu_hbox->add_child(list_select_button);
list_select_button->set_toggle_mode(true);
list_select_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_LIST_SELECT));
list_select_button->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
pivot_button = memnew(ToolButton);
hb->add_child(pivot_button);
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_EDIT_PIVOT));
pivot_button->set_tooltip(TTR("Click to change object's rotation pivot."));
pan_button = memnew(ToolButton);
hb->add_child(pan_button);
main_menu_hbox->add_child(pan_button);
pan_button->set_toggle_mode(true);
pan_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_PAN));
pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), KEY_G));
pan_button->set_tooltip(TTR("Pan Mode"));
ruler_button = memnew(ToolButton);
hb->add_child(ruler_button);
main_menu_hbox->add_child(ruler_button);
ruler_button->set_toggle_mode(true);
ruler_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_RULER));
ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), KEY_R));
ruler_button->set_tooltip(TTR("Ruler Mode"));
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
smart_snap_button = memnew(ToolButton);
hb->add_child(smart_snap_button);
main_menu_hbox->add_child(smart_snap_button);
smart_snap_button->set_toggle_mode(true);
smart_snap_button->connect("toggled", this, "_button_toggle_smart_snap");
smart_snap_button->set_tooltip(TTR("Toggle smart snapping."));
smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KEY_MASK_SHIFT | KEY_S));
grid_snap_button = memnew(ToolButton);
hb->add_child(grid_snap_button);
main_menu_hbox->add_child(grid_snap_button);
grid_snap_button->set_toggle_mode(true);
grid_snap_button->connect("toggled", this, "_button_toggle_grid_snap");
grid_snap_button->set_tooltip(TTR("Toggle grid snapping."));
grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KEY_MASK_SHIFT | KEY_G));
snap_config_menu = memnew(MenuButton);
hb->add_child(snap_config_menu);
main_menu_hbox->add_child(snap_config_menu);
snap_config_menu->set_h_size_flags(SIZE_SHRINK_END);
snap_config_menu->set_tooltip(TTR("Snapping Options"));
snap_config_menu->set_switch_on_hover(true);
@ -6072,37 +6078,37 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to Other Nodes")), SNAP_USE_OTHER_NODES);
smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to Guides")), SNAP_USE_GUIDES);
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
lock_button = memnew(ToolButton);
hb->add_child(lock_button);
main_menu_hbox->add_child(lock_button);
lock_button->connect("pressed", this, "_popup_callback", varray(LOCK_SELECTED));
lock_button->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L));
unlock_button = memnew(ToolButton);
hb->add_child(unlock_button);
main_menu_hbox->add_child(unlock_button);
unlock_button->connect("pressed", this, "_popup_callback", varray(UNLOCK_SELECTED));
unlock_button->set_tooltip(TTR("Unlock the selected object (can be moved)."));
unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L));
group_button = memnew(ToolButton);
hb->add_child(group_button);
main_menu_hbox->add_child(group_button);
group_button->connect("pressed", this, "_popup_callback", varray(GROUP_SELECTED));
group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G));
ungroup_button = memnew(ToolButton);
hb->add_child(ungroup_button);
main_menu_hbox->add_child(ungroup_button);
ungroup_button->connect("pressed", this, "_popup_callback", varray(UNGROUP_SELECTED));
ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G));
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
skeleton_menu = memnew(MenuButton);
hb->add_child(skeleton_menu);
main_menu_hbox->add_child(skeleton_menu);
skeleton_menu->set_tooltip(TTR("Skeleton Options"));
skeleton_menu->set_switch_on_hover(true);
@ -6117,21 +6123,21 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES);
p->connect("id_pressed", this, "_popup_callback");
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
override_camera_button = memnew(ToolButton);
hb->add_child(override_camera_button);
main_menu_hbox->add_child(override_camera_button);
override_camera_button->connect("toggled", this, "_button_override_camera");
override_camera_button->set_toggle_mode(true);
override_camera_button->set_disabled(true);
_update_override_camera_button(false);
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
view_menu = memnew(MenuButton);
// TRANSLATORS: Noun, name of the 2D/3D View menus.
view_menu->set_text(TTR("View"));
hb->add_child(view_menu);
main_menu_hbox->add_child(view_menu);
view_menu->get_popup()->connect("id_pressed", this, "_popup_callback");
view_menu->set_switch_on_hover(true);
@ -6164,20 +6170,20 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_P), PREVIEW_CANVAS_SCALE);
hb->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
context_menu_container = memnew(PanelContainer);
hbc_context_menu = memnew(HBoxContainer);
context_menu_container->add_child(hbc_context_menu);
context_menu_panel = memnew(PanelContainer);
context_menu_hbox = memnew(HBoxContainer);
context_menu_panel->add_child(context_menu_hbox);
// Use a custom stylebox to make contextual menu items stand out from the rest.
// This helps with editor usability as contextual menu items change when selecting nodes,
// even though it may not be immediately obvious at first.
hb->add_child(context_menu_container);
main_flow->add_child(context_menu_panel);
_update_context_menu_stylebox();
presets_menu = memnew(MenuButton);
presets_menu->set_text(TTR("Layout"));
hbc_context_menu->add_child(presets_menu);
context_menu_hbox->add_child(presets_menu);
presets_menu->hide();
presets_menu->set_switch_on_hover(true);
@ -6190,13 +6196,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
anchors_popup->connect("id_pressed", this, "_popup_callback");
anchor_mode_button = memnew(ToolButton);
hbc_context_menu->add_child(anchor_mode_button);
context_menu_hbox->add_child(anchor_mode_button);
anchor_mode_button->set_toggle_mode(true);
anchor_mode_button->hide();
anchor_mode_button->connect("toggled", this, "_button_toggle_anchor_mode");
animation_hb = memnew(HBoxContainer);
hbc_context_menu->add_child(animation_hb);
context_menu_hbox->add_child(animation_hb);
animation_hb->add_child(memnew(VSeparator));
animation_hb->hide();

View file

@ -238,11 +238,10 @@ private:
HScrollBar *h_scroll;
VScrollBar *v_scroll;
HBoxContainer *hb;
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
PanelContainer *context_menu_container;
HBoxContainer *hbc_context_menu;
PanelContainer *context_menu_panel = nullptr;
HBoxContainer *context_menu_hbox = nullptr;
ToolButton *zoom_minus;
ToolButton *zoom_reset;
@ -584,8 +583,6 @@ protected:
static void _bind_methods();
HBoxContainer *get_panel_hb() { return hb; }
struct compare_items_x {
bool operator()(const CanvasItem *a, const CanvasItem *b) const {
return a->get_global_transform().elements[2].x < b->get_global_transform().elements[2].x;

View file

@ -49,6 +49,7 @@
#include "scene/3d/physics_body.h"
#include "scene/3d/room_manager.h"
#include "scene/3d/visual_instance.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/viewport_container.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/surface_tool.h"
@ -1171,26 +1172,18 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
case BUTTON_WHEEL_UP: {
if (b->get_alt()) {
scale_fov(-0.05);
if (is_freelook_active()) {
scale_freelook_speed(zoom_factor);
} else {
if (is_freelook_active()) {
scale_freelook_speed(zoom_factor);
} else {
scale_cursor_distance(1.0 / zoom_factor);
}
scale_cursor_distance(1.0 / zoom_factor);
}
} break;
case BUTTON_WHEEL_DOWN: {
if (b->get_alt()) {
scale_fov(0.05);
if (is_freelook_active()) {
scale_freelook_speed(1.0 / zoom_factor);
} else {
if (is_freelook_active()) {
scale_freelook_speed(1.0 / zoom_factor);
} else {
scale_cursor_distance(zoom_factor);
}
scale_cursor_distance(zoom_factor);
}
} break;
@ -5810,7 +5803,7 @@ void SpatialEditor::_update_context_menu_stylebox() {
context_menu_stylebox->set_border_color(accent_color);
context_menu_stylebox->set_border_width(MARGIN_BOTTOM, Math::round(2 * EDSCALE));
context_menu_stylebox->set_default_margin(MARGIN_BOTTOM, 0);
context_menu_container->add_style_override("panel", context_menu_stylebox);
context_menu_panel->add_style_override("panel", context_menu_stylebox);
}
void SpatialEditor::_update_gizmos_menu() {
@ -6330,11 +6323,11 @@ void SpatialEditor::_notification(int p_what) {
}
void SpatialEditor::add_control_to_menu_panel(Control *p_control) {
hbc_context_menu->add_child(p_control);
context_menu_hbox->add_child(p_control);
}
void SpatialEditor::remove_control_from_menu_panel(Control *p_control) {
hbc_context_menu->remove_child(p_control);
context_menu_hbox->remove_child(p_control);
}
void SpatialEditor::set_can_preview(Camera *p_preview) {
@ -6576,15 +6569,20 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
camera_override_viewport_id = 0;
hbc_menu = memnew(HBoxContainer);
vbc->add_child(hbc_menu);
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
vbc->add_child(main_flow);
// Main toolbars.
HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
main_flow->add_child(main_menu_hbox);
Vector<Variant> button_binds;
button_binds.resize(1);
String sct;
tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
main_menu_hbox->add_child(tool_button[TOOL_MODE_SELECT]);
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_SELECT]->set_flat(true);
tool_button[TOOL_MODE_SELECT]->set_pressed(true);
@ -6592,10 +6590,10 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
main_menu_hbox->add_child(tool_button[TOOL_MODE_MOVE]);
tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
tool_button[TOOL_MODE_MOVE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_MOVE;
@ -6603,7 +6601,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
main_menu_hbox->add_child(tool_button[TOOL_MODE_ROTATE]);
tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
tool_button[TOOL_MODE_ROTATE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_ROTATE;
@ -6611,17 +6609,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
main_menu_hbox->add_child(tool_button[TOOL_MODE_SCALE]);
tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
tool_button[TOOL_MODE_SCALE]->set_flat(true);
button_binds.write[0] = MENU_TOOL_SCALE;
tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
main_menu_hbox->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
button_binds.write[0] = MENU_TOOL_LIST_SELECT;
@ -6629,37 +6627,37 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]);
button_binds.write[0] = MENU_LOCK_SELECTED;
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L));
tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
button_binds.write[0] = MENU_UNLOCK_SELECTED;
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L));
tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]);
button_binds.write[0] = MENU_GROUP_SELECTED;
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G));
tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
button_binds.write[0] = MENU_UNGROUP_SELECTED;
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G));
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
main_menu_hbox->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
@ -6667,17 +6665,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
main_menu_hbox->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
button_binds.write[0] = MENU_TOOL_USE_SNAP;
tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds);
tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
main_menu_hbox->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
@ -6686,7 +6684,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
_update_camera_override_button(false);
tool_button[TOOL_CONVERT_ROOMS] = memnew(ToolButton);
hbc_menu->add_child(tool_button[TOOL_CONVERT_ROOMS]);
main_menu_hbox->add_child(tool_button[TOOL_CONVERT_ROOMS]);
tool_button[TOOL_CONVERT_ROOMS]->set_toggle_mode(false);
tool_button[TOOL_CONVERT_ROOMS]->set_flat(true);
button_binds.write[0] = MENU_TOOL_CONVERT_ROOMS;
@ -6694,7 +6692,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_CONVERT_ROOMS]->set_shortcut(ED_SHORTCUT("spatial_editor/convert_rooms", TTR("Convert Rooms"), KEY_MASK_ALT | KEY_C));
tool_button[TOOL_CONVERT_ROOMS]->set_tooltip(TTR("Converts rooms for portal culling."));
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
// Drag and drop support;
preview_node = memnew(Spatial);
@ -6727,7 +6725,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
transform_menu = memnew(MenuButton);
transform_menu->set_text(TTR("Transform"));
transform_menu->set_switch_on_hover(true);
hbc_menu->add_child(transform_menu);
main_menu_hbox->add_child(transform_menu);
p = transform_menu->get_popup();
p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR);
@ -6742,17 +6740,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
// TRANSLATORS: Noun, name of the 2D/3D View menus.
view_menu->set_text(TTR("View"));
view_menu->set_switch_on_hover(true);
hbc_menu->add_child(view_menu);
main_menu_hbox->add_child(view_menu);
hbc_menu->add_child(memnew(VSeparator));
main_menu_hbox->add_child(memnew(VSeparator));
context_menu_container = memnew(PanelContainer);
hbc_context_menu = memnew(HBoxContainer);
context_menu_container->add_child(hbc_context_menu);
context_menu_panel = memnew(PanelContainer);
context_menu_hbox = memnew(HBoxContainer);
context_menu_panel->add_child(context_menu_hbox);
// Use a custom stylebox to make contextual menu items stand out from the rest.
// This helps with editor usability as contextual menu items change when selecting nodes,
// even though it may not be immediately obvious at first.
hbc_menu->add_child(context_menu_container);
main_flow->add_child(context_menu_panel);
_update_context_menu_stylebox();
// Get the view menu popup and have it stay open when a checkable item is selected

View file

@ -712,11 +712,10 @@ private:
void _update_camera_override_button(bool p_game_running);
void _update_camera_override_viewport(Object *p_viewport);
HBoxContainer *hbc_menu;
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
PanelContainer *context_menu_container;
HBoxContainer *hbc_context_menu;
PanelContainer *context_menu_panel = nullptr;
HBoxContainer *context_menu_hbox = nullptr;
void _generate_selection_boxes();
UndoRedo *undo_redo;

View file

@ -745,9 +745,13 @@ void SpriteFramesEditor::_animation_name_edited() {
undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim);
for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) {
String current = E->get()->call("get_animation");
StringName current = E->get()->call("get_animation");
if (current != edited_anim) {
continue;
}
undo_redo->add_do_method(E->get(), "set_animation", name);
undo_redo->add_undo_method(E->get(), "set_animation", edited_anim);
undo_redo->add_undo_method(E->get(), "set_animation", current);
}
undo_redo->add_do_method(this, "_update_library");
@ -775,8 +779,14 @@ void SpriteFramesEditor::_animation_add() {
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
// Assign the newly added animation to the edited anim sprite and to all other anim sprites having invalid animation.
Object *edited_anim_sprite = EditorNode::get_singleton()->get_inspector()->get_edited_object();
for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) {
String current = E->get()->call("get_animation");
StringName current = E->get()->call("get_animation");
if (frames->has_animation(current) && E->get() != edited_anim_sprite) {
continue;
}
undo_redo->add_do_method(E->get(), "set_animation", name);
undo_redo->add_undo_method(E->get(), "set_animation", current);
}
@ -811,10 +821,35 @@ void SpriteFramesEditor::_animation_remove_confirmed() {
Ref<Texture> frame = frames->get_frame(edited_anim, i);
undo_redo->add_undo_method(frames, "add_frame", edited_anim, frame);
}
StringName new_edited_anim = StringName();
List<StringName> anim_names;
frames->get_animation_list(&anim_names);
anim_names.sort_custom<StringName::AlphCompare>();
// If removing not the last animation, make the first animation left the new edited one.
if (anim_names.size() > 1) {
new_edited_anim = edited_anim != anim_names.front()->get() ? anim_names.front()->get() : anim_names.front()->next()->get();
List<Node *> nodes;
_find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
for (List<Node *>::Element *E = nodes.front(); E; E = E->next()) {
StringName current = E->get()->call("get_animation");
if (current != edited_anim) {
continue;
}
undo_redo->add_do_method(E->get(), "set_animation", new_edited_anim);
undo_redo->add_undo_method(E->get(), "set_animation", current);
}
}
undo_redo->add_do_method(this, "_update_library");
undo_redo->add_undo_method(this, "_update_library");
edited_anim = StringName();
edited_anim = new_edited_anim;
undo_redo->commit_action();
}

View file

@ -1315,6 +1315,10 @@ void SceneTreeDialog::_select() {
}
}
void SceneTreeDialog::_selected_changed() {
get_ok()->set_disabled(!tree->get_selected());
}
void SceneTreeDialog::_filter_changed(const String &p_filter) {
tree->set_filter(p_filter);
}
@ -1322,6 +1326,7 @@ void SceneTreeDialog::_filter_changed(const String &p_filter) {
void SceneTreeDialog::_bind_methods() {
ClassDB::bind_method("_select", &SceneTreeDialog::_select);
ClassDB::bind_method("_cancel", &SceneTreeDialog::_cancel);
ClassDB::bind_method(D_METHOD("_selected_changed"), &SceneTreeDialog::_selected_changed);
ClassDB::bind_method(D_METHOD("_filter_changed"), &SceneTreeDialog::_filter_changed);
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::NODE_PATH, "path")));
@ -1343,6 +1348,10 @@ SceneTreeDialog::SceneTreeDialog() {
tree->set_v_size_flags(SIZE_EXPAND_FILL);
tree->get_scene_tree()->connect("item_activated", this, "_select");
vbc->add_child(tree);
// Disable the OK button when no node is selected.
get_ok()->set_disabled(!tree->get_selected());
tree->connect("node_selected", this, "_selected_changed");
}
SceneTreeDialog::~SceneTreeDialog() {

View file

@ -170,6 +170,7 @@ class SceneTreeDialog : public ConfirmationDialog {
void _select();
void _cancel();
void _selected_changed();
void _filter_changed(const String &p_filter);
protected:

View file

@ -425,7 +425,7 @@
<argument index="1" name="to" type="float" />
<argument index="2" name="weight" type="float" />
<description>
Returns an interpolation or extrapolation factor considering the range specified in [code]from[/code] and [code]to[/code], and the interpolated value specified in [code]weight[/code]. The returned value will be between [code]0.0[/code] and [code]1.0[/code] if [code]weight[/code] is between [code]from[/code] and [code]to[/code] (inclusive). If [code]weight[/code] is located outside this range, then an extrapolation factor will be returned (return value lower than [code]0.0[/code] or greater than [code]1.0[/code]).
Returns an interpolation or extrapolation factor considering the range specified in [code]from[/code] and [code]to[/code], and the interpolated value specified in [code]weight[/code]. The returned value will be between [code]0.0[/code] and [code]1.0[/code] if [code]weight[/code] is between [code]from[/code] and [code]to[/code] (inclusive). If [code]weight[/code] is located outside this range, then an extrapolation factor will be returned (return value lower than [code]0.0[/code] or greater than [code]1.0[/code]). Use [method clamp] on the result of [method inverse_lerp] if this is not desired.
[codeblock]
# The interpolation ratio in the `lerp()` call below is 0.75.
var middle = lerp(20, 30, 0.75)
@ -434,7 +434,7 @@
var ratio = inverse_lerp(20, 30, 27.5)
# `ratio` is now 0.75.
[/codeblock]
See also [method lerp] which performs the reverse of this operation.
See also [method lerp] which performs the reverse of this operation, and [method range_lerp] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
@ -494,14 +494,14 @@
<argument index="1" name="to" type="Variant" />
<argument index="2" name="weight" type="float" />
<description>
Linearly interpolates between two values by the factor defined in [code]weight[/code]. To perform interpolation, [code]weight[/code] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
Linearly interpolates between two values by the factor defined in [code]weight[/code]. To perform interpolation, [code]weight[/code] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. Use [method clamp] on the result of [method lerp] if this is not desired.
If the [code]from[/code] and [code]to[/code] arguments are of type [int] or [float], the return value is a [float].
If both are of the same vector type ([Vector2], [Vector3] or [Color]), the return value will be of the same type ([code]lerp[/code] then calls the vector type's [code]linear_interpolate[/code] method).
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
lerp(Vector2(1, 5), Vector2(3, 2), 0.5) # Returns Vector2(2, 3.5)
[/codeblock]
See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep].
See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method range_lerp] to map a continuous series of values to another.
</description>
</method>
<method name="lerp_angle">
@ -892,10 +892,11 @@
<argument index="3" name="ostart" type="float" />
<argument index="4" name="ostop" type="float" />
<description>
Maps a [code]value[/code] from range [code][istart, istop][/code] to [code][ostart, ostop][/code].
Maps a [code]value[/code] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [code]value[/code] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method range_lerp] if this is not desired.
[codeblock]
range_lerp(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
</description>
</method>
<method name="round">

View file

@ -66,6 +66,9 @@ namespace GodotTools.Ides.Rider
if (string.IsNullOrEmpty(path))
return false;
if (path.IndexOfAny(System.IO.Path.GetInvalidPathChars()) != -1)
return false;
var fileInfo = new FileInfo(path);
string filename = fileInfo.Name.ToLowerInvariant();
return filename.StartsWith("rider", StringComparison.Ordinal);

View file

@ -147,7 +147,7 @@ void SpriteFrames::clear(const StringName &p_anim) {
void SpriteFrames::clear_all() {
animations.clear();
add_animation("default");
add_animation("default"); // Also emits changed.
}
void SpriteFrames::add_animation(const StringName &p_anim) {
@ -155,13 +155,16 @@ void SpriteFrames::add_animation(const StringName &p_anim) {
animations[p_anim] = Anim();
animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
emit_changed();
}
bool SpriteFrames::has_animation(const StringName &p_anim) const {
return animations.has(p_anim);
}
void SpriteFrames::remove_animation(const StringName &p_anim) {
animations.erase(p_anim);
if (animations.erase(p_anim)) {
emit_changed();
}
}
void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
@ -172,17 +175,7 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &
animations.erase(p_prev);
animations[p_next] = anim;
animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX;
}
Vector<String> SpriteFrames::_get_animation_list() const {
Vector<String> ret;
List<StringName> al;
get_animation_list(&al);
for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
ret.push_back(E->get());
}
return ret;
emit_changed();
}
void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
@ -578,8 +571,12 @@ bool AnimatedSprite::is_flipped_v() const {
void AnimatedSprite::_res_changed() {
set_frame(frame);
_change_notify("frame");
_change_notify("animation");
// Calling _change_notify("frame") and _change_notify("animation") instead wouldn't
// make EditorInspector trigger calls to _validate_property(property) which would
// lead to not updating valid values for "frame" and "animation" properties.
_change_notify();
update();
}

View file

@ -58,8 +58,6 @@ class SpriteFrames : public Resource {
Array _get_animations() const;
void _set_animations(const Array &p_animations);
Vector<String> _get_animation_list() const;
protected:
static void _bind_methods();

View file

@ -412,7 +412,7 @@ real_t NavigationPolygonInstance::get_enter_cost() const {
void NavigationPolygonInstance::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
travel_cost = MAX(p_travel_cost, 0.0);
Navigation2DServer::get_singleton()->region_set_enter_cost(region, travel_cost);
Navigation2DServer::get_singleton()->region_set_travel_cost(region, travel_cost);
}
real_t NavigationPolygonInstance::get_travel_cost() const {

View file

@ -157,7 +157,11 @@ void TileMap::_update_quadrant_transform() {
Transform2D nav_rel;
if (bake_navigation) {
nav_rel = get_relative_transform_to_parent(navigation);
if (navigation) {
nav_rel = get_relative_transform_to_parent(navigation);
} else {
nav_rel = get_transform();
}
}
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
@ -339,7 +343,11 @@ void TileMap::update_dirty_quadrants() {
Vector2 tofs = get_cell_draw_offset();
Transform2D nav_rel;
if (bake_navigation) {
nav_rel = get_relative_transform_to_parent(navigation);
if (navigation) {
nav_rel = get_relative_transform_to_parent(navigation);
} else {
nav_rel = get_transform();
}
}
Vector2 qofs;

View file

@ -94,7 +94,7 @@ real_t NavigationMeshInstance::get_enter_cost() const {
void NavigationMeshInstance::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
travel_cost = MAX(p_travel_cost, 0.0);
NavigationServer::get_singleton()->region_set_enter_cost(region, travel_cost);
NavigationServer::get_singleton()->region_set_travel_cost(region, travel_cost);
}
real_t NavigationMeshInstance::get_travel_cost() const {

View file

@ -448,6 +448,7 @@ public:
virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0;
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0;
virtual uint32_t skeleton_get_revision(RID p_skeleton) const = 0;
/* Light API */
@ -947,19 +948,24 @@ public:
};
Transform2D xform;
bool clip;
bool visible;
bool behind;
bool update_when_visible;
//VS::MaterialBlendMode blend_mode;
int light_mask;
bool clip : 1;
bool visible : 1;
bool behind : 1;
bool update_when_visible : 1;
bool distance_field : 1;
bool light_masked : 1;
mutable bool custom_rect : 1;
mutable bool rect_dirty : 1;
Vector<Command *> commands;
mutable bool custom_rect;
mutable bool rect_dirty;
mutable Rect2 rect;
RID material;
RID skeleton;
//VS::MaterialBlendMode blend_mode;
int32_t light_mask;
mutable uint32_t skeleton_revision;
Item *next;
struct CopyBackBuffer {
@ -975,15 +981,29 @@ public:
Item *final_clip_owner;
Item *material_owner;
ViewportRender *vp_render;
bool distance_field;
bool light_masked;
Rect2 global_rect_cache;
const Rect2 &get_rect() const {
if (custom_rect || (!rect_dirty && !update_when_visible)) {
if (custom_rect) {
return rect;
}
if (!rect_dirty && !update_when_visible) {
if (skeleton == RID()) {
return rect;
} else {
// special case for skeletons
uint32_t rev = RasterizerStorage::base_singleton->skeleton_get_revision(skeleton);
if (rev == skeleton_revision) {
// no change to the skeleton since we last calculated the bounding rect
return rect;
} else {
// We need to recalculate.
// Mark as done for next time.
skeleton_revision = rev;
}
}
}
//must update rect
int s = commands.size();
@ -1171,6 +1191,7 @@ public:
}
Item() {
light_mask = 1;
skeleton_revision = 0;
vp_render = nullptr;
next = nullptr;
final_clip_owner = nullptr;