diff options
-rw-r--r-- | core/bind/core_bind.cpp | 6 | ||||
-rw-r--r-- | core/bind/core_bind.h | 1 | ||||
-rw-r--r-- | core/math/geometry.h | 14 | ||||
-rw-r--r-- | doc/classes/AnimationNodeStateMachine.xml | 29 | ||||
-rw-r--r-- | doc/classes/AnimationNodeStateMachinePlayback.xml | 12 | ||||
-rw-r--r-- | doc/classes/Geometry.xml | 9 | ||||
-rw-r--r-- | editor/animation_track_editor.cpp | 5 | ||||
-rw-r--r-- | editor/filesystem_dock.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.cpp | 44 | ||||
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.h | 2 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 2 | ||||
-rw-r--r-- | scene/2d/canvas_modulate.cpp | 2 | ||||
-rw-r--r-- | scene/gui/base_button.cpp | 202 | ||||
-rw-r--r-- | scene/gui/base_button.h | 1 | ||||
-rw-r--r-- | scene/gui/line_edit.cpp | 1 | ||||
-rw-r--r-- | scene/gui/spin_box.cpp | 1 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 125 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 3 | ||||
-rw-r--r-- | servers/audio/effects/audio_effect_spectrum_analyzer.cpp | 2 |
19 files changed, 227 insertions, 236 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 7562c82e8a..ddb60e1345 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1501,6 +1501,11 @@ Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2> &p_polygon) { return Geometry::triangulate_polygon(p_polygon); } +Vector<int> _Geometry::triangulate_delaunay_2d(const Vector<Vector2> &p_points) { + + return Geometry::triangulate_delaunay_2d(p_points); +} + Vector<Point2> _Geometry::convex_hull_2d(const Vector<Point2> &p_points) { return Geometry::convex_hull_2d(p_points); @@ -1674,6 +1679,7 @@ void _Geometry::_bind_methods() { ClassDB::bind_method(D_METHOD("is_polygon_clockwise", "polygon"), &_Geometry::is_polygon_clockwise); ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry::triangulate_polygon); + ClassDB::bind_method(D_METHOD("triangulate_delaunay_2d", "points"), &_Geometry::triangulate_delaunay_2d); ClassDB::bind_method(D_METHOD("convex_hull_2d", "points"), &_Geometry::convex_hull_2d); ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry::clip_polygon); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 561449f29e..d4fa3bc735 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -404,6 +404,7 @@ public: bool is_polygon_clockwise(const Vector<Vector2> &p_polygon); Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon); + Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points); Vector<Point2> convex_hull_2d(const Vector<Point2> &p_points); Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane); diff --git a/core/math/geometry.h b/core/math/geometry.h index c62573dd13..0e144e491f 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -31,6 +31,7 @@ #ifndef GEOMETRY_H #define GEOMETRY_H +#include "core/math/delaunay.h" #include "core/math/face3.h" #include "core/math/rect2.h" #include "core/math/triangulate.h" @@ -857,6 +858,19 @@ public: return points; } + static Vector<int> triangulate_delaunay_2d(const Vector<Vector2> &p_points) { + + Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(p_points); + Vector<int> triangles; + + for (int i = 0; i < tr.size(); i++) { + triangles.push_back(tr[i].points[0]); + triangles.push_back(tr[i].points[1]); + triangles.push_back(tr[i].points[2]); + } + return triangles; + } + static Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon) { Vector<int> triangles; diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml index 8f4e6dff69..2834f83d2f 100644 --- a/doc/classes/AnimationNodeStateMachine.xml +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -1,12 +1,13 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AnimationNodeStateMachine" inherits="AnimationRootNode" category="Core" version="3.2"> <brief_description> + State machine for control of animations. </brief_description> <description> - Contains multiple root nodes as children in a graph. Each node is used as a state, and provides multiple functions to alternate between states. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programmatically. + Contains multiple nodes representing animation states, connected in a graph. Nodes transitions can be configured to happen automatically or via code, using a shortest-path algorithm. Retrieve the AnimationNodeStateMachinePlayback object from the [AnimationTree] node to control it programatically. Example: [codeblock] - var state_machine = anim_tree["parameters/StateMachine/playback"] - state_machine.travel("SomeState") + var state_machine = $AnimationTree.get("parameters/playback") + state_machine.travel("some_state") [/codeblock] </description> <tutorials> @@ -22,6 +23,7 @@ <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> </argument> <description> + Adds a new node to the graph. The [code]position[/code] is used for display in the editor. </description> </method> <method name="add_transition"> @@ -34,18 +36,21 @@ <argument index="2" name="transition" type="AnimationNodeStateMachineTransition"> </argument> <description> + Adds a transition between the given nodes. </description> </method> <method name="get_end_node" qualifiers="const"> <return type="String"> </return> <description> + Returns the graph's end node. </description> </method> <method name="get_graph_offset" qualifiers="const"> <return type="Vector2"> </return> <description> + Returns the draw offset of the graph. Used for display in the editor. </description> </method> <method name="get_node" qualifiers="const"> @@ -54,6 +59,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns the animation node with the given name. </description> </method> <method name="get_node_name" qualifiers="const"> @@ -62,6 +68,7 @@ <argument index="0" name="node" type="AnimationNode"> </argument> <description> + Returns the given animation node's name. </description> </method> <method name="get_node_position" qualifiers="const"> @@ -70,12 +77,14 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns the given node's coordinates. Used for display in the editor. </description> </method> <method name="get_start_node" qualifiers="const"> <return type="String"> </return> <description> + Returns the graph's end node. </description> </method> <method name="get_transition" qualifiers="const"> @@ -84,12 +93,14 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition. </description> </method> <method name="get_transition_count" qualifiers="const"> <return type="int"> </return> <description> + Returns the number of connections in the graph. </description> </method> <method name="get_transition_from" qualifiers="const"> @@ -98,6 +109,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition's start node. </description> </method> <method name="get_transition_to" qualifiers="const"> @@ -106,6 +118,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Returns the given transition's end node. </description> </method> <method name="has_node" qualifiers="const"> @@ -114,6 +127,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Returns [code]true[/code] if the graph contains the given node. </description> </method> <method name="has_transition" qualifiers="const"> @@ -124,6 +138,7 @@ <argument index="1" name="to" type="String"> </argument> <description> + Returns [code]true[/code] if there is a transition between the given nodes. </description> </method> <method name="remove_node"> @@ -132,6 +147,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Deletes the given node from the graph. </description> </method> <method name="remove_transition"> @@ -142,6 +158,7 @@ <argument index="1" name="to" type="String"> </argument> <description> + Deletes the given transition. </description> </method> <method name="remove_transition_by_index"> @@ -150,6 +167,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> + Deletes the given transition. </description> </method> <method name="rename_node"> @@ -160,6 +178,7 @@ <argument index="1" name="new_name" type="String"> </argument> <description> + Renames the given node. </description> </method> <method name="set_end_node"> @@ -168,6 +187,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Sets the given node as the graph end point. </description> </method> <method name="set_graph_offset"> @@ -176,6 +196,7 @@ <argument index="0" name="offset" type="Vector2"> </argument> <description> + Sets the draw offset of the graph. Used for display in the editor. </description> </method> <method name="set_node_position"> @@ -186,6 +207,7 @@ <argument index="1" name="position" type="Vector2"> </argument> <description> + Sets the node's coordinates. Used for display in the editor. </description> </method> <method name="set_start_node"> @@ -194,6 +216,7 @@ <argument index="0" name="name" type="String"> </argument> <description> + Sets the given node as the graph start point. </description> </method> </methods> diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml index fd38c28b16..796d92d7d6 100644 --- a/doc/classes/AnimationNodeStateMachinePlayback.xml +++ b/doc/classes/AnimationNodeStateMachinePlayback.xml @@ -1,8 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AnimationNodeStateMachinePlayback" inherits="Resource" category="Core" version="3.2"> <brief_description> + Playback control for AnimationNodeStateMachine. </brief_description> <description> + Allows control of [AnimationTree] state machines created with [AnimationNodeStateMachine]. Retrieve with [code]$AnimationTree.get("parameters/playback")[/code]. Example: + [codeblock] + var state_machine = $AnimationTree.get("parameters/playback") + state_machine.travel("some_state") + [/codeblock] </description> <tutorials> </tutorials> @@ -11,6 +17,7 @@ <return type="String"> </return> <description> + Returns the currently playing animation state. </description> </method> <method name="get_travel_path" qualifiers="const"> @@ -23,6 +30,7 @@ <return type="bool"> </return> <description> + Returns [code]true[/code] if an animation is playing. </description> </method> <method name="start"> @@ -31,12 +39,14 @@ <argument index="0" name="node" type="String"> </argument> <description> + Starts playing the given animation. </description> </method> <method name="stop"> <return type="void"> </return> <description> + Stops the currently playing animation. </description> </method> <method name="travel"> @@ -45,7 +55,7 @@ <argument index="0" name="to_node" type="String"> </argument> <description> - Transition from the current state to another one, while visiting all the intermediate ones. This is done via the A* algorithm. + Transitions from the current state to another one, following the shortest path. </description> </method> </methods> diff --git a/doc/classes/Geometry.xml b/doc/classes/Geometry.xml index b95b888cf1..e2ba3fb7b0 100644 --- a/doc/classes/Geometry.xml +++ b/doc/classes/Geometry.xml @@ -428,6 +428,15 @@ Can be useful in conjuction with performing polygon boolean operations in CSG manner, see [method merge_polygons_2d], [method clip_polygons_2d], [method intersect_polygons_2d], [method exclude_polygons_2d]. </description> </method> + <method name="triangulate_delaunay_2d"> + <return type="PoolIntArray"> + </return> + <argument index="0" name="points" type="PoolVector2Array"> + </argument> + <description> + Triangulates the area specified by discrete set of [code]points[/code] such that no point is inside the circumcircle of any resulting triangle. Returns a [PoolIntArray] where each triangle consists of three consecutive point indices into [code]points[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PoolIntArray] is returned. + </description> + </method> <method name="triangulate_polygon"> <return type="PoolIntArray"> </return> diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index b2af11fab0..1985c91f31 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3656,7 +3656,8 @@ void AnimationTrackEditor::_update_step(double p_new_step) { step->set_block_signals(true); undo_redo->commit_action(); step->set_block_signals(false); - emit_signal("animation_step_changed", step_value); + emit_signal("animation_step_changed", p_new_step); + animation->_change_notify("step"); } void AnimationTrackEditor::_update_length(double p_new_len) { @@ -4931,7 +4932,6 @@ void AnimationTrackEditor::_bind_methods() { ClassDB::bind_method("_update_scroll", &AnimationTrackEditor::_update_scroll); ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks); ClassDB::bind_method("_update_step", &AnimationTrackEditor::_update_step); - ClassDB::bind_method("_update_length", &AnimationTrackEditor::_update_length); ClassDB::bind_method("_dropped_track", &AnimationTrackEditor::_dropped_track); ClassDB::bind_method("_add_track", &AnimationTrackEditor::_add_track); ClassDB::bind_method("_new_track_node_selected", &AnimationTrackEditor::_new_track_node_selected); @@ -4992,7 +4992,6 @@ AnimationTrackEditor::AnimationTrackEditor() { timeline->connect("name_limit_changed", this, "_name_limit_changed"); timeline->connect("track_added", this, "_add_track"); timeline->connect("value_changed", this, "_timeline_value_changed"); - timeline->connect("length_changed", this, "_update_length"); scroll = memnew(ScrollContainer); timeline_vbox->add_child(scroll); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index b7e9d36d88..52ed94e428 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -756,7 +756,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { Ref<Texture> type_icon; Ref<Texture> big_icon; - String tooltip = fname; + String tooltip = fpath; // Select the icons if (!finfo->import_broken) { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 3c67d26828..c6b7df56a0 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -293,25 +293,40 @@ void AnimationPlayerEditor::_pause_pressed() { //player->set_pause( pause->is_pressed() ); } -void AnimationPlayerEditor::_animation_selected(int p_which) { - if (updating) - return; +String AnimationPlayerEditor::_get_current_animation() const { + // when selecting an animation, the idea is that the only interesting behavior // ui-wise is that it should play/blend the next one if currently playing - String current; if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); + return animation->get_item_text(animation->get_selected()); } - if (current != "") { + return ""; +} - player->set_assigned_animation(current); +void AnimationPlayerEditor::_animation_selected(int p_which) { + + if (updating) + return; + + _current_animation_updated(); +} +void AnimationPlayerEditor::_current_animation_updated() { + + String current = _get_current_animation(); + + if (current != "") { Ref<Animation> anim = player->get_animation(current); + + player->set_assigned_animation(current); { + if (!anim->is_connected("changed", this, "_current_animation_updated")) + anim->connect("changed", this, "_current_animation_updated"); + track_editor->set_animation(anim); Node *root = player->get_node(player->get_root()); if (root) { @@ -1068,17 +1083,19 @@ void AnimationPlayerEditor::_list_changed() { _update_player(); } -void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) { - - frame->set_max(p_len); -} - void AnimationPlayerEditor::_animation_key_editor_anim_step_changed(float p_len) { if (p_len) frame->set_step(p_len); else frame->set_step(0.00001); + + String current = _get_current_animation(); + + if (current != "") { + Ref<Animation> anim = player->get_animation(current); + anim->_change_notify("step"); + } } void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag) { @@ -1558,6 +1575,7 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_autoplay_pressed"), &AnimationPlayerEditor::_autoplay_pressed); ClassDB::bind_method(D_METHOD("_pause_pressed"), &AnimationPlayerEditor::_pause_pressed); ClassDB::bind_method(D_METHOD("_animation_selected"), &AnimationPlayerEditor::_animation_selected); + ClassDB::bind_method(D_METHOD("_current_animation_updated"), &AnimationPlayerEditor::_current_animation_updated); ClassDB::bind_method(D_METHOD("_animation_name_edited"), &AnimationPlayerEditor::_animation_name_edited); ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename); @@ -1577,7 +1595,6 @@ void AnimationPlayerEditor::_bind_methods() { //ClassDB::bind_method(D_METHOD("_editor_load_all"),&AnimationPlayerEditor::_editor_load_all); ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_seek"), &AnimationPlayerEditor::_animation_key_editor_seek); - ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_len_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_len_changed); ClassDB::bind_method(D_METHOD("_animation_key_editor_anim_step_changed"), &AnimationPlayerEditor::_animation_key_editor_anim_step_changed); ClassDB::bind_method(D_METHOD("_hide_anim_editors"), &AnimationPlayerEditor::_hide_anim_editors); ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate); @@ -1810,7 +1827,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay add_child(track_editor); track_editor->set_v_size_flags(SIZE_EXPAND_FILL); track_editor->connect("timeline_changed", this, "_animation_key_editor_seek"); - track_editor->connect("animation_len_changed", this, "_animation_key_editor_anim_len_changed"); track_editor->connect("animation_step_changed", this, "_animation_key_editor_anim_step_changed"); _update_player(); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index c6ab6c5e30..6162181f8c 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -173,7 +173,9 @@ class AnimationPlayerEditor : public VBoxContainer { void _autoplay_pressed(); void _stop_pressed(); void _pause_pressed(); + String _get_current_animation() const; void _animation_selected(int p_which); + void _current_animation_updated(); void _animation_new(); void _animation_rename(); void _animation_name_edited(); diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 5c408cf29e..5e3c379f2b 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2218,7 +2218,7 @@ Control *VisualScriptEditor::get_edit_menu() { void VisualScriptEditor::_change_base_type() { - select_base_type->popup_create(true); + select_base_type->popup_create(true, true); } void VisualScriptEditor::clear_edit_menu() { diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index bd7bb97b03..009d664462 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -70,7 +70,7 @@ void CanvasModulate::_bind_methods() { void CanvasModulate::set_color(const Color &p_color) { color = p_color; - if (is_inside_tree()) { + if (is_visible_in_tree()) { VS::get_singleton()->canvas_set_modulate(get_canvas(), color); } } diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index e95781c181..5669743ec1 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -56,185 +56,53 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) { if (status.disabled) // no interaction with disabled button return; - Ref<InputEventMouseButton> b = p_event; + Ref<InputEventMouseButton> mouse_button = p_event; + bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); - if (b.is_valid()) { - if (((1 << (b->get_button_index() - 1)) & button_mask) == 0) - return; - - if (status.pressing_button) - return; - - if (action_mode == ACTION_MODE_BUTTON_PRESS) { - - if (b->is_pressed()) { - - emit_signal("button_down"); - - if (!toggle_mode) { //mouse press attempt - - status.press_attempt = true; - status.pressing_inside = true; + bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0; + if (button_masked || ui_accept) { + if (p_event->is_pressed()) { + status.press_attempt = true; + status.pressing_inside = true; + emit_signal("button_down"); + } - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); + if (status.press_attempt && status.pressing_inside) { + if (toggle_mode) { + if ((p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_PRESS) || (!p_event->is_pressed() && action_mode == ACTION_MODE_BUTTON_RELEASE)) { + if (action_mode == ACTION_MODE_BUTTON_PRESS) { + status.press_attempt = false; + status.pressing_inside = false; } - - _unpress_group(); - emit_signal("pressed"); - - } else { - status.pressed = !status.pressed; - pressed(); - _unpress_group(); - emit_signal("pressed"); - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); + pressed(); } - } else { - - emit_signal("button_up"); - - /* this is pointless if (status.press_attempt && status.pressing_inside) { - //released(); - emit_signal("released"); + if (!p_event->is_pressed()) { + pressed(); } -*/ - status.press_attempt = false; } - update(); - return; } - if (b->is_pressed()) { - - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else { - + if (!p_event->is_pressed()) { // pressed state should be correct with button_up signal emit_signal("button_up"); - - if (status.press_attempt && status.pressing_inside) { - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } - } - status.press_attempt = false; } update(); + return; } - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - if (status.press_attempt && status.pressing_button == 0) { + Ref<InputEventMouseMotion> mouse_motion = p_event; + if (mouse_motion.is_valid()) { + if (status.press_attempt) { bool last_press_inside = status.pressing_inside; - status.pressing_inside = has_point(mm->get_position()); - if (last_press_inside != status.pressing_inside) + status.pressing_inside = has_point(mouse_motion->get_position()); + if (last_press_inside != status.pressing_inside) { update(); - } - } - - if (!mm.is_valid() && !b.is_valid()) { - - if (p_event->is_echo()) { - return; - } - - if (status.disabled) { - return; - } - - if (status.press_attempt && status.pressing_button == 0) { - return; - } - - if (p_event->is_action("ui_accept")) { - - if (p_event->is_pressed()) { - - status.pressing_button++; - status.press_attempt = true; - status.pressing_inside = true; - emit_signal("button_down"); - - } else if (status.press_attempt) { - - if (status.pressing_button) - status.pressing_button--; - - if (status.pressing_button) - return; - - status.press_attempt = false; - status.pressing_inside = false; - - emit_signal("button_up"); - - if (!toggle_mode) { //mouse press attempt - - pressed(); - if (get_script_instance()) { - Variant::CallError ce; - get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce); - } - - _unpress_group(); - emit_signal("pressed"); - } else { - - status.pressed = !status.pressed; - - pressed(); - _unpress_group(); - emit_signal("pressed"); - - toggled(status.pressed); - if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, status.pressed); - } - emit_signal("toggled", status.pressed); - } } - - accept_event(); - update(); } } } @@ -255,7 +123,6 @@ void BaseButton::_notification(int p_what) { if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; update(); } } @@ -268,9 +135,8 @@ void BaseButton::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_EXIT) { - if (status.pressing_button && status.press_attempt) { + if (status.press_attempt) { status.press_attempt = false; - status.pressing_button = 0; status.hovering = false; update(); } else if (status.hovering) { @@ -290,21 +156,23 @@ void BaseButton::_notification(int p_what) { status.hovering = false; status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } } void BaseButton::pressed() { - if (get_script_instance()) - get_script_instance()->call("pressed"); + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed); + } + emit_signal("pressed"); } void BaseButton::toggled(bool p_pressed) { if (get_script_instance()) { - get_script_instance()->call("toggled", p_pressed); + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed); } + emit_signal("toggled", p_pressed); } void BaseButton::set_disabled(bool p_disabled) { @@ -318,7 +186,6 @@ void BaseButton::set_disabled(bool p_disabled) { } status.press_attempt = false; status.pressing_inside = false; - status.pressing_button = 0; } update(); _change_notify("disabled"); @@ -341,6 +208,10 @@ void BaseButton::set_pressed(bool p_pressed) { if (p_pressed) { _unpress_group(); } + if (toggle_mode) { + toggled(status.pressed); + } + update(); } @@ -585,7 +456,6 @@ BaseButton::BaseButton() { status.hovering = false; status.pressing_inside = false; status.disabled = false; - status.pressing_button = 0; set_focus_mode(FOCUS_ALL); enabled_focus_mode = FOCUS_ALL; action_mode = ACTION_MODE_BUTTON_RELEASE; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 22a8f6d8fe..4762c27b28 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -65,7 +65,6 @@ private: bool pressing_inside; bool disabled; - int pressing_button; } status; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index ed74851755..fa1a63f5e2 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -68,6 +68,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { + accept_event(); //don't pass event further when clicked on text field if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index d21143739c..e778af3ceb 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -277,6 +277,7 @@ SpinBox::SpinBox() { add_child(line_edit); line_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE); + line_edit->set_mouse_filter(MOUSE_FILTER_PASS); //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered", this, "_text_entered", Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", this, "_line_edit_focus_exit", Vector<Variant>(), CONNECT_DEFERRED); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e039558abc..1686ea9690 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -104,6 +104,13 @@ static CharType _get_right_pair_symbol(CharType c) { return 0; } +static int _find_first_non_whitespace_column_of_line(const String &line) { + int left = 0; + while (left < line.length() && _is_whitespace(line[left])) + left++; + return left; +} + void TextEdit::Text::set_font(const Ref<Font> &p_font) { font = p_font; @@ -1645,31 +1652,25 @@ void TextEdit::backspace_at_cursor() { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { // handle space indentation - if (cursor.column - indent_size >= 0 && indent_using_spaces) { - - // if there is enough spaces to count as a tab + if (cursor.column != 0 && indent_using_spaces) { + // check if there are no other chars before cursor, just indentation bool unindent = true; - for (int i = 1; i <= indent_size; i++) { - if (text[cursor.line][cursor.column - i] != ' ') { - unindent = false; - break; - } - } - - // and it is before the first character int i = 0; while (i < cursor.column && i < text[cursor.line].length()) { - if (text[cursor.line][i] != ' ' && text[cursor.line][i] != '\t') { + if (!_is_whitespace(text[cursor.line][i])) { unindent = false; break; } i++; } - // then we can remove it as a single character. + // then we can remove all spaces as a single character. if (unindent) { - _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column); - prev_column = cursor.column - indent_size; + // we want to remove spaces up to closest indent + // or whole indent if cursor is pointing at it + int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); + prev_column = cursor.column - spaces_to_delete; + _remove_text(cursor.line, prev_column, cursor.line, cursor.column); } else { _remove_text(prev_line, prev_column, cursor.line, cursor.column); } @@ -1686,6 +1687,10 @@ void TextEdit::indent_right() { int start_line; int end_line; + + // this value informs us by how much we changed selection position by indenting right + // default is 1 for tab indentation + int selection_offset = 1; begin_complex_operation(); if (is_selection_active()) { @@ -1704,18 +1709,24 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); if (indent_using_spaces) { - line_text = space_indent + line_text; + // we don't really care where selection is - we just need to know indentation level at the beginning of the line + int left = _find_first_non_whitespace_column_of_line(line_text); + int spaces_to_add = _calculate_spaces_till_next_right_indent(left); + // since we will add this much spaces we want move whole selection and cursor by this much + selection_offset = spaces_to_add; + for (int j = 0; j < spaces_to_add; j++) + line_text = ' ' + line_text; } else { line_text = '\t' + line_text; } set_line(i, line_text); } - // fix selection and cursor being off by one on the last line + // fix selection and cursor being off after shifting selection right if (is_selection_active()) { - select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); + select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); } - cursor_set_column(cursor.column + 1, false); + cursor_set_column(cursor.column + selection_offset, false); end_complex_operation(); update(); } @@ -1724,6 +1735,15 @@ void TextEdit::indent_left() { int start_line; int end_line; + + // moving cursor and selection after unindenting can get tricky + // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either) + // therefore we just remember initial values + // and at the end of the operation offset them by number of removed characters + int removed_characters = 0; + int initial_selection_end_column = selection.to_column; + int initial_cursor_column = cursor.column; + begin_complex_operation(); if (is_selection_active()) { @@ -1746,21 +1766,43 @@ void TextEdit::indent_left() { if (line_text.begins_with("\t")) { line_text = line_text.substr(1, line_text.length()); set_line(i, line_text); - } else if (line_text.begins_with(space_indent)) { - line_text = line_text.substr(indent_size, line_text.length()); + removed_characters = 1; + } else if (line_text.begins_with(" ")) { + // when unindenting we aim to remove spaces before line that has selection no matter what is selected + // so we start of by finding first non whitespace character of line + int left = _find_first_non_whitespace_column_of_line(line_text); + + // here we remove only enough spaces to align text to nearest full multiple of indentation_size + // in case where selection begins at the start of indentation_size multiple we remove whole indentation level + int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); + + line_text = line_text.substr(spaces_to_remove, line_text.length()); set_line(i, line_text); + removed_characters = spaces_to_remove; } } // fix selection and cursor being off by one on the last line if (is_selection_active() && last_line_text != get_line(end_line)) { - select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); + select(selection.from_line, selection.from_column - removed_characters, + selection.to_line, initial_selection_end_column - removed_characters); } - cursor_set_column(cursor.column - 1, false); + cursor_set_column(initial_cursor_column - removed_characters, false); end_complex_operation(); update(); } +int TextEdit::_calculate_spaces_till_next_left_indent(int column) { + int spaces_till_indent = column % indent_size; + if (spaces_till_indent == 0) + spaces_till_indent = indent_size; + return spaces_till_indent; +} + +int TextEdit::_calculate_spaces_till_next_right_indent(int column) { + return indent_size - column % indent_size; +} + void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const { float rows = p_mouse.y; @@ -2517,15 +2559,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (k->get_shift()) { - //simple unindent + // simple unindent int cc = cursor.column; - - const int len = text[cursor.line].length(); const String &line = text[cursor.line]; - int left = 0; // number of whitespace chars at beginning of line - while (left < len && (line[left] == '\t' || line[left] == ' ')) - left++; + int left = _find_first_non_whitespace_column_of_line(line); cc = MIN(cc, left); while (cc < indent_size && cc < left && line[cc] == ' ') @@ -2533,24 +2571,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc > 0 && cc <= text[cursor.line].length()) { if (text[cursor.line][cc - 1] == '\t') { + // tabs unindentation _remove_text(cursor.line, cc - 1, cursor.line, cc); if (cursor.column >= left) cursor_set_column(MAX(0, cursor.column - 1)); update(); } else { - int n = 0; - - for (int i = 1; i <= MIN(cc, indent_size); i++) { - if (line[cc - i] != ' ') { - break; - } - n++; - } - - if (n > 0) { - _remove_text(cursor.line, cc - n, cursor.line, cc); - if (cursor.column > left - n) // inside text? - cursor_set_column(MAX(0, cursor.column - n)); + // spaces unindentation + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); + if (cursor.column > left - spaces_to_remove) // inside text? + cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); update(); } } @@ -2559,9 +2591,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } } else { - //simple indent + // simple indent if (indent_using_spaces) { - _insert_text_at_cursor(space_indent); + // insert only as much spaces as needed till next indentation level + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); + String indent_to_insert = String(); + for (int i = 0; i < spaces_to_add; i++) + indent_to_insert = ' ' + indent_to_insert; + _insert_text_at_cursor(indent_to_insert); } else { _insert_text_at_cursor("\t"); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 64cbafc717..68e590f1e6 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -437,6 +437,9 @@ private: void _confirm_completion(); void _update_completion_candidates(); + int _calculate_spaces_till_next_left_indent(int column); + int _calculate_spaces_till_next_right_indent(int column); + protected: virtual String get_tooltip(const Point2 &p_pos) const; diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 05cba416be..8e15e9288f 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -170,7 +170,7 @@ Vector2 AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range(f for (int i = begin_pos; i <= end_pos; i++) { max.x = MAX(max.x, r[i].l); - max.y = MAX(max.x, r[i].r); + max.y = MAX(max.y, r[i].r); } return max; |