summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_bezier_editor.cpp956
-rw-r--r--editor/animation_bezier_editor.h44
-rw-r--r--editor/animation_track_editor.cpp73
-rw-r--r--editor/animation_track_editor.h5
-rw-r--r--editor/debugger/editor_network_profiler.cpp22
-rw-r--r--editor/debugger/editor_network_profiler.h6
-rw-r--r--editor/debugger/script_editor_debugger.cpp48
-rw-r--r--editor/editor_about.cpp3
-rw-r--r--editor/editor_node.cpp1
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp113
-rw-r--r--editor/plugins/node_3d_editor_plugin.h79
-rw-r--r--editor/project_manager.cpp1
-rw-r--r--editor/scene_tree_dock.cpp2
13 files changed, 874 insertions, 479 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index da376c588e..67cdba043a 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -35,6 +35,8 @@
#include "scene/gui/view_panner.h"
#include "scene/resources/text_line.h"
+#include <limits.h>
+
float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
float h = p_h;
h = (h - v_scroll) / v_zoom;
@@ -55,15 +57,16 @@ static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, con
void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float scale = timeline->get_zoom_scale();
+
int limit = timeline->get_name_limit();
- int right_limit = get_size().width - timeline->get_buttons_width();
+ int right_limit = get_size().width;
//selection may have altered the order of keys
Map<float, int> key_order;
for (int i = 0; i < animation->track_get_key_count(p_track); i++) {
float ofs = animation->track_get_key_time(p_track, i);
- if (moving_selection && track == p_track && selection.has(i)) {
+ if (moving_selection && selection.has(IntPair(p_track, i))) {
ofs += moving_selection_offset.x;
}
@@ -82,11 +85,11 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset = animation->track_get_key_time(p_track, i);
float height = animation->bezier_track_get_key_value(p_track, i);
Vector2 out_handle = animation->bezier_track_get_key_out_handle(p_track, i);
- if (track == p_track && moving_handle != 0 && moving_handle_key == i) {
+ if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i) {
out_handle = moving_handle_right;
}
- if (moving_selection && track == p_track && selection.has(i)) {
+ if (moving_selection && selection.has(IntPair(p_track, i))) {
offset += moving_selection_offset.x;
height += moving_selection_offset.y;
}
@@ -96,11 +99,11 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset_n = animation->track_get_key_time(p_track, i_n);
float height_n = animation->bezier_track_get_key_value(p_track, i_n);
Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n);
- if (track == p_track && moving_handle != 0 && moving_handle_key == i_n) {
+ if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i_n) {
in_handle = moving_handle_left;
}
- if (moving_selection && track == p_track && selection.has(i_n)) {
+ if (moving_selection && selection.has(IntPair(p_track, i_n))) {
offset_n += moving_selection_offset.x;
height_n += moving_selection_offset.y;
}
@@ -221,20 +224,10 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
}
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- close_button->set_icon(get_theme_icon(SNAME("Close"), SNAME("EditorIcons")));
-
bezier_icon = get_theme_icon(SNAME("KeyBezierPoint"), SNAME("EditorIcons"));
bezier_handle_icon = get_theme_icon(SNAME("KeyBezierHandle"), SNAME("EditorIcons"));
selected_icon = get_theme_icon(SNAME("KeyBezierSelected"), SNAME("EditorIcons"));
}
- if (p_what == NOTIFICATION_RESIZED) {
- int right_limit = get_size().width - timeline->get_buttons_width();
- int hsep = get_theme_constant(SNAME("hseparation"), SNAME("ItemList"));
- int vsep = get_theme_constant(SNAME("vseparation"), SNAME("ItemList"));
-
- right_column->set_position(Vector2(right_limit + hsep, vsep));
- right_column->set_size(Vector2(timeline->get_buttons_width() - hsep * 2, get_size().y - vsep * 2));
- }
if (p_what == NOTIFICATION_DRAW) {
if (animation.is_null()) {
return;
@@ -258,101 +251,191 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
- int right_limit = get_size().width - timeline->get_buttons_width();
+ int right_limit = get_size().width;
- draw_line(Point2(right_limit, 0), Point2(right_limit, get_size().height), linecolor, Math::round(EDSCALE));
-
- String base_path = animation->track_get_path(track);
- int end = base_path.find(":");
- if (end != -1) {
- base_path = base_path.substr(0, end + 1);
- }
-
- // NAMES AND ICON
int vofs = vsep;
int margin = 0;
- {
- NodePath path = animation->track_get_path(track);
+ Map<int, Color> subtrack_colors;
+ Color selected_track_color;
+ subtracks.clear();
+ subtrack_icons.clear();
+
+ Map<String, Vector<int>> track_indices;
+ int track_count = animation->get_track_count();
+ for (int i = 0; i < track_count; ++i) {
+ if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
+ continue;
+ }
- Node *node = nullptr;
+ String base_path = animation->track_get_path(i);
+ if (is_filtered) {
+ if (root && root->has_node(base_path)) {
+ Node *node = root->get_node(base_path);
+ if (!node) {
+ continue; // No node, no filter.
+ }
+ if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ continue; // Skip track due to not selected.
+ }
+ }
+ }
- if (root && root->has_node(path)) {
- node = root->get_node(path);
+ int end = base_path.find(":");
+ if (end != -1) {
+ base_path = base_path.substr(0, end + 1);
}
+ Vector<int> indices = track_indices.has(base_path) ? track_indices[base_path] : Vector<int>();
+ indices.push_back(i);
+ track_indices[base_path] = indices;
+ }
- String text;
+ for (const KeyValue<String, Vector<int>> &E : track_indices) {
+ String base_path = E.key;
- if (node) {
- int ofs = 0;
+ Vector<int> tracks = E.value;
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
+ // NAMES AND ICON
+ {
+ NodePath path = animation->track_get_path(tracks[0]);
- text = node->get_name();
- ofs += hsep;
- ofs += icon->get_width();
+ Node *node = nullptr;
- TextLine text_buf = TextLine(text, font, font_size);
- text_buf.set_width(limit - ofs - hsep);
+ if (root && root->has_node(path)) {
+ node = root->get_node(path);
+ }
- int h = MAX(text_buf.get_size().y, icon->get_height());
+ String text;
- draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2));
+ if (node) {
+ int ofs = 0;
- margin = icon->get_width();
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
- Vector2 string_pos = Point2(ofs, vofs + (h - text_buf.get_size().y) / 2 + text_buf.get_line_ascent());
- string_pos = string_pos.floor();
- text_buf.draw(get_canvas_item(), string_pos, color);
+ text = node->get_name();
+ ofs += hsep;
- vofs += h + vsep;
- }
- }
+ TextLine text_buf = TextLine(text, font, font_size);
+ text_buf.set_width(limit - ofs - icon->get_width() - hsep);
- // RELATED TRACKS TITLES
+ int h = MAX(text_buf.get_size().y, icon->get_height());
- Map<int, Color> subtrack_colors;
- subtracks.clear();
+ draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2));
+ ofs += icon->get_width();
- for (int i = 0; i < animation->get_track_count(); i++) {
- if (animation->track_get_type(i) != Animation::TYPE_BEZIER) {
- continue;
- }
- String path = animation->track_get_path(i);
- if (!path.begins_with(base_path)) {
- continue; //another node
+ margin = icon->get_width();
+
+ Vector2 string_pos = Point2(ofs, vofs);
+ string_pos = string_pos.floor();
+ text_buf.draw(get_canvas_item(), string_pos, color);
+
+ vofs += h + vsep;
+ }
}
- path = path.replace_first(base_path, "");
- Color cc = color;
- TextLine text_buf = TextLine(path, font, font_size);
- text_buf.set_width(limit - margin - hsep);
+ Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
+ float remove_hpos = limit - hsep - remove->get_width();
+
+ Ref<Texture2D> lock = get_theme_icon(SNAME("Lock"), SNAME("EditorIcons"));
+ Ref<Texture2D> unlock = get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons"));
+ float lock_hpos = remove_hpos - hsep - lock->get_width();
+
+ Ref<Texture2D> visible = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
+ Ref<Texture2D> hidden = get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"));
+ float visibility_hpos = lock_hpos - hsep - visible->get_width();
+
+ Ref<Texture2D> solo = get_theme_icon(SNAME("AudioBusSolo"), SNAME("EditorIcons"));
+ float solo_hpos = visibility_hpos - hsep - solo->get_width();
+
+ float buttons_width = remove->get_width() + lock->get_width() + visible->get_width() + solo->get_width() + hsep * 3;
+
+ for (int i = 0; i < tracks.size(); ++i) {
+ // RELATED TRACKS TITLES
+
+ int current_track = tracks[i];
+
+ String path = animation->track_get_path(current_track);
+ path = path.replace_first(base_path, "");
+
+ Color cc = color;
+ TextLine text_buf = TextLine(path, font, font_size);
+ text_buf.set_width(limit - margin - buttons_width);
+
+ Rect2 rect = Rect2(margin, vofs, solo_hpos - hsep - solo->get_width(), text_buf.get_size().y + vsep);
- Rect2 rect = Rect2(margin, vofs, limit - margin - hsep, text_buf.get_size().y + vsep);
- if (i != track) {
cc.a *= 0.7;
- uint32_t hash = path.hash();
- hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
- hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
- hash = (hash >> 16) ^ hash;
- float h = (hash % 65535) / 65536.0;
- Color subcolor;
- subcolor.set_hsv(h, 0.2, 0.8);
- subcolor.a = 0.5;
- draw_rect(Rect2(0, vofs + text_buf.get_size().y * 0.1, margin - hsep, text_buf.get_size().y * 0.8), subcolor);
- subtrack_colors[i] = subcolor;
-
- subtracks[i] = rect;
- } else {
- Color ac = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- ac.a = 0.5;
- draw_rect(rect, ac);
- }
+ float h;
+ if (path.ends_with(":x")) {
+ h = 0;
+ } else if (path.ends_with(":y")) {
+ h = 0.33f;
+ } else if (path.ends_with(":z")) {
+ h = 0.66f;
+ } else {
+ uint32_t hash = path.hash();
+ hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
+ hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
+ hash = (hash >> 16) ^ hash;
+ h = (hash % 65535) / 65536.0;
+ }
+
+ if (current_track != selected_track) {
+ Color track_color;
+ if (locked_tracks.has(current_track)) {
+ track_color.set_hsv(h, 0, 0.4);
+ } else {
+ track_color.set_hsv(h, 0.2, 0.8);
+ }
+ track_color.a = 0.5;
+ draw_rect(Rect2(0, vofs, margin - hsep, text_buf.get_size().y * 0.8), track_color);
+ subtrack_colors[current_track] = track_color;
+
+ subtracks[current_track] = rect;
+ } else {
+ Color ac = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ ac.a = 0.5;
+ draw_rect(rect, ac);
+ if (locked_tracks.has(selected_track)) {
+ selected_track_color.set_hsv(h, 0.0, 0.4);
+ } else {
+ selected_track_color.set_hsv(h, 0.8, 0.8);
+ }
+ }
+
+ Vector2 string_pos = Point2(margin, vofs);
+ text_buf.draw(get_canvas_item(), string_pos, cc);
+
+ float icon_start_height = vofs + rect.size.y / 2;
+ Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2, remove->get_width(), remove->get_height());
+ draw_texture(remove, remove_rect.position);
+
+ Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2, lock->get_width(), lock->get_height());
+ if (locked_tracks.has(current_track)) {
+ draw_texture(lock, lock_rect.position);
+ } else {
+ draw_texture(unlock, lock_rect.position);
+ }
+
+ Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2, visible->get_width(), visible->get_height());
+ if (hidden_tracks.has(current_track)) {
+ draw_texture(hidden, visible_rect.position);
+ } else {
+ draw_texture(visible, visible_rect.position);
+ }
- Vector2 string_pos = Point2(margin, vofs + text_buf.get_line_ascent());
- text_buf.draw(get_canvas_item(), string_pos, cc);
+ Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2, solo->get_width(), solo->get_height());
+ draw_texture(solo, solo_rect.position);
- vofs += text_buf.get_size().y + vsep;
+ Map<int, Rect2> track_icons;
+ track_icons[REMOVE_ICON] = remove_rect;
+ track_icons[LOCK_ICON] = lock_rect;
+ track_icons[VISIBILITY_ICON] = visible_rect;
+ track_icons[SOLO_ICON] = solo_rect;
+
+ subtrack_icons[current_track] = track_icons;
+
+ vofs += text_buf.get_size().y + vsep;
+ }
}
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
@@ -398,6 +481,9 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
float scale = timeline->get_zoom_scale();
Ref<Texture2D> point = get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons"));
for (const KeyValue<int, Color> &E : subtrack_colors) {
+ if (hidden_tracks.has(E.key)) {
+ continue;
+ }
_draw_track(E.key, E.value);
for (int i = 0; i < animation->track_get_key_count(E.key); i++) {
@@ -412,70 +498,116 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
}
- //draw edited curve
- const Color highlight = get_theme_color(SNAME("highlight_color"), SNAME("Editor"));
- _draw_track(track, highlight);
+ if (track_count > 0 && !hidden_tracks.has(selected_track)) {
+ //draw edited curve
+ _draw_track(selected_track, selected_track_color);
+ }
}
//draw editor handles
{
edit_points.clear();
-
float scale = timeline->get_zoom_scale();
- for (int i = 0; i < animation->track_get_key_count(track); i++) {
- float offset = animation->track_get_key_time(track, i);
- float value = animation->bezier_track_get_key_value(track, i);
- if (moving_selection && selection.has(i)) {
- offset += moving_selection_offset.x;
- value += moving_selection_offset.y;
+ for (int i = 0; i < track_count; ++i) {
+ if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i)) {
+ continue;
}
- Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
-
- Vector2 in_vec = animation->bezier_track_get_key_in_handle(track, i);
- if (moving_handle != 0 && moving_handle_key == i) {
- in_vec = moving_handle_left;
+ if (hidden_tracks.has(i) || locked_tracks.has(i)) {
+ continue;
}
- Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
- Vector2 out_vec = animation->bezier_track_get_key_out_handle(track, i);
+ int key_count = animation->track_get_key_count(i);
+ String path = animation->track_get_path(i);
- if (moving_handle != 0 && moving_handle_key == i) {
- out_vec = moving_handle_right;
+ if (is_filtered) {
+ if (root && root->has_node(path)) {
+ Node *node = root->get_node(path);
+ if (!node) {
+ continue; // No node, no filter.
+ }
+ if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ continue; // Skip track due to not selected.
+ }
+ }
}
- Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
+ for (int j = 0; j < key_count; ++j) {
+ float offset = animation->track_get_key_time(i, j);
+ float value = animation->bezier_track_get_key_value(i, j);
+
+ if (moving_selection && selection.has(IntPair(i, j))) {
+ offset += moving_selection_offset.x;
+ value += moving_selection_offset.y;
+ }
- _draw_line_clipped(pos, pos_in, accent, limit, right_limit);
- _draw_line_clipped(pos, pos_out, accent, limit, right_limit);
+ Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
- EditPoint ep;
- if (pos.x >= limit && pos.x <= right_limit) {
- ep.point_rect.position = (pos - bezier_icon->get_size() / 2).floor();
- ep.point_rect.size = bezier_icon->get_size();
- if (selection.has(i)) {
- draw_texture(selected_icon, ep.point_rect.position);
- draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
- draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
- } else {
- draw_texture(bezier_icon, ep.point_rect.position);
+ Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
+ if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+ in_vec = moving_handle_left;
+ }
+ Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
+
+ Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
+
+ if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+ out_vec = moving_handle_right;
+ }
+
+ Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
+
+ if (i == selected_track || selection.has(IntPair(i, j))) {
+ _draw_line_clipped(pos, pos_in, accent, limit, right_limit);
+ _draw_line_clipped(pos, pos_out, accent, limit, right_limit);
+ }
+
+ EditPoint ep;
+ ep.track = i;
+ ep.key = j;
+ if (pos.x >= limit && pos.x <= right_limit) {
+ ep.point_rect.position = (pos - bezier_icon->get_size() / 2).floor();
+ ep.point_rect.size = bezier_icon->get_size();
+ if (selection.has(IntPair(i, j))) {
+ draw_texture(selected_icon, ep.point_rect.position);
+ draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
+ draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
+ } else {
+ Color track_color = Color(1, 1, 1, 1);
+ if (i != selected_track) {
+ track_color = subtrack_colors[i];
+ }
+ draw_texture(bezier_icon, ep.point_rect.position, track_color);
+ }
+ ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
+ }
+ if (i == selected_track || selection.has(IntPair(i, j))) {
+ if (pos_in.x >= limit && pos_in.x <= right_limit) {
+ ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2).floor();
+ ep.in_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.in_rect.position);
+ ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
+ }
+ if (pos_out.x >= limit && pos_out.x <= right_limit) {
+ ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2).floor();
+ ep.out_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.out_rect.position);
+ ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ }
+ }
+ if (!locked_tracks.has(i)) {
+ edit_points.push_back(ep);
}
- ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
- }
- if (pos_in.x >= limit && pos_in.x <= right_limit) {
- ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2).floor();
- ep.in_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.in_rect.position);
- ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
}
- if (pos_out.x >= limit && pos_out.x <= right_limit) {
- ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2).floor();
- ep.out_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.out_rect.position);
- ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ }
+
+ for (int i = 0; i < edit_points.size(); ++i) {
+ if (edit_points[i].track == selected_track) {
+ EditPoint ep = edit_points[i];
+ edit_points.remove_at(i);
+ edit_points.insert(0, ep);
}
- edit_points.push_back(ep);
}
}
@@ -506,15 +638,7 @@ Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
animation = p_animation;
- track = p_track;
- if (is_connected("select_key", Callable(editor, "_key_selected"))) {
- disconnect("select_key", Callable(editor, "_key_selected"));
- }
- if (is_connected("deselect_key", Callable(editor, "_key_deselected"))) {
- disconnect("deselect_key", Callable(editor, "_key_deselected"));
- }
- connect("select_key", Callable(editor, "_key_selected"), varray(p_track), CONNECT_DEFERRED);
- connect("deselect_key", Callable(editor, "_key_deselected"), varray(p_track), CONNECT_DEFERRED);
+ selected_track = p_track;
update();
}
@@ -529,11 +653,14 @@ void AnimationBezierTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
timeline = p_timeline;
timeline->connect("zoom_changed", callable_mp(this, &AnimationBezierTrackEdit::_zoom_changed));
+ timeline->connect("name_limit_changed", callable_mp(this, &AnimationBezierTrackEdit::_zoom_changed));
}
void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
editor = p_editor;
connect("clear_selection", Callable(editor, "_clear_selection"), varray(false));
+ connect("select_key", Callable(editor, "_key_selected"), varray(), CONNECT_DEFERRED);
+ connect("deselect_key", Callable(editor, "_key_deselected"), varray(), CONNECT_DEFERRED);
}
void AnimationBezierTrackEdit::_play_position_draw() {
@@ -544,9 +671,11 @@ void AnimationBezierTrackEdit::_play_position_draw() {
float scale = timeline->get_zoom_scale();
int h = get_size().height;
- int px = (-timeline->get_value() + play_position_pos) * scale + timeline->get_name_limit();
+ int limit = timeline->get_name_limit();
+
+ int px = (-timeline->get_value() + play_position_pos) * scale + limit;
- if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
+ if (px >= limit && px < (get_size().width)) {
Color color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
}
@@ -565,11 +694,84 @@ void AnimationBezierTrackEdit::set_root(Node *p_root) {
root = p_root;
}
+void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
+ is_filtered = p_filtered;
+ if (animation == nullptr) {
+ return;
+ }
+ String base_path = animation->track_get_path(selected_track);
+ if (is_filtered) {
+ if (root && root->has_node(base_path)) {
+ Node *node = root->get_node(base_path);
+ if (!node || !EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ for (int i = 0; i < animation->get_track_count(); ++i) {
+ if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
+ continue;
+ }
+
+ base_path = animation->track_get_path(i);
+ if (root && root->has_node(base_path)) {
+ node = root->get_node(base_path);
+ if (!node) {
+ continue; // No node, no filter.
+ }
+ if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ continue; // Skip track due to not selected.
+ }
+
+ set_animation_and_track(animation, i);
+ break;
+ }
+ }
+ }
+ }
+ }
+ update();
+}
+
void AnimationBezierTrackEdit::_zoom_changed() {
update();
play_position->update();
}
+void AnimationBezierTrackEdit::_update_locked_tracks_after(int p_track) {
+ if (locked_tracks.has(p_track)) {
+ locked_tracks.erase(p_track);
+ }
+
+ Vector<int> updated_locked_tracks;
+ for (Set<int>::Element *E = locked_tracks.front(); E; E = E->next()) {
+ updated_locked_tracks.push_back(E->get());
+ }
+ locked_tracks.clear();
+ for (int i = 0; i < updated_locked_tracks.size(); ++i) {
+ if (updated_locked_tracks[i] > p_track) {
+ locked_tracks.insert(updated_locked_tracks[i] - 1);
+ } else {
+ locked_tracks.insert(updated_locked_tracks[i]);
+ }
+ }
+}
+
+void AnimationBezierTrackEdit::_update_hidden_tracks_after(int p_track) {
+ if (hidden_tracks.has(p_track)) {
+ hidden_tracks.erase(p_track);
+ }
+
+ Vector<int> updated_hidden_tracks;
+ for (Set<int>::Element *E = hidden_tracks.front(); E; E = E->next()) {
+ updated_hidden_tracks.push_back(E->get());
+ }
+ hidden_tracks.clear();
+ for (int i = 0; i < updated_hidden_tracks.size(); ++i) {
+ if (updated_hidden_tracks[i] > p_track) {
+ hidden_tracks.insert(updated_hidden_tracks[i] - 1);
+ } else {
+ hidden_tracks.insert(updated_hidden_tracks[i]);
+ }
+ }
+}
+
String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const {
return Control::get_tooltip(p_pos);
}
@@ -583,10 +785,10 @@ void AnimationBezierTrackEdit::_clear_selection() {
void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) {
undo_redo->create_action(TTR("Update Selected Key Handles"));
double ratio = timeline->get_zoom_scale() * v_zoom;
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- const int key_index = E->get();
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, animation->bezier_track_get_key_handle_mode(track, key_index), ratio);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key_index, p_mode, ratio);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ const IntPair track_key_pair = E->get();
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), ratio);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, p_mode, ratio);
}
undo_redo->commit_action();
}
@@ -606,8 +808,8 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
int idx = animation->track_find_key(p_track, p_pos, true);
ERR_FAIL_COND(idx < 0);
- selection.insert(idx);
- emit_signal(SNAME("select_key"), idx, true);
+ selection.insert(IntPair(p_track, idx));
+ emit_signal(SNAME("select_key"), p_track, idx, true);
update();
}
@@ -631,14 +833,100 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
+ Ref<InputEventKey> key_press = p_event;
+
+ if (key_press.is_valid() && key_press->is_pressed()) {
+ if (ED_GET_SHORTCUT("animation_bezier_editor/focus")->matches_event(p_event)) {
+ SelectionSet focused_keys;
+ if (selection.is_empty()) {
+ for (int i = 0; i < edit_points.size(); ++i) {
+ IntPair key_pair = IntPair(edit_points[i].track, edit_points[i].key);
+ focused_keys.insert(key_pair);
+ }
+ } else {
+ for (SelectionSet::Element *E = selection.front(); E; E = E->next()) {
+ focused_keys.insert(E->get());
+ if (E->get().second > 0) {
+ IntPair previous_key = IntPair(E->get().first, E->get().second - 1);
+ focused_keys.insert(previous_key);
+ }
+ if (E->get().second < animation->track_get_key_count(E->get().first) - 1) {
+ IntPair next_key = IntPair(E->get().first, E->get().second + 1);
+ focused_keys.insert(next_key);
+ }
+ }
+ }
+ if (focused_keys.is_empty()) {
+ accept_event();
+ return;
+ }
+
+ float minimum_time = INFINITY;
+ float maximum_time = -INFINITY;
+ float minimum_value = INFINITY;
+ float maximum_value = -INFINITY;
+
+ for (SelectionSet::Element *E = focused_keys.front(); E; E = E->next()) {
+ IntPair key_pair = E->get();
+
+ float time = animation->track_get_key_time(key_pair.first, key_pair.second);
+ float value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
+
+ minimum_time = MIN(time, minimum_time);
+ maximum_time = MAX(time, maximum_time);
+ minimum_value = MIN(value, minimum_value);
+ maximum_value = MAX(value, maximum_value);
+ }
+
+ float width = get_size().width - timeline->get_name_limit() - timeline->get_buttons_width();
+ float padding = width * 0.1;
+ float desired_scale = (width - padding / 2) / (maximum_time - minimum_time);
+ minimum_time = MAX(0, minimum_time - (padding / 2) / desired_scale);
+
+ float zv = Math::pow(100 / desired_scale, 0.125f);
+ if (zv < 1) {
+ zv = Math::pow(desired_scale / 100, 0.125f) - 1;
+ zv = 1 - zv;
+ }
+ float zoom_value = timeline->get_zoom()->get_max() - zv;
+
+ timeline->get_zoom()->set_value(zoom_value);
+ timeline->call_deferred("set_value", minimum_time);
+
+ v_scroll = (maximum_value + minimum_value) / 2.0;
+ v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
+
+ update();
+ accept_event();
+ return;
+ } else if (ED_GET_SHORTCUT("animation_bezier_editor/select_all_keys")->matches_event(p_event)) {
+ for (int i = 0; i < edit_points.size(); ++i) {
+ selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
+ }
+
+ update();
+ accept_event();
+ return;
+ } else if (ED_GET_SHORTCUT("animation_bezier_editor/deselect_all_keys")->matches_event(p_event)) {
+ selection.clear();
+
+ update();
+ accept_event();
+ return;
+ }
+ }
+
Ref<InputEventMouseButton> mb = p_event;
+ int limit = timeline->get_name_limit();
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position();
- if (menu_insert_key.x >= timeline->get_name_limit() && menu_insert_key.x <= get_size().width - timeline->get_buttons_width()) {
+ if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) {
Vector2 popup_pos = get_screen_position() + mb->get_position();
menu->clear();
- menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
+ if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
+ menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
+ }
if (selection.size()) {
menu->add_separator();
menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
@@ -649,50 +937,163 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
}
- menu->set_as_minsize();
- menu->set_position(popup_pos);
- menu->popup();
+ if (menu->get_item_count()) {
+ menu->set_as_minsize();
+ menu->set_position(popup_pos);
+ menu->popup();
+ }
}
}
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
for (const KeyValue<int, Rect2> &E : subtracks) {
if (E.value.has_point(mb->get_position())) {
- set_animation_and_track(animation, E.key);
- _clear_selection();
+ if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) {
+ set_animation_and_track(animation, E.key);
+ _clear_selection();
+ }
return;
}
}
+ for (const KeyValue<int, Map<int, Rect2>> &E : subtrack_icons) {
+ int track = E.key;
+ Map<int, Rect2> track_icons = E.value;
+ for (const KeyValue<int, Rect2> &I : track_icons) {
+ if (I.value.has_point(mb->get_position())) {
+ if (I.key == REMOVE_ICON) {
+ undo_redo->create_action("Remove Bezier Track");
+
+ undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
+ undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
+
+ undo_redo->add_do_method(animation.ptr(), "remove_track", track);
+
+ undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
+
+ for (int i = 0; i < animation->track_get_key_count(track); ++i) {
+ undo_redo->add_undo_method(
+ animation.ptr(),
+ "bezier_track_insert_key",
+ track, animation->track_get_key_time(track, i),
+ animation->bezier_track_get_key_value(track, i),
+ animation->bezier_track_get_key_in_handle(track, i),
+ animation->bezier_track_get_key_out_handle(track, i),
+ animation->bezier_track_get_key_handle_mode(track, i));
+ }
+
+ undo_redo->commit_action();
+
+ selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
+ return;
+ } else if (I.key == LOCK_ICON) {
+ if (locked_tracks.has(track)) {
+ locked_tracks.erase(track);
+ } else {
+ locked_tracks.insert(track);
+ if (selected_track == track) {
+ for (int i = 0; i < animation->get_track_count(); ++i) {
+ if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ set_animation_and_track(animation, i);
+ break;
+ }
+ }
+ }
+ }
+ update();
+ return;
+ } else if (I.key == VISIBILITY_ICON) {
+ if (hidden_tracks.has(track)) {
+ hidden_tracks.erase(track);
+ } else {
+ hidden_tracks.insert(track);
+ if (selected_track == track) {
+ for (int i = 0; i < animation->get_track_count(); ++i) {
+ if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ set_animation_and_track(animation, i);
+ break;
+ }
+ }
+ }
+ }
+
+ Vector<int> visible_tracks;
+ for (int i = 0; i < animation->get_track_count(); ++i) {
+ if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ visible_tracks.push_back(i);
+ }
+ }
+
+ if (visible_tracks.size() == 1) {
+ solo_track = visible_tracks[0];
+ } else {
+ solo_track = -1;
+ }
+
+ update();
+ return;
+ } else if (I.key == SOLO_ICON) {
+ if (solo_track == track) {
+ solo_track = -1;
+
+ hidden_tracks.clear();
+ } else {
+ if (hidden_tracks.has(track)) {
+ hidden_tracks.erase(track);
+ }
+ for (int i = 0; i < animation->get_track_count(); ++i) {
+ if (animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ if (i != track && !hidden_tracks.has(i)) {
+ hidden_tracks.insert(i);
+ }
+ }
+ }
+
+ set_animation_and_track(animation, track);
+ solo_track = track;
+ }
+ update();
+ return;
+ }
+ return;
+ }
+ }
+ }
+
for (int i = 0; i < edit_points.size(); i++) {
//first check point
//command makes it ignore the main point, so control point editors can be force-edited
//path 2D editing in the 3D and 2D editors works the same way
if (!mb->is_command_pressed()) {
if (edit_points[i].point_rect.has_point(mb->get_position())) {
+ IntPair pair = IntPair(edit_points[i].track, edit_points[i].key);
if (mb->is_shift_pressed()) {
//add to selection
- if (selection.has(i)) {
- selection.erase(i);
+ if (selection.has(pair)) {
+ selection.erase(pair);
} else {
- selection.insert(i);
+ selection.insert(pair);
}
update();
- select_single_attempt = -1;
- } else if (selection.has(i)) {
+ select_single_attempt = IntPair(-1, -1);
+ } else if (selection.has(pair)) {
moving_selection_attempt = true;
moving_selection = false;
- moving_selection_from_key = i;
+ moving_selection_from_key = pair.second;
+ moving_selection_from_track = pair.first;
moving_selection_offset = Vector2();
- select_single_attempt = i;
+ select_single_attempt = pair;
update();
} else {
moving_selection_attempt = true;
moving_selection = true;
- moving_selection_from_key = i;
+ moving_selection_from_key = pair.second;
+ moving_selection_from_track = pair.first;
moving_selection_offset = Vector2();
+ set_animation_and_track(animation, pair.first);
selection.clear();
- selection.insert(i);
+ selection.insert(pair);
update();
}
return;
@@ -701,26 +1102,27 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (edit_points[i].in_rect.has_point(mb->get_position())) {
moving_handle = -1;
- moving_handle_key = i;
- moving_handle_left = animation->bezier_track_get_key_in_handle(track, i);
- moving_handle_right = animation->bezier_track_get_key_out_handle(track, i);
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
update();
return;
}
if (edit_points[i].out_rect.has_point(mb->get_position())) {
moving_handle = 1;
- moving_handle_key = i;
- moving_handle_left = animation->bezier_track_get_key_in_handle(track, i);
- moving_handle_right = animation->bezier_track_get_key_out_handle(track, i);
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
update();
return;
- ;
}
}
//insert new point
- if (mb->is_command_pressed() && mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
+ if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_pressed()) {
Array new_point;
new_point.resize(6);
@@ -733,34 +1135,35 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
new_point[4] = 0;
new_point[5] = 0;
- float time = ((mb->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
- while (animation->track_find_key(track, time, true) != -1) {
+ float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ while (animation->track_find_key(selected_track, time, true) != -1) {
time += 0.001;
}
undo_redo->create_action(TTR("Add Bezier Point"));
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
//then attempt to move
- int index = animation->track_find_key(track, time, true);
+ int index = animation->track_find_key(selected_track, time, true);
ERR_FAIL_COND(index == -1);
_clear_selection();
- selection.insert(index);
+ selection.insert(IntPair(selected_track, index));
moving_selection_attempt = true;
moving_selection = false;
moving_selection_from_key = index;
+ moving_selection_from_track = selected_track;
moving_selection_offset = Vector2();
- select_single_attempt = -1;
+ select_single_attempt = IntPair(-1, -1);
update();
return;
}
//box select
- if (mb->get_position().x >= timeline->get_name_limit() && mb->get_position().x < get_size().width - timeline->get_buttons_width()) {
+ if (mb->get_position().x >= limit && mb->get_position().x < get_size().width) {
box_selecting_attempt = true;
box_selecting = false;
box_selecting_add = false;
@@ -786,14 +1189,44 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
Rect2 selection_rect(bs_from, bs_to - bs_from);
+ bool track_set = false;
for (int i = 0; i < edit_points.size(); i++) {
if (edit_points[i].point_rect.intersects(selection_rect)) {
- selection.insert(i);
+ selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
+ if (!track_set) {
+ track_set = true;
+ set_animation_and_track(animation, edit_points[i].track);
+ }
}
}
} else {
_clear_selection(); //clicked and nothing happened, so clear the selection
+
+ //select by clicking on curve
+ int track_count = animation->get_track_count();
+
+ float animation_length = animation->get_length();
+ animation->set_length(real_t(INT_MAX)); //bezier_track_interpolate doesn't find keys if they exist beyond anim length
+
+ float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+
+ for (int i = 0; i < track_count; ++i) {
+ if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i) || locked_tracks.has(i)) {
+ continue;
+ }
+
+ float track_h = animation->bezier_track_interpolate(i, time);
+ float track_height = _bezier_h_to_pixel(track_h);
+
+ if (abs(mb->get_position().y - track_height) < 10) {
+ set_animation_and_track(animation, i);
+ break;
+ }
+ }
+
+ animation->set_length(animation_length);
}
+
box_selecting_attempt = false;
box_selecting = false;
update();
@@ -801,10 +1234,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
undo_redo->create_action(TTR("Move Bezier Points"));
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, animation->bezier_track_get_key_in_handle(track, moving_handle_key));
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, animation->bezier_track_get_key_out_handle(track, moving_handle_key));
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key));
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key));
undo_redo->commit_action();
moving_handle = 0;
@@ -819,60 +1252,60 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
List<AnimMoveRestore> to_restore;
// 1-remove the keys
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, E->get());
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
}
// 2- remove overlapped keys
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float newtime = editor->snap_time(animation->track_get_key_time(track, E->get()) + moving_selection_offset.x);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- int idx = animation->track_find_key(track, newtime, true);
+ int idx = animation->track_find_key(E->get().first, newtime, true);
if (idx == -1) {
continue;
}
- if (selection.has(idx)) {
+ if (selection.has(IntPair(E->get().first, idx))) {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
AnimMoveRestore amr;
- amr.key = animation->track_get_key_value(track, idx);
- amr.track = track;
+ amr.key = animation->track_get_key_value(E->get().first, idx);
+ amr.track = E->get().first;
amr.time = newtime;
to_restore.push_back(amr);
}
// 3-move the keys (re insert them)
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(track, E->get()) + moving_selection_offset.x);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
/*
if (newpos<0)
continue; //no add at the beginning
*/
- Array key = animation->track_get_key_value(track, E->get());
+ Array key = animation->track_get_key_value(E->get().first, E->get().second);
float h = key[0];
h += moving_selection_offset.y;
key[0] = h;
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, newpos, key, 1);
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1);
}
// 4-(undo) remove inserted keys
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(track, E->get()) + moving_selection_offset.x);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
/*
if (newpos<0)
continue; //no remove what no inserted
*/
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
}
// 5-(undo) reinsert keys
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(track, E->get());
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, oldpos, animation->track_get_key_value(track, E->get()), 1);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1);
}
// 6-(undo) reinsert overlapped keys
@@ -885,20 +1318,21 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
// 7-reselect
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(track, E->get());
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
float newpos = editor->snap_time(oldpos + moving_selection_offset.x);
- undo_redo->add_do_method(this, "_select_at_anim", animation, track, newpos);
- undo_redo->add_undo_method(this, "_select_at_anim", animation, track, oldpos);
+ undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
+ undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
}
undo_redo->commit_action();
moving_selection = false;
- } else if (select_single_attempt != -1) {
+ } else if (select_single_attempt != IntPair(-1, -1)) {
selection.clear();
selection.insert(select_single_attempt);
+ set_animation_and_track(animation, select_single_attempt.first);
}
moving_selection_attempt = false;
@@ -909,13 +1343,13 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_selection_attempt && mm.is_valid()) {
if (!moving_selection) {
moving_selection = true;
- select_single_attempt = -1;
+ select_single_attempt = IntPair(-1, -1);
}
float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
- float x = editor->snap_time(((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value());
+ float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value());
- moving_selection_offset = Vector2(x - animation->track_get_key_time(track, moving_selection_from_key), y - animation->bezier_track_get_key_value(track, moving_selection_from_key));
+ moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
update();
}
@@ -938,17 +1372,17 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
- Vector2 key_pos = Vector2(animation->track_get_key_time(track, moving_handle_key), animation->bezier_track_get_key_value(track, moving_handle_key));
+ Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key));
Vector2 moving_handle_value = Vector2(x, y) - key_pos;
- moving_handle_left = animation->bezier_track_get_key_in_handle(track, moving_handle_key);
- moving_handle_right = animation->bezier_track_get_key_out_handle(track, moving_handle_key);
+ moving_handle_left = animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key);
if (moving_handle == -1) {
moving_handle_left = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
+ if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
double ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -961,7 +1395,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} else if (moving_handle == 1) {
moving_handle_right = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
+ if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
double ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -980,12 +1414,12 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Move Bezier Points"));
if (moving_handle == -1) {
double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, animation->bezier_track_get_key_in_handle(track, moving_handle_key), ratio);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
} else if (moving_handle == 1) {
double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, animation->bezier_track_get_key_out_handle(track, moving_handle_key), ratio);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
}
undo_redo->commit_action();
@@ -1028,27 +1462,32 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or
void AnimationBezierTrackEdit::_menu_selected(int p_index) {
switch (p_index) {
case MENU_KEY_INSERT: {
- Array new_point;
- new_point.resize(6);
+ if (animation->get_track_count() > 0) {
+ Array new_point;
+ new_point.resize(6);
- float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;
+ float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;
- new_point[0] = h;
- new_point[1] = -0.25;
- new_point[2] = 0;
- new_point[3] = 0.25;
- new_point[4] = 0;
- new_point[5] = Animation::HANDLE_MODE_BALANCED;
+ new_point[0] = h;
+ new_point[1] = -0.25;
+ new_point[2] = 0;
+ new_point[3] = 0.25;
+ new_point[4] = 0;
+ new_point[5] = Animation::HANDLE_MODE_BALANCED;
- float time = ((menu_insert_key.x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
- while (animation->track_find_key(track, time, true) != -1) {
- time += 0.001;
- }
+ int limit = timeline->get_name_limit();
- undo_redo->create_action(TTR("Add Bezier Point"));
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
- undo_redo->commit_action();
+ float time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+
+ while (animation->track_find_key(selected_track, time, true) != -1) {
+ time += 0.001;
+ }
+
+ undo_redo->create_action(TTR("Add Bezier Point"));
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
+ undo_redo->commit_action();
+ }
} break;
case MENU_KEY_DUPLICATE: {
@@ -1072,8 +1511,8 @@ void AnimationBezierTrackEdit::duplicate_selection() {
}
float top_time = 1e10;
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(track, E->get());
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float t = animation->track_get_key_time(E->get().first, E->get().second);
if (t < top_time) {
top_time = t;
}
@@ -1083,21 +1522,21 @@ void AnimationBezierTrackEdit::duplicate_selection() {
List<Pair<int, float>> new_selection_values;
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(track, E->get());
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ float t = animation->track_get_key_time(E->get().first, E->get().second);
float dst_time = t + (timeline->get_play_position() - top_time);
- int existing_idx = animation->track_find_key(track, dst_time, true);
+ int existing_idx = animation->track_find_key(E->get().first, dst_time, true);
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, dst_time, animation->track_get_key_value(track, E->get()), animation->track_get_key_transition(track, E->get()));
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, dst_time);
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second));
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
Pair<int, float> p;
- p.first = track;
+ p.first = E->get().first;
p.second = dst_time;
new_selection_values.push_back(p);
if (existing_idx != -1) {
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, dst_time, animation->track_get_key_value(track, existing_idx), animation->track_get_key_transition(track, existing_idx));
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, existing_idx), animation->track_get_key_transition(E->get().first, existing_idx));
}
}
@@ -1116,7 +1555,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
continue;
}
- selection.insert(existing_idx);
+ selection.insert(IntPair(track, existing_idx));
}
update();
@@ -1126,9 +1565,9 @@ void AnimationBezierTrackEdit::delete_selection() {
if (selection.size()) {
undo_redo->create_action(TTR("Anim Delete Keys"));
- for (Set<int>::Element *E = selection.back(); E; E = E->prev()) {
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, E->get());
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, animation->track_get_key_time(track, E->get()), animation->track_get_key_value(track, E->get()), 1);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, animation->track_get_key_time(E->get().first, E->get().second), animation->track_get_key_value(E->get().first, E->get().second), 1);
}
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
@@ -1142,12 +1581,14 @@ void AnimationBezierTrackEdit::_bind_methods() {
ClassDB::bind_method("_clear_selection", &AnimationBezierTrackEdit::_clear_selection);
ClassDB::bind_method("_clear_selection_for_anim", &AnimationBezierTrackEdit::_clear_selection_for_anim);
ClassDB::bind_method("_select_at_anim", &AnimationBezierTrackEdit::_select_at_anim);
+ ClassDB::bind_method("_update_hidden_tracks_after", &AnimationBezierTrackEdit::_update_hidden_tracks_after);
+ ClassDB::bind_method("_update_locked_tracks_after", &AnimationBezierTrackEdit::_update_locked_tracks_after);
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag")));
ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "ofs")));
- ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
- ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
+ ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("clear_selection"));
ADD_SIGNAL(MethodInfo("close_request"));
@@ -1170,14 +1611,9 @@ AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
set_clip_contents(true);
- close_button = memnew(Button);
- close_button->connect("pressed", Callable(this, SNAME("emit_signal")), varray(SNAME("close_request")));
- close_button->set_text(TTR("Close"));
-
- right_column = memnew(VBoxContainer);
- right_column->add_child(close_button);
- right_column->add_spacer();
- add_child(right_column);
+ ED_SHORTCUT("animation_bezier_editor/focus", TTR("Focus"), Key::F);
+ ED_SHORTCUT("animation_bezier_editor/select_all_keys", TTR("Select All Keys"), KeyModifierMask::CMD | Key::A);
+ ED_SHORTCUT("animation_bezier_editor/deselect_all_keys", TTR("Deselect All Keys"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::A);
menu = memnew(PopupMenu);
add_child(menu);
diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h
index cf719a0355..fa6fc405f2 100644
--- a/editor/animation_bezier_editor.h
+++ b/editor/animation_bezier_editor.h
@@ -46,9 +46,6 @@ class AnimationBezierTrackEdit : public Control {
MENU_KEY_SET_HANDLE_BALANCED,
};
- VBoxContainer *right_column;
- Button *close_button;
-
AnimationTimelineEdit *timeline = nullptr;
UndoRedo *undo_redo = nullptr;
Node *root = nullptr;
@@ -56,7 +53,7 @@ class AnimationBezierTrackEdit : public Control {
float play_position_pos = 0;
Ref<Animation> animation;
- int track;
+ int selected_track;
Vector<Rect2> view_rects;
@@ -66,6 +63,19 @@ class AnimationBezierTrackEdit : public Control {
Map<int, Rect2> subtracks;
+ enum {
+ REMOVE_ICON,
+ LOCK_ICON,
+ SOLO_ICON,
+ VISIBILITY_ICON
+ };
+
+ Map<int, Map<int, Rect2>> subtrack_icons;
+ Set<int> locked_tracks;
+ Set<int> hidden_tracks;
+ int solo_track = -1;
+ bool is_filtered = false;
+
float v_scroll = 0;
float v_zoom = 1;
@@ -73,6 +83,9 @@ class AnimationBezierTrackEdit : public Control {
void _zoom_changed();
+ void _update_locked_tracks_after(int p_track);
+ void _update_hidden_tracks_after(int p_track);
+
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _menu_selected(int p_index);
@@ -80,10 +93,13 @@ class AnimationBezierTrackEdit : public Control {
Vector2 insert_at_pos;
+ typedef Pair<int, int> IntPair;
+
bool moving_selection_attempt = false;
- int select_single_attempt = -1;
+ IntPair select_single_attempt;
bool moving_selection = false;
int moving_selection_from_key;
+ int moving_selection_from_track;
Vector2 moving_selection_offset;
@@ -95,6 +111,7 @@ class AnimationBezierTrackEdit : public Control {
int moving_handle = 0; //0 no move -1 or +1 out
int moving_handle_key = 0;
+ int moving_handle_track = 0;
Vector2 moving_handle_left;
Vector2 moving_handle_right;
int moving_handle_mode; // value from Animation::HandleMode
@@ -119,11 +136,25 @@ class AnimationBezierTrackEdit : public Control {
Rect2 point_rect;
Rect2 in_rect;
Rect2 out_rect;
+ int track;
+ int key;
};
Vector<EditPoint> edit_points;
- Set<int> selection;
+ struct SelectionCompare {
+ bool operator()(const IntPair &lh, const IntPair &rh) {
+ if (lh.first == rh.first) {
+ return lh.second < rh.second;
+ } else {
+ return lh.first < rh.first;
+ }
+ }
+ };
+
+ typedef Set<IntPair, SelectionCompare> SelectionSet;
+
+ SelectionSet selection;
Ref<ViewPanner> panner;
void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
@@ -151,6 +182,7 @@ public:
void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
+ void set_filtered(bool p_filtered);
void set_play_position(float p_pos);
void update_play_position();
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 2f33619a52..de924e84dc 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -570,7 +570,7 @@ public:
p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
} break;
case Animation::TYPE_ROTATION_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "rotation"));
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation"));
} break;
case Animation::TYPE_SCALE_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
@@ -2118,23 +2118,19 @@ void AnimationTrackEdit::_notification(int p_what) {
update_mode_rect.position.y = 0;
update_mode_rect.size.y = get_size().height;
- ofs += update_icon->get_width() + hsep;
- update_mode_rect.size.x += hsep;
+ ofs += update_icon->get_width() + hsep / 2;
+ update_mode_rect.size.x += hsep / 2;
if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
update_mode_rect.size.x += down_icon->get_width();
- bezier_edit_rect = Rect2();
} else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
update_mode_rect.size.x += down_icon->get_width();
- bezier_edit_rect.position = update_mode_rect.position + (update_mode_rect.size - bezier_icon->get_size()) / 2;
- bezier_edit_rect.size = bezier_icon->get_size();
- draw_texture(bezier_icon, bezier_edit_rect.position);
+
update_mode_rect = Rect2();
} else {
update_mode_rect = Rect2();
- bezier_edit_rect = Rect2();
}
ofs += down_icon->get_width();
@@ -2160,8 +2156,8 @@ void AnimationTrackEdit::_notification(int p_what) {
interp_mode_rect.position.y = 0;
interp_mode_rect.size.y = get_size().height;
- ofs += icon->get_width() + hsep;
- interp_mode_rect.size.x += hsep;
+ ofs += icon->get_width() + hsep / 2;
+ interp_mode_rect.size.x += hsep / 2;
if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
@@ -2193,8 +2189,8 @@ void AnimationTrackEdit::_notification(int p_what) {
loop_wrap_rect.position.y = 0;
loop_wrap_rect.size.y = get_size().height;
- ofs += icon->get_width() + hsep;
- loop_wrap_rect.size.x += hsep;
+ ofs += icon->get_width() + hsep / 2;
+ loop_wrap_rect.size.x += hsep / 2;
if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
@@ -2213,7 +2209,7 @@ void AnimationTrackEdit::_notification(int p_what) {
Ref<Texture2D> icon = get_theme_icon(animation->track_is_compressed(track) ? SNAME("Lock") : SNAME("Remove"), SNAME("EditorIcons"));
- remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width()) / 2;
+ remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width());
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
remove_rect.size = icon->get_size();
@@ -2792,11 +2788,6 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (bezier_edit_rect.has_point(pos)) {
- emit_signal(SNAME("bezier_edit"));
- accept_event();
- }
-
// Check keyframes.
if (!animation->track_is_compressed(track)) { // Selecting compressed keyframes for editing is not possible.
@@ -3326,10 +3317,21 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
snap->set_disabled(false);
snap_mode->set_disabled(false);
+ bezier_edit_icon->set_disabled(true);
+
imported_anim_warning->hide();
+ bool import_warning_done = false;
+ bool bezier_done = false;
for (int i = 0; i < animation->get_track_count(); i++) {
if (animation->track_is_imported(i)) {
imported_anim_warning->show();
+ import_warning_done = true;
+ }
+ if (animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ bezier_edit_icon->set_disabled(false);
+ bezier_done = true;
+ }
+ if (import_warning_done && bezier_done) {
break;
}
}
@@ -3343,6 +3345,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
step->set_read_only(true);
snap->set_disabled(true);
snap_mode->set_disabled(true);
+ bezier_edit_icon->set_disabled(true);
}
}
@@ -4167,13 +4170,15 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
} break;
case Animation::TYPE_BEZIER: {
Array array;
- array.resize(5);
+ array.resize(6);
array[0] = p_id.value;
array[1] = -0.25;
array[2] = 0;
array[3] = 0.25;
array[4] = 0;
+ array[5] = Animation::HANDLE_MODE_BALANCED;
value = array;
+ bezier_edit_icon->set_disabled(false);
} break;
case Animation::TYPE_ANIMATION: {
@@ -4399,7 +4404,6 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->connect("insert_key", callable_mp(this, &AnimationTrackEditor::_insert_key_from_track), varray(i), CONNECT_DEFERRED);
track_edit->connect("select_key", callable_mp(this, &AnimationTrackEditor::_key_selected), varray(i), CONNECT_DEFERRED);
track_edit->connect("deselect_key", callable_mp(this, &AnimationTrackEditor::_key_deselected), varray(i), CONNECT_DEFERRED);
- track_edit->connect("bezier_edit", callable_mp(this, &AnimationTrackEditor::_bezier_edit), varray(i), CONNECT_DEFERRED);
track_edit->connect("move_selection_begin", callable_mp(this, &AnimationTrackEditor::_move_selection_begin));
track_edit->connect("move_selection", callable_mp(this, &AnimationTrackEditor::_move_selection));
track_edit->connect("move_selection_commit", callable_mp(this, &AnimationTrackEditor::_move_selection_commit));
@@ -4515,6 +4519,7 @@ void AnimationTrackEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
zoom_icon->set_texture(get_theme_icon(SNAME("Zoom"), SNAME("EditorIcons")));
+ bezier_edit_icon->set_icon(get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")));
snap->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
selected_filter->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
@@ -4630,6 +4635,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
adding_track_path = path_to;
prop_selector->set_type_filter(filter);
prop_selector->select_property_from_instance(node);
+ bezier_edit_icon->set_disabled(false);
} break;
case Animation::TYPE_AUDIO: {
if (!node->is_class("AudioStreamPlayer") && !node->is_class("AudioStreamPlayer2D") && !node->is_class("AudioStreamPlayer3D")) {
@@ -4946,7 +4952,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
EditorNode::get_singleton()->show_warning(TTR("Method not found in object: ") + p_method);
}
-void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track) {
+void AnimationTrackEditor::_key_selected(int p_track, int p_key, bool p_single) {
ERR_FAIL_INDEX(p_track, animation->get_track_count());
ERR_FAIL_INDEX(p_key, animation->track_get_key_count(p_track));
@@ -5294,6 +5300,20 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
}
}
+void AnimationTrackEditor::_toggle_bezier_edit() {
+ if (bezier_edit->is_visible()) {
+ _cancel_bezier_edit();
+ } else {
+ int track_count = animation->get_track_count();
+ for (int i = 0; i < track_count; ++i) {
+ if (animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
+ _bezier_edit(i);
+ return;
+ }
+ }
+ }
+}
+
void AnimationTrackEditor::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
if (p_alt) {
if (p_scroll_vec.x < 0 || p_scroll_vec.y < 0) {
@@ -5322,6 +5342,7 @@ void AnimationTrackEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin
void AnimationTrackEditor::_cancel_bezier_edit() {
bezier_edit->hide();
scroll->show();
+ bezier_edit_icon->set_pressed(false);
}
void AnimationTrackEditor::_bezier_edit(int p_for_track) {
@@ -5908,6 +5929,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
void AnimationTrackEditor::_view_group_toggle() {
_update_tracks();
view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
+ bezier_edit->set_filtered(selected_filter->is_pressed());
}
bool AnimationTrackEditor::is_grouping_tracks() {
@@ -6153,6 +6175,15 @@ AnimationTrackEditor::AnimationTrackEditor() {
bottom_hb->add_spacer();
+ bezier_edit_icon = memnew(Button);
+ bezier_edit_icon->set_flat(true);
+ bezier_edit_icon->set_disabled(true);
+ bezier_edit_icon->set_toggle_mode(true);
+ bezier_edit_icon->connect("pressed", callable_mp(this, &AnimationTrackEditor::_toggle_bezier_edit));
+ bezier_edit_icon->set_tooltip(TTR("Toggle between the bezier curve editor and track editor."));
+
+ bottom_hb->add_child(bezier_edit_icon);
+
selected_filter = memnew(Button);
selected_filter->set_flat(true);
selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same.
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 50c5c692c0..edba784310 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -164,7 +164,6 @@ class AnimationTrackEdit : public Control {
Rect2 interp_mode_rect;
Rect2 loop_wrap_rect;
Rect2 remove_rect;
- Rect2 bezier_edit_rect;
Ref<Texture2D> type_icon;
Ref<Texture2D> selected_icon;
@@ -300,6 +299,7 @@ class AnimationTrackEditor : public VBoxContainer {
EditorSpinSlider *step;
TextureRect *zoom_icon;
Button *snap;
+ Button *bezier_edit_icon;
OptionButton *snap_mode;
Button *imported_anim_warning;
@@ -406,7 +406,7 @@ class AnimationTrackEditor : public VBoxContainer {
Map<SelectedKey, KeyInfo> selection;
- void _key_selected(int p_key, bool p_single, int p_track);
+ void _key_selected(int p_track, int p_key, bool p_single);
void _key_deselected(int p_key, int p_track);
bool moving_selection;
@@ -431,6 +431,7 @@ class AnimationTrackEditor : public VBoxContainer {
Vector<Ref<AnimationTrackEditPlugin>> track_edit_plugins;
+ void _toggle_bezier_edit();
void _cancel_bezier_edit();
void _bezier_edit(int p_for_track);
diff --git a/editor/debugger/editor_network_profiler.cpp b/editor/debugger/editor_network_profiler.cpp
index 698e950f57..b05134144e 100644
--- a/editor/debugger/editor_network_profiler.cpp
+++ b/editor/debugger/editor_network_profiler.cpp
@@ -56,7 +56,7 @@ void EditorNetworkProfiler::_update_frame() {
TreeItem *root = counters_display->create_item();
- for (const KeyValue<ObjectID, DebuggerMarshalls::MultiplayerNodeInfo> &E : nodes_data) {
+ for (const KeyValue<ObjectID, SceneDebugger::RPCNodeInfo> &E : nodes_data) {
TreeItem *node = counters_display->create_item(root);
for (int j = 0; j < counters_display->get_columns(); ++j) {
@@ -65,9 +65,7 @@ void EditorNetworkProfiler::_update_frame() {
node->set_text(0, E.value.node_path);
node->set_text(1, E.value.incoming_rpc == 0 ? "-" : itos(E.value.incoming_rpc));
- node->set_text(2, E.value.incoming_rset == 0 ? "-" : itos(E.value.incoming_rset));
- node->set_text(3, E.value.outgoing_rpc == 0 ? "-" : itos(E.value.outgoing_rpc));
- node->set_text(4, E.value.outgoing_rset == 0 ? "-" : itos(E.value.outgoing_rset));
+ node->set_text(2, E.value.outgoing_rpc == 0 ? "-" : itos(E.value.outgoing_rpc));
}
}
@@ -91,14 +89,12 @@ void EditorNetworkProfiler::_clear_pressed() {
}
}
-void EditorNetworkProfiler::add_node_frame_data(const DebuggerMarshalls::MultiplayerNodeInfo p_frame) {
+void EditorNetworkProfiler::add_node_frame_data(const SceneDebugger::RPCNodeInfo p_frame) {
if (!nodes_data.has(p_frame.node)) {
nodes_data.insert(p_frame.node, p_frame);
} else {
nodes_data[p_frame.node].incoming_rpc += p_frame.incoming_rpc;
- nodes_data[p_frame.node].incoming_rset += p_frame.incoming_rset;
nodes_data[p_frame.node].outgoing_rpc += p_frame.outgoing_rpc;
- nodes_data[p_frame.node].outgoing_rset += p_frame.outgoing_rset;
}
if (frame_delay->is_stopped()) {
@@ -174,7 +170,7 @@ EditorNetworkProfiler::EditorNetworkProfiler() {
counters_display->set_v_size_flags(SIZE_EXPAND_FILL);
counters_display->set_hide_folding(true);
counters_display->set_hide_root(true);
- counters_display->set_columns(5);
+ counters_display->set_columns(3);
counters_display->set_column_titles_visible(true);
counters_display->set_column_title(0, TTR("Node"));
counters_display->set_column_expand(0, true);
@@ -184,18 +180,10 @@ EditorNetworkProfiler::EditorNetworkProfiler() {
counters_display->set_column_expand(1, false);
counters_display->set_column_clip_content(1, true);
counters_display->set_column_custom_minimum_width(1, 120 * EDSCALE);
- counters_display->set_column_title(2, TTR("Incoming RSET"));
+ counters_display->set_column_title(2, TTR("Outgoing RPC"));
counters_display->set_column_expand(2, false);
counters_display->set_column_clip_content(2, true);
counters_display->set_column_custom_minimum_width(2, 120 * EDSCALE);
- counters_display->set_column_title(3, TTR("Outgoing RPC"));
- counters_display->set_column_expand(3, false);
- counters_display->set_column_clip_content(3, true);
- counters_display->set_column_custom_minimum_width(3, 120 * EDSCALE);
- counters_display->set_column_title(4, TTR("Outgoing RSET"));
- counters_display->set_column_expand(4, false);
- counters_display->set_column_clip_content(4, true);
- counters_display->set_column_custom_minimum_width(4, 120 * EDSCALE);
add_child(counters_display);
frame_delay = memnew(Timer);
diff --git a/editor/debugger/editor_network_profiler.h b/editor/debugger/editor_network_profiler.h
index 320dd2a826..3e95eb0de6 100644
--- a/editor/debugger/editor_network_profiler.h
+++ b/editor/debugger/editor_network_profiler.h
@@ -31,7 +31,7 @@
#ifndef EDITORNETWORKPROFILER_H
#define EDITORNETWORKPROFILER_H
-#include "core/debugger/debugger_marshalls.h"
+#include "scene/debugger/scene_debugger.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
@@ -50,7 +50,7 @@ private:
Timer *frame_delay;
- Map<ObjectID, DebuggerMarshalls::MultiplayerNodeInfo> nodes_data;
+ Map<ObjectID, SceneDebugger::RPCNodeInfo> nodes_data;
void _update_frame();
@@ -62,7 +62,7 @@ protected:
static void _bind_methods();
public:
- void add_node_frame_data(const DebuggerMarshalls::MultiplayerNodeInfo p_frame);
+ void add_node_frame_data(const SceneDebugger::RPCNodeInfo p_frame);
void set_bandwidth(int p_incoming, int p_outgoing);
bool is_profiling();
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 6aedfa6ccb..28e8edb26e 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -36,7 +36,6 @@
#include "core/io/marshalls.h"
#include "core/string/ustring.h"
#include "core/version.h"
-#include "core/version_hash.gen.h"
#include "editor/debugger/debug_adapter/debug_adapter_protocol.h"
#include "editor/debugger/editor_network_profiler.h"
#include "editor/debugger/editor_performance_profiler.h"
@@ -64,6 +63,7 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/tree.h"
#include "scene/resources/packed_scene.h"
+#include "servers/debugger/servers_debugger.h"
#include "servers/display_server.h"
using CameraOverride = EditorDebuggerNode::CameraOverride;
@@ -128,6 +128,7 @@ void ScriptEditorDebugger::debug_continue() {
_clear_execution();
_put_msg("continue", Array());
+ _put_msg("servers:foreground", Array());
}
void ScriptEditorDebugger::update_tabs() {
@@ -278,7 +279,7 @@ void ScriptEditorDebugger::_remote_object_property_updated(ObjectID p_id, const
}
void ScriptEditorDebugger::_video_mem_request() {
- _put_msg("core:memory", Array());
+ _put_msg("servers:memory", Array());
}
void ScriptEditorDebugger::_video_mem_export() {
@@ -344,15 +345,15 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
if (id.is_valid()) {
emit_signal(SNAME("remote_object_updated"), id);
}
- } else if (p_msg == "memory:usage") {
+ } else if (p_msg == "servers:memory_usage") {
vmem_tree->clear();
TreeItem *root = vmem_tree->create_item();
- DebuggerMarshalls::ResourceUsage usage;
+ ServersDebugger::ResourceUsage usage;
usage.deserialize(p_data);
uint64_t total = 0;
- for (const DebuggerMarshalls::ResourceInfo &E : usage.infos) {
+ for (const ServersDebugger::ResourceInfo &E : usage.infos) {
TreeItem *it = vmem_tree->create_item(root);
String type = E.type;
int bytes = E.vram;
@@ -445,7 +446,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
performance_profiler->add_profile_frame(frame_data);
} else if (p_msg == "visual:profile_frame") {
- DebuggerMarshalls::VisualProfilerFrame frame;
+ ServersDebugger::VisualProfilerFrame frame;
frame.deserialize(p_data);
EditorVisualProfiler::Metric metric;
@@ -592,13 +593,13 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else if (p_msg == "servers:function_signature") {
// Cache a profiler signature.
- DebuggerMarshalls::ScriptFunctionSignature sig;
+ ServersDebugger::ScriptFunctionSignature sig;
sig.deserialize(p_data);
profiler_signature[sig.id] = sig.name;
} else if (p_msg == "servers:profile_frame" || p_msg == "servers:profile_total") {
EditorProfiler::Metric metric;
- DebuggerMarshalls::ServersProfilerFrame frame;
+ ServersDebugger::ServersProfilerFrame frame;
frame.deserialize(p_data);
metric.valid = true;
metric.frame_number = frame.frame_number;
@@ -642,7 +643,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
for (int i = 0; i < frame.servers.size(); i++) {
- const DebuggerMarshalls::ServerInfo &srv = frame.servers[i];
+ const ServersDebugger::ServerInfo &srv = frame.servers[i];
EditorProfiler::Metric::Category c;
const String name = srv.name;
c.name = name.capitalize();
@@ -709,14 +710,14 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
profiler->add_frame_metric(metric, true);
}
- } else if (p_msg == "network:profile_frame") {
- DebuggerMarshalls::NetworkProfilerFrame frame;
+ } else if (p_msg == "multiplayer:rpc") {
+ SceneDebugger::RPCProfilerFrame frame;
frame.deserialize(p_data);
for (int i = 0; i < frame.infos.size(); i++) {
network_profiler->add_node_frame_data(frame.infos[i]);
}
- } else if (p_msg == "network:bandwidth") {
+ } else if (p_msg == "multiplayer:bandwidth") {
ERR_FAIL_COND(p_data.size() < 2);
network_profiler->set_bandwidth(p_data[0], p_data[1]);
@@ -833,6 +834,9 @@ void ScriptEditorDebugger::_notification(int p_what) {
msg.push_back(cam->get_far());
_put_msg("scene:override_camera_3D:transform", msg);
}
+ if (breaked) {
+ _put_msg("servers:draw", Array());
+ }
}
const uint64_t until = OS::get_singleton()->get_ticks_msec() + 20;
@@ -971,7 +975,8 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
data.push_back(p_enable);
switch (p_type) {
case PROFILER_NETWORK:
- _put_msg("profiler:network", data);
+ _put_msg("profiler:multiplayer", data);
+ _put_msg("profiler:rpc", data);
break;
case PROFILER_VISUAL:
_put_msg("profiler:visual", data);
@@ -1543,19 +1548,10 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
const int line_number = file_line_number[1].to_int();
// Construct a GitHub repository URL and open it in the user's default web browser.
- if (String(VERSION_HASH).length() >= 1) {
- // Git commit hash information available; use it for greater accuracy, including for development versions.
- OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s/%s#L%d",
- VERSION_HASH,
- file,
- line_number));
- } else {
- // Git commit hash information unavailable; fall back to tagged releases.
- OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s-stable/%s#L%d",
- VERSION_NUMBER,
- file,
- line_number));
- }
+ // If the commit hash is available, use it for greater accuracy. Otherwise fall back to tagged release.
+ String git_ref = String(VERSION_HASH).is_empty() ? String(VERSION_NUMBER) + "-stable" : String(VERSION_HASH);
+ OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s/%s#L%d",
+ git_ref, file, line_number));
} break;
case ACTION_DELETE_BREAKPOINT: {
const TreeItem *selected = breakpoints_tree->get_selected();
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 54377971c6..4309f55a2b 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -29,13 +29,12 @@
/*************************************************************************/
#include "editor_about.h"
-#include "editor_node.h"
#include "core/authors.gen.h"
#include "core/donors.gen.h"
#include "core/license.gen.h"
#include "core/version.h"
-#include "core/version_hash.gen.h"
+#include "editor_node.h"
// The metadata key used to store and retrieve the version text to copy to the clipboard.
static const String META_TEXT_TO_COPY = "text_to_copy";
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 10ce7228e0..4b2f1c5104 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -47,7 +47,6 @@
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "core/version.h"
-#include "core/version_hash.gen.h"
#include "main/main.h"
#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/gui/center_container.h"
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index f79b5027cb..e35af6dd64 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -886,15 +886,13 @@ void Node3DEditorViewport::_update_name() {
view_menu->reset_size();
}
-void Node3DEditorViewport::_compute_edit(const Point2 &p_point, const bool p_auto_center) {
+void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
_edit.original_local = spatial_editor->are_local_coords_enabled();
_edit.click_ray = _get_ray(p_point);
_edit.click_ray_pos = _get_ray_pos(p_point);
_edit.plane = TRANSFORM_VIEW;
- if (p_auto_center) {
- _edit.center = spatial_editor->get_gizmo_transform().origin;
- }
spatial_editor->update_transform_gizmo();
+ _edit.center = spatial_editor->get_gizmo_transform().origin;
Node3D *selected = spatial_editor->get_single_selected_node();
Node3DEditorSelectedItem *se = selected ? editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(selected) : nullptr;
@@ -1366,7 +1364,6 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
- _edit.center = spatial_editor->get_gizmo_target_center();
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -1471,6 +1468,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
} break;
case MouseButton::LEFT: {
if (b->is_pressed()) {
+ clicked_wants_append = b->is_shift_pressed();
+
if (_edit.mode != TRANSFORM_NONE && _edit.instant) {
commit_transform();
break; // just commit the edit, stop processing the event so we don't deselect the object
@@ -1600,8 +1599,6 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
//clicking is always deferred to either move or release
- clicked_wants_append = b->is_shift_pressed();
-
if (clicked.is_null()) {
//default to regionselect
cursor.region_select = true;
@@ -1730,6 +1727,12 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_edit.mode = TRANSFORM_TRANSLATE;
}
+ // enable region-select if nothing has been selected yet or multi-select (shift key) is active
+ if (movement_threshold_passed && (get_selected_count() == 0 || clicked_wants_append)) {
+ cursor.region_select = true;
+ cursor.region_begin = _edit.original_mouse_pos;
+ }
+
if (cursor.region_select) {
cursor.region_end = m->get_position();
surface->update();
@@ -3367,7 +3370,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
Transform3D xform = spatial_editor->get_gizmo_transform();
- const Transform3D camera_xform = camera->get_transform();
+ Transform3D camera_xform = camera->get_transform();
if (xform.origin.is_equal_approx(camera_xform.origin)) {
for (int i = 0; i < 3; i++) {
@@ -3386,63 +3389,11 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
const Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
const Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
const Plane p = Plane(camz, camera_xform.origin);
- const real_t gizmo_d = CLAMP(Math::abs(p.distance_to(xform.origin)), camera->get_near() * 2, camera->get_far() / 2);
+ const real_t gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
const real_t d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
const real_t d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
const real_t dd = MAX(Math::abs(d0 - d1), CMP_EPSILON);
- // This code ensures the gizmo stays on the screen. This includes if
- // the gizmo would otherwise be behind the camera, to the sides of
- // the camera, too close to the edge of the screen, too close to
- // the camera, or too far away from the camera. First we calculate
- // where the gizmo would go on screen, then we put it there.
- const Vector3 object_position = spatial_editor->get_gizmo_target_center();
- Vector2 gizmo_screen_position = camera->unproject_position(object_position);
- const Vector2 viewport_size = viewport->get_size();
- // We would use "camera.is_position_behind(parent_translation)" instead of dot,
- // except that it also accounts for the near clip plane, which we don't want.
- const bool is_in_front = camera_xform.basis.get_column(2).dot(object_position - camera_xform.origin) < 0;
- const bool is_in_viewport = is_in_front && Rect2(Vector2(0, 0), viewport_size).has_point(gizmo_screen_position);
- if (spatial_editor->is_keep_gizmo_onscreen_enabled()) {
- if (!spatial_editor->is_gizmo_visible() || is_in_viewport) {
- // In this case, the gizmo is either not visible, or in the viewport
- // already, so we should hide the offscreen line.
- gizmo_offscreen_line->hide();
- } else {
- // In this case, the point is not "normally" on screen, and
- // it should be placed in the center.
- const Vector2 half_viewport_size = viewport_size / 2;
- gizmo_screen_position = half_viewport_size;
- // The rest of this is for drawing the offscreen line.
- // One point goes in the center of the viewport.
- // Calculate where to put the other point of the line.
- Vector2 unprojected_position = camera->unproject_position(object_position);
- if (!is_in_front) {
- // When the object is behind, we need to flip and grow the line.
- unprojected_position -= half_viewport_size;
- unprojected_position = unprojected_position.normalized() * -half_viewport_size.length_squared();
- unprojected_position += half_viewport_size;
- }
- gizmo_offscreen_line->point1 = half_viewport_size;
- gizmo_offscreen_line->point2 = unprojected_position;
- gizmo_offscreen_line->update();
- gizmo_offscreen_line->show();
- }
- // Update the gizmo's position using what we calculated.
- xform.origin = camera->project_position(gizmo_screen_position, gizmo_d);
- } else {
- // In this case, the user does not want the gizmo to be
- // kept on screen, so we should hide the offscreen line,
- // and just use the gizmo's unmodified position.
- gizmo_offscreen_line->hide();
- if (is_in_viewport) {
- xform.origin = camera->project_position(gizmo_screen_position, gizmo_d);
- } else {
- xform.origin = object_position;
- }
- }
- spatial_editor->set_gizmo_transform(xform);
-
const real_t gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
// At low viewport heights, multiply the gizmo scale based on the viewport height.
// This prevents the gizmo from growing very large and going outside the viewport.
@@ -3451,6 +3402,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
(gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) *
MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height /
subviewport_container->get_stretch_shrink();
+ Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
// if the determinant is zero, we should disable the gizmo from being rendered
// this prevents supplying bad values to the renderer and then having to filter it out again
@@ -3472,7 +3424,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
if (xform.basis.get_axis(i).normalized().dot(xform.basis.get_axis((i + 1) % 3).normalized()) < 1.0) {
axis_angle = axis_angle.looking_at(xform.basis.get_axis(i).normalized(), xform.basis.get_axis((i + 1) % 3).normalized());
}
- axis_angle.basis *= gizmo_scale;
+ axis_angle.basis.scale(scale);
axis_angle.origin = xform.origin;
RenderingServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], axis_angle);
RenderingServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE));
@@ -3495,7 +3447,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
// Rotation white outline
xform.orthonormalize();
- xform.basis *= gizmo_scale;
+ xform.basis.scale(scale);
RenderingServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
RenderingServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[3], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE));
}
@@ -4077,7 +4029,7 @@ void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_
void Node3DEditorViewport::begin_transform(TransformMode p_mode, bool instant) {
if (get_selected_count() > 0) {
_edit.mode = p_mode;
- _compute_edit(_edit.mouse_pos, false);
+ _compute_edit(_edit.mouse_pos);
_edit.instant = instant;
_edit.snap = spatial_editor->is_snap_enabled();
}
@@ -4480,14 +4432,15 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
zoom_indicator_delay = 0.0;
spatial_editor = p_spatial_editor;
- subviewport_container = memnew(SubViewportContainer);
- subviewport_container->set_stretch(true);
- add_child(subviewport_container);
- subviewport_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ SubViewportContainer *c = memnew(SubViewportContainer);
+ subviewport_container = c;
+ c->set_stretch(true);
+ add_child(c);
+ c->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
viewport = memnew(SubViewport);
viewport->set_disable_input(true);
- subviewport_container->add_child(viewport);
+ c->add_child(viewport);
surface = memnew(Control);
surface->set_drag_forwarding(this);
add_child(surface);
@@ -4500,9 +4453,6 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
camera->make_current();
surface->set_focus_mode(FOCUS_ALL);
- gizmo_offscreen_line = memnew(GizmoOffScreenLine);
- subviewport_container->add_child(gizmo_offscreen_line);
-
VBoxContainer *vbox = memnew(VBoxContainer);
surface->add_child(vbox);
vbox->set_offset(SIDE_LEFT, 10 * EDSCALE);
@@ -5127,7 +5077,6 @@ void Node3DEditor::update_transform_gizmo() {
gizmo.visible = count > 0;
gizmo.transform.origin = (count > 0) ? gizmo_center / count : Vector3();
gizmo.transform.basis = (count == 1) ? gizmo_basis : Basis();
- gizmo.target_center = gizmo_center / count;
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i]->update_transform_gizmo_view();
@@ -5280,7 +5229,6 @@ Dictionary Node3DEditor::get_state() const {
d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
- d["keep_gizmo_onscreen"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_KEEP_GIZMO_ONSCREEN));
d["fov"] = get_fov();
d["znear"] = get_znear();
d["zfar"] = get_zfar();
@@ -5405,13 +5353,6 @@ void Node3DEditor::set_state(const Dictionary &p_state) {
RenderingServer::get_singleton()->instance_set_visible(origin_instance, use);
}
}
- if (d.has("keep_gizmo_onscreen")) {
- bool use = d["keep_gizmo_onscreen"];
-
- if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_KEEP_GIZMO_ONSCREEN))) {
- _menu_item_pressed(MENU_KEEP_GIZMO_ONSCREEN);
- }
- }
if (d.has("gizmos_status")) {
Dictionary gizmos_status = d["gizmos_status"];
@@ -5765,13 +5706,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
_init_grid();
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
- } break;
- case MENU_KEEP_GIZMO_ONSCREEN: {
- keep_gizmo_onscreen = !view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
- for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
- get_editor_viewport(i)->update_transform_gizmo_view();
- }
- view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), keep_gizmo_onscreen);
+
} break;
case MENU_VIEW_CAMERA_SETTINGS: {
settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
@@ -7756,14 +7691,12 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), Key::NUMBERSIGN), MENU_VIEW_GRID);
- p->add_check_shortcut(ED_SHORTCUT("spatial_editor/keep_gizmo_onscreen", TTR("Keep Gizmo On Screen"), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::G), MENU_KEEP_GIZMO_ONSCREEN);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
- p->set_item_checked(p->get_item_index(MENU_KEEP_GIZMO_ONSCREEN), true);
p->connect("id_pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed));
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index f14f8b90b9..bbe5615570 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -87,19 +87,6 @@ public:
void set_viewport(Node3DEditorViewport *p_viewport);
};
-class GizmoOffScreenLine : public Control {
- GDCLASS(GizmoOffScreenLine, Control);
-
-public:
- Vector2 point1;
- Vector2 point2;
- void _notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW && is_visible()) {
- draw_line(point1, point2, Color(0.0f, 0.75f, 0.75f), 2);
- }
- }
-};
-
class Node3DEditorViewport : public Control {
GDCLASS(Node3DEditorViewport, Control);
friend class Node3DEditor;
@@ -214,7 +201,6 @@ private:
CheckBox *preview_camera;
SubViewportContainer *subviewport_container;
- GizmoOffScreenLine *gizmo_offscreen_line;
MenuButton *view_menu;
PopupMenu *display_submenu;
@@ -251,7 +237,7 @@ private:
};
void _update_name();
- void _compute_edit(const Point2 &p_point, const bool p_auto_center = true);
+ void _compute_edit(const Point2 &p_point);
void _clear_selected();
void _select_clicked(bool p_allow_locked);
ObjectID _select_ray(const Point2 &p_pos);
@@ -521,35 +507,6 @@ class Node3DEditor : public VBoxContainer {
public:
static const unsigned int VIEWPORTS_COUNT = 4;
- enum MenuOption {
- MENU_GROUP_SELECTED,
- MENU_KEEP_GIZMO_ONSCREEN,
- MENU_LOCK_SELECTED,
- MENU_SNAP_TO_FLOOR,
- MENU_TOOL_LIST_SELECT,
- MENU_TOOL_LOCAL_COORDS,
- MENU_TOOL_MOVE,
- MENU_TOOL_OVERRIDE_CAMERA,
- MENU_TOOL_ROTATE,
- MENU_TOOL_SCALE,
- MENU_TOOL_SELECT,
- MENU_TOOL_USE_SNAP,
- MENU_TRANSFORM_CONFIGURE_SNAP,
- MENU_TRANSFORM_DIALOG,
- MENU_UNGROUP_SELECTED,
- MENU_UNLOCK_SELECTED,
- MENU_VIEW_CAMERA_SETTINGS,
- MENU_VIEW_GIZMOS_3D_ICONS,
- MENU_VIEW_GRID,
- MENU_VIEW_ORIGIN,
- MENU_VIEW_USE_1_VIEWPORT,
- MENU_VIEW_USE_2_VIEWPORTS,
- MENU_VIEW_USE_2_VIEWPORTS_ALT,
- MENU_VIEW_USE_3_VIEWPORTS,
- MENU_VIEW_USE_3_VIEWPORTS_ALT,
- MENU_VIEW_USE_4_VIEWPORTS,
- };
-
enum ToolMode {
TOOL_MODE_SELECT,
TOOL_MODE_MOVE,
@@ -568,6 +525,7 @@ public:
TOOL_OPT_USE_SNAP,
TOOL_OPT_OVERRIDE_CAMERA,
TOOL_OPT_MAX
+
};
private:
@@ -596,7 +554,6 @@ private:
Camera3D::Projection grid_camera_last_update_perspective = Camera3D::PROJECTION_PERSPECTIVE;
Vector3 grid_camera_last_update_position = Vector3();
- bool keep_gizmo_onscreen = true;
Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3];
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
@@ -630,10 +587,37 @@ private:
struct Gizmo {
bool visible = false;
real_t scale = 0;
- Vector3 target_center;
Transform3D transform;
} gizmo;
+ enum MenuOption {
+ MENU_TOOL_SELECT,
+ MENU_TOOL_MOVE,
+ MENU_TOOL_ROTATE,
+ MENU_TOOL_SCALE,
+ MENU_TOOL_LIST_SELECT,
+ MENU_TOOL_LOCAL_COORDS,
+ MENU_TOOL_USE_SNAP,
+ MENU_TOOL_OVERRIDE_CAMERA,
+ MENU_TRANSFORM_CONFIGURE_SNAP,
+ MENU_TRANSFORM_DIALOG,
+ MENU_VIEW_USE_1_VIEWPORT,
+ MENU_VIEW_USE_2_VIEWPORTS,
+ MENU_VIEW_USE_2_VIEWPORTS_ALT,
+ MENU_VIEW_USE_3_VIEWPORTS,
+ MENU_VIEW_USE_3_VIEWPORTS_ALT,
+ MENU_VIEW_USE_4_VIEWPORTS,
+ MENU_VIEW_ORIGIN,
+ MENU_VIEW_GRID,
+ MENU_VIEW_GIZMOS_3D_ICONS,
+ MENU_VIEW_CAMERA_SETTINGS,
+ MENU_LOCK_SELECTED,
+ MENU_UNLOCK_SELECTED,
+ MENU_GROUP_SELECTED,
+ MENU_UNGROUP_SELECTED,
+ MENU_SNAP_TO_FLOOR
+ };
+
Button *tool_button[TOOL_MAX];
Button *tool_option_button[TOOL_OPT_MAX];
@@ -792,10 +776,7 @@ public:
float get_zfar() const { return settings_zfar->get_value(); }
float get_fov() const { return settings_fov->get_value(); }
- Vector3 get_gizmo_target_center() const { return gizmo.target_center; }
Transform3D get_gizmo_transform() const { return gizmo.transform; }
- void set_gizmo_transform(const Transform3D &p_transform) { gizmo.transform = p_transform; }
- bool is_keep_gizmo_onscreen_enabled() const { return keep_gizmo_onscreen; }
bool is_gizmo_visible() const;
ToolMode get_tool_mode() const { return tool_mode; }
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index cfb42c0741..57e47a15fd 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -40,7 +40,6 @@
#include "core/os/os.h"
#include "core/string/translation.h"
#include "core/version.h"
-#include "core/version_hash.gen.h"
#include "editor/editor_vcs_interface.h"
#include "editor_scale.h"
#include "editor_settings.h"
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 0e362b13c6..a4f9563840 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1560,7 +1560,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, Map<Node *, NodePath> *p_
for (int i = 0; i < anim->get_track_count(); i++) {
NodePath track_np = anim->track_get_path(i);
- Node *n = root->get_node(track_np);
+ Node *n = root->get_node_or_null(track_np);
if (!n) {
continue;
}