initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled

This commit is contained in:
2025-09-16 20:46:46 -04:00
commit 9d30169a8d
13378 changed files with 7050105 additions and 0 deletions

6
editor/animation/SCsub Normal file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
env.add_source_files(env.editor_sources, "*.cpp")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,237 @@
/**************************************************************************/
/* animation_bezier_editor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "animation_track_editor.h"
#include "core/templates/hashfuncs.h"
class ViewPanner;
class AnimationBezierTrackEdit : public Control {
GDCLASS(AnimationBezierTrackEdit, Control);
enum {
MENU_KEY_INSERT,
MENU_KEY_DUPLICATE,
MENU_KEY_CUT,
MENU_KEY_COPY,
MENU_KEY_PASTE,
MENU_KEY_DELETE,
MENU_KEY_SET_HANDLE_FREE,
MENU_KEY_SET_HANDLE_LINEAR,
MENU_KEY_SET_HANDLE_BALANCED,
MENU_KEY_SET_HANDLE_MIRRORED,
MENU_KEY_SET_HANDLE_AUTO_BALANCED,
MENU_KEY_SET_HANDLE_AUTO_MIRRORED,
};
AnimationTimelineEdit *timeline = nullptr;
Node *root = nullptr;
Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster
real_t play_position_pos = 0;
Ref<Animation> animation;
bool read_only = false;
int selected_track = 0;
Vector<Rect2> view_rects;
Ref<Texture2D> bezier_icon;
Ref<Texture2D> bezier_handle_icon;
Ref<Texture2D> selected_icon;
RBMap<int, Rect2> subtracks;
enum {
REMOVE_ICON,
LOCK_ICON,
SOLO_ICON,
VISIBILITY_ICON
};
RBMap<int, RBMap<int, Rect2>> subtrack_icons;
HashSet<int> locked_tracks;
HashSet<int> hidden_tracks;
int solo_track = -1;
bool is_filtered = false;
float track_v_scroll = 0;
float track_v_scroll_max = 0;
float timeline_v_scroll = 0;
float timeline_v_zoom = 1;
PopupMenu *menu = nullptr;
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);
void _play_position_draw();
bool _is_track_displayed(int p_track_index);
bool _is_track_curves_displayed(int p_track_index);
Vector2 insert_at_pos;
typedef Pair<int, int> IntPair;
bool moving_selection_attempt = false;
bool moving_inserted_key = false;
Point2 moving_selection_mouse_begin;
IntPair select_single_attempt;
bool moving_selection = false;
int moving_selection_from_key = 0;
int moving_selection_from_track = 0;
Vector2 moving_selection_offset;
bool box_selecting_attempt = false;
bool box_selecting = false;
bool box_selecting_add = false;
Vector2 box_selection_from;
Vector2 box_selection_to;
Rect2 selection_rect;
Rect2 selection_handles_rect;
bool scaling_selection = false;
Vector2i scaling_selection_handles;
Vector2 scaling_selection_scale = Vector2(1, 1);
Vector2 scaling_selection_offset;
Point2 scaling_selection_pivot;
int moving_handle = 0; //0 no move -1 or +1 out, 2 both (drawing only)
int moving_handle_key = 0;
int moving_handle_track = 0;
Vector2 moving_handle_left;
Vector2 moving_handle_right;
int moving_handle_mode = 0; // value from Animation::HandleMode
struct PairHasher {
static _FORCE_INLINE_ uint32_t hash(const Pair<int, int> &p_value) {
int32_t hash = 23;
hash = hash * 31 * hash_one_uint64(p_value.first);
hash = hash * 31 * hash_one_uint64(p_value.second);
return hash;
}
};
HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_lefts;
HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_rights;
void _clear_selection();
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
void _select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos, bool p_single);
bool _try_select_at_ui_pos(const Point2 &p_pos, bool p_aggregate, bool p_deselectable);
void _change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto = false);
Vector2 menu_insert_key;
struct AnimMoveRestore {
int track = 0;
double time = 0;
Variant key;
real_t transition = 0;
};
AnimationTrackEditor *editor = nullptr;
struct EditPoint {
Rect2 point_rect;
Rect2 in_rect;
Rect2 out_rect;
int track = 0;
int key = 0;
};
Vector<EditPoint> edit_points;
struct PairCompare {
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 RBSet<IntPair, PairCompare> SelectionSet;
SelectionSet selection;
Ref<ViewPanner> panner;
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
void _draw_line_clipped(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, int p_clip_left, int p_clip_right);
void _draw_track(int p_track, const Color &p_color);
float _bezier_h_to_pixel(float p_h);
void _zoom_vertically(real_t p_minimum_value, real_t p_maximum_value);
protected:
static void _bind_methods();
void _notification(int p_what);
public:
static float get_bezier_key_value(Array p_bezier_key_array);
virtual String get_tooltip(const Point2 &p_pos) const override;
Ref<Animation> get_animation() const;
void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
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 auto_fit_vertically();
void set_play_position(real_t p_pos);
void update_play_position();
void duplicate_selected_keys(real_t p_ofs, bool p_ofs_valid);
void copy_selected_keys(bool p_cut);
void paste_keys(real_t p_ofs, bool p_ofs_valid);
void delete_selection();
void _bezier_track_insert_key_at_anim(const Ref<Animation> &p_anim, int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode, Animation::HandleSetMode p_handle_set_mode = Animation::HANDLE_SET_MODE_NONE);
AnimationBezierTrackEdit();
};

View File

@@ -0,0 +1,816 @@
/**************************************************************************/
/* animation_blend_space_1d_editor.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "animation_blend_space_1d_editor.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/settings/editor_settings.h"
#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/separator.h"
#include "scene/gui/spin_box.h"
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position";
return path;
}
void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
if (!tree) {
return;
}
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1) {
if (!read_only) {
_erase_selected();
}
accept_event();
}
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
if (!read_only) {
menu->clear(false);
animations_menu->clear();
animations_to_add.clear();
LocalVector<StringName> classes;
ClassDB::get_inheriters_from_class("AnimationRootNode", classes);
classes.sort_custom<StringName::AlphCompare>();
menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);
List<StringName> names;
tree->get_animation_list(&names);
for (const StringName &E : names) {
animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E);
animations_to_add.push_back(E);
}
for (const StringName &E : classes) {
String name = String(E).replace_first("AnimationNode", "");
if (name == "Animation" || name == "StartState" || name == "EndState") {
continue;
}
int idx = menu->get_item_count();
menu->add_item(vformat(TTR("Add %s"), name), idx);
menu->set_item_metadata(idx, E);
}
Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
if (clipb.is_valid()) {
menu->add_separator();
menu->add_item(TTR("Paste"), MENU_PASTE);
}
menu->add_separator();
menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
menu->reset_size();
menu->popup();
add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
add_point_pos += blend_space->get_min_space();
if (snap->is_pressed()) {
add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
}
}
}
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
blend_space_draw->queue_redraw(); // why not
// try to see if a point can be selected
selected_point = -1;
_update_tool_erase();
for (int i = 0; i < points.size(); i++) {
if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) {
selected_point = i;
Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
EditorNode::get_singleton()->push_item(node.ptr(), "", true);
dragging_selected_attempt = true;
drag_from = mb->get_position();
_update_tool_erase();
_update_edited_point_pos();
return;
}
}
}
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
if (!read_only) {
if (dragging_selected) {
// move
float point = blend_space->get_blend_point_position(selected_point);
point += drag_ofs.x;
if (snap->is_pressed()) {
point = Math::snapped(point, blend_space->get_snap());
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->add_do_method(this, "_update_edited_point_pos");
undo_redo->add_undo_method(this, "_update_edited_point_pos");
undo_redo->commit_action();
updating = false;
}
dragging_selected_attempt = false;
dragging_selected = false;
blend_space_draw->queue_redraw();
}
}
// *set* the blend
if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
tree->set(get_blend_position_path(), blend_pos);
blend_space_draw->queue_redraw();
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0));
blend_space_draw->queue_redraw();
_update_edited_point_pos();
}
if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
tree->set(get_blend_position_path(), blend_pos);
blend_space_draw->queue_redraw();
}
}
void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
if (!tree) {
return;
}
Color linecolor = get_theme_color(SceneStringName(font_color), SNAME("Label"));
Color linecolor_soft = linecolor;
linecolor_soft.a *= 0.5;
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
Ref<Texture2D> icon = get_editor_theme_icon(SNAME("KeyValue"));
Ref<Texture2D> icon_selected = get_editor_theme_icon(SNAME("KeySelected"));
Size2 s = blend_space_draw->get_size();
if (blend_space_draw->has_focus()) {
Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
}
blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor, Math::round(EDSCALE));
if (blend_space->get_min_space() < 0) {
float point = 0.0;
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s.width;
float x = point;
blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor, Math::round(EDSCALE));
blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);
blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft, Math::round(EDSCALE));
}
if (snap->is_pressed()) {
linecolor_soft.a = linecolor.a * 0.1;
if (blend_space->get_snap() > 0) {
int prev_idx = -1;
for (int i = 0; i < s.x; i++) {
float v = blend_space->get_min_space() + i * (blend_space->get_max_space() - blend_space->get_min_space()) / s.x;
int idx = int(v / blend_space->get_snap());
if (i > 0 && prev_idx != idx) {
blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft, Math::round(EDSCALE));
}
prev_idx = idx;
}
}
}
points.clear();
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
float point = blend_space->get_blend_point_position(i);
if (!read_only) {
if (dragging_selected && selected_point == i) {
point += drag_ofs.x;
if (snap->is_pressed()) {
point = Math::snapped(point, blend_space->get_snap());
}
}
}
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s.width;
points.push_back(point);
Vector2 gui_point = Vector2(point, s.height / 2.0);
gui_point -= (icon->get_size() / 2.0);
gui_point = gui_point.floor();
if (i == selected_point) {
blend_space_draw->draw_texture(icon_selected, gui_point);
} else {
blend_space_draw->draw_texture(icon, gui_point);
}
}
// blend position
{
Color color;
if (tool_blend->is_pressed()) {
color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
} else {
color = linecolor;
color.a *= 0.5;
}
float point = tree->get(get_blend_position_path());
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s.width;
Vector2 gui_point = Vector2(point, s.height / 2.0);
float mind = 5 * EDSCALE;
float maxd = 15 * EDSCALE;
blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, Math::round(2 * EDSCALE));
blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, Math::round(2 * EDSCALE));
blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, Math::round(2 * EDSCALE));
blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, Math::round(2 * EDSCALE));
}
}
void AnimationNodeBlendSpace1DEditor::_update_space() {
if (updating) {
return;
}
updating = true;
max_value->set_value(blend_space->get_max_space());
min_value->set_value(blend_space->get_min_space());
sync->set_pressed(blend_space->is_using_sync());
interpolation->select(blend_space->get_blend_mode());
label_value->set_text(blend_space->get_value_label());
snap_value->set_value(blend_space->get_snap());
blend_space_draw->queue_redraw();
updating = false;
}
void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
if (updating) {
return;
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Config"));
undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());
undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());
undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
updating = false;
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
if (updating) {
return;
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text());
undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label());
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
updating = false;
}
void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
} else {
EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));
}
}
void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
Ref<AnimationRootNode> node;
if (p_index == MENU_LOAD_FILE) {
open_file->clear_filters();
List<String> filters;
ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
for (const String &E : filters) {
open_file->add_filter("*." + E);
}
open_file->popup_file_dialog();
return;
} else if (p_index == MENU_LOAD_FILE_CONFIRM) {
node = file_loaded;
file_loaded.unref();
} else if (p_index == MENU_PASTE) {
node = EditorSettings::get_singleton()->get_resource_clipboard();
} else {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instantiate(type);
ERR_FAIL_NULL(obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
ERR_FAIL_NULL(an);
node = Ref<AnimationNode>(an);
}
if (node.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
return;
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
updating = false;
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
Ref<AnimationNodeAnimation> anim;
anim.instantiate();
anim->set_animation(animations_to_add[p_index]);
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
updating = false;
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
if (p_tool == 0) {
tool_erase->show();
tool_erase_sep->show();
} else {
tool_erase->hide();
tool_erase_sep->hide();
}
_update_tool_erase();
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
if (updating) {
return;
}
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
float pos = blend_space->get_blend_point_position(selected_point);
if (dragging_selected) {
pos += drag_ofs.x;
if (snap->is_pressed()) {
pos = Math::snapped(pos, blend_space->get_snap());
}
}
updating = true;
edit_value->set_value(pos);
updating = false;
}
}
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
tool_erase->set_disabled(!point_valid || read_only);
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
open_editor->show();
} else {
open_editor->hide();
}
if (!read_only) {
edit_hb->show();
} else {
edit_hb->hide();
}
} else {
edit_hb->hide();
}
}
void AnimationNodeBlendSpace1DEditor::_erase_selected() {
if (selected_point != -1) {
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove BlendSpace1D Point"));
undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action();
updating = false;
blend_space_draw->queue_redraw();
}
}
void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
if (updating) {
return;
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
undo_redo->add_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space");
undo_redo->add_do_method(this, "_update_edited_point_pos");
undo_redo->add_undo_method(this, "_update_edited_point_pos");
undo_redo->commit_action();
updating = false;
blend_space_draw->queue_redraw();
}
void AnimationNodeBlendSpace1DEditor::_open_editor() {
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
ERR_FAIL_COND(an.is_null());
AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
}
}
void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
tool_blend->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));
tool_select->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));
tool_create->set_button_icon(get_editor_theme_icon(SNAME("EditKey")));
tool_erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
snap->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));
open_editor->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
interpolation->clear();
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackContinuous")), TTR("Continuous"), 0);
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackDiscrete")), TTR("Discrete"), 1);
interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackCapture")), TTR("Capture"), 2);
} break;
case NOTIFICATION_PROCESS: {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
if (!tree) {
return;
}
String error;
if (!tree->is_active()) {
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
} else if (tree->is_state_invalid()) {
error = tree->get_invalid_state_reason();
}
if (error != error_label->get_text()) {
error_label->set_text(error);
if (!error.is_empty()) {
error_panel->show();
} else {
error_panel->hide();
}
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
set_process(is_visible_in_tree());
} break;
}
}
void AnimationNodeBlendSpace1DEditor::_bind_methods() {
ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space);
ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase);
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);
}
bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {
Ref<AnimationNodeBlendSpace1D> b1d = p_node;
return b1d.is_valid();
}
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space = p_node;
read_only = false;
if (blend_space.is_valid()) {
read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
_update_space();
}
tool_create->set_disabled(read_only);
edit_value->set_editable(!read_only);
label_value->set_editable(!read_only);
min_value->set_editable(!read_only);
max_value->set_editable(!read_only);
sync->set_disabled(read_only);
interpolation->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
singleton = this;
HBoxContainer *top_hb = memnew(HBoxContainer);
add_child(top_hb);
Ref<ButtonGroup> bg;
bg.instantiate();
tool_blend = memnew(Button);
tool_blend->set_theme_type_variation(SceneStringName(FlatButton));
tool_blend->set_toggle_mode(true);
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
tool_blend->set_pressed(true);
tool_blend->set_tooltip_text(TTR("Set the blending position within the space"));
tool_blend->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(3));
tool_select = memnew(Button);
tool_select->set_theme_type_variation(SceneStringName(FlatButton));
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB."));
tool_select->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0));
tool_create = memnew(Button);
tool_create->set_theme_type_variation(SceneStringName(FlatButton));
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
tool_create->set_tooltip_text(TTR("Create points."));
tool_create->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(1));
tool_erase_sep = memnew(VSeparator);
top_hb->add_child(tool_erase_sep);
tool_erase = memnew(Button);
tool_erase->set_theme_type_variation(SceneStringName(FlatButton));
top_hb->add_child(tool_erase);
tool_erase->set_tooltip_text(TTR("Erase points."));
tool_erase->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));
top_hb->add_child(memnew(VSeparator));
snap = memnew(Button);
snap->set_theme_type_variation(SceneStringName(FlatButton));
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
snap->set_tooltip_text(TTR("Enable snap and show grid."));
snap->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled));
snap_value = memnew(SpinBox);
top_hb->add_child(snap_value);
snap_value->set_min(0.01);
snap_value->set_step(0.01);
snap_value->set_max(1000);
snap_value->set_accessibility_name(TTRC("Grid Step"));
top_hb->add_child(memnew(VSeparator));
top_hb->add_child(memnew(Label(TTR("Sync:"))));
sync = memnew(CheckBox);
top_hb->add_child(sync);
sync->connect(SceneStringName(toggled), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
top_hb->add_child(memnew(VSeparator));
top_hb->add_child(memnew(Label(TTR("Blend:"))));
interpolation = memnew(OptionButton);
top_hb->add_child(interpolation);
interpolation->connect(SceneStringName(item_selected), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
edit_hb = memnew(HBoxContainer);
top_hb->add_child(edit_hb);
edit_hb->add_child(memnew(VSeparator));
edit_hb->add_child(memnew(Label(TTR("Point"))));
edit_value = memnew(SpinBox);
edit_hb->add_child(edit_value);
edit_value->set_min(-1000);
edit_value->set_max(1000);
edit_value->set_step(0.01);
edit_value->set_accessibility_name(TTRC("Blend Value"));
edit_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_pos));
open_editor = memnew(Button);
edit_hb->add_child(open_editor);
open_editor->set_text(TTR("Open Editor"));
open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), CONNECT_DEFERRED);
edit_hb->hide();
open_editor->hide();
VBoxContainer *main_vb = memnew(VBoxContainer);
add_child(main_vb);
main_vb->set_v_size_flags(SIZE_EXPAND_FILL);
panel = memnew(PanelContainer);
panel->set_clip_contents(true);
main_vb->add_child(panel);
panel->set_h_size_flags(SIZE_EXPAND_FILL);
panel->set_v_size_flags(SIZE_EXPAND_FILL);
blend_space_draw = memnew(Control);
blend_space_draw->connect(SceneStringName(gui_input), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input));
blend_space_draw->connect(SceneStringName(draw), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_draw));
blend_space_draw->set_focus_mode(FOCUS_ALL);
panel->add_child(blend_space_draw);
{
HBoxContainer *bottom_hb = memnew(HBoxContainer);
main_vb->add_child(bottom_hb);
bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL);
min_value = memnew(SpinBox);
min_value->set_min(-10000);
min_value->set_max(0);
min_value->set_step(0.01);
min_value->set_accessibility_name(TTRC("Min"));
max_value = memnew(SpinBox);
max_value->set_min(0.01);
max_value->set_max(10000);
max_value->set_step(0.01);
max_value->set_accessibility_name(TTRC("Max"));
label_value = memnew(LineEdit);
label_value->set_expand_to_text_length_enabled(true);
label_value->set_accessibility_name(TTRC("Value"));
// now add
bottom_hb->add_child(min_value);
bottom_hb->add_spacer();
bottom_hb->add_child(label_value);
bottom_hb->add_spacer();
bottom_hb->add_child(max_value);
}
snap_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
min_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
max_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
label_value->connect(SceneStringName(text_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_labels_changed));
error_panel = memnew(PanelContainer);
add_child(error_panel);
error_label = memnew(Label);
error_label->set_focus_mode(FOCUS_ACCESSIBILITY);
error_panel->add_child(error_label);
error_panel->hide();
menu = memnew(PopupMenu);
add_child(menu);
menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type));
animations_menu = memnew(PopupMenu);
animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
menu->add_child(animations_menu);
animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_animation_type));
open_file = memnew(EditorFileDialog);
add_child(open_file);
open_file->set_title(TTR("Open Animation Node"));
open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));
set_custom_minimum_size(Size2(0, 150 * EDSCALE));
}

View File

@@ -0,0 +1,137 @@
/**************************************************************************/
/* animation_blend_space_1d_editor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/animation/animation_tree_editor_plugin.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_blend_space_1d.h"
#include "scene/gui/graph_edit.h"
class Button;
class CheckBox;
class LineEdit;
class OptionButton;
class PanelContainer;
class SpinBox;
class VSeparator;
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
Button *tool_select = nullptr;
Button *tool_create = nullptr;
VSeparator *tool_erase_sep = nullptr;
Button *tool_erase = nullptr;
Button *snap = nullptr;
SpinBox *snap_value = nullptr;
LineEdit *label_value = nullptr;
SpinBox *max_value = nullptr;
SpinBox *min_value = nullptr;
CheckBox *sync = nullptr;
OptionButton *interpolation = nullptr;
HBoxContainer *edit_hb = nullptr;
SpinBox *edit_value = nullptr;
Button *open_editor = nullptr;
int selected_point = -1;
Control *blend_space_draw = nullptr;
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
bool updating = false;
static AnimationNodeBlendSpace1DEditor *singleton;
void _blend_space_gui_input(const Ref<InputEvent> &p_event);
void _blend_space_draw();
void _update_space();
void _config_changed(double);
void _labels_changed(String);
void _snap_toggled();
PopupMenu *menu = nullptr;
PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
float add_point_pos = 0.0f;
Vector<real_t> points;
bool dragging_selected_attempt = false;
bool dragging_selected = false;
Vector2 drag_from;
Vector2 drag_ofs;
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
void _tool_switch(int p_tool);
void _update_edited_point_pos();
void _update_tool_erase();
void _erase_selected();
void _edit_point_pos(double);
void _open_editor();
EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
StringName get_blend_position_path() const;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; }
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
AnimationNodeBlendSpace1DEditor();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,148 @@
/**************************************************************************/
/* animation_blend_space_2d_editor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/animation/animation_tree_editor_plugin.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_blend_space_2d.h"
#include "scene/gui/graph_edit.h"
class Button;
class CheckBox;
class LineEdit;
class OptionButton;
class PanelContainer;
class SpinBox;
class VSeparator;
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_triangle = nullptr;
VSeparator *tool_erase_sep = nullptr;
Button *tool_erase = nullptr;
Button *snap = nullptr;
SpinBox *snap_x = nullptr;
SpinBox *snap_y = nullptr;
CheckBox *sync = nullptr;
OptionButton *interpolation = nullptr;
Button *auto_triangles = nullptr;
LineEdit *label_x = nullptr;
LineEdit *label_y = nullptr;
SpinBox *max_x_value = nullptr;
SpinBox *min_x_value = nullptr;
SpinBox *max_y_value = nullptr;
SpinBox *min_y_value = nullptr;
HBoxContainer *edit_hb = nullptr;
SpinBox *edit_x = nullptr;
SpinBox *edit_y = nullptr;
Button *open_editor = nullptr;
int selected_point;
int selected_triangle;
Control *blend_space_draw = nullptr;
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
bool updating;
static AnimationNodeBlendSpace2DEditor *singleton;
void _blend_space_gui_input(const Ref<InputEvent> &p_event);
void _blend_space_draw();
void _update_space();
void _config_changed(double);
void _labels_changed(String);
void _snap_toggled();
PopupMenu *menu = nullptr;
PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
Vector2 add_point_pos;
Vector<Vector2> points;
bool dragging_selected_attempt;
bool dragging_selected;
Vector2 drag_from;
Vector2 drag_ofs;
Vector<int> making_triangle;
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
void _tool_switch(int p_tool);
void _update_edited_point_pos();
void _update_tool_erase();
void _erase_selected();
void _edit_point_pos(double);
void _open_editor();
void _auto_triangles_toggled();
StringName get_blend_position_path() const;
EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
void _blend_space_changed();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; }
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
AnimationNodeBlendSpace2DEditor();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
/**************************************************************************/
/* animation_blend_tree_editor_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/object/script_language.h"
#include "editor/animation/animation_tree_editor_plugin.h"
#include "editor/inspector/editor_inspector.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/tree.h"
class AcceptDialog;
class CheckBox;
class ProgressBar;
class EditorFileDialog;
class EditorProperty;
class MenuButton;
class PanelContainer;
class EditorInspectorPluginAnimationNodeAnimation;
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
bool read_only = false;
GraphEdit *graph = nullptr;
MenuButton *add_node = nullptr;
Vector2 position_from_popup_menu;
bool use_position_from_popup_menu;
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
AcceptDialog *filter_dialog = nullptr;
Tree *filters = nullptr;
CheckBox *filter_enabled = nullptr;
Button *filter_fill_selection = nullptr;
Button *filter_invert_selection = nullptr;
Button *filter_clear_selection = nullptr;
HashMap<StringName, ProgressBar *> animations;
Vector<EditorProperty *> visible_properties;
String to_node = "";
int to_slot = -1;
String from_node = "";
struct AddOption {
String name;
String type;
Ref<Script> script;
int input_port_count;
AddOption(const String &p_name = String(), const String &p_type = String(), int p_input_port_count = 0) :
name(p_name),
type(p_type),
input_port_count(p_input_port_count) {
}
};
Vector<AddOption> add_options;
void _add_node(int p_idx);
void _update_options_menu(bool p_has_input_ports = false);
static AnimationNodeBlendTreeEditor *singleton;
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Ref<AnimationNode> p_node);
void _node_rename_lineedit_changed(const String &p_text);
void _node_changed(const StringName &p_node_name);
String current_node_rename_text;
bool updating;
void _connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
void _disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
void _scroll_changed(const Vector2 &p_scroll);
void _node_selected(Object *p_node);
void _open_in_editor(const String &p_which);
void _anim_selected(int p_index, const Array &p_options, const String &p_node);
void _delete_node_request(const String &p_which);
void _delete_nodes_request(const TypedArray<StringName> &p_nodes);
bool _update_filters(const Ref<AnimationNode> &anode);
void _inspect_filters(const String &p_which);
void _filter_edited();
void _filter_toggled();
void _filter_fill_selection();
void _filter_invert_selection();
void _filter_clear_selection();
void _filter_fill_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item, bool p_parent_filtered);
void _filter_invert_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item);
void _filter_clear_selection_recursive(EditorUndoRedoManager *p_undo_redo, TreeItem *p_item);
Ref<AnimationNode> _filter_edit;
void _popup(bool p_has_input_ports, const Vector2 &p_node_position);
void _popup_request(const Vector2 &p_position);
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
void _popup_hide();
void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _update_editor_settings();
EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
Ref<EditorInspectorPluginAnimationNodeAnimation> animation_node_inspector_plugin;
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeBlendTreeEditor *get_singleton() { return singleton; }
void add_custom_type(const String &p_name, const Ref<Script> &p_script);
void remove_custom_type(const Ref<Script> &p_script);
virtual Size2 get_minimum_size() const override;
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
void update_graph();
AnimationNodeBlendTreeEditor();
};
// EditorPluginAnimationNodeAnimation
class EditorInspectorPluginAnimationNodeAnimation : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginAnimationNodeAnimation, EditorInspectorPlugin);
public:
virtual bool can_handle(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) override;
};
class AnimationNodeAnimationEditorDialog : public ConfirmationDialog {
GDCLASS(AnimationNodeAnimationEditorDialog, ConfirmationDialog);
friend class AnimationNodeAnimationEditor;
OptionButton *select_start = nullptr;
OptionButton *select_end = nullptr;
public:
AnimationNodeAnimationEditorDialog();
};
class AnimationNodeAnimationEditor : public VBoxContainer {
GDCLASS(AnimationNodeAnimationEditor, VBoxContainer);
Ref<AnimationNodeAnimation> animation_node_animation;
Button *button = nullptr;
AnimationNodeAnimationEditorDialog *dialog = nullptr;
void _open_set_custom_timeline_from_marker_dialog();
void _validate_markers(int p_id);
void _confirm_set_custom_timeline_from_marker_dialog();
public:
AnimationNodeAnimationEditor(Ref<AnimationNodeAnimation> p_animation_node_animation);
protected:
void _notification(int p_what);
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
/**************************************************************************/
/* animation_library_editor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/io/config_file.h"
#include "core/templates/vector.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_mixer.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
class AnimationMixer;
class EditorFileDialog;
class AnimationLibraryEditor : public AcceptDialog {
GDCLASS(AnimationLibraryEditor, AcceptDialog)
enum {
LIB_BUTTON_ADD,
LIB_BUTTON_LOAD,
LIB_BUTTON_PASTE,
LIB_BUTTON_FILE,
LIB_BUTTON_DELETE,
};
enum {
ANIM_BUTTON_COPY,
ANIM_BUTTON_FILE,
ANIM_BUTTON_DELETE,
};
enum FileMenuAction {
FILE_MENU_SAVE_LIBRARY,
FILE_MENU_SAVE_AS_LIBRARY,
FILE_MENU_MAKE_LIBRARY_UNIQUE,
FILE_MENU_EDIT_LIBRARY,
FILE_MENU_SAVE_ANIMATION,
FILE_MENU_SAVE_AS_ANIMATION,
FILE_MENU_MAKE_ANIMATION_UNIQUE,
FILE_MENU_EDIT_ANIMATION,
};
enum FileDialogAction {
FILE_DIALOG_ACTION_OPEN_LIBRARY,
FILE_DIALOG_ACTION_SAVE_LIBRARY,
FILE_DIALOG_ACTION_OPEN_ANIMATION,
FILE_DIALOG_ACTION_SAVE_ANIMATION,
};
FileDialogAction file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION;
StringName file_dialog_animation;
StringName file_dialog_library;
Button *new_library_button = nullptr;
Button *load_library_button = nullptr;
AcceptDialog *error_dialog = nullptr;
bool adding_animation = false;
StringName adding_animation_to_library;
EditorFileDialog *file_dialog = nullptr;
ConfirmationDialog *add_library_dialog = nullptr;
LineEdit *add_library_name = nullptr;
Label *add_library_validate = nullptr;
PopupMenu *file_popup = nullptr;
Tree *tree = nullptr;
AnimationMixer *mixer = nullptr;
void _add_library();
void _add_library_validate(const String &p_name);
void _add_library_confirm();
void _load_library();
void _load_file(const String &p_path);
void _load_files(const PackedStringArray &p_paths);
void _save_mixer_lib_folding(TreeItem *p_item);
Vector<uint64_t> _load_mixer_libs_folding();
void _load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section);
String _get_mixer_signature() const;
void _item_renamed();
void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button);
void _file_popup_selected(int p_id);
bool updating = false;
protected:
void _notification(int p_what);
void _update_editor(Object *p_mixer);
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
static void _bind_methods();
public:
void set_animation_mixer(Object *p_mixer);
void show_dialog();
void update_tree();
AnimationLibraryEditor();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,368 @@
/**************************************************************************/
/* animation_player_editor_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/animation/animation_library_editor.h"
#include "editor/animation/animation_track_editor.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_button.h"
#include "scene/gui/tree.h"
class AnimationPlayerEditorPlugin;
class ImageTexture;
class AnimationPlayerEditor : public VBoxContainer {
GDCLASS(AnimationPlayerEditor, VBoxContainer);
friend AnimationPlayerEditorPlugin;
AnimationPlayerEditorPlugin *plugin = nullptr;
AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree.
AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy.
ObjectID cached_root_node_id;
bool is_dummy = false;
enum {
TOOL_NEW_ANIM,
TOOL_ANIM_LIBRARY,
TOOL_DUPLICATE_ANIM,
TOOL_RENAME_ANIM,
TOOL_EDIT_TRANSITIONS,
TOOL_REMOVE_ANIM,
TOOL_EDIT_RESOURCE
};
enum {
ONION_SKINNING_ENABLE,
ONION_SKINNING_PAST,
ONION_SKINNING_FUTURE,
ONION_SKINNING_1_STEP,
ONION_SKINNING_2_STEPS,
ONION_SKINNING_3_STEPS,
ONION_SKINNING_LAST_STEPS_OPTION = ONION_SKINNING_3_STEPS,
ONION_SKINNING_DIFFERENCES_ONLY,
ONION_SKINNING_FORCE_WHITE_MODULATE,
ONION_SKINNING_INCLUDE_GIZMOS,
};
enum {
ANIM_OPEN,
ANIM_SAVE,
ANIM_SAVE_AS
};
enum {
RESOURCE_LOAD,
RESOURCE_SAVE
};
OptionButton *animation = nullptr;
Button *stop = nullptr;
Button *play = nullptr;
Button *play_from = nullptr;
Button *play_bw = nullptr;
Button *play_bw_from = nullptr;
Button *autoplay = nullptr;
MenuButton *tool_anim = nullptr;
Button *onion_toggle = nullptr;
MenuButton *onion_skinning = nullptr;
Button *pin = nullptr;
SpinBox *frame = nullptr;
LineEdit *scale = nullptr;
LineEdit *name = nullptr;
OptionButton *library = nullptr;
Label *name_title = nullptr;
Ref<Texture2D> stop_icon;
Ref<Texture2D> pause_icon;
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
Ref<ImageTexture> autoplay_reset_icon;
bool finishing = false;
bool last_active = false;
float timeline_position = 0;
EditorFileDialog *file = nullptr;
ConfirmationDialog *delete_dialog = nullptr;
AnimationLibraryEditor *library_editor = nullptr;
struct BlendEditor {
AcceptDialog *dialog = nullptr;
Tree *tree = nullptr;
OptionButton *next = nullptr;
} blend_editor;
ConfirmationDialog *name_dialog = nullptr;
AcceptDialog *error_dialog = nullptr;
int name_dialog_op = TOOL_NEW_ANIM;
bool updating = false;
bool updating_blends = false;
AnimationTrackEditor *track_editor = nullptr;
static AnimationPlayerEditor *singleton;
// Onion skinning.
struct {
// Settings.
bool enabled = false;
bool past = true;
bool future = false;
uint32_t steps = 1;
bool differences_only = false;
bool force_white_modulate = false;
bool include_gizmos = false;
uint32_t get_capture_count() const {
// 'Differences only' needs a capture of the present.
return (past && future ? 2 * steps : steps) + (differences_only ? 1 : 0);
}
// Rendering.
int64_t last_frame = 0;
int can_overlay = 0;
Size2 capture_size;
LocalVector<RID> captures;
LocalVector<bool> captures_valid;
struct {
RID canvas;
RID canvas_item;
Ref<ShaderMaterial> material;
Ref<Shader> shader;
} capture;
// Cross-call state.
struct {
double anim_player_position = 0.0;
Ref<AnimatedValuesBackup> anim_values_backup;
Rect2 screen_rect;
Dictionary canvas_edit_state;
Dictionary spatial_edit_state;
} temp;
} onion;
void _select_anim_by_name(const String &p_anim);
float _get_editor_step() const;
void _go_to_nearest_keyframe(bool p_backward);
void _play_pressed();
void _play_from_pressed();
void _play_bw_pressed();
void _play_bw_from_pressed();
void _autoplay_pressed();
void _stop_pressed();
void _animation_selected(int p_which);
void _animation_new();
void _animation_rename();
void _animation_name_edited();
void _animation_remove();
void _animation_remove_confirmed();
void _animation_edit();
void _animation_duplicate();
Ref<Animation> _animation_clone(const Ref<Animation> p_anim);
void _animation_resource_edit();
void _scale_changed(const String &p_scale);
void _seek_value_changed(float p_value, bool p_timeline_only = false);
void _blend_editor_next_changed(const int p_idx);
void _edit_animation_blend();
void _update_animation_blend();
void _list_changed();
void _animation_finished(const String &p_name);
void _current_animation_changed(const String &p_name);
void _update_animation();
void _update_player();
void _set_controls_disabled(bool p_disabled);
void _update_animation_list_icons();
void _update_name_dialog_library_dropdown();
void _blend_edited();
void _animation_player_changed(Object *p_pl);
void _animation_libraries_updated();
void _animation_key_editor_seek(float p_pos, bool p_timeline_only = false, bool p_update_position_only = false);
void _animation_key_editor_anim_len_changed(float p_len);
void _animation_update_key_frame();
virtual void shortcut_input(const Ref<InputEvent> &p_ev) override;
void _animation_tool_menu(int p_option);
void _onion_skinning_menu(int p_option);
void _editor_visibility_changed();
bool _are_onion_layers_valid();
void _allocate_onion_layers();
void _free_onion_layers();
void _prepare_onion_layers_1();
void _prepare_onion_layers_2_prolog();
void _prepare_onion_layers_2_step_prepare(int p_step_offset, uint32_t p_capture_idx);
void _prepare_onion_layers_2_step_capture(int p_step_offset, uint32_t p_capture_idx);
void _prepare_onion_layers_2_epilog();
void _start_onion_skinning();
void _stop_onion_skinning();
bool _validate_tracks(const Ref<Animation> p_anim);
void _pin_pressed();
String _get_current() const;
void _ensure_dummy_player();
~AnimationPlayerEditor();
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
public:
AnimationMixer *get_editing_node() const;
AnimationPlayer *get_player() const;
AnimationMixer *fetch_mixer_for_library() const;
Node *get_cached_root_node() const;
static AnimationPlayerEditor *get_singleton() { return singleton; }
bool is_pinned() const { return pin->is_pressed(); }
void unpin() {
pin->set_pressed(false);
_pin_pressed();
}
AnimationTrackEditor *get_track_editor() { return track_editor; }
Dictionary get_state() const;
void set_state(const Dictionary &p_state);
void clear();
void ensure_visibility();
void edit(AnimationMixer *p_node, AnimationPlayer *p_player, bool p_is_dummy);
void forward_force_draw_over_viewport(Control *p_overlay);
AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin);
};
class AnimationPlayerEditorPlugin : public EditorPlugin {
GDCLASS(AnimationPlayerEditorPlugin, EditorPlugin);
friend AnimationPlayerEditor;
AnimationPlayerEditor *anim_editor = nullptr;
AnimationPlayer *player = nullptr;
AnimationPlayer *dummy_player = nullptr;
ObjectID last_mixer;
void _update_dummy_player(AnimationMixer *p_mixer);
void _clear_dummy_player();
protected:
void _notification(int p_what);
void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance);
void _transform_key_request(Object *sp, const String &p_sub, const Transform3D &p_key);
void _update_keying();
public:
virtual Dictionary get_state() const override { return anim_editor->get_state(); }
virtual void set_state(const Dictionary &p_state) override { anim_editor->set_state(p_state); }
virtual void clear() override { anim_editor->clear(); }
virtual String get_plugin_name() const override { return "Anim"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
virtual void forward_3d_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
AnimationPlayerEditorPlugin();
~AnimationPlayerEditorPlugin();
};
// AnimationTrackKeyEditEditorPlugin
class EditorInspectorPluginAnimationTrackKeyEdit : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginAnimationTrackKeyEdit, EditorInspectorPlugin);
AnimationTrackKeyEditEditor *atk_editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
};
class AnimationTrackKeyEditEditorPlugin : public EditorPlugin {
GDCLASS(AnimationTrackKeyEditEditorPlugin, EditorPlugin);
EditorInspectorPluginAnimationTrackKeyEdit *atk_plugin = nullptr;
public:
bool has_main_screen() const override { return false; }
virtual bool handles(Object *p_object) const override;
virtual String get_plugin_name() const override { return "AnimationTrackKeyEdit"; }
AnimationTrackKeyEditEditorPlugin();
};
// AnimationMarkerKeyEditEditorPlugin
class EditorInspectorPluginAnimationMarkerKeyEdit : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginAnimationMarkerKeyEdit, EditorInspectorPlugin);
AnimationMarkerKeyEditEditor *amk_editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
};
class AnimationMarkerKeyEditEditorPlugin : public EditorPlugin {
GDCLASS(AnimationMarkerKeyEditEditorPlugin, EditorPlugin);
EditorInspectorPluginAnimationMarkerKeyEdit *amk_plugin = nullptr;
public:
bool has_main_screen() const override { return false; }
virtual bool handles(Object *p_object) const override;
virtual String get_plugin_name() const override { return "AnimationMarkerKeyEdit"; }
AnimationMarkerKeyEditEditorPlugin();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,322 @@
/**************************************************************************/
/* animation_state_machine_editor.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/animation/animation_tree_editor_plugin.h"
#include "scene/animation/animation_node_state_machine.h"
#include "scene/gui/graph_edit.h"
#include "scene/gui/popup.h"
class ConfirmationDialog;
class EditorFileDialog;
class LineEdit;
class OptionButton;
class PanelContainer;
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
bool read_only = false;
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
Popup *name_edit_popup = nullptr;
LineEdit *name_edit = nullptr;
HBoxContainer *selection_tools_hb = nullptr;
Button *tool_erase = nullptr;
HBoxContainer *transition_tools_hb = nullptr;
OptionButton *switch_mode = nullptr;
Button *auto_advance = nullptr;
OptionButton *play_mode = nullptr;
PanelContainer *panel = nullptr;
StringName selected_node;
HashSet<StringName> selected_nodes;
HScrollBar *h_scroll = nullptr;
VScrollBar *v_scroll = nullptr;
Control *state_machine_draw = nullptr;
Control *state_machine_play_pos = nullptr;
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
struct ThemeCache {
Ref<StyleBox> panel_style;
Ref<StyleBox> error_panel_style;
Color error_color;
Ref<Texture2D> tool_icon_select;
Ref<Texture2D> tool_icon_create;
Ref<Texture2D> tool_icon_connect;
Ref<Texture2D> tool_icon_erase;
Ref<Texture2D> transition_icon_immediate;
Ref<Texture2D> transition_icon_sync;
Ref<Texture2D> transition_icon_end;
Ref<Texture2D> play_icon_start;
Ref<Texture2D> play_icon_travel;
Ref<Texture2D> play_icon_auto;
Ref<Texture2D> animation_icon;
Ref<StyleBox> node_frame;
Ref<StyleBox> node_frame_selected;
Ref<StyleBox> node_frame_playing;
Ref<StyleBox> node_frame_start;
Ref<StyleBox> node_frame_end;
Ref<Font> node_title_font;
int node_title_font_size = 0;
Color node_title_font_color;
Ref<Texture2D> play_node;
Ref<Texture2D> edit_node;
Color transition_color;
Color transition_disabled_color;
Color transition_icon_color;
Color transition_icon_disabled_color;
Color highlight_color;
Color highlight_disabled_color;
Color focus_color;
Color guideline_color;
Ref<Texture2D> transition_icons[6]{};
Color playback_color;
Color playback_background_color;
} theme_cache;
bool updating = false;
static AnimationNodeStateMachineEditor *singleton;
void _state_machine_gui_input(const Ref<InputEvent> &p_event);
void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_is_across_group, float p_opacity = 1.0);
void _state_machine_draw();
void _state_machine_pos_draw_individual(const String &p_name, float p_ratio);
void _state_machine_pos_draw_all();
void _update_graph();
PopupMenu *menu = nullptr;
PopupMenu *connect_menu = nullptr;
PopupMenu *state_machine_menu = nullptr;
PopupMenu *end_menu = nullptr;
PopupMenu *animations_menu = nullptr;
Vector<String> animations_to_add;
Vector<String> nodes_to_connect;
Vector2 add_node_pos;
bool box_selecting = false;
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
HashSet<StringName> previous_selected;
bool dragging_selected_attempt = false;
bool dragging_selected = false;
Vector2 drag_from;
Vector2 drag_ofs;
StringName snap_x;
StringName snap_y;
bool connecting = false;
bool connection_follows_cursor = false;
StringName connecting_from;
Vector2 connecting_to;
StringName connecting_to_node;
void _add_menu_type(int p_index);
void _add_animation_type(int p_index);
void _connect_to(int p_index);
struct NodeRect {
StringName node_name;
Rect2 node;
Rect2 play;
Rect2 name;
Rect2 edit;
bool can_edit;
};
Vector<NodeRect> node_rects;
struct TransitionLine {
StringName from_node;
StringName to_node;
Vector2 from;
Vector2 to;
AnimationNodeStateMachineTransition::SwitchMode mode;
StringName advance_condition_name;
bool advance_condition_state = false;
bool disabled = false;
bool auto_advance = false;
float width = 0;
bool selected;
bool travel;
float fade_ratio;
bool hidden;
int transition_index;
bool is_across_group = false;
};
Vector<TransitionLine> transition_lines;
struct NodeUR {
StringName name;
Ref<AnimationNode> node;
Vector2 position;
};
struct TransitionUR {
StringName new_from;
StringName new_to;
StringName old_from;
StringName old_to;
Ref<AnimationNodeStateMachineTransition> transition;
};
StringName selected_transition_from;
StringName selected_transition_to;
int selected_transition_index = -1;
void _add_transition(const bool p_nested_action = false);
enum HoveredNodeArea {
HOVER_NODE_NONE = -1,
HOVER_NODE_PLAY = 0,
HOVER_NODE_EDIT = 1,
};
StringName hovered_node_name;
HoveredNodeArea hovered_node_area = HOVER_NODE_NONE;
String prev_name;
void _name_edited(const String &p_text);
void _name_edited_focus_out();
void _open_editor(const String &p_name);
void _scroll_changed(double);
String _get_root_playback_path(String &r_node_directory);
void _clip_src_line_to_rect(Vector2 &r_from, const Vector2 &p_to, const Rect2 &p_rect);
void _clip_dst_line_to_rect(const Vector2 &p_from, Vector2 &r_to, const Rect2 &p_rect);
void _erase_selected(const bool p_nested_action = false);
void _update_mode();
void _open_menu(const Vector2 &p_position);
bool _create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path);
void _stop_connecting();
bool last_active = false;
StringName last_fading_from_node;
StringName last_current_node;
Vector<StringName> last_travel_path;
float fade_from_last_play_pos = 0.0f;
float fade_from_current_play_pos = 0.0f;
float fade_from_length = 0.0f;
float last_play_pos = 0.0f;
float current_play_pos = 0.0f;
float current_length = 0.0f;
float last_fading_time = 0.0f;
float last_fading_pos = 0.0f;
float fading_time = 0.0f;
float fading_pos = 0.0f;
float error_time = 0.0f;
String error_text;
EditorFileDialog *open_file = nullptr;
Ref<AnimationNode> file_loaded;
void _file_opened(const String &p_file);
enum {
MENU_LOAD_FILE = 1000,
MENU_PASTE = 1001,
MENU_LOAD_FILE_CONFIRM = 1002
};
HashSet<StringName> connected_nodes;
void _update_connected_nodes(const StringName &p_node);
Ref<StyleBox> _adjust_stylebox_opacity(Ref<StyleBox> p_style, float p_opacity);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static AnimationNodeStateMachineEditor *get_singleton() { return singleton; }
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
virtual String get_tooltip(const Point2 &p_pos) const override;
AnimationNodeStateMachineEditor();
};
class EditorAnimationMultiTransitionEdit : public RefCounted {
GDCLASS(EditorAnimationMultiTransitionEdit, RefCounted);
struct Transition {
StringName from;
StringName to;
Ref<AnimationNodeStateMachineTransition> transition;
};
Vector<Transition> transitions;
protected:
bool _set(const StringName &p_name, const Variant &p_property);
bool _get(const StringName &p_name, Variant &r_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
void add_transition(const StringName &p_from, const StringName &p_to, Ref<AnimationNodeStateMachineTransition> p_transition);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,165 @@
/**************************************************************************/
/* animation_track_editor_plugins.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/animation/animation_track_editor.h"
class AnimationTrackEditBool : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditBool, AnimationTrackEdit);
Ref<Texture2D> icon_checked;
Ref<Texture2D> icon_unchecked;
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
};
class AnimationTrackEditColor : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditColor, AnimationTrackEdit);
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
virtual void draw_key_link(int p_index, float p_pixels_sec, int p_x, int p_next_x, int p_clip_left, int p_clip_right) override;
};
class AnimationTrackEditAudio : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditAudio, AnimationTrackEdit);
ObjectID id;
void _preview_changed(ObjectID p_which);
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
void set_node(Object *p_object);
AnimationTrackEditAudio();
};
class AnimationTrackEditSpriteFrame : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditSpriteFrame, AnimationTrackEdit);
ObjectID id;
bool is_coords = false;
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
void set_node(Object *p_object);
void set_as_coords();
};
class AnimationTrackEditSubAnim : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditSubAnim, AnimationTrackEdit);
ObjectID id;
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
void set_node(Object *p_object);
};
class AnimationTrackEditTypeAudio : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditTypeAudio, AnimationTrackEdit);
void _preview_changed(ObjectID p_which);
bool len_resizing = false;
bool len_resizing_start = false;
int len_resizing_index = 0;
float len_resizing_from_px = 0.0f;
float len_resizing_rel = 0.0f;
bool over_drag_position = false;
public:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
virtual void drop_data(const Point2 &p_point, const Variant &p_data) override;
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
AnimationTrackEditTypeAudio();
};
class AnimationTrackEditTypeAnimation : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditTypeAnimation, AnimationTrackEdit);
ObjectID id;
public:
virtual int get_key_height() const override;
virtual Rect2 get_key_rect(int p_index, float p_pixels_sec) override;
virtual bool is_key_selectable_by_distance() const override;
virtual void draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) override;
void set_node(Object *p_object);
};
class AnimationTrackEditVolumeDB : public AnimationTrackEdit {
GDCLASS(AnimationTrackEditVolumeDB, AnimationTrackEdit);
public:
virtual void draw_bg(int p_clip_left, int p_clip_right) override;
virtual void draw_fg(int p_clip_left, int p_clip_right) override;
virtual int get_key_height() const override;
virtual void draw_key_link(int p_index, float p_pixels_sec, int p_x, int p_next_x, int p_clip_left, int p_clip_right) override;
};
class AnimationTrackEditDefaultPlugin : public AnimationTrackEditPlugin {
GDCLASS(AnimationTrackEditDefaultPlugin, AnimationTrackEditPlugin);
public:
virtual AnimationTrackEdit *create_value_track_edit(Object *p_object, Variant::Type p_type, const String &p_property, PropertyHint p_hint, const String &p_hint_string, int p_usage) override;
virtual AnimationTrackEdit *create_audio_track_edit() override;
virtual AnimationTrackEdit *create_animation_track_edit(Object *p_object) override;
};

View File

@@ -0,0 +1,310 @@
/**************************************************************************/
/* animation_tree_editor_plugin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "animation_tree_editor_plugin.h"
#include "animation_blend_space_1d_editor.h"
#include "animation_blend_space_2d_editor.h"
#include "animation_blend_tree_editor_plugin.h"
#include "animation_state_machine_editor.h"
#include "editor/editor_node.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/settings/editor_command_palette.h"
#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/gui/button.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/separator.h"
void AnimationTreeEditor::edit(AnimationTree *p_tree) {
if (p_tree && !p_tree->is_connected("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
p_tree->connect("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED);
}
if (tree == p_tree) {
return;
}
if (tree && tree->is_connected("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
tree->disconnect("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed));
}
tree = p_tree;
Vector<String> path;
if (tree) {
edit_path(path);
}
}
void AnimationTreeEditor::_node_removed(Node *p_node) {
if (p_node == tree) {
tree = nullptr;
_clear_editors();
}
}
void AnimationTreeEditor::_path_button_pressed(int p_path) {
edited_path.clear();
for (int i = 0; i <= p_path; i++) {
edited_path.push_back(button_path[i]);
}
}
void AnimationTreeEditor::_animation_list_changed() {
AnimationNodeBlendTreeEditor *bte = AnimationNodeBlendTreeEditor::get_singleton();
if (bte) {
bte->update_graph();
}
}
void AnimationTreeEditor::_update_path() {
while (path_hb->get_child_count() > 1) {
memdelete(path_hb->get_child(1));
}
Ref<ButtonGroup> group;
group.instantiate();
Button *b = memnew(Button);
b->set_text(TTR("Root"));
b->set_toggle_mode(true);
b->set_button_group(group);
b->set_pressed(true);
b->set_focus_mode(FOCUS_ACCESSIBILITY);
b->connect(SceneStringName(pressed), callable_mp(this, &AnimationTreeEditor::_path_button_pressed).bind(-1));
path_hb->add_child(b);
for (int i = 0; i < button_path.size(); i++) {
b = memnew(Button);
b->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
b->set_text(button_path[i]);
b->set_toggle_mode(true);
b->set_button_group(group);
path_hb->add_child(b);
b->set_pressed(true);
b->set_focus_mode(FOCUS_ACCESSIBILITY);
b->connect(SceneStringName(pressed), callable_mp(this, &AnimationTreeEditor::_path_button_pressed).bind(i));
}
}
void AnimationTreeEditor::edit_path(const Vector<String> &p_path) {
button_path.clear();
Ref<AnimationNode> node = tree->get_root_animation_node();
if (node.is_valid()) {
current_root = node->get_instance_id();
for (int i = 0; i < p_path.size(); i++) {
Ref<AnimationNode> child = node->get_child_by_name(p_path[i]);
ERR_BREAK(child.is_null());
node = child;
button_path.push_back(p_path[i]);
}
edited_path = button_path;
for (int i = 0; i < editors.size(); i++) {
if (editors[i]->can_edit(node)) {
editors[i]->edit(node);
editors[i]->show();
} else {
editors[i]->edit(Ref<AnimationNode>());
editors[i]->hide();
}
}
} else {
current_root = ObjectID();
edited_path = button_path;
for (int i = 0; i < editors.size(); i++) {
editors[i]->edit(Ref<AnimationNode>());
editors[i]->hide();
}
}
_update_path();
}
void AnimationTreeEditor::_clear_editors() {
button_path.clear();
current_root = ObjectID();
edited_path = button_path;
for (int i = 0; i < editors.size(); i++) {
editors[i]->edit(Ref<AnimationNode>());
editors[i]->hide();
}
_update_path();
}
Vector<String> AnimationTreeEditor::get_edited_path() const {
return button_path;
}
void AnimationTreeEditor::enter_editor(const String &p_path) {
Vector<String> path = edited_path;
path.push_back(p_path);
edit_path(path);
}
void AnimationTreeEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
get_tree()->connect("node_removed", callable_mp(this, &AnimationTreeEditor::_node_removed));
} break;
case NOTIFICATION_PROCESS: {
ObjectID root;
if (tree && tree->get_root_animation_node().is_valid()) {
root = tree->get_root_animation_node()->get_instance_id();
}
if (root != current_root) {
edit_path(Vector<String>());
}
if (button_path.size() != edited_path.size()) {
edit_path(edited_path);
}
} break;
case NOTIFICATION_EXIT_TREE: {
get_tree()->disconnect("node_removed", callable_mp(this, &AnimationTreeEditor::_node_removed));
} break;
}
}
AnimationTreeEditor *AnimationTreeEditor::singleton = nullptr;
void AnimationTreeEditor::add_plugin(AnimationTreeNodeEditorPlugin *p_editor) {
ERR_FAIL_COND(p_editor->get_parent());
editor_base->add_child(p_editor);
editors.push_back(p_editor);
p_editor->set_h_size_flags(SIZE_EXPAND_FILL);
p_editor->set_v_size_flags(SIZE_EXPAND_FILL);
p_editor->hide();
}
void AnimationTreeEditor::remove_plugin(AnimationTreeNodeEditorPlugin *p_editor) {
ERR_FAIL_COND(p_editor->get_parent() != editor_base);
editor_base->remove_child(p_editor);
editors.erase(p_editor);
}
String AnimationTreeEditor::get_base_path() {
String path = Animation::PARAMETERS_BASE_PATH;
for (int i = 0; i < edited_path.size(); i++) {
path += edited_path[i] + "/";
}
return path;
}
bool AnimationTreeEditor::can_edit(const Ref<AnimationNode> &p_node) const {
for (int i = 0; i < editors.size(); i++) {
if (editors[i]->can_edit(p_node)) {
return true;
}
}
return false;
}
Vector<String> AnimationTreeEditor::get_animation_list() {
// This can be called off the main thread due to resource preview generation. Quit early in that case.
if (!singleton->tree || !Thread::is_main_thread() || !singleton->is_visible()) {
// When tree is empty, singleton not in the main thread.
return Vector<String>();
}
AnimationTree *tree = singleton->tree;
if (!tree) {
return Vector<String>();
}
List<StringName> anims;
tree->get_animation_list(&anims);
Vector<String> ret;
for (const StringName &E : anims) {
ret.push_back(E);
}
return ret;
}
AnimationTreeEditor::AnimationTreeEditor() {
AnimationNodeAnimation::get_editable_animation_list = get_animation_list;
path_edit = memnew(ScrollContainer);
add_child(path_edit);
path_edit->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
path_hb = memnew(HBoxContainer);
path_edit->add_child(path_hb);
path_hb->add_child(memnew(Label(TTR("Path:"))));
add_child(memnew(HSeparator));
singleton = this;
editor_base = memnew(MarginContainer);
editor_base->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(editor_base);
add_plugin(memnew(AnimationNodeBlendTreeEditor));
add_plugin(memnew(AnimationNodeBlendSpace1DEditor));
add_plugin(memnew(AnimationNodeBlendSpace2DEditor));
add_plugin(memnew(AnimationNodeStateMachineEditor));
}
void AnimationTreeEditorPlugin::edit(Object *p_object) {
anim_tree_editor->edit(Object::cast_to<AnimationTree>(p_object));
}
bool AnimationTreeEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationTree");
}
void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
//editor->hide_animation_player_editors();
//editor->animation_panel_make_visible(true);
button->show();
EditorNode::get_bottom_panel()->make_item_visible(anim_tree_editor);
anim_tree_editor->set_process(true);
} else {
if (anim_tree_editor->is_visible_in_tree()) {
EditorNode::get_bottom_panel()->hide_bottom_panel();
}
button->hide();
anim_tree_editor->set_process(false);
}
}
AnimationTreeEditorPlugin::AnimationTreeEditorPlugin() {
anim_tree_editor = memnew(AnimationTreeEditor);
anim_tree_editor->set_custom_minimum_size(Size2(0, 300) * EDSCALE);
button = EditorNode::get_bottom_panel()->add_item(TTRC("AnimationTree"), anim_tree_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_animation_tree_bottom_panel", TTRC("Toggle AnimationTree Bottom Panel")));
button->hide();
}

View File

@@ -0,0 +1,109 @@
/**************************************************************************/
/* animation_tree_editor_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_tree.h"
#include "scene/gui/graph_edit.h"
class Button;
class EditorFileDialog;
class ScrollContainer;
class AnimationTreeNodeEditorPlugin : public VBoxContainer {
GDCLASS(AnimationTreeNodeEditorPlugin, VBoxContainer);
public:
virtual bool can_edit(const Ref<AnimationNode> &p_node) = 0;
virtual void edit(const Ref<AnimationNode> &p_node) = 0;
};
class AnimationTreeEditor : public VBoxContainer {
GDCLASS(AnimationTreeEditor, VBoxContainer);
ScrollContainer *path_edit = nullptr;
HBoxContainer *path_hb = nullptr;
AnimationTree *tree = nullptr;
MarginContainer *editor_base = nullptr;
Vector<String> button_path;
Vector<String> edited_path;
Vector<AnimationTreeNodeEditorPlugin *> editors;
void _update_path();
void _clear_editors();
ObjectID current_root;
void _path_button_pressed(int p_path);
void _animation_list_changed();
static Vector<String> get_animation_list();
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static AnimationTreeEditor *singleton;
public:
AnimationTree *get_animation_tree() { return tree; }
void add_plugin(AnimationTreeNodeEditorPlugin *p_editor);
void remove_plugin(AnimationTreeNodeEditorPlugin *p_editor);
String get_base_path();
bool can_edit(const Ref<AnimationNode> &p_node) const;
void edit_path(const Vector<String> &p_path);
Vector<String> get_edited_path() const;
void enter_editor(const String &p_path = "");
static AnimationTreeEditor *get_singleton() { return singleton; }
void edit(AnimationTree *p_tree);
AnimationTreeEditor();
};
class AnimationTreeEditorPlugin : public EditorPlugin {
GDCLASS(AnimationTreeEditorPlugin, EditorPlugin);
AnimationTreeEditor *anim_tree_editor = nullptr;
Button *button = nullptr;
public:
virtual String get_plugin_name() const override { return "AnimationTree"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
AnimationTreeEditorPlugin();
};