summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/engine.cpp6
-rw-r--r--doc/classes/GraphEdit.xml3
-rw-r--r--doc/classes/GraphNode.xml12
-rwxr-xr-xdoc/tools/make_rst.py121
-rw-r--r--editor/editor_spin_slider.cpp4
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp160
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h1
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp163
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h1
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp85
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp77
-rw-r--r--editor/plugins/animation_state_machine_editor.h2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp30
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h4
-rw-r--r--modules/raycast/config.py3
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp5
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm5
-rw-r--r--platform/uwp/os_uwp.cpp3
-rw-r--r--platform/uwp/os_uwp.h1
-rw-r--r--platform/windows/crash_handler_windows.cpp10
-rw-r--r--platform/windows/detect.py373
-rw-r--r--platform/windows/export/export_plugin.cpp2
-rw-r--r--platform/windows/os_windows.cpp4
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--scene/gui/graph_edit.cpp78
-rw-r--r--scene/gui/graph_edit.h5
-rw-r--r--scene/gui/graph_node.cpp24
-rw-r--r--scene/gui/graph_node.h8
-rw-r--r--thirdparty/README.md6
-rw-r--r--thirdparty/mbedtls/library/timing.c4
-rw-r--r--thirdparty/minimp3/minimp3.h23
34 files changed, 832 insertions, 401 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 3efc0e822a..94db3612b4 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -191,11 +191,11 @@ String Engine::get_architecture_name() const {
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
return "x86_32";
-#elif defined(__aarch64__) || defined(_M_ARM64)
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
return "arm64";
-#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__)
- return "armv7";
+#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__) || defined(_M_ARM)
+ return "arm32";
#elif defined(__riscv)
#if __riscv_xlen == 8
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index e5aa78971e..dc093acdcd 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -221,6 +221,9 @@
</method>
</methods>
<members>
+ <member name="arrange_nodes_button_hidden" type="bool" setter="set_arrange_nodes_button_hidden" getter="is_arrange_nodes_button_hidden" default="false">
+ If [code]true[/code], the Arrange Nodes button is hidden.
+ </member>
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
<member name="connection_lines_antialiased" type="bool" setter="set_connection_lines_antialiased" getter="is_connection_lines_antialiased" default="true">
If [code]true[/code], the lines between nodes will use antialiasing.
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 009c329ee2..ebd4525b19 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -156,7 +156,7 @@
<description>
Sets properties of the slot with ID [param idx].
If [param enable_left]/[param enable_right], a port will appear and the slot will be able to be connected from this side.
- [param type_left]/[param type_right] is an arbitrary type of the port. Only ports with the same type values can be connected.
+ [param type_left]/[param type_right] is an arbitrary type of the port. Only ports with the same type values can be connected and negative values will disallow all connections to be made via user inputs.
[param color_left]/[param color_right] is the tint of the port's icon on this side.
[param custom_left]/[param custom_right] is a custom texture for this side's port.
[b]Note:[/b] This method only sets properties of the slot. To create the slot, add a [Control]-derived child to the GraphNode.
@@ -208,7 +208,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_left" type="int" />
<description>
- Sets the left (input) type of the slot [param idx] to [param type_left].
+ Sets the left (input) type of the slot [param idx] to [param type_left]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
<method name="set_slot_type_right">
@@ -216,7 +216,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_right" type="int" />
<description>
- Sets the right (output) type of the slot [param idx] to [param type_right].
+ Sets the right (output) type of the slot [param idx] to [param type_right]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
</methods>
@@ -224,6 +224,9 @@
<member name="comment" type="bool" setter="set_comment" getter="is_comment" default="false">
If [code]true[/code], the GraphNode is a comment node.
</member>
+ <member name="draggable" type="bool" setter="set_draggable" getter="is_draggable" default="true">
+ If [code]true[/code], the user can drag the GraphNode.
+ </member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member>
@@ -239,6 +242,9 @@
If [code]true[/code], the user can resize the GraphNode.
[b]Note:[/b] Dragging the handle will only emit the [signal resize_request] signal, the GraphNode needs to be resized manually.
</member>
+ <member name="selectable" type="bool" setter="set_selectable" getter="is_selectable" default="true">
+ If [code]true[/code], the user can select the GraphNode.
+ </member>
<member name="selected" type="bool" setter="set_selected" getter="is_selected" default="false">
If [code]true[/code], the GraphNode is selected.
</member>
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 519554e026..bc50e39812 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -878,7 +878,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n")
if i == 0:
- f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name.strip("@")))
+ f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name))
_, signature = make_method_signature(class_def, m, "", state)
f.write("- {}\n\n".format(signature))
@@ -1337,8 +1337,10 @@ def format_text_block(
# Cross-references to items in this or other class documentation pages.
elif is_in_tagset(cmd, RESERVED_CROSSLINK_TAGS):
+ link_type: str = ""
link_target: str = ""
if space_pos >= 0:
+ link_type = tag_text[:space_pos]
link_target = tag_text[space_pos + 1 :].strip()
if link_target == "":
@@ -1350,11 +1352,13 @@ def format_text_block(
else:
if (
cmd.startswith("method")
+ or cmd.startswith("constructor")
+ or cmd.startswith("operator")
or cmd.startswith("member")
or cmd.startswith("signal")
- or cmd.startswith("constant")
or cmd.startswith("annotation")
or cmd.startswith("theme_item")
+ or cmd.startswith("constant")
):
if link_target.find(".") != -1:
ss = link_target.split(".")
@@ -1371,48 +1375,62 @@ def format_text_block(
class_param = state.current_class
method_param = link_target
- ref_type = ""
+ # Default to the tag command name. This works by default for most tags,
+ # but member and theme_item have special cases.
+ ref_type = "_{}".format(link_type)
+ if link_type == "member":
+ ref_type = "_property"
+
if class_param in state.classes:
class_def = state.classes[class_param]
- if cmd.startswith("constructor"):
- if method_param not in class_def.constructors:
- print_error(
- '{}.xml: Unresolved constructor reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_constructor"
- elif cmd.startswith("method"):
- if method_param not in class_def.methods:
- print_error(
- '{}.xml: Unresolved method reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_method"
+ if cmd.startswith("method") and method_param not in class_def.methods:
+ print_error(
+ '{}.xml: Unresolved method reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
- elif cmd.startswith("operator"):
- if method_param not in class_def.operators:
- print_error(
- '{}.xml: Unresolved operator reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_operator"
+ elif cmd.startswith("constructor") and method_param not in class_def.constructors:
+ print_error(
+ '{}.xml: Unresolved constructor reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
- elif cmd.startswith("member"):
- if method_param not in class_def.properties:
- print_error(
- '{}.xml: Unresolved member reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_property"
+ elif cmd.startswith("operator") and method_param not in class_def.operators:
+ print_error(
+ '{}.xml: Unresolved operator reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("member") and method_param not in class_def.properties:
+ print_error(
+ '{}.xml: Unresolved member reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("signal") and method_param not in class_def.signals:
+ print_error(
+ '{}.xml: Unresolved signal reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("annotation") and method_param not in class_def.annotations:
+ print_error(
+ '{}.xml: Unresolved annotation reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
elif cmd.startswith("theme_item"):
if method_param not in class_def.theme_items:
@@ -1422,27 +1440,9 @@ def format_text_block(
),
state,
)
- ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
-
- elif cmd.startswith("signal"):
- if method_param not in class_def.signals:
- print_error(
- '{}.xml: Unresolved signal reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_signal"
-
- elif cmd.startswith("annotation"):
- if method_param not in class_def.annotations:
- print_error(
- '{}.xml: Unresolved annotation reference "{}" in {}.'.format(
- state.current_class, link_target, context_name
- ),
- state,
- )
- ref_type = "_annotation"
+ else:
+ # Needs theme data type to be properly linked, which we cannot get without a class.
+ ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
elif cmd.startswith("constant"):
found = False
@@ -1473,7 +1473,6 @@ def format_text_block(
),
state,
)
- ref_type = "_constant"
else:
print_error(
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 5b98460e8e..b9a3e9decf 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -149,6 +149,10 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventMouseButton> mb = p_event;
if (grabbing_grabber) {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 2578099a9f..1cc4894b7d 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -48,7 +48,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -56,62 +58,64 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
- List<StringName> classes;
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- classes.sort_custom<StringName::AlphCompare>();
+ List<StringName> classes;
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ classes.sort_custom<StringName::AlphCompare>();
- menu->add_submenu_item(TTR("Add Animation"), "animations");
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
- if (gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue;
- }
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue;
+ }
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
+ }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
- if (snap->is_pressed()) {
- add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ if (snap->is_pressed()) {
+ add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ }
}
}
@@ -138,31 +142,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
- if (dragging_selected) {
- // move
- float point = blend_space->get_blend_point_position(selected_point);
- point += drag_ofs.x;
+ if (!read_only) {
+ if (dragging_selected) {
+ // move
+ float point = blend_space->get_blend_point_position(selected_point);
+ point += drag_ofs.x;
+
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ dragging_selected_attempt = false;
+ dragging_selected = false;
+ blend_space_draw->update();
}
-
- dragging_selected_attempt = false;
- dragging_selected = false;
- blend_space_draw->update();
}
// *set* the blend
@@ -255,10 +261,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
float point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs.x;
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs.x;
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
}
}
@@ -475,7 +483,7 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
- tool_erase->set_disabled(!point_valid);
+ tool_erase->set_disabled(!point_valid || read_only);
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
@@ -486,7 +494,11 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -590,10 +602,20 @@ bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ edit_value->set_editable(!read_only);
+ label_value->set_editable(!read_only);
+ min_value->set_editable(!read_only);
+ max_value->set_editable(!read_only);
+ sync->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 125a3382fa..c8b01cb54b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
+ bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index c0723cef87..2730beb549 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -60,11 +60,29 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
}
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
+ max_x_value->set_editable(!read_only);
+ min_x_value->set_editable(!read_only);
+ max_y_value->set_editable(!read_only);
+ min_y_value->set_editable(!read_only);
+ label_x->set_editable(!read_only);
+ label_y->set_editable(!read_only);
+ edit_x->set_editable(!read_only);
+ edit_y->set_editable(!read_only);
+ tool_triangle->set_disabled(read_only);
+ auto_triangles->set_disabled(read_only);
+ sync->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
}
StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
@@ -76,7 +94,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1 || selected_triangle != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -84,57 +104,59 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
- List<StringName> classes;
- classes.sort_custom<StringName::AlphCompare>();
-
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- menu->add_submenu_item(TTR("Add Animation"), "animations");
-
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
+ List<StringName> classes;
+ classes.sort_custom<StringName::AlphCompare>();
+
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
+
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
+ if (gp && gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue; // nope
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue; // nope
+ }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
}
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
-
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size());
- add_point_pos.y = 1.0 - add_point_pos.y;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
-
- if (snap->is_pressed()) {
- add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size());
+ add_point_pos.y = 1.0 - add_point_pos.y;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
+
+ if (snap->is_pressed()) {
+ add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ }
}
}
@@ -222,17 +244,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
point = point.snapped(blend_space->get_snap());
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ if (!read_only) {
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
+ }
}
dragging_selected_attempt = false;
dragging_selected = false;
@@ -259,7 +283,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
- drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ if (!read_only) {
+ drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ }
blend_space_draw->update();
_update_edited_point_pos();
}
@@ -355,7 +381,10 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
}
void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
- tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
+ tool_erase->set_disabled(
+ (!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())) ||
+ read_only);
+
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
@@ -363,7 +392,11 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
} else {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -503,10 +536,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
points.clear();
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
Vector2 point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs;
- if (snap->is_pressed()) {
- point = point.snapped(blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs;
+ if (snap->is_pressed()) {
+ point = point.snapped(blend_space->get_snap());
+ }
}
}
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index df2bcf254d..1f015a1804 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
+ bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index e4f5576d66..8dd3223b19 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -134,6 +134,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
GraphNode *node = memnew(GraphNode);
graph->add_child(node);
+ node->set_draggable(!read_only);
+
Ref<AnimationNode> agnode = blend_tree->get_node(E);
ERR_CONTINUE(!agnode.is_valid());
@@ -146,9 +148,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E);
+ name->set_editable(!read_only);
name->set_expand_to_text_length_enabled(true);
node->add_child(name);
- node->set_slot(0, false, 0, Color(), true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
+ node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED);
base = 1;
@@ -160,7 +163,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
Label *in_name = memnew(Label);
node->add_child(in_name);
in_name->set_text(agnode->get_input_name(i));
- node->set_slot(base + i, true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
+ node->set_slot(base + i, true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
}
List<PropertyInfo> pinfo;
@@ -172,6 +175,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
+ prop->set_read_only(read_only);
prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -195,12 +199,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (agnode->has_filter()) {
node->add_child(memnew(HSeparator));
- Button *edit_filters = memnew(Button);
- edit_filters->set_text(TTR("Edit Filters"));
- edit_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
- node->add_child(edit_filters);
- edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters).bind(E), CONNECT_DEFERRED);
- edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
+ Button *inspect_filters = memnew(Button);
+ if (read_only) {
+ inspect_filters->set_text(TTR("Inspect Filters"));
+ } else {
+ inspect_filters->set_text(TTR("Edit Filters"));
+ }
+ inspect_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
+ node->add_child(inspect_filters);
+ inspect_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED);
+ inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
}
Ref<AnimationNodeAnimation> anim = agnode;
@@ -208,6 +216,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
mb->set_icon(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")));
+ mb->set_disabled(read_only);
Array options;
node->add_child(memnew(HSeparator));
@@ -370,10 +379,18 @@ void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2
}
void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ if (read_only) {
+ return;
+ }
+
_popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position);
}
void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_from);
if (node.is_valid()) {
from_node = p_from;
@@ -382,6 +399,10 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in
}
void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_to);
if (node.is_valid()) {
to_node = p_to;
@@ -402,6 +423,10 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
}
void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from);
if (err != AnimationNodeBlendTree::CONNECTION_OK) {
@@ -418,6 +443,10 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
}
void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
@@ -445,6 +474,10 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
}
void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
+ if (read_only) {
+ return;
+ }
+
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -464,6 +497,10 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {
+ if (read_only) {
+ return;
+ }
+
List<StringName> to_erase;
if (p_nodes.is_empty()) {
@@ -495,6 +532,10 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
}
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
+ if (read_only) {
+ return;
+ }
+
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -679,7 +720,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
}
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
@@ -692,7 +733,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -714,7 +755,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, types_text);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -727,7 +768,15 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
return true;
}
-void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) {
+void AnimationNodeBlendTreeEditor::_inspect_filters(const String &p_which) {
+ if (read_only) {
+ filter_dialog->set_title(TTR("Inspect Filtered Tracks:"));
+ } else {
+ filter_dialog->set_title(TTR("Edit Filtered Tracks:"));
+ }
+
+ filter_enabled->set_disabled(read_only);
+
Ref<AnimationNode> anode = blend_tree->get_node(p_which);
ERR_FAIL_COND(!anode.is_valid());
@@ -838,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
+ if (read_only) {
+ return;
+ }
+
if (updating) {
return;
}
@@ -944,13 +997,20 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
blend_tree = p_node;
+ read_only = false;
+
if (blend_tree.is_null()) {
hide();
} else {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
_update_graph();
}
+
+ add_node->set_disabled(read_only);
+ graph->set_arrange_nodes_button_hidden(read_only);
}
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
@@ -986,6 +1046,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false));
+ add_node->set_disabled(read_only);
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index af43da6197..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -47,6 +47,9 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
+
+ bool read_only = false;
+
GraphEdit *graph = nullptr;
MenuButton *add_node = nullptr;
Vector2 position_from_popup_menu;
@@ -106,7 +109,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _delete_nodes_request(const TypedArray<StringName> &p_nodes);
bool _update_filters(const Ref<AnimationNode> &anode);
- void _edit_filters(const String &p_which);
+ void _inspect_filters(const String &p_which);
void _filter_edited();
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index ef4ae3dca4..ecba4ba888 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -56,7 +56,11 @@ bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
state_machine = p_node;
+ read_only = false;
+
if (state_machine.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(state_machine);
+
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_transition_index = -1;
@@ -66,6 +70,9 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
_update_mode();
_update_graph();
}
+
+ tool_create->set_disabled(read_only);
+ tool_connect->set_disabled(read_only);
}
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
@@ -77,7 +84,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -95,9 +104,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
// Add new node
- if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
- connecting_from = StringName();
- _open_menu(mb->get_position());
+ if (!read_only) {
+ if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
+ connecting_from = StringName();
+ _open_menu(mb->get_position());
+ }
}
// Select node or push a field inside
@@ -121,22 +132,24 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
return;
}
- if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
- Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
+ if (!read_only) {
+ if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
+ Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
- Rect2 edit_rect = node_rects[i].name;
- edit_rect.position -= line_sb->get_offset();
- edit_rect.size += line_sb->get_minimum_size();
+ Rect2 edit_rect = node_rects[i].name;
+ edit_rect.position -= line_sb->get_offset();
+ edit_rect.size += line_sb->get_minimum_size();
- name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
- name_edit_popup->set_size(edit_rect.size);
- name_edit->set_text(node_rects[i].node_name);
- name_edit_popup->popup();
- name_edit->grab_focus();
- name_edit->select_all();
+ name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
+ name_edit_popup->set_size(edit_rect.size);
+ name_edit->set_text(node_rects[i].node_name);
+ name_edit_popup->popup();
+ name_edit->grab_focus();
+ name_edit->select_all();
- prev_name = node_rects[i].node_name;
- return;
+ prev_name = node_rects[i].node_name;
+ return;
+ }
}
if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
@@ -319,7 +332,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting) {
+ if (mm.is_valid() && connecting && !read_only) {
connecting_to = mm->get_position();
connecting_to_node = StringName();
state_machine_draw->update();
@@ -333,7 +346,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while moving a node
- if (mm.is_valid() && dragging_selected_attempt) {
+ if (mm.is_valid() && dragging_selected_attempt && !read_only) {
dragging_selected = true;
drag_ofs = mm->get_position() - drag_from;
snap_x = StringName();
@@ -478,17 +491,21 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Point2 &p_pos) const {
- // Put ibeam (text cursor) over names to make it clearer that they are editable.
- Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
- Point2 pos = xform.xform_inv(p_pos);
Control::CursorShape cursor_shape = get_default_cursor_shape();
-
- for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
- if (node_rects[i].node.has_point(pos)) {
- if (node_rects[i].name.has_point(pos)) {
- cursor_shape = Control::CURSOR_IBEAM;
+ if (!read_only) {
+ // Put ibeam (text cursor) over names to make it clearer that they are editable.
+ Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
+ Point2 pos = xform.xform_inv(p_pos);
+
+ for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
+ if (node_rects[i].node.has_point(pos)) {
+ if (node_rects[i].name.has_point(pos)) {
+ if (state_machine->can_edit_node(node_rects[i].node_name)) {
+ cursor_shape = Control::CURSOR_IBEAM;
+ }
+ }
+ break;
}
- break;
}
}
return cursor_shape;
@@ -1848,9 +1865,9 @@ void AnimationNodeStateMachineEditor::_update_mode() {
tool_erase_hb->show();
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
- tool_erase->set_disabled(nothing_selected || start_end_selected);
+ tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
- if (selected_nodes.is_empty() || start_end_selected) {
+ if (selected_nodes.is_empty() || start_end_selected || read_only) {
tool_group->set_disabled(true);
tool_group->set_visible(true);
tool_ungroup->set_visible(false);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index fdd1af0f6d..3a59e94a5f 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -47,6 +47,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeStateMachine> state_machine;
+ bool read_only = false;
+
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index b9560ea69b..61df8cdf06 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -293,7 +293,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
String word = str.substr(j, to - j);
Color col = Color();
- if (keywords.has(word)) {
+ if (global_functions.has(word)) {
+ // "assert" and "preload" are reserved, so highlight even if not followed by a bracket.
+ if (word == "assert" || word == "preload" || str[to] == '(') {
+ col = global_function_color;
+ }
+ } else if (keywords.has(word)) {
col = keywords[word];
} else if (member_keywords.has(word)) {
col = member_keywords[word];
@@ -302,12 +307,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
if (col != Color()) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = Color(); // keyword & member indexing not allowed
+ col = Color(); // keyword, member & global func indexing not allowed
break;
} else if (str[k] > 32) {
break;
}
}
+
if (col != Color()) {
in_keyword = true;
keyword_color = col;
@@ -535,6 +541,7 @@ PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const {
void GDScriptSyntaxHighlighter::_update_cache() {
keywords.clear();
member_keywords.clear();
+ global_functions.clear();
color_regions.clear();
color_region_cache.clear();
@@ -591,6 +598,17 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
}
+ /* Global functions. */
+ List<StringName> global_function_list;
+ GDScriptUtilityFunctions::get_function_list(&global_function_list);
+ Variant::get_utility_function_list(&global_function_list);
+ // "assert" and "preload" are not utility functions, but are global nonetheless, so insert them.
+ global_functions.insert(SNAME("assert"));
+ global_functions.insert(SNAME("preload"));
+ for (const StringName &E : global_function_list) {
+ global_functions.insert(E);
+ }
+
/* Comments */
const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
@@ -643,12 +661,14 @@ void GDScriptSyntaxHighlighter::_update_cache() {
if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) {
function_definition_color = Color(0.4, 0.9, 1.0);
+ global_function_color = Color(0.6, 0.6, 0.9);
node_path_color = Color(0.72, 0.77, 0.49);
node_ref_color = Color(0.39, 0.76, 0.35);
annotation_color = Color(1.0, 0.7, 0.45);
string_name_color = Color(1.0, 0.76, 0.65);
} else {
function_definition_color = Color(0, 0.6, 0.6);
+ global_function_color = Color(0.4, 0.2, 0.8);
node_path_color = Color(0.18, 0.55, 0);
node_ref_color = Color(0.0, 0.5, 0);
annotation_color = Color(0.8, 0.37, 0);
@@ -656,6 +676,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color);
+ EDITOR_DEF("text_editor/theme/highlighting/gdscript/global_function_color", global_function_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_reference_color", node_ref_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color);
@@ -666,6 +687,10 @@ void GDScriptSyntaxHighlighter::_update_cache() {
function_definition_color,
true);
EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/theme/highlighting/gdscript/global_function_color",
+ global_function_color,
+ true);
+ EditorSettings::get_singleton()->set_initial_value(
"text_editor/theme/highlighting/gdscript/node_path_color",
node_path_color,
true);
@@ -684,6 +709,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color");
+ global_function_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/global_function_color");
node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color");
node_ref_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_reference_color");
annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color");
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index f434d03a31..60b5b092d4 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -49,6 +49,7 @@ private:
HashMap<StringName, Color> keywords;
HashMap<StringName, Color> member_keywords;
+ HashSet<StringName> global_functions;
enum Type {
NONE,
@@ -67,10 +68,11 @@ private:
TYPE,
};
- // colours
+ // Colors.
Color font_color;
Color symbol_color;
Color function_color;
+ Color global_function_color;
Color function_definition_color;
Color built_in_type_color;
Color number_color;
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
index 438779343e..833ad50018 100644
--- a/modules/raycast/config.py
+++ b/modules/raycast/config.py
@@ -1,5 +1,8 @@
def can_build(env, platform):
# Depends on Embree library, which only supports x86_64 and arm64.
+ if platform == "windows":
+ return env["arch"] == "x86_64" # TODO build for Windows on ARM
+
return env["arch"] in ["x86_64", "arm64"]
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 197d31dc81..a74ca155a4 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -519,8 +519,6 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
}
void OS_LinuxBSD::run() {
- force_quit = false;
-
if (!main_loop) {
return;
}
@@ -532,7 +530,7 @@ void OS_LinuxBSD::run() {
//int frames=0;
//uint64_t frame=0;
- while (!force_quit) {
+ while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
#ifdef JOYDEV_ENABLED
joypad->process_joypads();
@@ -730,7 +728,6 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
OS_LinuxBSD::OS_LinuxBSD() {
main_loop = nullptr;
- force_quit = false;
#ifdef PULSEAUDIO_ENABLED
AudioDriverManager::add_driver(&driver_pulseaudio);
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index cc4e91e885..d5b2321316 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -43,8 +43,6 @@
class OS_LinuxBSD : public OS_Unix {
virtual void delete_main_loop() override;
- bool force_quit;
-
#ifdef FONTCONFIG_ENABLED
bool font_config_initialized = false;
#endif
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index a1eb0f7f69..61db99689c 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -40,8 +40,6 @@
#include "servers/audio_server.h"
class OS_MacOS : public OS_Unix {
- bool force_quit = false;
-
JoypadMacOS *joypad_macos = nullptr;
#ifdef COREAUDIO_ENABLED
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index cc550043de..47b53bba69 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -512,8 +512,6 @@ Error OS_MacOS::move_to_trash(const String &p_path) {
}
void OS_MacOS::run() {
- force_quit = false;
-
if (!main_loop) {
return;
}
@@ -521,7 +519,7 @@ void OS_MacOS::run() {
main_loop->initialize();
bool quit = false;
- while (!force_quit && !quit) {
+ while (!quit) {
@try {
if (DisplayServer::get_singleton()) {
DisplayServer::get_singleton()->process_events(); // Get rid of pending events.
@@ -541,7 +539,6 @@ void OS_MacOS::run() {
OS_MacOS::OS_MacOS() {
main_loop = nullptr;
- force_quit = false;
Vector<Logger *> loggers;
loggers.push_back(memnew(MacOSTerminalLogger));
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 40f93bb18b..494f5ec4b9 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -781,7 +781,7 @@ void OS_UWP::run() {
int frames = 0;
uint64_t frame = 0;
- while (!force_quit) {
+ while (true) {
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
if (managed_object->alert_close_handle) {
continue;
@@ -811,7 +811,6 @@ bool OS_UWP::_check_internal_feature_support(const String &p_feature) {
OS_UWP::OS_UWP() {
key_event_pos = 0;
- force_quit = false;
alt_mem = false;
gr_mem = false;
shift_mem = false;
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index fe61f60548..5a58486ee7 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -106,7 +106,6 @@ private:
bool shift_mem;
bool control_mem;
bool meta_mem;
- bool force_quit;
MouseButton last_button_state = MouseButton::NONE;
CursorShape cursor_shape;
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 6ce10e6f0f..b501ee78db 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -173,10 +173,18 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
-#ifdef _M_X64
+#if defined(_M_X64)
frame.AddrPC.Offset = context->Rip;
frame.AddrStack.Offset = context->Rsp;
frame.AddrFrame.Offset = context->Rbp;
+#elif defined(_M_ARM64) || defined(_M_ARM64EC)
+ frame.AddrPC.Offset = context->Pc;
+ frame.AddrStack.Offset = context->Sp;
+ frame.AddrFrame.Offset = context->Fp;
+#elif defined(_M_ARM)
+ frame.AddrPC.Offset = context->Pc;
+ frame.AddrStack.Offset = context->Sp;
+ frame.AddrFrame.Offset = context->R11;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrStack.Offset = context->Esp;
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 6dd6892757..5607eab342 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,5 +1,7 @@
import methods
import os
+import subprocess
+import sys
from platform_methods import detect_arch
# To match other platforms
@@ -14,6 +16,38 @@ def get_name():
return "Windows"
+def try_cmd(test, prefix, arch):
+ if arch:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, arch) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
+ else:
+ for a in ["x86_64", "x86_32", "arm64", "arm32"]:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, a) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
+
+ return False
+
+
def can_build():
if os.name == "nt":
# Building natively on Windows
@@ -21,7 +55,7 @@ def can_build():
if os.getenv("VCINSTALLDIR"): # MSVC, manual setup
return True
- # Otherwise, let SCons find MSVC if installed, or else Mingw.
+ # Otherwise, let SCons find MSVC if installed, or else MinGW.
# Since we're just returning True here, if there's no compiler
# installed, we'll get errors when it tries to build with the
# null compiler.
@@ -29,47 +63,132 @@ def can_build():
if os.name == "posix":
# Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
- mingw32 = "i686-w64-mingw32-"
- mingw64 = "x86_64-w64-mingw32-"
+ prefix = os.getenv("MINGW_PREFIX", "")
- if os.getenv("MINGW32_PREFIX"):
- mingw32 = os.getenv("MINGW32_PREFIX")
- if os.getenv("MINGW64_PREFIX"):
- mingw64 = os.getenv("MINGW64_PREFIX")
-
- test = "gcc --version > /dev/null 2>&1"
- if os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0:
+ if try_cmd("gcc --version", prefix, "") or try_cmd("clang --version", prefix, ""):
return True
return False
+def get_mingw_bin_prefix(prefix, arch):
+ if not prefix:
+ mingw_bin_prefix = ""
+ elif prefix[-1] != "/":
+ mingw_bin_prefix = prefix + "/bin/"
+ else:
+ mingw_bin_prefix = prefix + "bin/"
+
+ if arch == "x86_64":
+ mingw_bin_prefix += "x86_64-w64-mingw32-"
+ elif arch == "x86_32":
+ mingw_bin_prefix += "i686-w64-mingw32-"
+ elif arch == "arm32":
+ mingw_bin_prefix += "armv7-w64-mingw32-"
+ elif arch == "arm64":
+ mingw_bin_prefix += "aarch64-w64-mingw32-"
+
+ return mingw_bin_prefix
+
+
+def detect_build_env_arch():
+ msvc_target_aliases = {
+ "amd64": "x86_64",
+ "i386": "x86_32",
+ "i486": "x86_32",
+ "i586": "x86_32",
+ "i686": "x86_32",
+ "x86": "x86_32",
+ "x64": "x86_64",
+ "x86_64": "x86_64",
+ "arm": "arm32",
+ "arm64": "arm64",
+ "aarch64": "arm64",
+ }
+ if os.getenv("VCINSTALLDIR") or os.getenv("VCTOOLSINSTALLDIR"):
+ if os.getenv("Platform"):
+ msvc_arch = os.getenv("Platform").lower()
+ if msvc_arch in msvc_target_aliases.keys():
+ return msvc_target_aliases[msvc_arch]
+
+ if os.getenv("VSCMD_ARG_TGT_ARCH"):
+ msvc_arch = os.getenv("VSCMD_ARG_TGT_ARCH").lower()
+ if msvc_arch in msvc_target_aliases.keys():
+ return msvc_target_aliases[msvc_arch]
+
+ # Pre VS 2017 checks.
+ if os.getenv("VCINSTALLDIR"):
+ PATH = os.getenv("PATH").upper()
+ VCINSTALLDIR = os.getenv("VCINSTALLDIR").upper()
+ path_arch = {
+ "BIN\\x86_ARM;": "arm32",
+ "BIN\\amd64_ARM;": "arm32",
+ "BIN\\x86_ARM64;": "arm64",
+ "BIN\\amd64_ARM64;": "arm64",
+ "BIN\\x86_amd64;": "a86_64",
+ "BIN\\amd64;": "x86_64",
+ "BIN\\amd64_x86;": "x86_32",
+ "BIN;": "x86_32",
+ }
+ for path, arch in path_arch.items():
+ final_path = VCINSTALLDIR + path
+ if final_path in PATH:
+ return arch
+
+ # VS 2017 and newer.
+ if os.getenv("VCTOOLSINSTALLDIR"):
+ host_path_index = os.getenv("PATH").upper().find(os.getenv("VCTOOLSINSTALLDIR").upper() + "BIN\\HOST")
+ if host_path_index > -1:
+ first_path_arch = os.getenv("PATH").split(";")[0].rsplit("\\", 1)[-1].lower()
+ return msvc_target_aliases[first_path_arch]
+
+ msys_target_aliases = {
+ "mingw32": "x86_32",
+ "mingw64": "x86_64",
+ "ucrt64": "x86_64",
+ "clang64": "x86_64",
+ "clang32": "x86_32",
+ "clangarm64": "arm64",
+ }
+ if os.getenv("MSYSTEM"):
+ msys_arch = os.getenv("MSYSTEM").lower()
+ if msys_arch in msys_target_aliases.keys():
+ return msys_target_aliases[msys_arch]
+
+ return ""
+
+
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
- # TODO: These shouldn't be hard-coded for x86.
- mingw32 = ""
- mingw64 = ""
- if os.name == "posix":
- mingw32 = "i686-w64-mingw32-"
- mingw64 = "x86_64-w64-mingw32-"
-
- if os.getenv("MINGW32_PREFIX"):
- mingw32 = os.getenv("MINGW32_PREFIX")
- if os.getenv("MINGW64_PREFIX"):
- mingw64 = os.getenv("MINGW64_PREFIX")
+ mingw = os.getenv("MINGW_PREFIX", "")
return [
- ("mingw_prefix_32", "MinGW prefix (Win32)", mingw32),
- ("mingw_prefix_64", "MinGW prefix (Win64)", mingw64),
+ ("mingw_prefix", "MinGW prefix", mingw),
# Targeted Windows version: 7 (and later), minimum supported version
# 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"),
- BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
+ (
+ "target_win_version",
+ "Targeted Windows version, >= 0x0601 (Windows 7)",
+ "0x0601",
+ ),
+ BoolVariable(
+ "debug_symbols",
+ "Add debugging symbols to release/release_debug builds",
+ True,
+ ),
EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")),
- 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(
+ "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.", False),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
@@ -79,73 +198,63 @@ def get_opts():
def get_flags():
+ arch = detect_build_env_arch() or detect_arch()
+
return [
- ("arch", detect_arch()),
+ ("arch", arch),
]
def build_res_file(target, source, env):
- # TODO: This shouldn't be hard-coded for x86.
- if env["arch"] == "x86_32":
- cmdbase = env["mingw_prefix_32"]
- else:
- cmdbase = env["mingw_prefix_64"]
- cmdbase = cmdbase + "windres --include-dir . "
- import subprocess
+ arch_aliases = {
+ "x86_32": "pe-i386",
+ "x86_64": "pe-x86-64",
+ "arm32": "armv7-w64-mingw32",
+ "arm64": "aarch64-w64-mingw32",
+ }
+ cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]]
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
for x in range(len(source)):
- cmd = cmdbase + "-i " + str(source[x]) + " -o " + str(target[x])
+ ok = True
+ # Try prefixed executable (MinGW on Linux).
+ cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
- return 1
+ ok = False
except Exception:
- return 1
+ ok = False
+
+ # Try generic executable (MSYS2).
+ if not ok:
+ cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
+ try:
+ out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
+ if len(out[1]):
+ return -1
+ except Exception:
+ return -1
+
return 0
def setup_msvc_manual(env):
- # FIXME: This is super hacky, and probably obsolete.
- # Won't work with detect_arch() used for `arch` by default.
+ """Running from VCVARS environment"""
- """Set up env to use MSVC manually, using VCINSTALLDIR"""
- if env["arch"] != "auto":
+ env_arch = detect_build_env_arch()
+ if env["arch"] != env_arch:
print(
"""
- Arch argument is not supported for MSVC manual configuration (VCINSTALLDIR configured).
- Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons.
- As a consequence, the arch argument is disabled. Run scons again without arch argument (example: scons p=windows)
- and SCons will attempt to detect what MSVC compiler will be executed and inform you.
+ Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s).
+ Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
"""
+ % (env["arch"], env_arch)
)
- raise SCons.Errors.UserError("Arch argument should not be used when using VCINSTALLDIR")
-
- # Force ARCH arg
- # (Actually msys2 mingw can support 64-bit, we could detect that)
- # TODO: This is wrong, but not sure what to do about it.
- # We want to determine the arch and bitness in the SConstruct only.
- # We can check if it's correct in here, but if it's not, it should
- # just fail with an error message instead of trying to force it.
-
- # find compiler manually
- compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
- print("Found MSVC compiler: " + compiler_version_str)
-
- # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm
- if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
- env["arch"] = "x86_64"
- env["x86_libtheora_opt_vc"] = False
- print("Compiled program architecture will be a 64 bit executable (forcing arch=x86_64).")
- elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
- env["arch"] = "x86_32"
- env["x86_libtheora_opt_vc"] = True
- print("Compiled program architecture will be a 32 bit executable (forcing arch=x86_32).")
- else:
- print(
- "Failed to manually detect MSVC compiler architecture version.\n"
- "You should check your settings/compilation setup, or avoid setting VCINSTALLDIR."
- )
- sys.exit()
+ sys.exit(200)
+
+ print("Found MSVC, arch %s" % (env_arch))
def setup_msvc_auto(env):
@@ -179,23 +288,50 @@ def setup_msvc_auto(env):
env["MSVC_VERSION"] = env["msvc_version"]
env.Tool("msvc")
env.Tool("mssdk") # we want the MS SDK
+
# Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
- print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["TARGET_ARCH"]))
- if env["arch"] == "x86_32":
- env["x86_libtheora_opt_vc"] = False
+ print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"]))
def setup_mingw(env):
"""Set up env for use with mingw"""
- # Nothing to do here
- print("Using MinGW")
+
+ env_arch = detect_build_env_arch()
+ if os.getenv("MSYSTEM") == "MSYS":
+ print(
+ """
+ Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64).
+ """
+ )
+ sys.exit(201)
+
+ if env_arch != "" and env["arch"] != env_arch:
+ print(
+ """
+ Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).
+ Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you.
+ """
+ % (env["arch"], env_arch)
+ )
+ sys.exit(202)
+
+ if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd(
+ "clang --version", env["mingw_prefix"], env["arch"]
+ ):
+ print(
+ """
+ No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.
+ """
+ )
+ sys.exit(202)
+
+ print("Using MinGW, arch %s" % (env["arch"]))
-def configure_msvc(env, manual_msvc_config):
+def configure_msvc(env, vcvars_msvc_config):
"""Configure env to work with MSVC"""
# Build type
-
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
@@ -235,6 +371,9 @@ def configure_msvc(env, manual_msvc_config):
else:
env.AppendUnique(CCFLAGS=["/MD"])
+ if env["arch"] == "x86_32":
+ env["x86_libtheora_opt_vc"] = True
+
env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
@@ -243,7 +382,7 @@ def configure_msvc(env, manual_msvc_config):
# for notes on why this shouldn't be enabled for gcc
env.AppendUnique(CCFLAGS=["/bigobj"])
- if manual_msvc_config: # should be automatic if SCons found it
+ if vcvars_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"])
else:
@@ -302,7 +441,7 @@ def configure_msvc(env, manual_msvc_config):
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
- if manual_msvc_config:
+ if vcvars_msvc_config:
if os.getenv("WindowsSdkDir") is not None:
env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"])
else:
@@ -318,7 +457,7 @@ def configure_msvc(env, manual_msvc_config):
else:
env.AppendUnique(LINKFLAGS=["/LTCG"])
- if manual_msvc_config:
+ if vcvars_msvc_config:
env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
@@ -342,6 +481,12 @@ def configure_mingw(env):
## Build type
+ if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]):
+ env["use_llvm"] = True
+
+ if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]):
+ env["use_llvm"] = False
+
if env["target"] == "release":
env.Append(CCFLAGS=["-msse2"])
@@ -383,36 +528,39 @@ def configure_mingw(env):
if os.name != "nt":
env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
- mingw_prefix = ""
-
- # TODO: This doesn't seem to be working, or maybe I just have
- # MinGW set up incorrectly. It always gives me x86_64 builds,
- # even though arch == "x86_32" and the file name has x86_32 in it.
if env["arch"] == "x86_32":
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static"])
env.Append(LINKFLAGS=["-static-libgcc"])
env.Append(LINKFLAGS=["-static-libstdc++"])
- mingw_prefix = env["mingw_prefix_32"]
else:
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static"])
- mingw_prefix = env["mingw_prefix_64"]
+
+ if env["arch"] in ["x86_32", "x86_64"]:
+ env["x86_libtheora_opt_gcc"] = True
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
if env["use_llvm"]:
- env["CC"] = mingw_prefix + "clang"
- env["CXX"] = mingw_prefix + "clang++"
- env["AS"] = mingw_prefix + "as"
- env["AR"] = mingw_prefix + "ar"
- env["RANLIB"] = mingw_prefix + "ranlib"
+ env["CC"] = mingw_bin_prefix + "clang"
+ env["CXX"] = mingw_bin_prefix + "clang++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "ar"
+ if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "ranlib"
+ env.extra_suffix = ".llvm" + env.extra_suffix
else:
- env["CC"] = mingw_prefix + "gcc"
- env["CXX"] = mingw_prefix + "g++"
- env["AS"] = mingw_prefix + "as"
- env["AR"] = mingw_prefix + "gcc-ar"
- env["RANLIB"] = mingw_prefix + "gcc-ranlib"
-
- env["x86_libtheora_opt_gcc"] = True
+ env["CC"] = mingw_bin_prefix + "gcc"
+ env["CXX"] = mingw_bin_prefix + "g++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "gcc-ar"
+ if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
if env["use_lto"]:
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
@@ -430,10 +578,16 @@ def configure_mingw(env):
## Compile flags
- env.Append(CCFLAGS=["-mwindows"])
+ if not env["use_llvm"]:
+ env.Append(CCFLAGS=["-mwindows"])
env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"])
- env.Append(CPPDEFINES=[("WINVER", env["target_win_version"]), ("_WIN32_WINNT", env["target_win_version"])])
+ env.Append(
+ CPPDEFINES=[
+ ("WINVER", env["target_win_version"]),
+ ("_WIN32_WINNT", env["target_win_version"]),
+ ]
+ )
env.Append(
LIBS=[
"mingw32",
@@ -492,22 +646,21 @@ def configure(env):
env["ENV"]["TMP"] = os.environ["TMP"]
# First figure out which compiler, version, and target arch we're using
- if os.getenv("VCINSTALLDIR") and not env["use_mingw"]:
- # Manual setup of MSVC
+ if os.getenv("VCINSTALLDIR") and detect_build_env_arch() and not env["use_mingw"]:
setup_msvc_manual(env)
env.msvc = True
- manual_msvc_config = True
+ vcvars_msvc_config = True
elif env.get("MSVC_VERSION", "") and not env["use_mingw"]:
setup_msvc_auto(env)
env.msvc = True
- manual_msvc_config = False
+ vcvars_msvc_config = False
else:
setup_mingw(env)
env.msvc = False
# Now set compiler/linker flags
if env.msvc:
- configure_msvc(env, manual_msvc_config)
+ configure_msvc(env, vcvars_msvc_config)
else: # MinGW
configure_mingw(env)
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index cb0bd44cfb..016d201f2c 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -123,7 +123,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32"), "x86_64"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ad4be950cc..0e4d5f79b9 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -902,7 +902,7 @@ void OS_Windows::run() {
main_loop->initialize();
- while (!force_quit) {
+ while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
if (Main::iteration()) {
break;
@@ -1132,8 +1132,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
main_loop = nullptr;
process_map = nullptr;
- force_quit = false;
-
hInstance = _hInstance;
#ifdef STDOUT_FILE
stdo = fopen("stdout.txt", "wb");
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 80fc860738..3e054c068c 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -110,7 +110,6 @@ class OS_Windows : public OS {
ErrorHandlerList error_handlers;
#endif
- bool force_quit;
HWND main_window;
// functions used by main to initialize/deinitialize the OS
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index e6198b44ff..a4c2236706 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -607,13 +607,16 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(to)->get_connection_input_color(E.to_port);
connecting_target = false;
connecting_to = pos;
- just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- to = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(to)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ just_disconnected = true;
+
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ to = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(to)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
}
return;
}
@@ -621,7 +624,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = true;
@@ -629,8 +631,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
return;
}
}
@@ -657,11 +662,13 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_to = pos;
just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- fr = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(fr)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ fr = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(fr)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
}
return;
}
@@ -669,7 +676,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = false;
@@ -677,8 +683,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
return;
}
}
@@ -1127,7 +1136,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
drag_accum += mm->get_relative();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (gn && gn->is_selected()) {
+ if (gn && gn->is_selected() && gn->is_draggable()) {
Vector2 pos = (gn->get_drag_from() * zoom + drag_accum) / zoom;
// Snapping can be toggled temporarily by holding down Ctrl.
@@ -1166,7 +1175,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (gn->is_selected() && !box_selection_mode_additive) {
emit_signal(SNAME("node_deselected"), gn);
}
- gn->set_selected(box_selection_mode_additive);
+ if (gn->is_selectable()) {
+ gn->set_selected(box_selection_mode_additive);
+ }
} else {
bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
@@ -1174,7 +1185,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (!gn->is_selected() && select) {
emit_signal(SNAME("node_selected"), gn);
}
- gn->set_selected(select);
+ if (gn->is_selectable()) {
+ gn->set_selected(select);
+ }
}
}
@@ -1193,7 +1206,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previous_selected.find(gn) != nullptr);
+ bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal(SNAME("node_deselected"), gn);
} else if (!gn->is_selected() && select) {
@@ -1285,7 +1298,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (o_gn) {
if (o_gn == gn) {
- o_gn->set_selected(true);
+ o_gn->set_selected(o_gn->is_selectable());
} else {
if (o_gn->is_selected()) {
emit_signal(SNAME("node_deselected"), o_gn);
@@ -1296,7 +1309,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
}
- gn->set_selected(true);
+ gn->set_selected(gn->is_selectable());
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1711,6 +1724,19 @@ bool GraphEdit::is_minimap_enabled() const {
return minimap_button->is_pressed();
}
+void GraphEdit::set_arrange_nodes_button_hidden(bool p_enable) {
+ arrange_nodes_button_hidden = p_enable;
+ if (arrange_nodes_button_hidden) {
+ layout_button->hide();
+ } else {
+ layout_button->show();
+ }
+}
+
+bool GraphEdit::is_arrange_nodes_button_hidden() const {
+ return arrange_nodes_button_hidden;
+}
+
void GraphEdit::_minimap_toggled() {
if (is_minimap_enabled()) {
minimap->set_visible(true);
@@ -2343,6 +2369,9 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
+ ClassDB::bind_method(D_METHOD("set_arrange_nodes_button_hidden", "enable"), &GraphEdit::set_arrange_nodes_button_hidden);
+ ClassDB::bind_method(D_METHOD("is_arrange_nodes_button_hidden"), &GraphEdit::is_arrange_nodes_button_hidden);
+
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
@@ -2382,6 +2411,9 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size", PROPERTY_HINT_NONE, "suffix:px"), "set_minimap_size", "get_minimap_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
+ ADD_GROUP("UI", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arrange_nodes_button_hidden"), "set_arrange_nodes_button_hidden", "is_arrange_nodes_button_hidden");
+
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position")));
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index b8c9be9983..0a0676699f 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -133,6 +133,8 @@ private:
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ bool arrange_nodes_button_hidden = false;
+
bool connecting = false;
String connecting_from;
bool connecting_out = false;
@@ -323,6 +325,9 @@ public:
void set_minimap_enabled(bool p_enable);
bool is_minimap_enabled() const;
+ void set_arrange_nodes_button_hidden(bool p_enable);
+ bool is_arrange_nodes_button_hidden() const;
+
GraphEditFilter *get_top_layer() const { return top_layer; }
GraphEditMinimap *get_minimap() const { return minimap; }
void get_connection_list(List<Connection> *r_connections) const;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 7d31e929dc..b07d401e6b 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -1003,6 +1003,22 @@ bool GraphNode::is_resizable() const {
return resizable;
}
+void GraphNode::set_draggable(bool p_draggable) {
+ draggable = p_draggable;
+}
+
+bool GraphNode::is_draggable() {
+ return draggable;
+}
+
+void GraphNode::set_selectable(bool p_selectable) {
+ selectable = p_selectable;
+}
+
+bool GraphNode::is_selectable() {
+ return selectable;
+}
+
Vector<int> GraphNode::get_allowed_size_flags_horizontal() const {
Vector<int> flags;
flags.append(SIZE_FILL);
@@ -1064,6 +1080,12 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &GraphNode::set_resizable);
ClassDB::bind_method(D_METHOD("is_resizable"), &GraphNode::is_resizable);
+ ClassDB::bind_method(D_METHOD("set_draggable", "draggable"), &GraphNode::set_draggable);
+ ClassDB::bind_method(D_METHOD("is_draggable"), &GraphNode::is_draggable);
+
+ ClassDB::bind_method(D_METHOD("set_selectable", "selectable"), &GraphNode::set_selectable);
+ ClassDB::bind_method(D_METHOD("is_selectable"), &GraphNode::is_selectable);
+
ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
@@ -1089,6 +1111,8 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_position_offset", "get_position_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draggable"), "set_draggable", "is_draggable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selectable"), "set_selectable", "is_selectable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index d575b6ceed..9c8f926403 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -67,6 +67,8 @@ private:
Vector2 position_offset;
bool comment = false;
bool resizable = false;
+ bool draggable = true;
+ bool selectable = true;
bool resizing = false;
Vector2 resizing_from;
@@ -183,6 +185,12 @@ public:
void set_resizable(bool p_enable);
bool is_resizable() const;
+ void set_draggable(bool p_draggable);
+ bool is_draggable();
+
+ void set_selectable(bool p_selectable);
+ bool is_selectable();
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 4514217dd8..ffc8137819 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -345,6 +345,9 @@ File extracted from upstream release tarball:
- Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h`
providing configuration for light bundling with core.
+Some changes have been made in order to fix Windows on ARM build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+
## meshoptimizer
@@ -375,6 +378,9 @@ Files extracted from upstream repository:
- `minimp3_ex.h`
- `LICENSE`
+Some changes have been made in order to fix Windows on ARM build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+
## miniupnpc
diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c
index 57bc9bcc12..78bfa10cfb 100644
--- a/thirdparty/mbedtls/library/timing.c
+++ b/thirdparty/mbedtls/library/timing.c
@@ -195,8 +195,10 @@ unsigned long mbedtls_timing_hardclock( void )
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __ia64__ */
-#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
+// -- GODOT start --
+#if !defined(HAVE_HARDCLOCK) && defined(_WIN32) && \
!defined(EFIX64) && !defined(EFI32)
+// -- GODOT end --
#define HAVE_HARDCLOCK
diff --git a/thirdparty/minimp3/minimp3.h b/thirdparty/minimp3/minimp3.h
index 3220ae1a85..2a9975cc86 100644
--- a/thirdparty/minimp3/minimp3.h
+++ b/thirdparty/minimp3/minimp3.h
@@ -1566,7 +1566,18 @@ static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins)
#else /* MINIMP3_FLOAT_OUTPUT */
+// -- GODOT start --
+#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_ARM))
+ static f4 g_scale;
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 0);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 1);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 2);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 3);
+#else
static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
+#endif
+// -- GODOT end --
+
a = VMUL(a, g_scale);
b = VMUL(b, g_scale);
#if HAVE_SSE
@@ -1813,7 +1824,19 @@ void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples)
int aligned_count = num_samples & ~7;
for(; i < aligned_count; i += 8)
{
+
+// -- GODOT start --
+#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_ARM))
+ static f4 g_scale;
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 0);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 1);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 2);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 3);
+#else
static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f };
+#endif
+// -- GODOT end --
+
f4 a = VMUL(VLD(&in[i ]), g_scale);
f4 b = VMUL(VLD(&in[i+4]), g_scale);
#if HAVE_SSE