summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bind/core_bind.cpp6
-rw-r--r--core/bind/core_bind.h1
-rw-r--r--core/math/geometry.h14
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml29
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml12
-rw-r--r--doc/classes/Geometry.xml9
-rw-r--r--editor/animation_track_editor.cpp5
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp44
-rw-r--r--editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--modules/visual_script/visual_script_editor.cpp2
-rw-r--r--scene/2d/canvas_modulate.cpp2
-rw-r--r--scene/gui/base_button.cpp202
-rw-r--r--scene/gui/base_button.h1
-rw-r--r--scene/gui/line_edit.cpp1
-rw-r--r--scene/gui/spin_box.cpp1
-rw-r--r--scene/gui/text_edit.cpp125
-rw-r--r--scene/gui/text_edit.h3
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.cpp2
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;