From bed3efb17ede58a2bfc177b47cb3a49091aea30a Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 14 May 2016 23:48:23 -0300 Subject: [PATCH] New reworked AnimatedSprite! -New SpriteFrames editor, with support for drag&drop, multiple animation sets, animation speed and loop. -New AnimatedSprite, with support for all the new features! AnimatedSprite3D has not been updated yet. -Added support for drag&drop to other editors, such as resourcepreload, sample library, etc. --- core/object.cpp | 5 + core/object.h | 7 +- core/object_type_db.cpp | 12 +- core/object_type_db.h | 2 +- scene/2d/animated_sprite.cpp | 514 +++++++++++++--- scene/2d/animated_sprite.h | 79 ++- scene/2d/visibility_notifier_2d.cpp | 24 + scene/2d/visibility_notifier_2d.h | 1 + scene/3d/sprite_3d.cpp | 14 +- scene/3d/sprite_3d.h | 3 + scene/gui/item_list.cpp | 80 ++- scene/gui/item_list.h | 6 +- scene/gui/tree.cpp | 17 +- scene/gui/tree.h | 5 + scene/scene_string_names.cpp | 2 + scene/scene_string_names.h | 1 + .../resource_preloader_editor_plugin.cpp | 108 ++++ .../resource_preloader_editor_plugin.h | 5 + .../plugins/sample_library_editor_plugin.cpp | 124 ++++ .../plugins/sample_library_editor_plugin.h | 4 + .../plugins/sprite_frames_editor_plugin.cpp | 547 +++++++++++++++--- .../plugins/sprite_frames_editor_plugin.h | 32 +- tools/editor/property_editor.cpp | 1 + 23 files changed, 1400 insertions(+), 193 deletions(-) diff --git a/core/object.cpp b/core/object.cpp index 7bdec06c1be..ee4b5e288c7 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -463,6 +463,11 @@ void Object::get_property_list(List *p_list,bool p_reversed) const } } + +void Object::_validate_property(PropertyInfo& property) const { + +} + void Object::get_method_list(List *p_list) const { ObjectTypeDB::get_method_list(get_type_name(),p_list); diff --git a/core/object.h b/core/object.h index dcebf9b2a29..c34440100f4 100644 --- a/core/object.h +++ b/core/object.h @@ -274,12 +274,12 @@ virtual void _get_property_listv(List *p_list,bool p_reversed) con }\ p_list->push_back( PropertyInfo(Variant::NIL,get_type_static(),PROPERTY_HINT_NONE,String(),PROPERTY_USAGE_CATEGORY));\ if (!_is_gpl_reversed())\ - ObjectTypeDB::get_property_list(#m_type,p_list,true);\ + ObjectTypeDB::get_property_list(#m_type,p_list,true,this);\ if (m_type::_get_get_property_list() != m_inherits::_get_get_property_list()) {\ _get_property_list(p_list);\ }\ if (_is_gpl_reversed())\ - ObjectTypeDB::get_property_list(#m_type,p_list,true);\ + ObjectTypeDB::get_property_list(#m_type,p_list,true,this);\ if (p_reversed) {\ m_inherits::_get_property_listv(p_list,p_reversed);\ }\ @@ -462,6 +462,9 @@ protected: void _clear_internal_resource_paths(const Variant &p_var); +friend class ObjectTypeDB; + virtual void _validate_property(PropertyInfo& property) const; + public: //should be protected, but bug in clang++ static void initialize_type(); _FORCE_INLINE_ static void register_custom_data_to_otdb() {}; diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index 14b595d61b0..5f97df39a61 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -619,14 +619,22 @@ void ObjectTypeDB::add_property(StringName p_type,const PropertyInfo& p_pinfo, c } -void ObjectTypeDB::get_property_list(StringName p_type,List *p_list,bool p_no_inheritance) { +void ObjectTypeDB::get_property_list(StringName p_type, List *p_list, bool p_no_inheritance,const Object *p_validator) { TypeInfo *type=types.getptr(p_type); TypeInfo *check=type; while(check) { for(List::Element *E=type->property_list.front();E;E=E->next()) { - p_list->push_back(E->get()); + + + if (p_validator) { + PropertyInfo pi = E->get(); + p_validator->_validate_property(pi); + p_list->push_back(pi); + } else { + p_list->push_back(E->get()); + } } if (p_no_inheritance) diff --git a/core/object_type_db.h b/core/object_type_db.h index a4896fff819..8313091acd7 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -456,7 +456,7 @@ public: static void get_signal_list(StringName p_type,List *p_signals,bool p_no_inheritance=false); static void add_property(StringName p_type,const PropertyInfo& p_pinfo, const StringName& p_setter, const StringName& p_getter, int p_index=-1); - static void get_property_list(StringName p_type,List *p_list,bool p_no_inheritance=false); + static void get_property_list(StringName p_type, List *p_list, bool p_no_inheritance=false, const Object *p_validator=NULL); static bool set_property(Object* p_object, const StringName& p_property, const Variant& p_value, bool *r_valid=NULL); static bool get_property(Object* p_object,const StringName& p_property, Variant& r_value); static Variant::Type get_property_type(const StringName& p_type, const StringName& p_property,bool *r_is_valid=NULL); diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 1ed508aed3b..f482f775c42 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -29,6 +29,245 @@ #include "animated_sprite.h" #include "scene/scene_string_names.h" #include "os/os.h" +#include "scene/scene_string_names.h" + + + + +//////////////////////////// + + + +void SpriteFrames::add_frame(const StringName &p_anim, const Ref& p_frame, int p_at_pos) { + + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + + if (p_at_pos>=0 && p_at_posget().frames.size()) + E->get().frames.insert(p_at_pos,p_frame); + else + E->get().frames.push_back(p_frame); + + emit_changed(); +} + +int SpriteFrames::get_frame_count(const StringName &p_anim) const { + const Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,0); + + return E->get().frames.size(); +} + +void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { + + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + + E->get().frames.remove(p_idx); + emit_changed(); +} +void SpriteFrames::clear(const StringName &p_anim) { + + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + + E->get().frames.clear(); + emit_changed(); +} + +void SpriteFrames::clear_all() { + + animations.clear(); + add_animation("default"); +} + + + +void SpriteFrames::add_animation(const StringName& p_anim) { + + ERR_FAIL_COND(animations.has(p_anim)); + + animations[p_anim]=Anim(); +} + +bool SpriteFrames::has_animation(const StringName& p_anim) const{ + + return animations.has(p_anim); +} +void SpriteFrames::remove_animation(const StringName& p_anim){ + + animations.erase(p_anim); +} + +void SpriteFrames::rename_animation(const StringName& p_prev,const StringName& p_next) { + + ERR_FAIL_COND(!animations.has(p_prev)); + ERR_FAIL_COND(animations.has(p_next)); + + Anim anim = animations[p_prev]; + animations.erase(p_prev); + animations[p_next]=anim; + +} + +Vector SpriteFrames::_get_animation_list() const { + + Vector ret; + List al; + get_animation_list(&al); + for(List::Element *E=al.front();E;E=E->next()) { + + ret.push_back(E->get()); + } + + return ret; +} + +void SpriteFrames::get_animation_list(List *r_animations) const{ + + for (const Map::Element *E=animations.front();E;E=E->next()) { + r_animations->push_back(E->key()); + } +} + +void SpriteFrames::set_animation_speed(const StringName& p_anim,float p_fps){ + + ERR_FAIL_COND(p_fps<0); + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + E->get().speed=p_fps; +} +float SpriteFrames::get_animation_speed(const StringName& p_anim) const{ + + const Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,0); + return E->get().speed; +} + +void SpriteFrames::set_animation_loop(const StringName& p_anim,bool p_loop){ + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + E->get().loop=p_loop; +} +bool SpriteFrames::get_animation_loop(const StringName& p_anim) const{ + const Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,false); + return E->get().loop; + +} + +void SpriteFrames::_set_frames(const Array& p_frames) { + + clear_all(); + Map::Element *E=animations.find(SceneStringNames::get_singleton()->_default); + ERR_FAIL_COND(!E); + + E->get().frames.resize(p_frames.size()); + for(int i=0;iget().frames.size();i++) + E->get().frames[i]=p_frames[i]; + +} +Array SpriteFrames::_get_frames() const { + + return Array(); +} + +Array SpriteFrames::_get_animations() const { + + Array anims; + for (Map::Element *E=animations.front();E;E=E->next()) { + Dictionary d; + d["name"]=E->key(); + d["speed"]=E->get().speed; + d["loop"]=E->get().loop; + Array frames; + for(int i=0;iget().frames.size();i++) { + frames.push_back(E->get().frames[i]); + } + d["frames"]=frames; + anims.push_back(d); + } + + return anims; +} +void SpriteFrames::_set_animations(const Array& p_animations) { + + animations.clear(); + for(int i=0;i_default); + +} + + + + + void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { @@ -45,100 +284,122 @@ bool AnimatedSprite::edit_has_pivot() const { } -void SpriteFrames::add_frame(const Ref& p_frame,int p_at_pos) { +void AnimatedSprite::_validate_property(PropertyInfo& property) const { - if (p_at_pos>=0 && p_at_pos names; + frames->get_animation_list(&names); + names.sort_custom(); -int SpriteFrames::get_frame_count() const { + bool current_found=false; - return frames.size(); -} + for (List::Element *E=names.front();E;E=E->next()) { + if (E->prev()) { + property.hint_string+=","; + } -void SpriteFrames::remove_frame(int p_idx) { + property.hint_string+=String(E->get()); + if (animation==E->get()) { + current_found=true; + } + } - frames.remove(p_idx); - emit_changed(); -} -void SpriteFrames::clear() { - - frames.clear(); - emit_changed(); -} + if (!current_found) { + if (property.hint_string==String()) { + property.hint_string=String(animation); + } else { + property.hint_string=String(animation)+","+property.hint_string; + } + } + } -Array SpriteFrames::_get_frames() const { + if (property.name=="frame") { - Array arr; - arr.resize(frames.size()); - for(int i=0;ihas_animation(animation)) { + property.hint_string="0,"+itos(frames->get_frame_count(animation)-1)+",1"; + } else { + property.hint_string="0,0,0"; + } + } } - -void SpriteFrames::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("add_frame","frame","atpos"),&SpriteFrames::add_frame,DEFVAL(-1)); - ObjectTypeDB::bind_method(_MD("get_frame_count"),&SpriteFrames::get_frame_count); - ObjectTypeDB::bind_method(_MD("get_frame","idx"),&SpriteFrames::get_frame); - ObjectTypeDB::bind_method(_MD("set_frame","idx","txt"),&SpriteFrames::set_frame); - ObjectTypeDB::bind_method(_MD("remove_frame","idx"),&SpriteFrames::remove_frame); - ObjectTypeDB::bind_method(_MD("clear"),&SpriteFrames::clear); - - ObjectTypeDB::bind_method(_MD("_set_frames"),&SpriteFrames::_set_frames); - ObjectTypeDB::bind_method(_MD("_get_frames"),&SpriteFrames::_get_frames); - - ADD_PROPERTYNZ( PropertyInfo(Variant::ARRAY,"frames",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_frames"),_SCS("_get_frames")); - -} - - - - -SpriteFrames::SpriteFrames() { - - -} - - - - - - - -////////////////////////// - - void AnimatedSprite::_notification(int p_what) { switch(p_what) { - - case NOTIFICATION_DRAW: { + case NOTIFICATION_PROCESS: { if (frames.is_null()) return; - - if (frame<0 || frame>=frames->get_frame_count()) + if (!frames->has_animation(animation)) + return; + if (frame<0) return; - Ref texture = frames->get_frame(frame); - if (texture.is_null()) + float speed = frames->get_animation_speed(animation); + if (speed==0) + return; //do nothing + + float remaining = get_process_delta_time(); + + while(remaining) { + + if (timeout<=0) { + + timeout=1.0/speed; + + int fc = frames->get_frame_count(animation); + if (frame>=fc-1) { + if (frames->get_animation_loop(animation)) { + frame=0; + } else { + frame=fc-1; + } + } else { + frame++; + } + + update(); + _change_notify("frame"); + } + + float to_process = MIN(timeout,remaining); + remaining-=to_process; + timeout-=to_process; + } + } break; + + case NOTIFICATION_DRAW: { + + if (frames.is_null()) { + print_line("no draw no faemos"); return; + } + + if (frame<0) { + print_line("no draw frame <0"); + return; + } + + if (!frames->has_animation(animation)) { + print_line("no draw no anim: "+String(animation)); + return; + } + + + + Ref texture = frames->get_frame(animation,frame); + if (texture.is_null()) { + print_line("no draw texture is null"); + return; + } //print_line("DECIDED TO DRAW"); @@ -184,10 +445,14 @@ void AnimatedSprite::set_sprite_frames(const Ref &p_frames) { if (!frames.is_valid()) { frame=0; - } else { set_frame(frame); } + + + + _change_notify(); + _reset_timeout(); update(); } @@ -202,15 +467,23 @@ void AnimatedSprite::set_frame(int p_frame) { if (!frames.is_valid()) { return; } - if (p_frame>=frames->get_frame_count()) - p_frame=frames->get_frame_count()-1; + + if (frames->has_animation(animation)) { + int limit = frames->get_frame_count(animation); + if (p_frame>=limit) + p_frame=limit-1; + + } + if (p_frame<0) p_frame=0; + if (frame==p_frame) return; frame=p_frame; + _reset_timeout(); update(); _change_notify("frame"); emit_signal(SceneStringNames::get_singleton()->frame_changed); @@ -281,11 +554,13 @@ Color AnimatedSprite::get_modulate() const{ Rect2 AnimatedSprite::get_item_rect() const { - if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + if (!frames.is_valid() || !frames->has_animation(animation) || frame<0 || frame>=frames->get_frame_count(animation)) { return Node2D::get_item_rect(); } - Ref t = frames->get_frame(frame); + Ref t; + if (animation) + t = frames->get_frame(animation,frame); if (t.is_null()) return Node2D::get_item_rect(); Size2i s = t->get_size(); @@ -303,14 +578,92 @@ Rect2 AnimatedSprite::get_item_rect() const { void AnimatedSprite::_res_changed() { set_frame(frame); + _change_notify("frame"); + _change_notify("animation"); update(); } +void AnimatedSprite::_set_playing(bool p_playing) { + + if (playing==p_playing) + return; + playing=p_playing; + _reset_timeout(); + set_process(playing); +} + +bool AnimatedSprite::_is_playing() const { + + return playing; +} + +void AnimatedSprite::play(const StringName& p_animation) { + + if (p_animation) + set_animation(p_animation); + _set_playing(true); +} + +void AnimatedSprite::stop(){ + + _set_playing(false); +} + +bool AnimatedSprite::is_playing() const { + + return is_processing(); +} + +void AnimatedSprite::_reset_timeout() { + + if (!playing) + return; + + if (frames.is_valid() && frames->has_animation(animation)) { + float speed = frames->get_animation_speed(animation); + if (speed>0) { + timeout=1.0/speed; + } else { + timeout=0; + } + } else { + timeout=0; + } + +} + +void AnimatedSprite::set_animation(const StringName& p_animation){ + + if (animation==p_animation) + return; + + animation=p_animation; + _reset_timeout(); + set_frame(0); + _change_notify(); + update(); +} +StringName AnimatedSprite::get_animation() const{ + + return animation; +} + void AnimatedSprite::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_sprite_frames","sprite_frames:SpriteFrames"),&AnimatedSprite::set_sprite_frames); ObjectTypeDB::bind_method(_MD("get_sprite_frames:SpriteFrames"),&AnimatedSprite::get_sprite_frames); + ObjectTypeDB::bind_method(_MD("set_animation","animation"),&AnimatedSprite::set_animation); + ObjectTypeDB::bind_method(_MD("get_animation"),&AnimatedSprite::get_animation); + + ObjectTypeDB::bind_method(_MD("_set_playing","playing"),&AnimatedSprite::_set_playing); + ObjectTypeDB::bind_method(_MD("_is_playing"),&AnimatedSprite::_is_playing); + + ObjectTypeDB::bind_method(_MD("play","anim"),&AnimatedSprite::play,DEFVAL(StringName())); + ObjectTypeDB::bind_method(_MD("stop"),&AnimatedSprite::stop); + ObjectTypeDB::bind_method(_MD("is_playing"),&AnimatedSprite::is_playing); + ObjectTypeDB::bind_method(_MD("set_centered","centered"),&AnimatedSprite::set_centered); ObjectTypeDB::bind_method(_MD("is_centered"),&AnimatedSprite::is_centered); @@ -335,7 +688,9 @@ 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_PROPERTY( PropertyInfo( Variant::STRING, "animation"), _SCS("set_animation"),_SCS("get_animation")); ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "playing"), _SCS("_set_playing"),_SCS("_is_playing")); ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); @@ -351,9 +706,10 @@ AnimatedSprite::AnimatedSprite() { vflip=false; frame=0; - - + playing=false; + animation="default"; modulate=Color(1,1,1,1); + timeout=0; } diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index da4f1b99af4..bbf9c7aafb6 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -37,23 +37,69 @@ class SpriteFrames : public Resource { OBJ_TYPE(SpriteFrames,Resource); - Vector< Ref > frames; + struct Anim { + + float speed; + bool loop; + Vector< Ref > frames; + + Anim() { loop=true; speed=5; } + }; + + Map animations; Array _get_frames() const; void _set_frames(const Array& p_frames); + + Array _get_animations() const; + void _set_animations(const Array& p_animations); + + Vector _get_animation_list() const; + protected: static void _bind_methods(); public: + void add_animation(const StringName& p_anim); + bool has_animation(const StringName& p_anim) const; + void remove_animation(const StringName& p_anim); + void rename_animation(const StringName& p_prev,const StringName& p_next); + + void get_animation_list(List *r_animations) const; + + void set_animation_speed(const StringName& p_anim,float p_fps); + float get_animation_speed(const StringName& p_anim) const; + + void set_animation_loop(const StringName& p_anim,bool p_loop); + bool get_animation_loop(const StringName& p_anim) const; + + void add_frame(const StringName& p_anim,const Ref& p_frame,int p_at_pos=-1); + int get_frame_count(const StringName& p_anim) const; + _FORCE_INLINE_ Ref get_frame(const StringName& p_anim,int p_idx) const { + + const Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,Ref()); + ERR_FAIL_COND_V(p_idx<0,Ref()); + if (p_idx>=E->get().frames.size()) + return Ref(); + + return E->get().frames[p_idx]; + } + + void set_frame(const StringName& p_anim,int p_idx,const Ref& p_frame){ + Map::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(p_idx<0); + if (p_idx>=E->get().frames.size()) + return; + E->get().frames[p_idx]=p_frame; + } + void remove_frame(const StringName& p_anim,int p_idx); + void clear(const StringName& p_anim); + void clear_all(); - void add_frame(const Ref& p_frame,int p_at_pos=-1); - int get_frame_count() const; - _FORCE_INLINE_ Ref get_frame(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,frames.size(),Ref()); return frames[p_idx]; } - void set_frame(int p_idx,const Ref& p_frame){ ERR_FAIL_INDEX(p_idx,frames.size()); frames[p_idx]=p_frame; } - void remove_frame(int p_idx); - void clear(); SpriteFrames(); @@ -66,21 +112,32 @@ class AnimatedSprite : public Node2D { OBJ_TYPE(AnimatedSprite,Node2D); Ref frames; + bool playing; + StringName animation; int frame; bool centered; Point2 offset; + float timeout; + bool hflip; bool vflip; Color modulate; void _res_changed(); + + void _reset_timeout(); + void _set_playing(bool p_playing); + bool _is_playing() const; + + protected: static void _bind_methods(); void _notification(int p_what); + virtual void _validate_property(PropertyInfo& property) const; public: @@ -92,6 +149,13 @@ public: void set_sprite_frames(const Ref &p_frames); Ref get_sprite_frames() const; + void play(const StringName& p_animation=StringName()); + void stop(); + bool is_playing() const; + + void set_animation(const StringName& p_animation); + StringName get_animation() const; + void set_frame(int p_frame); int get_frame() const; @@ -116,4 +180,5 @@ public: AnimatedSprite(); }; + #endif // ANIMATED_SPRITE_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 60fa7f69c8b..426e86fa13a 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -30,6 +30,7 @@ #include "scene/scene_string_names.h" #include "scene/2d/physics_body_2d.h" +#include "scene/2d/animated_sprite.h" #include "scene/animation/animation_player.h" #include "scene/scene_string_names.h" #include "particles_2d.h" @@ -204,6 +205,16 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) { } + if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) { + + AnimatedSprite *as = p_node->cast_to(); + if (as) { + add=true; + } + + } + + if (enabler[ENABLER_PAUSE_PARTICLES]) { Particles2D *ps = p_node->cast_to(); @@ -301,6 +312,17 @@ void VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) { ap->set_active(p_enabled); } } + { + AnimatedSprite *as=p_node->cast_to(); + + if (as) { + + if (p_enabled) + as->play(); + else + as->stop(); + } + } { Particles2D *ps=p_node->cast_to(); @@ -333,12 +355,14 @@ void VisibilityEnabler2D::_bind_methods(){ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS ); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_particles"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_PARTICLES); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animated_sprites"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATED_SPRITES); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_PROCESS); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/fixed_process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_FIXED_PROCESS); BIND_CONSTANT( ENABLER_FREEZE_BODIES ); BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS ); BIND_CONSTANT( ENABLER_PAUSE_PARTICLES ); + BIND_CONSTANT( ENABLER_PAUSE_ANIMATED_SPRITES ); BIND_CONSTANT( ENABLER_PARENT_PROCESS ); BIND_CONSTANT( ENABLER_PARENT_FIXED_PROCESS ); BIND_CONSTANT( ENABLER_MAX); diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index 6ec24fd4d0a..647a5b6e910 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -76,6 +76,7 @@ public: ENABLER_PAUSE_PARTICLES, ENABLER_PARENT_PROCESS, ENABLER_PARENT_FIXED_PROCESS, + ENABLER_PAUSE_ANIMATED_SPRITES, ENABLER_MAX }; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index c7d1249a07c..da83e9b6d20 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -606,11 +606,11 @@ void AnimatedSprite3D::_draw() { RID immediate = get_immediate(); VS::get_singleton()->immediate_clear(immediate); - if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + if (!frames.is_valid() || !frames->get_frame_count(animation) || frame<0 || frame>=frames->get_frame_count(animation)) { return; } - Ref texture = frames->get_frame(frame); + Ref texture = frames->get_frame(animation,frame); if (!texture.is_valid()) return; //no texuture no life Vector2 tsize = texture->get_size(); @@ -748,7 +748,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref& p_sprite_frame if (frames.is_valid()) frames->connect("changed",this,"_queue_update"); - if (!frames.is_valid() || frame >=frames->get_frame_count()) { + if (!frames.is_valid() || frame >=frames->get_frame_count(animation)) { frame=0; } @@ -766,7 +766,7 @@ void AnimatedSprite3D::set_frame(int p_frame){ if (frames.is_null()) return; - ERR_FAIL_INDEX(p_frame,frames->get_frame_count()); + ERR_FAIL_INDEX(p_frame,frames->get_frame_count(animation)); if (frame==p_frame) return; @@ -783,11 +783,11 @@ int AnimatedSprite3D::get_frame() const{ Rect2 AnimatedSprite3D::get_item_rect() const { - if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + if (!frames.is_valid() || !frames->get_frame_count(animation) || frame<0 || frame>=frames->get_frame_count(animation)) { return Rect2(0,0,1,1); } - Ref t = frames->get_frame(frame); + Ref t = frames->get_frame(animation,frame); if (t.is_null()) return Rect2(0,0,1,1); Size2i s = t->get_size(); @@ -806,6 +806,8 @@ Rect2 AnimatedSprite3D::get_item_rect() const { AnimatedSprite3D::AnimatedSprite3D() { + animation="current"; frame=0; } + diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index fe8e1f6ebf4..d8e589556c1 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -158,12 +158,14 @@ public: // ~Sprite3D(); }; + class AnimatedSprite3D : public SpriteBase3D { OBJ_TYPE(AnimatedSprite3D,SpriteBase3D); Ref frames; + StringName animation; int frame; protected: @@ -186,6 +188,7 @@ public: // ~AnimatedSprite3D(); }; + VARIANT_ENUM_CAST(SpriteBase3D::DrawFlags); VARIANT_ENUM_CAST(SpriteBase3D::AlphaCutMode); #endif // SPRITE_3D_H diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index bf66a770d3e..7041f86f16d 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -383,6 +383,17 @@ Size2 ItemList::get_min_icon_size() const { return min_icon_size; } + +void ItemList::set_max_icon_size(const Size2& p_size) { + + max_icon_size=p_size; + update(); +} + +Size2 ItemList::get_max_icon_size() const { + + return max_icon_size; +} Size2 ItemList::Item::get_icon_size() const { if (icon.is_null()) @@ -690,6 +701,55 @@ void ItemList::ensure_current_is_visible() { update(); } +static Size2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) { + + if (p_max_size.x<=0) + p_max_size.x=1e20; + if (p_max_size.y<=0) + p_max_size.y=1e20; + + + Size2 new_size; + + if (p_size.x > p_max_size.x) { + + new_size.width=p_max_size.x; + new_size.height=p_size.height * p_max_size.width / p_size.width; + + if (new_size.height > p_max_size.height) { + new_size=Size2(); //invalid + } + } + + + if (p_size.y > p_max_size.y) { + + Size2 new_size2; + new_size2.height=p_max_size.y; + new_size2.width=p_size.width * p_max_size.height / p_size.height; + + if (new_size2.width < p_max_size.width) { + + if (new_size!=Size2()) { + + if (new_size2.x*new_size2.y > new_size.x*new_size.y) { + new_size=new_size2; + } + } else { + new_size=new_size2; + } + } + + } + + if (new_size==Size2()) + return p_size; + else + return new_size; + + +} + void ItemList::_notification(int p_what) { if (p_what==NOTIFICATION_RESIZED) { @@ -752,12 +812,7 @@ void ItemList::_notification(int p_what) { Size2 minsize; if (items[i].icon.is_valid()) { - minsize=items[i].get_icon_size(); - - if (min_icon_size.x!=0) - minsize.x = MAX(minsize.x,min_icon_size.x); - if (min_icon_size.y!=0) - minsize.y = MAX(minsize.y,min_icon_size.y); + minsize=_adjust_to_max_size(items[i].get_icon_size(),max_icon_size); if (items[i].text!="") { if (icon_mode==ICON_MODE_TOP) { @@ -902,7 +957,7 @@ void ItemList::_notification(int p_what) { Vector2 text_ofs; if (items[i].icon.is_valid()) { - Size2 icon_size = items[i].get_icon_size(); + Size2 icon_size = _adjust_to_max_size(items[i].get_icon_size(),max_icon_size); Vector2 icon_ofs; if (min_icon_size!=Vector2()) { @@ -922,7 +977,7 @@ void ItemList::_notification(int p_what) { } if (items[i].icon_region.has_no_area()) - draw_texture(items[i].icon, pos); + draw_texture_rect(items[i].icon, Rect2(pos,icon_size) ); else draw_texture_rect_region(items[i].icon, Rect2(pos, icon_size), items[i].icon_region); @@ -1044,7 +1099,7 @@ void ItemList::_scroll_changed(double) { update(); } -int ItemList::get_item_at_pos(const Point2& p_pos) const { +int ItemList::get_item_at_pos(const Point2& p_pos, bool p_exact) const { Vector2 pos=p_pos; Ref bg = get_stylebox("bg"); @@ -1067,7 +1122,7 @@ int ItemList::get_item_at_pos(const Point2& p_pos) const { } float dist = rc.distance_to(pos); - if (distget_item_at_pos(p_point); + if (!ti) + return Variant(); + + String name = ti->get_metadata(0); + + RES res = preloader->get_resource(name); + if (!res.is_valid()) + return Variant(); + + return EditorNode::get_singleton()->drag_resource(res,p_from); + +} + +bool ResourcePreloaderEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const { + + + + Dictionary d = p_data; + + if (!d.has("type")) + return false; + + if (d.has("from") && (Object*)(d["from"])==tree) + return false; + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + return r.is_valid(); + } + + + if (String(d["type"])=="files") { + + Vector files = d["files"]; + + if (files.size()==0) + return false; + + return true; + + } + return false; +} + +void ResourcePreloaderEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) { + + if (!can_drop_data_fw(p_point,p_data,p_from)) + return; + + Dictionary d = p_data; + + if (!d.has("type")) + return; + + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + if (r.is_valid()) { + + String basename; + if (r->get_name()!="") { + basename=r->get_name(); + } else if (r->get_path().is_resource_file()) { + basename = r->get_path().basename(); + } else { + basename="Resource"; + } + + String name=basename; + int counter=0; + while(preloader->has_resource(name)) { + counter++; + name=basename+"_"+itos(counter); + } + + undo_redo->create_action(TTR("Add Resource")); + undo_redo->add_do_method(preloader,"add_resource",name,r); + undo_redo->add_undo_method(preloader,"remove_resource",name); + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + undo_redo->commit_action(); + } + } + + + if (String(d["type"])=="files") { + + Vector files = d["files"]; + + _files_load_request(files); + } +} + + + void ResourcePreloaderEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&ResourcePreloaderEditor::_input_event); @@ -289,6 +389,13 @@ void ResourcePreloaderEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_delete_confirm_pressed"),&ResourcePreloaderEditor::_delete_confirm_pressed); ObjectTypeDB::bind_method(_MD("_files_load_request"),&ResourcePreloaderEditor::_files_load_request); ObjectTypeDB::bind_method(_MD("_update_library"),&ResourcePreloaderEditor::_update_library); + + + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw); + + } ResourcePreloaderEditor::ResourcePreloaderEditor() { @@ -326,6 +433,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { tree->set_column_expand(1,true); tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_drag_forwarding(this); vbc->add_child(tree); dialog = memnew( AcceptDialog ); diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.h b/tools/editor/plugins/resource_preloader_editor_plugin.h index 0bc94079a5e..4f0cb4be370 100644 --- a/tools/editor/plugins/resource_preloader_editor_plugin.h +++ b/tools/editor/plugins/resource_preloader_editor_plugin.h @@ -67,6 +67,11 @@ class ResourcePreloaderEditor : public PanelContainer { UndoRedo *undo_redo; + Variant get_drag_data_fw(const Point2& p_point,Control* p_from); + bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const; + void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from); + + protected: void _notification(int p_what); void _input_event(InputEvent p_event); diff --git a/tools/editor/plugins/sample_library_editor_plugin.cpp b/tools/editor/plugins/sample_library_editor_plugin.cpp index 0ab45b45c47..8b03c4651d7 100644 --- a/tools/editor/plugins/sample_library_editor_plugin.cpp +++ b/tools/editor/plugins/sample_library_editor_plugin.cpp @@ -290,6 +290,123 @@ void SampleLibraryEditor::edit(Ref p_sample_library) { } +Variant SampleLibraryEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) { + + TreeItem*ti =tree->get_item_at_pos(p_point); + if (!ti) + return Variant(); + + String name = ti->get_metadata(0); + + RES res = sample_library->get_sample(name); + if (!res.is_valid()) + return Variant(); + + return EditorNode::get_singleton()->drag_resource(res,p_from); + + +} + +bool SampleLibraryEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const { + + + + Dictionary d = p_data; + + if (!d.has("type")) + return false; + + if (d.has("from") && (Object*)(d["from"])==tree) + return false; + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + Ref sample = r; + + if (sample.is_valid()) { + + return true; + } + } + + + if (String(d["type"])=="files") { + + Vector files = d["files"]; + + if (files.size()==0) + return false; + + for(int i=0;iget_file_type(file); + + if (ftype!="Sample") { + return false; + } + + } + + return true; + + } + return false; +} + +void SampleLibraryEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) { + + if (!can_drop_data_fw(p_point,p_data,p_from)) + return; + + Dictionary d = p_data; + + if (!d.has("type")) + return; + + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + Ref sample = r; + + if (sample.is_valid()) { + + String basename; + if (sample->get_name()!="") { + basename=sample->get_name(); + } else if (sample->get_path().is_resource_file()) { + basename = sample->get_path().basename(); + } else { + basename="Sample"; + } + + String name=basename; + int counter=0; + while(sample_library->has_sample(name)) { + counter++; + name=basename+"_"+itos(counter); + } + + undo_redo->create_action(TTR("Add Sample")); + undo_redo->add_do_method(sample_library.operator->(),"add_sample",name,sample); + undo_redo->add_undo_method(sample_library.operator->(),"remove_sample",name); + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + undo_redo->commit_action(); + } + } + + + if (String(d["type"])=="files") { + + DVector files = d["files"]; + + _file_load_request(files); + + } + +} void SampleLibraryEditor::_bind_methods() { @@ -301,6 +418,11 @@ void SampleLibraryEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_file_load_request"),&SampleLibraryEditor::_file_load_request); ObjectTypeDB::bind_method(_MD("_update_library"),&SampleLibraryEditor::_update_library); ObjectTypeDB::bind_method(_MD("_button_pressed"),&SampleLibraryEditor::_button_pressed); + + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &SampleLibraryEditor::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &SampleLibraryEditor::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &SampleLibraryEditor::drop_data_fw); + } SampleLibraryEditor::SampleLibraryEditor() { @@ -349,6 +471,8 @@ SampleLibraryEditor::SampleLibraryEditor() { tree->set_column_expand(4,false); tree->set_column_expand(5,false); + tree->set_drag_forwarding(this); + dialog = memnew( ConfirmationDialog ); add_child( dialog ); diff --git a/tools/editor/plugins/sample_library_editor_plugin.h b/tools/editor/plugins/sample_library_editor_plugin.h index b46b9a7f3d0..f9fb184b7c1 100644 --- a/tools/editor/plugins/sample_library_editor_plugin.h +++ b/tools/editor/plugins/sample_library_editor_plugin.h @@ -68,6 +68,10 @@ class SampleLibraryEditor : public Panel { void _button_pressed(Object *p_item,int p_column, int p_id); + Variant get_drag_data_fw(const Point2& p_point,Control* p_from); + bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const; + void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from); + protected: void _notification(int p_what); void _input_event(InputEvent p_event); diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.cpp b/tools/editor/plugins/sprite_frames_editor_plugin.cpp index 796fc23d9a1..b2f10ccaae6 100644 --- a/tools/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/tools/editor/plugins/sprite_frames_editor_plugin.cpp @@ -49,6 +49,9 @@ void SpriteFramesEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { load->set_icon( get_icon("Folder","EditorIcons") ); _delete->set_icon( get_icon("Del","EditorIcons") ); + new_anim->set_icon( get_icon("New","EditorIcons") ); + remove_anim->set_icon( get_icon("Del","EditorIcons") ); + } if (p_what==NOTIFICATION_READY) { @@ -61,8 +64,9 @@ void SpriteFramesEditor::_notification(int p_what) { } } -void SpriteFramesEditor::_file_load_request(const DVector& p_path) { +void SpriteFramesEditor::_file_load_request(const DVector& p_path,int p_at_pos) { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); List< Ref > resources; @@ -85,28 +89,32 @@ void SpriteFramesEditor::_file_load_request(const DVector& p_path) { if (resources.empty()) { - print_line("added frames!"); + //print_line("added frames!"); return; } undo_redo->create_action(TTR("Add Frame")); - int fc=frames->get_frame_count(); + int fc=frames->get_frame_count(edited_anim); + + int count=0; for(List< Ref >::Element *E=resources.front();E;E=E->next() ) { - undo_redo->add_do_method(frames,"add_frame",E->get()); - undo_redo->add_undo_method(frames,"remove_frame",fc++); + undo_redo->add_do_method(frames,"add_frame",edited_anim,E->get(),p_at_pos==-1?-1:p_at_pos+count); + undo_redo->add_undo_method(frames,"remove_frame",edited_anim,p_at_pos==-1?fc:p_at_pos); + count++; } undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); - print_line("added frames!"); + //print_line("added frames!"); } void SpriteFramesEditor::_load_pressed() { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); loading_scene=false; file->clear_filters(); @@ -160,19 +168,21 @@ void SpriteFramesEditor::_item_edited() { void SpriteFramesEditor::_delete_confirm_pressed() { - if (!tree->get_selected()) + ERR_FAIL_COND(!frames->has_animation(edited_anim)); + + if (tree->get_current()<0) return; sel-=1; - if (sel<0 && frames->get_frame_count()) + if (sel<0 && frames->get_frame_count(edited_anim)) sel=0; - int to_remove = tree->get_selected()->get_metadata(0); + int to_remove = tree->get_current(); sel=to_remove; - Ref r = frames->get_frame(to_remove); + Ref r = frames->get_frame(edited_anim,to_remove); undo_redo->create_action(TTR("Delete Resource")); - undo_redo->add_do_method(frames,"remove_frame",to_remove); - undo_redo->add_undo_method(frames,"add_frame",r,to_remove); + undo_redo->add_do_method(frames,"remove_frame",edited_anim,to_remove); + undo_redo->add_undo_method(frames,"add_frame",edited_anim,r,to_remove); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -182,6 +192,8 @@ void SpriteFramesEditor::_delete_confirm_pressed() { void SpriteFramesEditor::_paste_pressed() { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); + Ref r=EditorSettings::get_singleton()->get_resource_clipboard(); if (!r.is_valid()) { dialog->set_text(TTR("Resource clipboard is empty or not a texture!")); @@ -194,8 +206,8 @@ void SpriteFramesEditor::_paste_pressed() { undo_redo->create_action(TTR("Paste Frame")); - undo_redo->add_do_method(frames,"add_frame",r); - undo_redo->add_undo_method(frames,"remove_frame",frames->get_frame_count()); + undo_redo->add_do_method(frames,"add_frame",edited_anim,r); + undo_redo->add_undo_method(frames,"remove_frame",edited_anim,frames->get_frame_count(edited_anim)); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -204,16 +216,17 @@ void SpriteFramesEditor::_paste_pressed() { void SpriteFramesEditor::_empty_pressed() { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); int from=-1; - if (tree->get_selected()) { + if (tree->get_current()>=0) { - from = tree->get_selected()->get_metadata(0); + from = tree->get_current(); sel=from; } else { - from=frames->get_frame_count(); + from=frames->get_frame_count(edited_anim); } @@ -221,8 +234,8 @@ void SpriteFramesEditor::_empty_pressed() { Ref r; undo_redo->create_action(TTR("Add Empty")); - undo_redo->add_do_method(frames,"add_frame",r,from); - undo_redo->add_undo_method(frames,"remove_frame",from); + undo_redo->add_do_method(frames,"add_frame",edited_anim,r,from); + undo_redo->add_undo_method(frames,"remove_frame",edited_anim,from); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -231,16 +244,17 @@ void SpriteFramesEditor::_empty_pressed() { void SpriteFramesEditor::_empty2_pressed() { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); int from=-1; - if (tree->get_selected()) { + if (tree->get_current()>=0) { - from = tree->get_selected()->get_metadata(0); + from = tree->get_current(); sel=from; } else { - from=frames->get_frame_count(); + from=frames->get_frame_count(edited_anim); } @@ -248,8 +262,8 @@ void SpriteFramesEditor::_empty2_pressed() { Ref r; undo_redo->create_action(TTR("Add Empty")); - undo_redo->add_do_method(frames,"add_frame",r,from+1); - undo_redo->add_undo_method(frames,"remove_frame",from+1); + undo_redo->add_do_method(frames,"add_frame",edited_anim,r,from+1); + undo_redo->add_undo_method(frames,"remove_frame",edited_anim,from+1); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -258,21 +272,24 @@ void SpriteFramesEditor::_empty2_pressed() { void SpriteFramesEditor::_up_pressed() { - if (!tree->get_selected()) + ERR_FAIL_COND(!frames->has_animation(edited_anim)); + + if (tree->get_current()<0) return; - int to_move = tree->get_selected()->get_metadata(0); + + int to_move = tree->get_current(); if (to_move<1) return; sel=to_move; sel-=1; - Ref r = frames->get_frame(to_move); + Ref r = frames->get_frame(edited_anim,to_move); undo_redo->create_action(TTR("Delete Resource")); - undo_redo->add_do_method(frames,"set_frame",to_move,frames->get_frame(to_move-1)); - undo_redo->add_do_method(frames,"set_frame",to_move-1,frames->get_frame(to_move)); - undo_redo->add_undo_method(frames,"set_frame",to_move,frames->get_frame(to_move)); - undo_redo->add_undo_method(frames,"set_frame",to_move-1,frames->get_frame(to_move-1)); + undo_redo->add_do_method(frames,"set_frame",edited_anim,to_move,frames->get_frame(edited_anim,to_move-1)); + undo_redo->add_do_method(frames,"set_frame",edited_anim,to_move-1,frames->get_frame(edited_anim,to_move)); + undo_redo->add_undo_method(frames,"set_frame",edited_anim,to_move,frames->get_frame(edited_anim,to_move)); + undo_redo->add_undo_method(frames,"set_frame",edited_anim,to_move-1,frames->get_frame(edited_anim,to_move-1)); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -281,21 +298,24 @@ void SpriteFramesEditor::_up_pressed() { void SpriteFramesEditor::_down_pressed() { - if (!tree->get_selected()) + ERR_FAIL_COND(!frames->has_animation(edited_anim)); + + if (tree->get_current()<0) return; - int to_move = tree->get_selected()->get_metadata(0); - if (to_move<0 || to_move>=frames->get_frame_count()-1) + + int to_move = tree->get_current(); + if (to_move<0 || to_move>=frames->get_frame_count(edited_anim)-1) return; sel=to_move; sel+=1; - Ref r = frames->get_frame(to_move); + Ref r = frames->get_frame(edited_anim,to_move); undo_redo->create_action(TTR("Delete Resource")); - undo_redo->add_do_method(frames,"set_frame",to_move,frames->get_frame(to_move+1)); - undo_redo->add_do_method(frames,"set_frame",to_move+1,frames->get_frame(to_move)); - undo_redo->add_undo_method(frames,"set_frame",to_move,frames->get_frame(to_move)); - undo_redo->add_undo_method(frames,"set_frame",to_move+1,frames->get_frame(to_move+1)); + undo_redo->add_do_method(frames,"set_frame",edited_anim,to_move,frames->get_frame(edited_anim,to_move+1)); + undo_redo->add_do_method(frames,"set_frame",edited_anim,to_move+1,frames->get_frame(edited_anim,to_move)); + undo_redo->add_undo_method(frames,"set_frame",edited_anim,to_move,frames->get_frame(edited_anim,to_move)); + undo_redo->add_undo_method(frames,"set_frame",edited_anim,to_move+1,frames->get_frame(edited_anim,to_move+1)); undo_redo->add_do_method(this,"_update_library"); undo_redo->add_undo_method(this,"_update_library"); undo_redo->commit_action(); @@ -308,7 +328,7 @@ void SpriteFramesEditor::_down_pressed() { void SpriteFramesEditor::_delete_pressed() { - if (!tree->get_selected()) + if (tree->get_current()<0) return; _delete_confirm_pressed(); //it has undo.. why bother with a dialog.. @@ -323,39 +343,211 @@ void SpriteFramesEditor::_delete_pressed() { } -void SpriteFramesEditor::_update_library() { +void SpriteFramesEditor::_animation_select() { - tree->clear(); - tree->set_hide_root(true); - TreeItem *root = tree->create_item(NULL); + if (updating) + return; - if (sel>=frames->get_frame_count()) - sel=frames->get_frame_count()-1; - else if (sel<0 && frames->get_frame_count()) - sel=0; + TreeItem *selected = animations->get_selected(); + ERR_FAIL_COND(!selected); + edited_anim=selected->get_text(0); + _update_library(true); - for(int i=0;iget_frame_count();i++) { +} - TreeItem *ti = tree->create_item(root); - ti->set_cell_mode(0,TreeItem::CELL_MODE_STRING); - ti->set_selectable(0,true); +void SpriteFramesEditor::_animation_name_edited(){ - if (frames->get_frame(i).is_null()) { + if (updating) + return; - ti->set_text(0,TTR("Frame ")+itos(i)+" (empty)"); + if (!frames->has_animation(edited_anim)) + return; - } else { - ti->set_text(0,TTR("Frame ")+itos(i)+" ("+frames->get_frame(i)->get_name()+")"); - ti->set_icon(0,frames->get_frame(i)); - } - if (frames->get_frame(i).is_valid()) - ti->set_tooltip(0,frames->get_frame(i)->get_path()); - ti->set_metadata(0,i); - ti->set_icon_max_width(0,96); - if (sel==i) - ti->select(0); + TreeItem *edited = animations->get_edited(); + if (!edited) + return; + + String new_name = edited->get_text(0); + + if (new_name==String(edited_anim)) + return; + + new_name=new_name.replace("/","_").replace(","," "); + + String name=new_name; + int counter=0; + while(frames->has_animation(name)) { + counter++; + name=new_name+" "+itos(counter); } + undo_redo->create_action(TTR("Rename Animation")); + undo_redo->add_do_method(frames,"rename_animation",edited_anim,name); + undo_redo->add_undo_method(frames,"rename_animation",name,edited_anim); + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + + edited_anim=new_name; + + undo_redo->commit_action(); + + + +} +void SpriteFramesEditor::_animation_add(){ + + + String new_name = "New Anim"; + + String name=new_name; + int counter=0; + while(frames->has_animation(name)) { + counter++; + name=new_name+" "+itos(counter); + } + + undo_redo->create_action(TTR("Add Animation")); + undo_redo->add_do_method(frames,"add_animation",name); + undo_redo->add_undo_method(frames,"remove_animation",name); + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + + edited_anim=new_name; + + undo_redo->commit_action(); + +} +void SpriteFramesEditor::_animation_remove(){ + + //fuck everything + if (updating) + return; + + if (!frames->has_animation(edited_anim)) + return; + + undo_redo->create_action(TTR("Remove Animation")); + undo_redo->add_do_method(frames,"remove_animation",edited_anim); + undo_redo->add_undo_method(frames,"add_animation",edited_anim); + undo_redo->add_undo_method(frames,"set_animation_speed",edited_anim,frames->get_animation_speed(edited_anim)); + undo_redo->add_undo_method(frames,"set_animation_loop",edited_anim,frames->get_animation_loop(edited_anim)); + int fc = frames->get_frame_count(edited_anim); + for(int i=0;i frame = frames->get_frame(edited_anim,i); + undo_redo->add_undo_method(frames,"add_frame",edited_anim,frame); + } + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + + undo_redo->commit_action(); + +} + + +void SpriteFramesEditor::_animation_loop_changed() { + + if (updating) + return; + + undo_redo->create_action(TTR("Change Animation Loop")); + undo_redo->add_do_method(frames,"set_animation_loop",edited_anim,anim_loop->is_pressed()); + undo_redo->add_undo_method(frames,"set_animation_loop",edited_anim,frames->get_animation_loop(edited_anim)); + undo_redo->add_do_method(this,"_update_library",true); + undo_redo->add_undo_method(this,"_update_library",true); + undo_redo->commit_action(); + +} + +void SpriteFramesEditor::_animation_fps_changed(double p_value) { + + if (updating) + return; + + undo_redo->create_action(TTR("Change Animation FPS"),true); + undo_redo->add_do_method(frames,"set_animation_speed",edited_anim,p_value); + undo_redo->add_undo_method(frames,"set_animation_speed",edited_anim,frames->get_animation_speed(edited_anim)); + undo_redo->add_do_method(this,"_update_library",true); + undo_redo->add_undo_method(this,"_update_library",true); + + undo_redo->commit_action(); + +} + +void SpriteFramesEditor::_update_library(bool p_skip_selector) { + + updating=true; + + if (!p_skip_selector) { + animations->clear(); + + TreeItem *anim_root=animations->create_item(); + + List anim_names; + + anim_names.sort_custom(); + + frames->get_animation_list(&anim_names); + + anim_names.sort_custom(); + + for(List::Element *E=anim_names.front();E;E=E->next()) { + + String name = E->get(); + + TreeItem *it = animations->create_item(anim_root); + + it->set_metadata(0,name); + + it->set_text(0,name); + it->set_editable(0,true); + + if (E->get()==edited_anim) { + it->select(0); + } + } + } + + + tree->clear(); + + if (!frames->has_animation(edited_anim)) { + updating=false; + return; + } + + + if (sel>=frames->get_frame_count(edited_anim)) + sel=frames->get_frame_count(edited_anim)-1; + else if (sel<0 && frames->get_frame_count(edited_anim)) + sel=0; + + for(int i=0;iget_frame_count(edited_anim);i++) { + + + String name; + Ref icon; + + + if (frames->get_frame(edited_anim,i).is_null()) { + + name=itos(i)+TTR(": (empty)"); + + } else { + name=itos(i)+": "+frames->get_frame(edited_anim,i)->get_name(); + icon=frames->get_frame(edited_anim,i); + } + + tree->add_item(name,icon); + if (frames->get_frame(edited_anim,i).is_valid()) + tree->set_item_tooltip(tree->get_item_count()-1,frames->get_frame(edited_anim,i)->get_path()); + if (sel==i) + tree->select(tree->get_item_count()-1); + } + + anim_speed->set_val(frames->get_animation_speed(edited_anim)); + anim_loop->set_pressed(frames->get_animation_loop(edited_anim)); + + updating=false; //player->add_resource("default",resource); } @@ -363,10 +555,27 @@ void SpriteFramesEditor::_update_library() { void SpriteFramesEditor::edit(SpriteFrames* p_frames) { + if (frames==p_frames) + return; + frames=p_frames; if (p_frames) { + + if (!p_frames->has_animation(edited_anim)) { + + List anim_names; + frames->get_animation_list(&anim_names); + anim_names.sort_custom(); + if (anim_names.size()) { + edited_anim=anim_names.front()->get(); + } else { + edited_anim=StringName(); + } + + } + _update_library(); } else { @@ -377,6 +586,110 @@ void SpriteFramesEditor::edit(SpriteFrames* p_frames) { } +Variant SpriteFramesEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) { + + if (!frames->has_animation(edited_anim)) + return false; + + int idx = tree->get_item_at_pos(p_point,true); + + if (idx<0 || idx>=frames->get_frame_count(edited_anim)) + return Variant(); + + RES frame = frames->get_frame(edited_anim,idx); + + if (frame.is_null()) + return Variant(); + + return EditorNode::get_singleton()->drag_resource(frame,p_from); + + +} + +bool SpriteFramesEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{ + + Dictionary d = p_data; + + if (!d.has("type")) + return false; + + if (d.has("from") && (Object*)(d["from"])==tree) + return false; + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + Ref texture = r; + + if (texture.is_valid()) { + + return true; + } + } + + + if (String(d["type"])=="files") { + + Vector files = d["files"]; + + if (files.size()==0) + return false; + + for(int i=0;iget_file_type(file); + + if (!ObjectTypeDB::is_type(ftype,"Texture")) { + return false; + } + + } + + return true; + + } + return false; +} + +void SpriteFramesEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){ + + if (!can_drop_data_fw(p_point,p_data,p_from)) + return; + + Dictionary d = p_data; + + if (!d.has("type")) + return; + + int at_pos = tree->get_item_at_pos(p_point,true); + + if (String(d["type"])=="resource" && d.has("resource")) { + RES r=d["resource"]; + + Ref texture = r; + + if (texture.is_valid()) { + + undo_redo->create_action(TTR("Add Frame")); + undo_redo->add_do_method(frames,"add_frame",edited_anim,texture,at_pos==-1?-1:at_pos); + undo_redo->add_undo_method(frames,"remove_frame",edited_anim,at_pos==-1?frames->get_frame_count(edited_anim):at_pos); + undo_redo->add_do_method(this,"_update_library"); + undo_redo->add_undo_method(this,"_update_library"); + undo_redo->commit_action(); + + } + } + + + if (String(d["type"])=="files") { + + DVector files = d["files"]; + + _file_load_request(files,at_pos); + } + +} + void SpriteFramesEditor::_bind_methods() { @@ -388,29 +701,94 @@ void SpriteFramesEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_delete_pressed"),&SpriteFramesEditor::_delete_pressed); ObjectTypeDB::bind_method(_MD("_paste_pressed"),&SpriteFramesEditor::_paste_pressed); ObjectTypeDB::bind_method(_MD("_delete_confirm_pressed"),&SpriteFramesEditor::_delete_confirm_pressed); - ObjectTypeDB::bind_method(_MD("_file_load_request"),&SpriteFramesEditor::_file_load_request); - ObjectTypeDB::bind_method(_MD("_update_library"),&SpriteFramesEditor::_update_library); + ObjectTypeDB::bind_method(_MD("_file_load_request","files","atpos"),&SpriteFramesEditor::_file_load_request,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("_update_library","skipsel"),&SpriteFramesEditor::_update_library,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("_up_pressed"),&SpriteFramesEditor::_up_pressed); ObjectTypeDB::bind_method(_MD("_down_pressed"),&SpriteFramesEditor::_down_pressed); + ObjectTypeDB::bind_method(_MD("_animation_select"),&SpriteFramesEditor::_animation_select); + ObjectTypeDB::bind_method(_MD("_animation_name_edited"),&SpriteFramesEditor::_animation_name_edited); + ObjectTypeDB::bind_method(_MD("_animation_add"),&SpriteFramesEditor::_animation_add); + ObjectTypeDB::bind_method(_MD("_animation_remove"),&SpriteFramesEditor::_animation_remove); + ObjectTypeDB::bind_method(_MD("_animation_loop_changed"),&SpriteFramesEditor::_animation_loop_changed); + ObjectTypeDB::bind_method(_MD("_animation_fps_changed"),&SpriteFramesEditor::_animation_fps_changed); + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw); + + } + SpriteFramesEditor::SpriteFramesEditor() { //add_style_override("panel", get_stylebox("panel","Panel")); + split = memnew( HSplitContainer ); + add_child(split); + + VBoxContainer *vbc_animlist = memnew( VBoxContainer ); + split->add_child(vbc_animlist); + vbc_animlist->set_custom_minimum_size(Size2(150,0)); + //vbc_animlist->set_v_size_flags(SIZE_EXPAND_FILL); + + + VBoxContainer *sub_vb = memnew( VBoxContainer ); + vbc_animlist->add_margin_child(TTR("Animations"),sub_vb,true); + sub_vb->set_v_size_flags(SIZE_EXPAND_FILL); + + HBoxContainer *hbc_animlist = memnew( HBoxContainer ); + sub_vb->add_child(hbc_animlist); + + new_anim = memnew( Button ); + hbc_animlist->add_child(new_anim); + new_anim->connect("pressed",this,"_animation_add"); + + + hbc_animlist->add_spacer(); + + remove_anim = memnew( Button ); + hbc_animlist->add_child(remove_anim); + remove_anim->connect("pressed",this,"_animation_remove"); + + animations = memnew( Tree ); + sub_vb->add_child(animations); + animations->set_v_size_flags(SIZE_EXPAND_FILL); + animations->set_hide_root(true); + animations->connect("cell_selected",this,"_animation_select"); + animations->connect("item_edited",this,"_animation_name_edited"); + animations->set_single_select_cell_editing_only_when_already_selected(true); + + + anim_speed = memnew( SpinBox); + vbc_animlist->add_margin_child(TTR("Speed (FPS):"),anim_speed); + anim_speed->set_min(0); + anim_speed->set_max(100); + anim_speed->set_step(0.01); + anim_speed->connect("value_changed",this,"_animation_fps_changed"); + + anim_loop = memnew( CheckButton ); + anim_loop->set_text(TTR("Loop")); + vbc_animlist->add_child(anim_loop); + anim_loop->connect("pressed",this,"_animation_loop_changed"); + VBoxContainer *vbc = memnew( VBoxContainer ); - add_child(vbc); + split->add_child(vbc); + vbc->set_h_size_flags(SIZE_EXPAND_FILL); + + sub_vb = memnew( VBoxContainer ); + vbc->add_margin_child(TTR("Animation Frames"),sub_vb,true); + HBoxContainer *hbc = memnew( HBoxContainer ); - vbc->add_child(hbc); + sub_vb->add_child(hbc); + + //animations = memnew( ItemList ); + load = memnew( Button ); load->set_tooltip(TTR("Load Resource")); hbc->add_child(load); - - - paste = memnew( Button ); paste->set_text(TTR("Paste")); hbc->add_child(paste); @@ -438,15 +816,22 @@ SpriteFramesEditor::SpriteFramesEditor() { add_child(file); - tree = memnew( Tree ); - tree->set_columns(2); - tree->set_column_min_width(0,3); - tree->set_column_min_width(1,1); - tree->set_column_expand(0,true); - tree->set_column_expand(1,true); + tree = memnew( ItemList ); tree->set_v_size_flags(SIZE_EXPAND_FILL); + tree->set_icon_mode(ItemList::ICON_MODE_TOP); - vbc->add_child(tree); + int thumbnail_size = 96; + tree->set_max_columns(0); + tree->set_icon_mode(ItemList::ICON_MODE_TOP); + tree->set_fixed_column_width(thumbnail_size*3/2); + tree->set_max_text_lines(2); + tree->set_max_icon_size(Size2(thumbnail_size,thumbnail_size)); + //tree->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); + tree->set_drag_forwarding(this); + + + + sub_vb->add_child(tree); dialog = memnew( AcceptDialog ); add_child( dialog ); @@ -460,10 +845,14 @@ SpriteFramesEditor::SpriteFramesEditor() { move_down->connect("pressed", this,"_down_pressed"); file->connect("files_selected", this,"_file_load_request"); //dialog->connect("confirmed", this,"_delete_confirm_pressed"); - tree->connect("item_edited", this,"_item_edited"); + //tree->connect("item_selected", this,"_item_edited"); loading_scene=false; sel=-1; + updating=false; + + edited_anim="default"; + } diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.h b/tools/editor/plugins/sprite_frames_editor_plugin.h index 5d0a6cb0359..f0aa84c23ab 100644 --- a/tools/editor/plugins/sprite_frames_editor_plugin.h +++ b/tools/editor/plugins/sprite_frames_editor_plugin.h @@ -36,6 +36,7 @@ #include "scene/2d/animated_sprite.h" #include "scene/gui/file_dialog.h" #include "scene/gui/dialogs.h" +#include "scene/gui/split_container.h" class SpriteFramesEditor : public PanelContainer { @@ -49,10 +50,18 @@ class SpriteFramesEditor : public PanelContainer { Button *empty2; Button *move_up; Button *move_down; - Tree *tree; + ItemList *tree; bool loading_scene; int sel; + HSplitContainer *split; + Button *new_anim; + Button *remove_anim; + + + Tree *animations; + SpinBox *anim_speed; + CheckButton *anim_loop; EditorFileDialog *file; @@ -60,10 +69,11 @@ class SpriteFramesEditor : public PanelContainer { SpriteFrames *frames; + StringName edited_anim; void _load_pressed(); void _load_scene_pressed(); - void _file_load_request(const DVector& p_path); + void _file_load_request(const DVector& p_path, int p_at_pos=-1); void _paste_pressed(); void _empty_pressed(); void _empty2_pressed(); @@ -71,11 +81,27 @@ class SpriteFramesEditor : public PanelContainer { void _delete_confirm_pressed(); void _up_pressed(); void _down_pressed(); - void _update_library(); + void _update_library(bool p_skip_selector=false); void _item_edited(); + + + void _animation_select(); + void _animation_name_edited(); + void _animation_add(); + void _animation_remove(); + void _animation_loop_changed(); + void _animation_fps_changed(double p_value); + + bool updating; + UndoRedo *undo_redo; + bool _is_drop_valid(const Dictionary& p_drag_data, const Dictionary& p_item_data) const; + Variant get_drag_data_fw(const Point2& p_point,Control* p_from); + bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const; + void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from); + protected: void _notification(int p_what); void _input_event(InputEvent p_event); diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 6f809101502..c4f54e04cbf 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -2287,6 +2287,7 @@ bool PropertyEditor::_is_drop_valid(const Dictionary& p_drag_data, const Diction } } + if (drag_data.has("type") && String(drag_data["type"])=="files") { Vector files = drag_data["files"];