From f36e7dcb405ead38c33d808f732fd7b4e23d19e5 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 25 May 2015 01:46:45 -0300 Subject: improved animation editor -same-value link keys -new layout -forward, backwards playback -integrated curve/property editor -auto increment sprite frame after insert -copy & paste animation resoucres --- core/object.cpp | 33 ++ core/object.h | 2 + core/os/main_loop.cpp | 27 +- scene/2d/animated_sprite.cpp | 2 +- scene/2d/sprite.cpp | 2 +- scene/3d/sprite_3d.cpp | 4 +- scene/animation/animation_player.cpp | 10 +- scene/animation/animation_player.h | 2 +- tools/editor/animation_editor.cpp | 525 ++++++++++++++++++--- tools/editor/animation_editor.h | 29 +- tools/editor/editor_file_system.cpp | 1 + tools/editor/editor_node.cpp | 4 +- tools/editor/editor_node.h | 2 +- tools/editor/icons/icon_curve_constant.png | Bin 0 -> 222 bytes tools/editor/icons/icon_curve_in.png | Bin 0 -> 319 bytes tools/editor/icons/icon_curve_in_out.png | Bin 0 -> 326 bytes tools/editor/icons/icon_curve_linear.png | Bin 0 -> 275 bytes tools/editor/icons/icon_curve_out.png | Bin 0 -> 319 bytes tools/editor/icons/icon_curve_out_in.png | Bin 0 -> 318 bytes tools/editor/icons/icon_key_next.png | Bin 0 -> 499 bytes tools/editor/icons/icon_pause.png | Bin 367 -> 228 bytes tools/editor/icons/icon_play.png | Bin 256 -> 260 bytes tools/editor/icons/icon_play_backwards.png | Bin 0 -> 256 bytes tools/editor/icons/icon_play_start.png | Bin 0 -> 282 bytes tools/editor/icons/icon_play_start_backwards.png | Bin 0 -> 289 bytes tools/editor/icons/icon_stop.png | Bin 138 -> 236 bytes .../plugins/animation_player_editor_plugin.cpp | 259 +++++++++- .../plugins/animation_player_editor_plugin.h | 15 + tools/editor/property_editor.cpp | 28 +- tools/editor/property_editor.h | 1 + 30 files changed, 840 insertions(+), 106 deletions(-) create mode 100644 tools/editor/icons/icon_curve_constant.png create mode 100644 tools/editor/icons/icon_curve_in.png create mode 100644 tools/editor/icons/icon_curve_in_out.png create mode 100644 tools/editor/icons/icon_curve_linear.png create mode 100644 tools/editor/icons/icon_curve_out.png create mode 100644 tools/editor/icons/icon_curve_out_in.png create mode 100644 tools/editor/icons/icon_key_next.png create mode 100644 tools/editor/icons/icon_play_backwards.png create mode 100644 tools/editor/icons/icon_play_start.png create mode 100644 tools/editor/icons/icon_play_start_backwards.png diff --git a/core/object.cpp b/core/object.cpp index 1a51e79a9f..84786df8d4 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -995,12 +995,44 @@ Variant Object::get_meta(const String& p_name) const { return metadata[p_name]; } + Array Object::_get_property_list_bind() const { List lpi; get_property_list(&lpi); return convert_property_list(&lpi); } + +Array Object::_get_method_list_bind() const { + + List ml; + get_method_list(&ml); + Array ret; + + for(List::Element *E=ml.front();E;E=E->next()) { + + Dictionary d; + d["name"]=E->get().name; + d["args"]=convert_property_list(&E->get().arguments); + Array da; + for(int i=0;iget().default_arguments.size();i++) + da.push_back(E->get().default_arguments[i]); + d["default_args"]=da; + d["flags"]=E->get().flags; + d["id"]=E->get().id; + Dictionary r; + r["type"]=E->get().return_val.type; + r["hint"]=E->get().return_val.hint; + r["hint_string"]=E->get().return_val.hint_string; + d["return_type"]=r; + //va.push_back(d); + ret.push_back(d); + } + + return ret; + +} + DVector Object::_get_meta_list_bind() const { DVector _metaret; @@ -1439,6 +1471,7 @@ void Object::_bind_methods() { ObjectTypeDB::bind_method(_MD("set","property","value"),&Object::_set_bind); ObjectTypeDB::bind_method(_MD("get","property"),&Object::_get_bind); ObjectTypeDB::bind_method(_MD("get_property_list"),&Object::_get_property_list_bind); + ObjectTypeDB::bind_method(_MD("get_method_list"),&Object::_get_method_list_bind); ObjectTypeDB::bind_method(_MD("notification","what"),&Object::notification,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_instance_ID"),&Object::get_instance_ID); diff --git a/core/object.h b/core/object.h index fc64b91412..8d1f8ebc5a 100644 --- a/core/object.h +++ b/core/object.h @@ -54,6 +54,7 @@ enum PropertyHint { PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing funciton (Math::ease) PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) + PROPERTY_HINT_SPRITE_FRAME, PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) PROPERTY_HINT_ALL_FLAGS, @@ -448,6 +449,7 @@ protected: DVector _get_meta_list_bind() const; Array _get_property_list_bind() const; + Array _get_method_list_bind() const; public: //should be protected, but bug in clang++ static void initialize_type(); diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 83d3155b03..b4c02ddbce 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -31,7 +31,20 @@ void MainLoop::_bind_methods() { - ObjectTypeDB::bind_method("input_event",&MainLoop::input_event); + ObjectTypeDB::bind_method(_MD("input_event","ev"),&MainLoop::input_event); + ObjectTypeDB::bind_method(_MD("input_text","text"),&MainLoop::input_text); + ObjectTypeDB::bind_method(_MD("init"),&MainLoop::init); + ObjectTypeDB::bind_method(_MD("iteration","delta"),&MainLoop::iteration); + ObjectTypeDB::bind_method(_MD("idle","delta"),&MainLoop::idle); + ObjectTypeDB::bind_method(_MD("finish"),&MainLoop::finish); + + BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"ev")) ); + BIND_VMETHOD( MethodInfo("_input_text",PropertyInfo(Variant::STRING,"text")) ); + BIND_VMETHOD( MethodInfo("_initialize") ); + BIND_VMETHOD( MethodInfo("_iteration",PropertyInfo(Variant::REAL,"delta")) ); + BIND_VMETHOD( MethodInfo("_idle",PropertyInfo(Variant::REAL,"delta")) ); + BIND_VMETHOD( MethodInfo("_finalize") ); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN); BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT); @@ -58,13 +71,15 @@ MainLoop::~MainLoop() void MainLoop::input_text( const String& p_text ) { + if (get_script_instance()) + get_script_instance()->call("_input_text",p_text); } void MainLoop::input_event( const InputEvent& p_event ) { if (get_script_instance()) - get_script_instance()->call("input_event",p_event); + get_script_instance()->call("_input_event",p_event); } @@ -74,13 +89,13 @@ void MainLoop::init() { set_script(init_script.get_ref_ptr()); if (get_script_instance()) - get_script_instance()->call("init"); + get_script_instance()->call("_initialize"); } bool MainLoop::iteration(float p_time) { if (get_script_instance()) - return get_script_instance()->call("iteration",p_time); + return get_script_instance()->call("_iteration",p_time); return false; @@ -88,14 +103,14 @@ bool MainLoop::iteration(float p_time) { bool MainLoop::idle(float p_time) { if (get_script_instance()) - return get_script_instance()->call("idle",p_time); + return get_script_instance()->call("_idle",p_time); return false; } void MainLoop::finish() { if (get_script_instance()) { - get_script_instance()->call("finish"); + get_script_instance()->call("_finalize"); set_script(RefPtr()); //clear script } diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 312b04d414..b49426f7e2 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -329,7 +329,7 @@ void AnimatedSprite::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_changed")); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); - ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 0c0a0d7822..067b4794b4 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -320,7 +320,7 @@ void Sprite::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 4952f742df..e9da95f3fb 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -580,7 +580,7 @@ void Sprite3D::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); @@ -727,7 +727,7 @@ void AnimatedSprite3D::_bind_methods(){ ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite3D::get_frame); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_SIGNAL(MethodInfo("frame_changed")); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 4949b33c47..6676f70981 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -967,14 +967,16 @@ String AnimationPlayer::get_current_animation() const { } -void AnimationPlayer::stop() { +void AnimationPlayer::stop(bool p_reset) { Playback &c=playback; c.blend.clear(); - c.current.from=NULL; + if (p_reset) { + c.current.from=NULL; + } _set_process(false); queued.clear(); - playing = false; + playing = false; } void AnimationPlayer::stop_all() { @@ -1211,7 +1213,7 @@ void AnimationPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_default_blend_time"),&AnimationPlayer::get_default_blend_time); ObjectTypeDB::bind_method(_MD("play","name","custom_blend","custom_speed","from_end"),&AnimationPlayer::play,DEFVAL(""),DEFVAL(-1),DEFVAL(1.0),DEFVAL(false)); - ObjectTypeDB::bind_method(_MD("stop"),&AnimationPlayer::stop); + ObjectTypeDB::bind_method(_MD("stop","reset"),&AnimationPlayer::stop,DEFVAL(true)); ObjectTypeDB::bind_method(_MD("stop_all"),&AnimationPlayer::stop_all); ObjectTypeDB::bind_method(_MD("is_playing"),&AnimationPlayer::is_playing); ObjectTypeDB::bind_method(_MD("set_current_animation","anim"),&AnimationPlayer::set_current_animation); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 8d7d6d04e0..3fddc283ae 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -260,7 +260,7 @@ public: void play(const StringName& p_name=StringName(),float p_custom_blend=-1,float p_custom_scale=1.0,bool p_from_end=false); void queue(const StringName& p_name); void clear_queue(); - void stop(); + void stop(bool p_reset=true); bool is_playing() const; String get_current_animation() const; void set_current_animation(const String& p_anim); diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index 63ab186a38..36fb6fb5f8 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -44,11 +44,207 @@ */ +class AnimationCurveEdit : public Control { + OBJ_TYPE( AnimationCurveEdit, Control ); +public: + enum Mode { + MODE_DISABLED, + MODE_SINGLE, + MODE_MULTIPLE + }; +private: + + Set multiples; + float transition; + Mode mode; + + void _notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW) { + + + RID ci = get_canvas_item(); + + Size2 s = get_size(); + Rect2 r(Point2(),s); + + //r=r.grow(3); + Ref sb = get_stylebox("normal","LineEdit"); + sb->draw(ci,r); + r.size-=sb->get_minimum_size(); + r.pos+=sb->get_offset(); + //VisualServer::get_singleton()->canvas_item_add + + Ref f = get_font("font","Label"); + r=r.grow(-2); + Color color = get_color("font_color","Label"); + + int points = 48; + if (mode==MODE_MULTIPLE) { + + int max_draw = 16; + Color mcolor=color; + mcolor.a*=0.3; + + Set::Element *E=multiples.front(); + for(int j=0;j<16;j++) { + + if (!E) + break; + + float prev=1.0; + float exp=E->get(); + bool flip=false;//hint_text=="attenuation"; + + + for(int i=1;i<=points;i++) { + + float ifl = i/float(points); + float iflp = (i-1)/float(points); + + float h = 1.0-Math::ease(ifl,exp); + + if (flip) { + ifl=1.0-ifl; + iflp=1.0-iflp; + } + + VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),mcolor); + prev=h; + } + + E=E->next(); + } + } + + float exp=transition; + if (mode!=MODE_DISABLED) { + + + float prev=1.0; + + bool flip=false;//hint_text=="attenuation"; + + + for(int i=1;i<=points;i++) { + + float ifl = i/float(points); + float iflp = (i-1)/float(points); + + float h = 1.0-Math::ease(ifl,exp); + + if (flip) { + ifl=1.0-ifl; + iflp=1.0-iflp; + } + + VisualServer::get_singleton()->canvas_item_add_line(ci,r.pos+Point2(iflp*r.size.width,prev*r.size.height),r.pos+Point2(ifl*r.size.width,h*r.size.height),color); + prev=h; + } + } + + String txt=String::num(exp,2); + if (mode==MODE_DISABLED) { + txt="Disabled"; + } else if (mode==MODE_MULTIPLE) { + txt+=" - All Selection"; + } + + f->draw(ci,Point2(10,10+f->get_ascent()),txt,color); + + } + } + + void _input_event(const InputEvent& p_ev) { + if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT) { + + if (mode==MODE_DISABLED) + return; + + float rel = p_ev.mouse_motion.relative_x; + if (rel==0) + return; + + bool flip=false; + + if (flip) + rel=-rel; + + float val = transition; + if (val==0) + return; + bool sg = val < 0; + val = Math::absf(val); + + val = Math::log(val)/Math::log(2); + //logspace + val+=rel*0.05; + // + + val = Math::pow(2,val); + if (sg) + val=-val; + + transition=val; + update(); + //emit_signal("variant_changed"); + emit_signal("transition_changed",transition); + } + } + +public: + + static void _bind_methods() { + + // ObjectTypeDB::bind_method("_update_obj",&AnimationKeyEdit::_update_obj); + ObjectTypeDB::bind_method("_input_event",&AnimationCurveEdit::_input_event); + ADD_SIGNAL(MethodInfo("transition_changed")); + } + + void set_mode(Mode p_mode) { + + mode=p_mode; + update(); + } + + void clear_multiples() { multiples.clear(); update();} + void set_multiple(float p_transition) { + + multiples.insert(p_transition); + } + + void set_transition(float p_transition) { + transition=p_transition; + update(); + } + + float get_transition() const { + return transition; + } + + void force_transition(float p_value) { + if (mode==MODE_DISABLED) + return; + transition=p_value; + emit_signal("transition_changed",p_value); + update(); + } + + AnimationCurveEdit() { + + transition=1.0; + set_default_cursor_shape(CURSOR_HSPLIT); + mode=MODE_DISABLED; + } + +}; + class AnimationKeyEdit : public Object { OBJ_TYPE(AnimationKeyEdit,Object); public: bool setting; + bool hidden; static void _bind_methods() { @@ -56,12 +252,12 @@ public: ObjectTypeDB::bind_method("_key_ofs_changed",&AnimationKeyEdit::_key_ofs_changed); } - PopupDialog *ke_dialog; + //PopupDialog *ke_dialog; void _update_obj(const Ref &p_anim) { if (setting) return; - if (!ke_dialog->is_visible()) + if (hidden) return; if (!(animation==p_anim)) return; @@ -69,7 +265,7 @@ public: } void _key_ofs_changed(const Ref &p_anim,float from, float to) { - if (!ke_dialog->is_visible()) + if (hidden) return; if (!(animation==p_anim)) return; @@ -408,8 +604,8 @@ public: } break; } - if (animation->track_get_type(track)!=Animation::TYPE_METHOD) - p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING)); + //if (animation->track_get_type(track)!=Animation::TYPE_METHOD) + // p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING)); } UndoRedo *undo_redo; @@ -425,7 +621,7 @@ public: _change_notify(); } - AnimationKeyEdit() { key_ofs=0; track=-1; setting=false; } + AnimationKeyEdit() { hidden=true; key_ofs=0; track=-1; setting=false; } }; @@ -610,6 +806,8 @@ void AnimationKeyEditor::_menu_track(int p_type) { selection=new_selection; track_editor->update(); + _edit_if_single_selection(); + } @@ -689,8 +887,31 @@ void AnimationKeyEditor::_menu_track(int p_type) { optimize_dialog->popup_centered(Size2(250,180)); } break; + case CURVE_SET_LINEAR: { + curve_edit->force_transition(1.0); + } break; + case CURVE_SET_IN: { + curve_edit->force_transition(4.0); + + } break; + case CURVE_SET_OUT: { + + curve_edit->force_transition(0.25); + } break; + case CURVE_SET_INOUT: { + curve_edit->force_transition(-4); + + } break; + case CURVE_SET_OUTIN: { + + curve_edit->force_transition(-0.25); + } break; + case CURVE_SET_CONSTANT: { + + curve_edit->force_transition(0); + } break; } @@ -774,6 +995,7 @@ void AnimationKeyEditor::_track_editor_draw() { h_scroll->hide(); menu_track->set_disabled(true); edit_button->set_disabled(true); + key_editor_tab->hide(); move_up_button->set_disabled(true); move_down_button->set_disabled(true); remove_button->set_disabled(true); @@ -785,6 +1007,8 @@ void AnimationKeyEditor::_track_editor_draw() { move_up_button->set_disabled(false); move_down_button->set_disabled(false); remove_button->set_disabled(false); + if (edit_button->is_pressed()) + key_editor_tab->show(); te_drawing=true; @@ -1000,8 +1224,13 @@ void AnimationKeyEditor::_track_editor_draw() { } } + Color sep_color=color; + color.a*=0.5; + for(int i=0;iget_val() + i; if (idx>=animation->get_track_count()) break; @@ -1090,6 +1319,7 @@ void AnimationKeyEditor::_track_editor_draw() { float key_hofs = -Math::floor(type_icon[tt]->get_height()/2); int kc=animation->track_get_key_count(idx); + bool first=true; for(int i=0;itrack_get_key_value(idx,i); + if (first && i>0 && value==animation->track_get_key_value(idx,i-1)) { + + te->draw_line(ofs+Vector2(name_limit,y+h/2),ofs+Point2(x,y+h/2),color); + } + + if (itrack_get_key_value(idx,i+1)) { + float x_n = key_hofs + name_limit + (animation->track_get_key_time(idx,i+1)-keys_from)*zoom_scale; + + x_n = MIN( x_n, settings_limit); + te->draw_line(ofs+Point2(x_n,y+h/2),ofs+Point2(x,y+h/2),color); + + } + te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor()); + first=false; } } @@ -1226,7 +1471,9 @@ void AnimationKeyEditor::_clear_selection_for_anim(const Ref& p_anim) if (!(animation==p_anim)) return; - selection.clear(); + //selection.clear(); + _clear_selection(); + } void AnimationKeyEditor::_select_at_anim(const Ref& p_anim,int p_track,float p_pos){ @@ -1244,6 +1491,7 @@ void AnimationKeyEditor::_select_at_anim(const Ref& p_anim,int p_trac ki.pos=p_pos; selection.insert(sk,ki); + } @@ -1283,6 +1531,83 @@ PropertyInfo AnimationKeyEditor::_find_hint_for_track(int p_idx) { } +void AnimationKeyEditor::_curve_transition_changed(float p_what) { + + if (selection.size()==0) + return; + if (selection.size()==1) + undo_redo->create_action("Edit Node Curve",true); + else + undo_redo->create_action("Edit Selection Curve",true); + + for(Map::Element *E=selection.front();E;E=E->next()) { + + int track = E->key().track; + int key = E->key().key; + float prev_val = animation->track_get_key_transition(track,key); + undo_redo->add_do_method(animation.ptr(),"track_set_key_transition",track,key,p_what); + undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",track,key,prev_val); + } + + undo_redo->commit_action(); + +} + +void AnimationKeyEditor::_toggle_edit_curves() { + + if (edit_button->is_pressed()) + key_editor_tab->show(); + else + key_editor_tab->hide(); +} + + +bool AnimationKeyEditor::_edit_if_single_selection() { + + if (selection.size()!=1) { + + if (selection.size()==0) { + curve_edit->set_mode(AnimationCurveEdit::MODE_DISABLED); + print_line("disable"); + } else { + + curve_edit->set_mode(AnimationCurveEdit::MODE_MULTIPLE); + curve_edit->set_transition(1.0); + curve_edit->clear_multiples(); + //add all + for(Map::Element *E=selection.front();E;E=E->next()) { + + curve_edit->set_multiple(animation->track_get_key_transition(E->key().track,E->key().key)); + } + print_line("multiple"); + + } + return false; + } + curve_edit->set_mode(AnimationCurveEdit::MODE_SINGLE); + print_line("regular"); + + int idx = selection.front()->key().track; + int key = selection.front()->key().key; + { + + key_edit->animation=animation; + key_edit->track=idx; + key_edit->key_ofs=animation->track_get_key_time(idx,key); + key_edit->hint=_find_hint_for_track(idx); + key_edit->notify_change(); + + curve_edit->set_transition(animation->track_get_key_transition(idx,key)); + + /*key_edit_dialog->set_size( Size2( 200,200) ); + key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20)); + key_edit_dialog->popup();*/ + + } + + return true; + +} void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { @@ -1364,9 +1689,12 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); } + undo_redo->add_do_method(this,"_clear_selection_for_anim",animation); + undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation); undo_redo->commit_action(); - selection.clear(); + //selection.clear(); accept_event(); + _edit_if_single_selection(); } } else if (animation.is_valid() && animation->get_track_count()>0) { @@ -1552,20 +1880,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } - if (mb.mod.command || edit_button->is_pressed()) { - - key_edit->animation=animation; - key_edit->track=idx; - key_edit->key_ofs=animation->track_get_key_time(idx,key); - key_edit->hint=_find_hint_for_track(idx); - - key_edit->notify_change(); - key_edit_dialog->set_size( Size2( 200,200) ); - key_edit_dialog->set_pos( track_editor->get_global_pos() + ofs + mpos +Point2(-100,20)); - key_edit_dialog->popup(); - - } SelectedKey sk; sk.track=idx; @@ -1577,7 +1892,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (!mb.mod.shift && !selection.has(sk)) - selection.clear(); + _clear_selection(); selection.insert(sk,ki); @@ -1588,7 +1903,10 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { selected_track=idx; track_editor->update(); - + if (_edit_if_single_selection() && mb.mod.command) { + edit_button->set_pressed(true); + key_editor_tab->show(); + } } else { //button column int ofsx = size.width - mpos.x; @@ -1824,7 +2142,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (from_track>to_track) { if (!click.shift) - selection.clear(); + _clear_selection(); + _edit_if_single_selection(); break; } @@ -1842,12 +2161,13 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (from_track > tracks_to || to_track < tracks_from) { if (!click.shift) - selection.clear(); + _clear_selection(); + _edit_if_single_selection(); break; } if (!click.shift) - selection.clear(); + _clear_selection(); int higher_track=0x7FFFFFFF; @@ -1880,6 +2200,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } + _edit_if_single_selection(); + } break; case ClickOver::CLICK_MOVE_KEYS: { @@ -1891,8 +2213,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { if (!click.shift) { KeyInfo ki=selection[click.selk]; - selection.clear(); + _clear_selection(); selection[click.selk]=ki; + _edit_if_single_selection(); } break; @@ -2007,6 +2330,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } undo_redo->commit_action(); + _edit_if_single_selection(); } break; default: {} @@ -2348,20 +2672,33 @@ void AnimationKeyEditor::_notification(int p_what) { optimize_dialog->connect("confirmed",this,"_animation_optimize"); menu_track->get_popup()->add_child(tpp); - menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions"); - menu_track->get_popup()->add_separator(); + //menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions"); + //menu_track->get_popup()->add_separator(); menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE); + curve_linear->set_icon(get_icon("CurveLinear","EditorIcons")); + curve_in->set_icon(get_icon("CurveIn","EditorIcons")); + curve_out->set_icon(get_icon("CurveOut","EditorIcons")); + curve_inout->set_icon(get_icon("CurveInOut","EditorIcons")); + curve_outin->set_icon(get_icon("CurveOutIn","EditorIcons")); + curve_constant->set_icon(get_icon("CurveConstant","EditorIcons")); - + curve_linear->connect("pressed",this,"_menu_track",varray(CURVE_SET_LINEAR)); + curve_in->connect("pressed",this,"_menu_track",varray(CURVE_SET_IN)); + curve_out->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUT)); + curve_inout->connect("pressed",this,"_menu_track",varray(CURVE_SET_INOUT)); + curve_outin->connect("pressed",this,"_menu_track",varray(CURVE_SET_OUTIN)); + curve_constant->connect("pressed",this,"_menu_track",varray(CURVE_SET_CONSTANT)); move_up_button->set_icon(get_icon("MoveUp","EditorIcons")); move_down_button->set_icon(get_icon("MoveDown","EditorIcons")); remove_button->set_icon(get_icon("Remove","EditorIcons")); edit_button->set_icon(get_icon("EditKey","EditorIcons")); + edit_button->connect("pressed",this,"_toggle_edit_curves"); loop->set_icon(get_icon("Loop","EditorIcons")); + curve_edit->connect("transition_changed",this,"_curve_transition_changed"); //edit_button->add_color_override("font_color",get_color("font_color","Tree")); //edit_button->add_color_override("font_color_hover",get_color("font_color","Tree")); @@ -2456,6 +2793,17 @@ void AnimationKeyEditor::_update_menu() { updating=false; } +void AnimationKeyEditor::_clear_selection() { + + selection.clear(); + key_edit->animation=Ref(); + key_edit->track=0; + key_edit->key_ofs=0; + key_edit->hint=PropertyInfo(); + key_edit->notify_change(); + +} + void AnimationKeyEditor::set_animation(const Ref& p_anim) { @@ -2466,11 +2814,12 @@ void AnimationKeyEditor::set_animation(const Ref& p_anim) { animation->connect("changed",this,"_update_paths"); timeline_pos=0; - selection.clear(); + _clear_selection(); _update_paths(); _update_menu(); selected_track=-1; + _edit_if_single_selection(); } void AnimationKeyEditor::set_root(Node *p_root) { @@ -2591,6 +2940,7 @@ void AnimationKeyEditor::insert_transform_key(Spatial *p_node,const String& p_su id.value=p_xform; id.type=Animation::TYPE_TRANSFORM; id.query="node '"+p_node->get_name()+"'"; + id.advance=false; //dialog insert @@ -2643,6 +2993,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro id.value=p_value; id.type=Animation::TYPE_VALUE; id.query="property '"+p_property+"'"; + id.advance=false; //dialog insert _query_insert(id); @@ -2650,7 +3001,7 @@ void AnimationKeyEditor::insert_node_value_key(Node* p_node, const String& p_pro } -void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value) { +void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant& p_value,bool p_advance) { ERR_FAIL_COND(!root); //let's build a node path @@ -2696,6 +3047,7 @@ void AnimationKeyEditor::insert_value_key(const String& p_property,const Variant id.value=p_value; id.type=Animation::TYPE_VALUE; id.query="property '"+p_property+"'"; + id.advance=p_advance; //dialog insert _query_insert(id); @@ -2928,13 +3280,31 @@ void AnimationKeyEditor::_insert_delay() { undo_redo->create_action("Anim Insert"); int last_track = animation->get_track_count(); + bool advance=false; while(insert_data.size()) { + if (insert_data.front()->get().advance) + advance=true; last_track=_confirm_insert(insert_data.front()->get(),last_track); insert_data.pop_front(); } undo_redo->commit_action(); + + if (advance) { + float step = animation->get_step(); + if (step==0) + step=1; + + float pos=timeline_pos; + + pos=Math::stepify(pos+step,step); + if (pos>animation->get_length()) + pos=animation->get_length(); + timeline_pos=pos; + track_pos->update(); + emit_signal("timeline_changed",pos); + } insert_queue=false; } @@ -3122,12 +3492,15 @@ void AnimationKeyEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_animation"),&AnimationKeyEditor::set_animation); ObjectTypeDB::bind_method(_MD("_animation_optimize"),&AnimationKeyEditor::_animation_optimize); + ObjectTypeDB::bind_method(_MD("_curve_transition_changed"),&AnimationKeyEditor::_curve_transition_changed); + ObjectTypeDB::bind_method(_MD("_toggle_edit_curves"),&AnimationKeyEditor::_toggle_edit_curves); ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) ); ADD_SIGNAL( MethodInfo("keying_changed" ) ); ADD_SIGNAL( MethodInfo("timeline_changed", PropertyInfo(Variant::REAL,"pos") ) ); ADD_SIGNAL( MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL,"len") ) ); + ADD_SIGNAL( MethodInfo("key_edited", PropertyInfo(Variant::INT,"track"), PropertyInfo(Variant::INT,"key") ) ); } @@ -3219,12 +3592,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h hb->add_child( memnew( VSeparator ) ); - edit_button = memnew( ToolButton ); - edit_button->set_toggle_mode(true); - edit_button->set_focus_mode(FOCUS_NONE); - edit_button->set_disabled(true); - hb->add_child(edit_button); - edit_button->set_tooltip("Enable editing of individual keys by clicking them."); move_up_button = memnew( ToolButton ); hb->add_child(move_up_button); @@ -3247,6 +3614,15 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h remove_button->set_disabled(true); remove_button->set_tooltip("Remove selected track."); + hb->add_child(memnew( VSeparator )); + + edit_button = memnew( ToolButton ); + edit_button->set_toggle_mode(true); + edit_button->set_focus_mode(FOCUS_NONE); + edit_button->set_disabled(true); + + hb->add_child(edit_button); + edit_button->set_tooltip("Enable editing of individual keys by clicking them."); optimize_dialog = memnew( ConfirmationDialog ); add_child(optimize_dialog); @@ -3297,7 +3673,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h // menu->get_popup()->connect("item_pressed",this,"_menu_callback"); ec = memnew (Control); - ec->set_custom_minimum_size(Size2(0,50)); + ec->set_custom_minimum_size(Size2(0,150)); add_child(ec); ec->set_v_size_flags(SIZE_EXPAND_FILL); @@ -3313,6 +3689,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h track_editor->set_focus_mode(Control::FOCUS_ALL); track_editor->set_h_size_flags(SIZE_EXPAND_FILL); + track_pos = memnew( Control ); track_pos->set_area_as_parent_rect(); track_pos->set_ignore_mouse(true); @@ -3325,6 +3702,56 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h v_scroll->connect("value_changed",this,"_scroll_changed"); v_scroll->set_val(0); + key_editor_tab = memnew(TabContainer); + hb->add_child(key_editor_tab); + key_editor_tab->set_custom_minimum_size(Size2(200,0)); + + key_editor = memnew( PropertyEditor ); + key_editor->set_area_as_parent_rect(); + key_editor->hide_top_label(); + key_editor->set_name("Key"); + key_editor_tab->add_child(key_editor); + + key_edit = memnew( AnimationKeyEdit ); + key_edit->undo_redo=undo_redo; + //key_edit->ke_dialog=key_edit_dialog; + key_editor->edit(key_edit); + type_menu = memnew( PopupMenu ); + add_child(type_menu); + for(int i=0;iadd_item(Variant::get_type_name(Variant::Type(i)),i); + type_menu->connect("item_pressed",this,"_create_value_item"); + + VBoxContainer *curve_vb = memnew( VBoxContainer ); + curve_vb->set_name("Transition"); + HBoxContainer *curve_hb = memnew( HBoxContainer ); + curve_vb->add_child(curve_hb); + + curve_linear = memnew( ToolButton ); + curve_linear->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_linear); + curve_in = memnew( ToolButton ); + curve_in->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_in); + curve_out = memnew( ToolButton ); + curve_out->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_out); + curve_inout = memnew( ToolButton ); + curve_inout->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_inout); + curve_outin = memnew( ToolButton ); + curve_outin->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_outin); + curve_constant = memnew( ToolButton ); + curve_constant->set_focus_mode(FOCUS_NONE); + curve_hb->add_child(curve_constant); + + + curve_edit = memnew( AnimationCurveEdit ); + curve_vb->add_child(curve_edit); + curve_edit->set_v_size_flags(SIZE_EXPAND_FILL); + key_editor_tab->add_child(curve_vb); + h_scroll = memnew( HScrollBar ); h_scroll->connect("value_changed",this,"_scroll_changed"); add_child(h_scroll); @@ -3340,7 +3767,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h add_child(track_menu); track_menu->connect("item_pressed",this,"_track_menu_selected"); - + key_editor_tab->hide(); last_idx =1; @@ -3359,24 +3786,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h timeline_pos=0; - key_edit_dialog = memnew( PopupDialog ); - key_editor = memnew( PropertyEditor ); - add_child(key_edit_dialog); - key_editor->set_area_as_parent_rect(); - key_editor->hide_top_label(); - for(int i=0;i<4;i++) - key_editor->set_margin(Margin(i),5); - key_edit_dialog->add_child(key_editor); - - key_edit = memnew( AnimationKeyEdit ); - key_edit->undo_redo=undo_redo; - key_edit->ke_dialog=key_edit_dialog; - key_editor->edit(key_edit); - type_menu = memnew( PopupMenu ); - add_child(type_menu); - for(int i=0;iadd_item(Variant::get_type_name(Variant::Type(i)),i); - type_menu->connect("item_pressed",this,"_create_value_item"); keying=false; insert_frame=0; insert_query=false; diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 885d46cf6c..35053fb6a3 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -37,6 +37,7 @@ #include "scene/gui/scroll_bar.h" #include "scene/gui/tool_button.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/tab_container.h" #include "scene/resources/animation.h" #include "scene/animation/animation_cache.h" @@ -46,6 +47,7 @@ class AnimationKeyEdit; +class AnimationCurveEdit; class AnimationKeyEditor : public VBoxContainer { @@ -86,7 +88,13 @@ class AnimationKeyEditor : public VBoxContainer { TRACK_MENU_SET_ALL_TRANS_OUTIN, TRACK_MENU_NEXT_STEP, TRACK_MENU_PREV_STEP, - TRACK_MENU_OPTIMIZE + TRACK_MENU_OPTIMIZE, + CURVE_SET_LINEAR, + CURVE_SET_IN, + CURVE_SET_OUT, + CURVE_SET_INOUT, + CURVE_SET_OUTIN, + CURVE_SET_CONSTANT }; struct MouseOver { @@ -169,6 +177,14 @@ class AnimationKeyEditor : public VBoxContainer { ToolButton *move_down_button; ToolButton *remove_button; + ToolButton *curve_linear; + ToolButton *curve_in; + ToolButton *curve_out; + ToolButton *curve_inout; + ToolButton *curve_outin; + ToolButton *curve_constant; + + ConfirmationDialog *optimize_dialog; SpinBox *optimize_linear_error; SpinBox *optimize_angular_error; @@ -183,11 +199,11 @@ class AnimationKeyEditor : public VBoxContainer { Control *track_editor; Control *track_pos; + TabContainer *key_editor_tab; ConfirmationDialog *scale_dialog; SpinBox *scale; - PopupDialog *key_edit_dialog; PropertyEditor *key_editor; Ref animation; @@ -203,6 +219,7 @@ class AnimationKeyEditor : public VBoxContainer { AnimationKeyEdit *key_edit; + AnimationCurveEdit *curve_edit; bool inserting; @@ -220,6 +237,7 @@ class AnimationKeyEditor : public VBoxContainer { int track_idx; Variant value; String query; + bool advance; };/* insert_data;*/ bool insert_query; @@ -254,7 +272,7 @@ class AnimationKeyEditor : public VBoxContainer { void _scale(); - + void _clear_selection(); //void _browse_path(); @@ -270,12 +288,15 @@ class AnimationKeyEditor : public VBoxContainer { void _clear_selection_for_anim(const Ref& p_anim); void _select_at_anim(const Ref& p_anim,int p_track,float p_pos); + void _curve_transition_changed(float p_what); PropertyInfo _find_hint_for_track(int p_idx); void _create_value_item(int p_type); void _pane_drag(const Point2& p_delta); + bool _edit_if_single_selection(); + void _toggle_edit_curves(); void _animation_len_update(); void _root_removed(); @@ -296,7 +317,7 @@ public: void set_anim_pos(float p_pos); void insert_node_value_key(Node* p_node, const String& p_property,const Variant& p_value,bool p_only_if_exists=false); - void insert_value_key(const String& p_property,const Variant& p_value); + void insert_value_key(const String& p_property, const Variant& p_value, bool p_advance); void insert_transform_key(Spatial *p_node,const String& p_sub,const Transform& p_xform); AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_history, EditorSelection *p_selection); diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index 8e96123c36..ae083db0ff 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -989,6 +989,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) { void EditorFileSystem::_resource_saved(const String& p_path){ + print_line("resource saved: "+p_path); EditorFileSystem::get_singleton()->update_file(p_path); } diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 56b813344a..7157dbda96 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -2838,9 +2838,9 @@ void EditorNode::_instance_request(const String& p_path){ request_instance_scene(p_path); } -void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value) { +void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value,bool p_advance) { - animation_editor->insert_value_key(p_keyed,p_value); + animation_editor->insert_value_key(p_keyed,p_value,p_advance); } void EditorNode::_transform_keyed(Object *sp,const String& p_sub,const Transform& p_key) { diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index 76e82b5a6b..614cec5bcc 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -348,7 +348,7 @@ class EditorNode : public Node { void _instance_request(const String& p_path); - void _property_keyed(const String& p_keyed,const Variant& p_value); + void _property_keyed(const String& p_keyed, const Variant& p_value, bool p_advance); void _transform_keyed(Object *sp,const String& p_sub,const Transform& p_key); void _update_keying(); diff --git a/tools/editor/icons/icon_curve_constant.png b/tools/editor/icons/icon_curve_constant.png new file mode 100644 index 0000000000..cdeac1785e Binary files /dev/null and b/tools/editor/icons/icon_curve_constant.png differ diff --git a/tools/editor/icons/icon_curve_in.png b/tools/editor/icons/icon_curve_in.png new file mode 100644 index 0000000000..2db202632e Binary files /dev/null and b/tools/editor/icons/icon_curve_in.png differ diff --git a/tools/editor/icons/icon_curve_in_out.png b/tools/editor/icons/icon_curve_in_out.png new file mode 100644 index 0000000000..f4cb593496 Binary files /dev/null and b/tools/editor/icons/icon_curve_in_out.png differ diff --git a/tools/editor/icons/icon_curve_linear.png b/tools/editor/icons/icon_curve_linear.png new file mode 100644 index 0000000000..9467dc97a3 Binary files /dev/null and b/tools/editor/icons/icon_curve_linear.png differ diff --git a/tools/editor/icons/icon_curve_out.png b/tools/editor/icons/icon_curve_out.png new file mode 100644 index 0000000000..c91ade6f4a Binary files /dev/null and b/tools/editor/icons/icon_curve_out.png differ diff --git a/tools/editor/icons/icon_curve_out_in.png b/tools/editor/icons/icon_curve_out_in.png new file mode 100644 index 0000000000..6499fa753e Binary files /dev/null and b/tools/editor/icons/icon_curve_out_in.png differ diff --git a/tools/editor/icons/icon_key_next.png b/tools/editor/icons/icon_key_next.png new file mode 100644 index 0000000000..759008d064 Binary files /dev/null and b/tools/editor/icons/icon_key_next.png differ diff --git a/tools/editor/icons/icon_pause.png b/tools/editor/icons/icon_pause.png index e63661353c..7c0a57003e 100644 Binary files a/tools/editor/icons/icon_pause.png and b/tools/editor/icons/icon_pause.png differ diff --git a/tools/editor/icons/icon_play.png b/tools/editor/icons/icon_play.png index 08cce495a9..d2bd9d310c 100644 Binary files a/tools/editor/icons/icon_play.png and b/tools/editor/icons/icon_play.png differ diff --git a/tools/editor/icons/icon_play_backwards.png b/tools/editor/icons/icon_play_backwards.png new file mode 100644 index 0000000000..8dff5f20e3 Binary files /dev/null and b/tools/editor/icons/icon_play_backwards.png differ diff --git a/tools/editor/icons/icon_play_start.png b/tools/editor/icons/icon_play_start.png new file mode 100644 index 0000000000..5b085aa1ed Binary files /dev/null and b/tools/editor/icons/icon_play_start.png differ diff --git a/tools/editor/icons/icon_play_start_backwards.png b/tools/editor/icons/icon_play_start_backwards.png new file mode 100644 index 0000000000..09afac637c Binary files /dev/null and b/tools/editor/icons/icon_play_start_backwards.png differ diff --git a/tools/editor/icons/icon_stop.png b/tools/editor/icons/icon_stop.png index fd568b61a8..0fd43b403a 100644 Binary files a/tools/editor/icons/icon_stop.png and b/tools/editor/icons/icon_stop.png differ diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp index fee2f4f977..9a93eed969 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.cpp +++ b/tools/editor/plugins/animation_player_editor_plugin.cpp @@ -28,7 +28,8 @@ /*************************************************************************/ #include "animation_player_editor_plugin.h" #include "io/resource_loader.h" - +#include "os/keyboard.h" +#include "tools/editor/editor_settings.h" void AnimationPlayerEditor::_node_removed(Node *p_node) { @@ -100,12 +101,18 @@ void AnimationPlayerEditor::_notification(int p_what) { remove_anim->set_icon( get_icon("Del","EditorIcons") ); edit_anim->set_icon( get_icon("Edit","EditorIcons") ); blend_anim->set_icon( get_icon("Blend","EditorIcons") ); - play->set_icon( get_icon("Play","EditorIcons") ); + play->set_icon( get_icon("PlayStart","EditorIcons") ); + play_from->set_icon( get_icon("Play","EditorIcons") ); + play_bw->set_icon( get_icon("PlayStartBackwards","EditorIcons") ); + play_bw_from->set_icon( get_icon("PlayBackwards","EditorIcons") ); + autoplay_icon=get_icon("AutoPlay","EditorIcons"); stop->set_icon( get_icon("Stop","EditorIcons") ); resource_edit_anim->set_icon( get_icon("EditResource","EditorIcons") ); pin->set_normal_texture(get_icon("Pin","EditorIcons") ); pin->set_pressed_texture( get_icon("PinPressed","EditorIcons") ); + tool_anim->set_icon(get_icon("Tools","EditorIcons")); + tool_anim->get_popup()->connect("item_pressed",this,"_animation_tool_menu"); blend_editor.next->connect("text_changed",this,"_blend_editor_next_changed"); @@ -180,9 +187,82 @@ void AnimationPlayerEditor::_play_pressed() { //unpause //pause->set_pressed(false); } + +void AnimationPlayerEditor::_play_from_pressed() { + + String current; + if (animation->get_selected()>=0 && animation->get_selected()get_item_count()) { + + current = animation->get_item_text( animation->get_selected() ); + } + + if (current!="") { + + float time = player->get_current_animation_pos(); + + if (current==player->get_current_animation() && player->is_playing()) { + + player->stop(); //so it wont blend with itself + } + + player->play( current ); + player->seek(time); + } + + //unstop + stop->set_pressed(false); + //unpause + //pause->set_pressed(false); +} + + +void AnimationPlayerEditor::_play_bw_pressed() { + + String current; + if (animation->get_selected()>=0 && animation->get_selected()get_item_count()) { + + current = animation->get_item_text( animation->get_selected() ); + } + + if (current!="") { + + if (current==player->get_current_animation()) + player->stop(); //so it wont blend with itself + player->play(current,-1,-1,true); + } + + //unstop + stop->set_pressed(false); + //unpause + //pause->set_pressed(false); +} + +void AnimationPlayerEditor::_play_bw_from_pressed() { + + String current; + if (animation->get_selected()>=0 && animation->get_selected()get_item_count()) { + + current = animation->get_item_text( animation->get_selected() ); + } + + if (current!="") { + + float time = player->get_current_animation_pos(); + if (current==player->get_current_animation()) + player->stop(); //so it wont blend with itself + + player->play(current,-1,-1,true); + player->seek(time); + } + + //unstop + stop->set_pressed(false); + //unpause + //pause->set_pressed(false); +} void AnimationPlayerEditor::_stop_pressed() { - player->stop(); + player->stop(false); play->set_pressed(false); stop->set_pressed(true); //pause->set_pressed(false); @@ -598,6 +678,9 @@ void AnimationPlayerEditor::_update_player() { stop->set_disabled(animlist.size()==0); play->set_disabled(animlist.size()==0); + play_bw->set_disabled(animlist.size()==0); + play_bw_from->set_disabled(animlist.size()==0); + play_from->set_disabled(animlist.size()==0); autoplay->set_disabled(animlist.size()==0); duplicate_anim->set_disabled(animlist.size()==0); rename_anim->set_disabled(animlist.size()==0); @@ -877,11 +960,108 @@ void AnimationPlayerEditor::_hide_anim_editors() { } } + +void AnimationPlayerEditor::_animation_tool_menu(int p_option) { + + switch(p_option) { + + case TOOL_COPY_ANIM: { + + if (!animation->get_item_count()) { + error_dialog->set_text("ERROR: No animation to copy!"); + error_dialog->popup_centered_minsize(); + return; + } + + String current = animation->get_item_text(animation->get_selected()); + Ref anim = player->get_animation(current); + //editor->edit_resource(anim); + EditorSettings::get_singleton()->set_resource_clipboard(anim); + + } break; + case TOOL_PASTE_ANIM: { + + Ref anim = EditorSettings::get_singleton()->get_resource_clipboard(); + if (!anim.is_valid()) { + error_dialog->set_text("ERROR: No animation resource on clipboard!"); + error_dialog->popup_centered_minsize(); + return; + } + + String name = anim->get_name(); + if (name=="") { + name="Pasted Animation"; + } + + int idx=1; + String base = name; + while (player->has_animation(name)) { + + idx++; + name=base+" "+itos(idx); + } + + undo_redo->create_action("Paste Animation"); + undo_redo->add_do_method(player,"add_animation",name,anim); + undo_redo->add_undo_method(player,"remove_animation",name); + undo_redo->add_do_method(this,"_animation_player_changed",player); + undo_redo->add_undo_method(this,"_animation_player_changed",player); + undo_redo->commit_action(); + + _select_anim_by_name(name); + + + } break; + case TOOL_EDIT_RESOURCE: { + + if (!animation->get_item_count()) { + error_dialog->set_text("ERROR: No animation to edit!"); + error_dialog->popup_centered_minsize(); + return; + } + + String current = animation->get_item_text(animation->get_selected()); + Ref anim = player->get_animation(current); + editor->edit_resource(anim); + + } break; + + } +} + +void AnimationPlayerEditor::_unhandled_key_input(const InputEvent& p_ev) { + + if (is_visible() && p_ev.type==InputEvent::KEY && p_ev.key.pressed && !p_ev.key.echo && !p_ev.key.mod.alt && !p_ev.key.mod.control && !p_ev.key.mod.meta) { + + switch(p_ev.key.scancode) { + + case KEY_A: { + if (!p_ev.key.mod.shift) + _play_bw_from_pressed(); + else + _play_bw_pressed(); + } break; + case KEY_S: { + _stop_pressed(); + } break; + case KEY_D: { + if (!p_ev.key.mod.shift) + _play_from_pressed(); + else + _play_pressed(); + } break; + } + } +} + void AnimationPlayerEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&AnimationPlayerEditor::_input_event); ObjectTypeDB::bind_method(_MD("_node_removed"),&AnimationPlayerEditor::_node_removed); ObjectTypeDB::bind_method(_MD("_play_pressed"),&AnimationPlayerEditor::_play_pressed); + ObjectTypeDB::bind_method(_MD("_play_from_pressed"),&AnimationPlayerEditor::_play_from_pressed); + ObjectTypeDB::bind_method(_MD("_play_bw_pressed"),&AnimationPlayerEditor::_play_bw_pressed); + ObjectTypeDB::bind_method(_MD("_play_bw_from_pressed"),&AnimationPlayerEditor::_play_bw_from_pressed); ObjectTypeDB::bind_method(_MD("_stop_pressed"),&AnimationPlayerEditor::_stop_pressed); ObjectTypeDB::bind_method(_MD("_autoplay_pressed"),&AnimationPlayerEditor::_autoplay_pressed); ObjectTypeDB::bind_method(_MD("_pause_pressed"),&AnimationPlayerEditor::_pause_pressed); @@ -908,6 +1088,8 @@ void AnimationPlayerEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_hide_anim_editors"),&AnimationPlayerEditor::_hide_anim_editors); ObjectTypeDB::bind_method(_MD("_animation_duplicate"),&AnimationPlayerEditor::_animation_duplicate); ObjectTypeDB::bind_method(_MD("_blend_editor_next_changed"),&AnimationPlayerEditor::_blend_editor_next_changed); + ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&AnimationPlayerEditor::_unhandled_key_input); + ObjectTypeDB::bind_method(_MD("_animation_tool_menu"),&AnimationPlayerEditor::_animation_tool_menu); @@ -935,47 +1117,56 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { add_child(hb); - add_anim = memnew( Button ); + add_anim = memnew( ToolButton ); add_anim->set_tooltip("Create new animation in player."); hb->add_child(add_anim); - - load_anim = memnew( Button ); + load_anim = memnew( ToolButton ); load_anim->set_tooltip("Load an animation from disk."); hb->add_child(load_anim); - duplicate_anim = memnew( Button ); + duplicate_anim = memnew( ToolButton ); hb->add_child(duplicate_anim); duplicate_anim->set_tooltip("Duplicate Animation"); + rename_anim = memnew( ToolButton ); + hb->add_child(rename_anim); + rename_anim->set_tooltip("Rename Animation"); + + remove_anim = memnew( ToolButton ); + + hb->add_child(remove_anim); + remove_anim->set_tooltip("Remove Animation"); + + animation = memnew( OptionButton ); hb->add_child(animation); animation->set_h_size_flags(SIZE_EXPAND_FILL); animation->set_tooltip("Display list of animations in player."); - autoplay = memnew( Button ); + autoplay = memnew( ToolButton ); hb->add_child(autoplay); autoplay->set_tooltip("Autoplay On Load"); - rename_anim = memnew( Button ); - hb->add_child(rename_anim); - rename_anim->set_tooltip("Rename Animation"); - - remove_anim = memnew( Button ); - - hb->add_child(remove_anim); - remove_anim->set_tooltip("Remove Animation"); - blend_anim = memnew( Button ); + blend_anim = memnew( ToolButton ); hb->add_child(blend_anim); blend_anim->set_tooltip("Edit Target Blend Times"); + tool_anim = memnew( MenuButton); + //tool_anim->set_flat(false); + tool_anim->set_tooltip("Animation Tools"); + tool_anim->get_popup()->add_item("Copy Animation",TOOL_COPY_ANIM); + tool_anim->get_popup()->add_item("Paste Animation",TOOL_PASTE_ANIM); + //tool_anim->get_popup()->add_separator(); + //tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM); + hb->add_child(tool_anim); - edit_anim = memnew( Button ); + edit_anim = memnew( ToolButton ); edit_anim->set_toggle_mode(true); hb->add_child(edit_anim); edit_anim->set_tooltip("Open animation editor.\nProperty editor will displays all editable keys too."); @@ -984,15 +1175,29 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { hb = memnew (HBoxContainer); add_child(hb); - play = memnew( Button ); - play->set_tooltip("Play selected animation."); + play_bw_from = memnew( ToolButton ); + play_bw_from->set_tooltip("Play backwards selected animation from current pos. (A)"); + hb->add_child(play_bw_from); - hb->add_child(play); + play_bw = memnew( ToolButton ); + play_bw->set_tooltip("Play backwards selected animation from end. (Shift+A)"); + hb->add_child(play_bw); - stop = memnew( Button ); + stop = memnew( ToolButton ); stop->set_toggle_mode(true); hb->add_child(stop); - play->set_tooltip("Stop animation playback."); + stop->set_tooltip("Stop animation playback. (S)"); + + play = memnew( ToolButton ); + play->set_tooltip("Play selected animation from start. (Shift+D)"); + hb->add_child(play); + + + play_from = memnew( ToolButton ); + play_from->set_tooltip("Play selected animation from current pos. (D)"); + hb->add_child(play_from); + + //pause = memnew( Button ); //pause->set_toggle_mode(true); @@ -1024,6 +1229,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { resource_edit_anim= memnew( Button ); hb->add_child(resource_edit_anim); + resource_edit_anim->hide(); file = memnew(FileDialog); @@ -1074,7 +1280,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { autoplay->connect("pressed", this,"_autoplay_pressed"); autoplay->set_toggle_mode(true); - play->connect("pressed", this,"_play_pressed"); + play->connect("pressed", this,"_play_pressed"); + play_from->connect("pressed", this,"_play_from_pressed"); + play_bw->connect("pressed", this,"_play_bw_pressed"); + play_bw_from->connect("pressed", this,"_play_bw_from_pressed"); stop->connect("pressed", this,"_stop_pressed"); //pause->connect("pressed", this,"_pause_pressed"); add_anim->connect("pressed", this,"_animation_new"); @@ -1104,6 +1313,8 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { renaming=false; last_active=false; + + set_process_unhandled_key_input(true); } diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h index 380dfd1903..5c9dc6cab8 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.h +++ b/tools/editor/plugins/animation_player_editor_plugin.h @@ -49,10 +49,19 @@ class AnimationPlayerEditor : public VBoxContainer { EditorNode *editor; AnimationPlayer *player; + enum { + TOOL_COPY_ANIM, + TOOL_PASTE_ANIM, + TOOL_EDIT_RESOURCE + }; OptionButton *animation; Button *stop; Button *play; + Button *play_from; + Button *play_bw; + Button *play_bw_from; + // Button *pause; Button *add_anim; Button *autoplay; @@ -63,6 +72,7 @@ class AnimationPlayerEditor : public VBoxContainer { Button *load_anim; Button *blend_anim; Button *remove_anim; + MenuButton *tool_anim; TextureButton *pin; Label *nodename; SpinBox *frame; @@ -95,6 +105,9 @@ class AnimationPlayerEditor : public VBoxContainer { void _select_anim_by_name(const String& p_anim); void _play_pressed(); + void _play_from_pressed(); + void _play_bw_pressed(); + void _play_bw_from_pressed(); void _autoplay_pressed(); void _stop_pressed(); void _pause_pressed(); @@ -126,6 +139,8 @@ class AnimationPlayerEditor : public VBoxContainer { void _animation_key_editor_seek(float p_pos); void _animation_key_editor_anim_len_changed(float p_new); + void _unhandled_key_input(const InputEvent& p_ev); + void _animation_tool_menu(int p_option); AnimationPlayerEditor(); protected: diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 1c6e57beaa..559267dc07 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -2629,7 +2629,12 @@ void PropertyEditor::update_tree() { if (keying) { - item->add_button(1,get_icon("Key","EditorIcons"),2); + if (p.hint==PROPERTY_HINT_SPRITE_FRAME) { + + item->add_button(1,get_icon("KeyNext","EditorIcons"),5); + } else { + item->add_button(1,get_icon("Key","EditorIcons"),2); + } } if (get_instanced_node()) { @@ -2904,6 +2909,16 @@ void PropertyEditor::edit(Object* p_object) { } +void PropertyEditor::_set_range_def(Object *p_item, String prop,float p_frame) { + + TreeItem *ti = p_item->cast_to(); + ERR_FAIL_COND(!ti); + + ti->call_deferred("set_range",1, p_frame); + obj->call_deferred("set",prop,p_frame); + +} + void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { TreeItem *ti = p_item->cast_to(); ERR_FAIL_COND(!ti); @@ -2915,7 +2930,15 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { if (!d.has("name")) return; String prop=d["name"]; - emit_signal("property_keyed",prop,obj->get(prop)); + emit_signal("property_keyed",prop,obj->get(prop),false); + } else if (p_button==5) { + print_line("PB5"); + if (!d.has("name")) + return; + String prop=d["name"]; + emit_signal("property_keyed",prop,obj->get(prop),true); + //set_range(p_column, ti->get_range(p_column)+1.0 ); + call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0); } else if (p_button==3) { if (!get_instanced_node()) @@ -3046,6 +3069,7 @@ void PropertyEditor::_bind_methods() { ObjectTypeDB::bind_method( "_edit_button",&PropertyEditor::_edit_button); ObjectTypeDB::bind_method( "_changed_callback",&PropertyEditor::_changed_callbacks); ObjectTypeDB::bind_method( "_draw_flags",&PropertyEditor::_draw_flags); + ObjectTypeDB::bind_method( "_set_range_def",&PropertyEditor::_set_range_def); ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value"))); ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) ); diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index 7a7354c88e..164643afaa 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -187,6 +187,7 @@ class PropertyEditor : public Control { Node *get_instanced_node(); void _refresh_item(TreeItem *p_item); + void _set_range_def(Object *p_item, String prop, float p_frame); UndoRedo *undo_redo; protected: -- cgit v1.2.3