diff options
39 files changed, 2523 insertions, 470 deletions
diff --git a/core/object.cpp b/core/object.cpp index 7bdec06c1b..ee4b5e288c 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -463,6 +463,11 @@ void Object::get_property_list(List<PropertyInfo> *p_list,bool p_reversed) const } } + +void Object::_validate_property(PropertyInfo& property) const { + +} + void Object::get_method_list(List<MethodInfo> *p_list) const { ObjectTypeDB::get_method_list(get_type_name(),p_list); diff --git a/core/object.h b/core/object.h index dcebf9b2a2..c34440100f 100644 --- a/core/object.h +++ b/core/object.h @@ -274,12 +274,12 @@ virtual void _get_property_listv(List<PropertyInfo> *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 14b595d61b..5f97df39a6 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<PropertyInfo> *p_list,bool p_no_inheritance) { +void ObjectTypeDB::get_property_list(StringName p_type, List<PropertyInfo> *p_list, bool p_no_inheritance,const Object *p_validator) { TypeInfo *type=types.getptr(p_type); TypeInfo *check=type; while(check) { for(List<PropertyInfo>::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 a4896fff81..8313091acd 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<MethodInfo> *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<PropertyInfo> *p_list,bool p_no_inheritance=false); + static void get_property_list(StringName p_type, List<PropertyInfo> *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/doc/base/classes.xml b/doc/base/classes.xml index 13d599778e..43f755d246 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -678,54 +678,79 @@ </methods> <members> <member name="Performance" type="Performance"> + [Performance] singleton </member> <member name="Globals" type="Globals"> + [Globals] singleton </member> <member name="IP" type="IP"> + [IP] singleton </member> <member name="Geometry" type="Geometry"> + [Geometry] singleton </member> <member name="ResourceLoader" type="ResourceLoader"> + [ResourceLoader] singleton </member> <member name="ResourceSaver" type="ResourceSaver"> + [ResourceSaver] singleton </member> <member name="PathRemap" type="PathRemap"> + [PathRemap] singleton </member> <member name="OS" type="OS"> + [OS] singleton </member> <member name="Marshalls" type="Reference"> + [Marshalls] singleton </member> <member name="TranslationServer" type="TranslationServer"> + [TranslationServer] singleton </member> <member name="TS" type="TranslationServer"> + [TranslationServer] singleton </member> <member name="Input" type="Input"> + [Input] singleton </member> <member name="InputMap" type="InputMap"> + [InputMap] singleton </member> <member name="VisualServer" type="VisualServer"> + [VisualServer] singleton </member> <member name="VS" type="VisualServer"> + [VisualServer] singleton </member> <member name="AudioServer" type="AudioServer"> + [AudioServer] singleton </member> <member name="AS" type="AudioServer"> + [AudioServer] singleton </member> <member name="PhysicsServer" type="PhysicsServer"> + [PhysicsServer] singleton </member> <member name="PS" type="PhysicsServer"> + [PhysicsServer] singleton </member> <member name="Physics2DServer" type="Physics2DServer"> + [Physics2DServer] singleton </member> <member name="PS2D" type="Physics2DServer"> + [Physics2DServer] singleton </member> <member name="SpatialSoundServer" type="SpatialSoundServer"> + [SpatialSoundServer] singleton </member> <member name="SS" type="SpatialSoundServer"> + [SpatialSoundServer] singleton </member> <member name="SpatialSound2DServer" type="SpatialSound2DServer"> + [SpatialSound2DServer] singleton </member> <member name="SS2D" type="SpatialSound2DServer"> + [SpatialSound2DServer] singleton </member> </members> <constants> @@ -943,34 +968,45 @@ Number 9 on Numpad </constant> <constant name="KEY_SUPER_L" value="16777260"> + Super Left key (windows key) </constant> <constant name="KEY_SUPER_R" value="16777261"> + Super Left key (windows key) </constant> <constant name="KEY_MENU" value="16777262"> + Context menu key </constant> <constant name="KEY_HYPER_L" value="16777263"> </constant> <constant name="KEY_HYPER_R" value="16777264"> </constant> <constant name="KEY_HELP" value="16777265"> + Help key </constant> <constant name="KEY_DIRECTION_L" value="16777266"> </constant> <constant name="KEY_DIRECTION_R" value="16777267"> </constant> <constant name="KEY_BACK" value="16777280"> + Back key </constant> <constant name="KEY_FORWARD" value="16777281"> + Forward key </constant> <constant name="KEY_STOP" value="16777282"> + Stop key </constant> <constant name="KEY_REFRESH" value="16777283"> + Refresh key </constant> <constant name="KEY_VOLUMEDOWN" value="16777284"> + Volume down key </constant> <constant name="KEY_VOLUMEMUTE" value="16777285"> + Mute volume key </constant> <constant name="KEY_VOLUMEUP" value="16777286"> + Volume up key </constant> <constant name="KEY_BASSBOOST" value="16777287"> </constant> @@ -983,20 +1019,28 @@ <constant name="KEY_TREBLEDOWN" value="16777291"> </constant> <constant name="KEY_MEDIAPLAY" value="16777292"> + Media play key </constant> <constant name="KEY_MEDIASTOP" value="16777293"> + Media stop key </constant> <constant name="KEY_MEDIAPREVIOUS" value="16777294"> + Previous song key </constant> <constant name="KEY_MEDIANEXT" value="16777295"> + Next song key </constant> <constant name="KEY_MEDIARECORD" value="16777296"> + Media record key </constant> <constant name="KEY_HOMEPAGE" value="16777297"> + Home page key </constant> <constant name="KEY_FAVORITES" value="16777298"> + Favorites key </constant> <constant name="KEY_SEARCH" value="16777299"> + Search key </constant> <constant name="KEY_STANDBY" value="16777300"> </constant> @@ -1044,34 +1088,49 @@ Space Key </constant> <constant name="KEY_EXCLAM" value="33"> + ! key </constant> <constant name="KEY_QUOTEDBL" value="34"> + " key </constant> <constant name="KEY_NUMBERSIGN" value="35"> + # key </constant> <constant name="KEY_DOLLAR" value="36"> + $ key </constant> <constant name="KEY_PERCENT" value="37"> + % key </constant> <constant name="KEY_AMPERSAND" value="38"> + & key </constant> <constant name="KEY_APOSTROPHE" value="39"> + ' key </constant> <constant name="KEY_PARENLEFT" value="40"> + ( key </constant> <constant name="KEY_PARENRIGHT" value="41"> + ) key </constant> <constant name="KEY_ASTERISK" value="42"> + * key </constant> <constant name="KEY_PLUS" value="43"> + + key </constant> <constant name="KEY_COMMA" value="44"> + , key </constant> <constant name="KEY_MINUS" value="45"> + - key </constant> <constant name="KEY_PERIOD" value="46"> + . key </constant> <constant name="KEY_SLASH" value="47"> + / key </constant> <constant name="KEY_0" value="48"> Number 0 @@ -1104,18 +1163,25 @@ Number 9 </constant> <constant name="KEY_COLON" value="58"> + : key </constant> <constant name="KEY_SEMICOLON" value="59"> + ; key </constant> <constant name="KEY_LESS" value="60"> + Lower than key </constant> <constant name="KEY_EQUAL" value="61"> + = key </constant> <constant name="KEY_GREATER" value="62"> + Greater than key </constant> <constant name="KEY_QUESTION" value="63"> + ? key </constant> <constant name="KEY_AT" value="64"> + @ key </constant> <constant name="KEY_A" value="65"> A Key @@ -1196,30 +1262,40 @@ Z Key </constant> <constant name="KEY_BRACKETLEFT" value="91"> + [ key </constant> <constant name="KEY_BACKSLASH" value="92"> + \ key </constant> <constant name="KEY_BRACKETRIGHT" value="93"> + ] key </constant> <constant name="KEY_ASCIICIRCUM" value="94"> + ^ key </constant> <constant name="KEY_UNDERSCORE" value="95"> + _ key </constant> <constant name="KEY_QUOTELEFT" value="96"> </constant> <constant name="KEY_BRACELEFT" value="123"> + { key </constant> <constant name="KEY_BAR" value="124"> + | key </constant> <constant name="KEY_BRACERIGHT" value="125"> + } key </constant> <constant name="KEY_ASCIITILDE" value="126"> + ~ key </constant> <constant name="KEY_NOBREAKSPACE" value="160"> </constant> <constant name="KEY_EXCLAMDOWN" value="161"> </constant> <constant name="KEY_CENT" value="162"> + ¢ key </constant> <constant name="KEY_STERLING" value="163"> </constant> @@ -1228,42 +1304,58 @@ <constant name="KEY_YEN" value="165"> </constant> <constant name="KEY_BROKENBAR" value="166"> + ¦ key </constant> <constant name="KEY_SECTION" value="167"> + § key </constant> <constant name="KEY_DIAERESIS" value="168"> + ¨ key </constant> <constant name="KEY_COPYRIGHT" value="169"> + © key </constant> <constant name="KEY_ORDFEMININE" value="170"> </constant> <constant name="KEY_GUILLEMOTLEFT" value="171"> + « key </constant> <constant name="KEY_NOTSIGN" value="172"> + » key </constant> <constant name="KEY_HYPHEN" value="173"> + ‐ key </constant> <constant name="KEY_REGISTERED" value="174"> + ® key </constant> <constant name="KEY_MACRON" value="175"> </constant> <constant name="KEY_DEGREE" value="176"> + ° key </constant> <constant name="KEY_PLUSMINUS" value="177"> + ± key </constant> <constant name="KEY_TWOSUPERIOR" value="178"> + ² key </constant> <constant name="KEY_THREESUPERIOR" value="179"> + ³ key </constant> <constant name="KEY_ACUTE" value="180"> + ´ key </constant> <constant name="KEY_MU" value="181"> + µ key </constant> <constant name="KEY_PARAGRAPH" value="182"> </constant> <constant name="KEY_PERIODCENTERED" value="183"> + · key </constant> <constant name="KEY_CEDILLA" value="184"> + ¬ key </constant> <constant name="KEY_ONESUPERIOR" value="185"> </constant> @@ -1274,6 +1366,7 @@ <constant name="KEY_ONEQUARTER" value="188"> </constant> <constant name="KEY_ONEHALF" value="189"> + ½ key </constant> <constant name="KEY_THREEQUARTERS" value="190"> </constant> @@ -1375,12 +1468,16 @@ Middle Mouse Button </constant> <constant name="BUTTON_WHEEL_UP" value="4"> + Mouse wheel up </constant> <constant name="BUTTON_WHEEL_DOWN" value="5"> + Mouse wheel down </constant> <constant name="BUTTON_WHEEL_LEFT" value="6"> + Mouse wheel left button </constant> <constant name="BUTTON_WHEEL_RIGHT" value="7"> + Mouse wheel right button </constant> <constant name="BUTTON_MASK_LEFT" value="1"> </constant> @@ -1440,36 +1537,52 @@ Joystick Button 16 </constant> <constant name="JOY_SNES_A" value="1"> + Super Nintendo Entertaiment System controller A button </constant> <constant name="JOY_SNES_B" value="0"> + Super Nintendo Entertaiment System controller B button </constant> <constant name="JOY_SNES_X" value="3"> + Super Nintendo Entertaiment System controller X button </constant> <constant name="JOY_SNES_Y" value="2"> + Super Nintendo Entertaiment System controller Y button </constant> <constant name="JOY_SONY_CIRCLE" value="1"> + DUALSHOCK circle button </constant> <constant name="JOY_SONY_X" value="0"> + DUALSHOCK X button </constant> <constant name="JOY_SONY_SQUARE" value="2"> + DUALSHOCK square button </constant> <constant name="JOY_SONY_TRIANGLE" value="3"> + DUALSHOCK triangle button </constant> <constant name="JOY_SEGA_B" value="1"> + SEGA controller B button </constant> <constant name="JOY_SEGA_A" value="0"> + SEGA controller A button </constant> <constant name="JOY_SEGA_X" value="2"> + SEGA controller X button </constant> <constant name="JOY_SEGA_Y" value="3"> + SEGA controller Y button </constant> <constant name="JOY_XBOX_B" value="1"> + XBOX controller B button </constant> <constant name="JOY_XBOX_A" value="0"> + XBOX controller A button </constant> <constant name="JOY_XBOX_X" value="2"> + XBOX controller X button </constant> <constant name="JOY_XBOX_Y" value="3"> + XBOX controller Y button </constant> <constant name="JOY_DS_A" value="1"> </constant> @@ -1721,13 +1834,13 @@ Variable is of type nil (only applied for null). </constant> <constant name="TYPE_BOOL" value="1"> - Variable is of type bool. + Variable is of type [bool]. </constant> <constant name="TYPE_INT" value="2"> - Variable is of type integer. + Variable is of type [int]. </constant> <constant name="TYPE_REAL" value="3"> - Variable is of type float/real. + Variable is of type [float]/real. </constant> <constant name="TYPE_STRING" value="4"> Variable is of type [String]. @@ -1961,6 +2074,7 @@ <argument index="1" name="to" type="Vector3"> </argument> <description> + Return true if the [AABB] intersects the line segment between from and to </description> </method> <method name="merge"> @@ -1986,10 +2100,13 @@ </methods> <members> <member name="pos" type="Vector3"> + Position (starting corner). </member> <member name="size" type="Vector3"> + Size from position to end. </member> <member name="end" type="Vector3"> + Ending corner. </member> </members> <constants> @@ -8083,26 +8200,37 @@ </methods> <members> <member name="r" type="float"> + Red (0 to 1) </member> <member name="g" type="float"> + Green (0 to 1) </member> <member name="b" type="float"> + Blue (0 to 1) </member> <member name="a" type="float"> + Alpha (0 to 1) </member> <member name="h" type="float"> + Hue (0 to 1) </member> <member name="s" type="float"> + Saturation (0 to 1) </member> <member name="v" type="float"> + Value (0 to 1) </member> <member name="r8" type="int"> + Red (0 to 255) </member> <member name="g8" type="int"> + Green (0 to 255) </member> <member name="b8" type="int"> + Blue (0 to 255) </member> <member name="a8" type="int"> + Alpha (0 to 255) </member> </members> <constants> @@ -29263,10 +29391,13 @@ This method controls whether the position between two cached points is interpola </methods> <members> <member name="pos" type="Vector2"> + Position (starting corner). </member> <member name="size" type="Vector2"> + Size from position to end. </member> <member name="end" type="Vector2"> + Ending corner. </member> </members> <constants> @@ -39054,6 +39185,7 @@ This method controls whether the position between two cached points is interpola <return type="Transform"> </return> <description> + Returns the inverse of the transfrom, even if the transform has scale or the axis vectors are not orthogonal. </description> </method> <method name="inverse"> @@ -39071,12 +39203,14 @@ This method controls whether the position between two cached points is interpola <argument index="1" name="up" type="Vector3"> </argument> <description> + Rotate the transform around the up vector to face the target. </description> </method> <method name="orthonormalized"> <return type="Transform"> </return> <description> + Returns a transfrom with the basis orthogonal (90 degrees), and normalized axis vectors. </description> </method> <method name="rotated"> @@ -39087,6 +39221,7 @@ This method controls whether the position between two cached points is interpola <argument index="1" name="phi" type="float"> </argument> <description> + Rotate the transform locally. </description> </method> <method name="scaled"> @@ -39095,6 +39230,7 @@ This method controls whether the position between two cached points is interpola <argument index="0" name="scale" type="Vector3"> </argument> <description> + Scale the transform locally. </description> </method> <method name="translated"> @@ -39103,6 +39239,7 @@ This method controls whether the position between two cached points is interpola <argument index="0" name="ofs" type="Vector3"> </argument> <description> + Translate the transform locally. </description> </method> <method name="xform"> @@ -39135,6 +39272,7 @@ This method controls whether the position between two cached points is interpola <argument index="3" name="origin" type="Vector3"> </argument> <description> + Construct the Transform from four Vector3. Each axis creates the basis. </description> </method> <method name="Transform"> @@ -39145,6 +39283,7 @@ This method controls whether the position between two cached points is interpola <argument index="1" name="origin" type="Vector3"> </argument> <description> + Construct the Transform from a Matrix3 and Vector3. </description> </method> <method name="Transform"> @@ -39153,6 +39292,7 @@ This method controls whether the position between two cached points is interpola <argument index="0" name="from" type="Matrix32"> </argument> <description> + Construct the Transform from a Matrix32. </description> </method> <method name="Transform"> @@ -39161,6 +39301,7 @@ This method controls whether the position between two cached points is interpola <argument index="0" name="from" type="Quat"> </argument> <description> + Construct the Transform from a Quat. The origin will be Vector3(0, 0, 0) </description> </method> <method name="Transform"> @@ -39169,13 +39310,16 @@ This method controls whether the position between two cached points is interpola <argument index="0" name="from" type="Matrix3"> </argument> <description> + Construct the Transform from a Matrix3. The origin will be Vector3(0, 0, 0) </description> </method> </methods> <members> <member name="basis" type="Matrix3"> + The basis contains 3 [Vector3]. X axis, Y axis, and Z axis. </member> <member name="origin" type="Vector3"> + The origin of the transform. Which is the translation offset. </member> </members> <constants> @@ -40952,12 +41096,16 @@ This method controls whether the position between two cached points is interpola </methods> <members> <member name="x" type="float"> + X component of the vector. </member> <member name="y" type="float"> + Y component of the vector. </member> <member name="width" type="float"> + Width of the vector (Same as X). </member> <member name="height" type="float"> + Height of the vector (Same as Y). </member> </members> <constants> @@ -41201,10 +41349,13 @@ This method controls whether the position between two cached points is interpola </methods> <members> <member name="x" type="float"> + X component of the vector. </member> <member name="y" type="float"> + Y component of the vector. </member> <member name="z" type="float"> + Z component of the vector. </member> </members> <constants> diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 1ed508aed3..f482f775c4 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -29,81 +29,229 @@ #include "animated_sprite.h" #include "scene/scene_string_names.h" #include "os/os.h" +#include "scene/scene_string_names.h" -void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { - set_offset(p_pivot); -} -Point2 AnimatedSprite::edit_get_pivot() const { - return get_offset(); -} -bool AnimatedSprite::edit_has_pivot() const { +//////////////////////////// + - return true; -} +void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture>& p_frame, int p_at_pos) { -void SpriteFrames::add_frame(const Ref<Texture>& p_frame,int p_at_pos) { + Map<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); - if (p_at_pos>=0 && p_at_pos<frames.size()) - frames.insert(p_at_pos,p_frame); + if (p_at_pos>=0 && p_at_pos<E->get().frames.size()) + E->get().frames.insert(p_at_pos,p_frame); else - frames.push_back(p_frame); + E->get().frames.push_back(p_frame); emit_changed(); } -int SpriteFrames::get_frame_count() const { +int SpriteFrames::get_frame_count(const StringName &p_anim) const { + const Map<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,0); - return frames.size(); + return E->get().frames.size(); } -void SpriteFrames::remove_frame(int p_idx) { +void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { - frames.remove(p_idx); + Map<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); + + E->get().frames.remove(p_idx); emit_changed(); } -void SpriteFrames::clear() { +void SpriteFrames::clear(const StringName &p_anim) { + + Map<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND(!E); - frames.clear(); + E->get().frames.clear(); emit_changed(); } +void SpriteFrames::clear_all() { -Array SpriteFrames::_get_frames() const { + 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<String> SpriteFrames::_get_animation_list() const { + + Vector<String> ret; + List<StringName> al; + get_animation_list(&al); + for(List<StringName>::Element *E=al.front();E;E=E->next()) { + + ret.push_back(E->get()); + } + + return ret; +} + +void SpriteFrames::get_animation_list(List<StringName> *r_animations) const{ + + for (const Map<StringName,Anim>::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<StringName,Anim>::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{ - Array arr; - arr.resize(frames.size()); - for(int i=0;i<frames.size();i++) - arr[i]=frames[i]; + const Map<StringName,Anim>::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<StringName,Anim>::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<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,false); + return E->get().loop; - return arr; } void SpriteFrames::_set_frames(const Array& p_frames) { - frames.resize(p_frames.size()); - for(int i=0;i<frames.size();i++) - frames[i]=p_frames[i]; + clear_all(); + Map<StringName,Anim>::Element *E=animations.find(SceneStringNames::get_singleton()->_default); + ERR_FAIL_COND(!E); + + E->get().frames.resize(p_frames.size()); + for(int i=0;i<E->get().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<StringName,Anim>::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;i<E->get().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<p_animations.size();i++) { + + Dictionary d=p_animations[i]; + + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("speed")); + ERR_CONTINUE(!d.has("loop")); + ERR_CONTINUE(!d.has("frames")); + + Anim anim; + anim.speed=d["speed"]; + anim.loop=d["loop"]; + Array frames=d["frames"]; + for(int i=0;i<frames.size();i++) { + RES res = frames[i]; + anim.frames.push_back(res); + } + + animations[d["name"]]=anim; + + + } } void SpriteFrames::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("add_animation","anim"),&SpriteFrames::add_animation); + ObjectTypeDB::bind_method(_MD("has_animation","anim"),&SpriteFrames::has_animation); + ObjectTypeDB::bind_method(_MD("remove_animation","anim"),&SpriteFrames::remove_animation); + ObjectTypeDB::bind_method(_MD("rename_animation","anim","newname"),&SpriteFrames::rename_animation); + + ObjectTypeDB::bind_method(_MD("set_animation_speed","anim","speed"),&SpriteFrames::set_animation_speed); + ObjectTypeDB::bind_method(_MD("get_animation_speed","anim"),&SpriteFrames::get_animation_speed); + + ObjectTypeDB::bind_method(_MD("set_animation_loop","anim","loop"),&SpriteFrames::set_animation_loop); + ObjectTypeDB::bind_method(_MD("get_animation_loop","anim"),&SpriteFrames::get_animation_loop); + 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("add_frame","anim","frame","atpos"),&SpriteFrames::add_frame,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("get_frame_count","anim"),&SpriteFrames::get_frame_count); + ObjectTypeDB::bind_method(_MD("get_frame","anim","idx"),&SpriteFrames::get_frame); + ObjectTypeDB::bind_method(_MD("set_frame","anim","idx","txt"),&SpriteFrames::set_frame); + ObjectTypeDB::bind_method(_MD("remove_frame","anim","idx"),&SpriteFrames::remove_frame); + ObjectTypeDB::bind_method(_MD("clear","anim"),&SpriteFrames::clear); + ObjectTypeDB::bind_method(_MD("clear_all"),&SpriteFrames::clear_all); 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")); + ADD_PROPERTYNZ( PropertyInfo(Variant::ARRAY,"frames",PROPERTY_HINT_NONE,"",0),_SCS("_set_frames"),_SCS("_get_frames")); //compatibility + + ObjectTypeDB::bind_method(_MD("_set_animations"),&SpriteFrames::_set_animations); + ObjectTypeDB::bind_method(_MD("_get_animations"),&SpriteFrames::_get_animations); + + ADD_PROPERTYNZ( PropertyInfo(Variant::ARRAY,"animations",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_animations"),_SCS("_get_animations")); //compatibility } @@ -112,6 +260,7 @@ void SpriteFrames::_bind_methods() { SpriteFrames::SpriteFrames() { + add_animation(SceneStringNames::get_singleton()->_default); } @@ -120,25 +269,137 @@ SpriteFrames::SpriteFrames() { +void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { + + set_offset(p_pivot); +} + +Point2 AnimatedSprite::edit_get_pivot() const { + + return get_offset(); +} +bool AnimatedSprite::edit_has_pivot() const { + + return true; +} + -////////////////////////// +void AnimatedSprite::_validate_property(PropertyInfo& property) const { + + if (!frames.is_valid()) + return; + if (property.name=="animation") { + property.hint=PROPERTY_HINT_ENUM; + List<StringName> names; + frames->get_animation_list(&names); + names.sort_custom<StringName::AlphCompare>(); + + bool current_found=false; + + for (List<StringName>::Element *E=names.front();E;E=E->next()) { + if (E->prev()) { + property.hint_string+=","; + } + + property.hint_string+=String(E->get()); + if (animation==E->get()) { + current_found=true; + } + } + + if (!current_found) { + if (property.hint_string==String()) { + property.hint_string=String(animation); + } else { + property.hint_string=String(animation)+","+property.hint_string; + } + } + } + + + if (property.name=="frame") { + + property.hint=PROPERTY_HINT_RANGE; + + if (frames->has_animation(animation)) { + property.hint_string="0,"+itos(frames->get_frame_count(animation)-1)+",1"; + } else { + property.hint_string="0,0,0"; + } + } + +} void AnimatedSprite::_notification(int p_what) { switch(p_what) { + case NOTIFICATION_PROCESS: { + + if (frames.is_null()) + return; + if (!frames->has_animation(animation)) + return; + if (frame<0) + return; + + 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()) + if (frames.is_null()) { + print_line("no draw no faemos"); + return; + } + + if (frame<0) { + print_line("no draw frame <0"); return; + } - if (frame<0 || frame>=frames->get_frame_count()) + if (!frames->has_animation(animation)) { + print_line("no draw no anim: "+String(animation)); return; + } - Ref<Texture> texture = frames->get_frame(frame); - if (texture.is_null()) + + + Ref<Texture> 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<SpriteFrames> &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<Texture> t = frames->get_frame(frame); + Ref<Texture> 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 da4f1b99af..bbf9c7aafb 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<Texture> > frames; + struct Anim { + + float speed; + bool loop; + Vector< Ref<Texture> > frames; + + Anim() { loop=true; speed=5; } + }; + + Map<StringName,Anim> animations; Array _get_frames() const; void _set_frames(const Array& p_frames); + + Array _get_animations() const; + void _set_animations(const Array& p_animations); + + Vector<String> _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<StringName> *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<Texture>& p_frame,int p_at_pos=-1); + int get_frame_count(const StringName& p_anim) const; + _FORCE_INLINE_ Ref<Texture> get_frame(const StringName& p_anim,int p_idx) const { + + const Map<StringName,Anim>::Element *E=animations.find(p_anim); + ERR_FAIL_COND_V(!E,Ref<Texture>()); + ERR_FAIL_COND_V(p_idx<0,Ref<Texture>()); + if (p_idx>=E->get().frames.size()) + return Ref<Texture>(); + + return E->get().frames[p_idx]; + } + + void set_frame(const StringName& p_anim,int p_idx,const Ref<Texture>& p_frame){ + Map<StringName,Anim>::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<Texture>& p_frame,int p_at_pos=-1); - int get_frame_count() const; - _FORCE_INLINE_ Ref<Texture> get_frame(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,frames.size(),Ref<Texture>()); return frames[p_idx]; } - void set_frame(int p_idx,const Ref<Texture>& 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<SpriteFrames> 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<SpriteFrames> &p_frames); Ref<SpriteFrames> 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 60fa7f69c8..426e86fa13 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<AnimatedSprite>(); + if (as) { + add=true; + } + + } + + if (enabler[ENABLER_PAUSE_PARTICLES]) { Particles2D *ps = p_node->cast_to<Particles2D>(); @@ -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<AnimatedSprite>(); + + if (as) { + + if (p_enabled) + as->play(); + else + as->stop(); + } + } { Particles2D *ps=p_node->cast_to<Particles2D>(); @@ -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 6ec24fd4d0..647a5b6e91 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 c7d1249a07..da83e9b6d2 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> texture = frames->get_frame(frame); + Ref<Texture> 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<SpriteFrames>& 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<Texture> t = frames->get_frame(frame); + Ref<Texture> 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 fe8e1f6ebf..d8e589556c 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<SpriteFrames> 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 bf66a770d3..c1a0e43e49 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()) @@ -399,16 +410,18 @@ void ItemList::_input_event(const InputEvent& p_event) { defer_select_single=-1; return; } + if (defer_select_single>=0 && p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && !p_event.mouse_button.pressed) { select(defer_select_single,true); + emit_signal("multi_selected",defer_select_single,true); defer_select_single=-1; return; } - if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==BUTTON_LEFT && p_event.mouse_button.pressed) { + if (p_event.type==InputEvent::MOUSE_BUTTON && (p_event.mouse_button.button_index==BUTTON_LEFT || (allow_rmb_select && p_event.mouse_button.button_index==BUTTON_RIGHT)) && p_event.mouse_button.pressed) { const InputEventMouseButton &mb = p_event.mouse_button; @@ -447,6 +460,7 @@ void ItemList::_input_event(const InputEvent& p_event) { if (select_mode==SELECT_MULTI && items[i].selected && mb.mod.command) { unselect(i); emit_signal("multi_selected",i,false); + } else if (select_mode==SELECT_MULTI && mb.mod.shift && current>=0 && current<items.size() && current!=i) { int from = current; @@ -460,29 +474,45 @@ void ItemList::_input_event(const InputEvent& p_event) { if (selected) emit_signal("multi_selected",i,true); } + + if (p_event.mouse_button.button_index==BUTTON_RIGHT) { + + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } } else { - if (!mb.doubleclick && !mb.mod.command && select_mode==SELECT_MULTI && items[i].selectable && items[i].selected) { + if (!mb.doubleclick && !mb.mod.command && select_mode==SELECT_MULTI && items[i].selectable && items[i].selected && p_event.mouse_button.button_index==BUTTON_LEFT) { defer_select_single=i; return; } - bool selected = !items[i].selected; - select(i,select_mode==SELECT_SINGLE || !mb.mod.command); - if (selected) { - if (select_mode==SELECT_SINGLE) { - emit_signal("item_selected",i); - } else - emit_signal("multi_selected",i,true); - } + if (items[i].selected && p_event.mouse_button.button_index==BUTTON_RIGHT) { - if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) { + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } else { + bool selected = !items[i].selected; - emit_signal("item_activated",i); - } + select(i,select_mode==SELECT_SINGLE || !mb.mod.command); + + if (selected) { + if (select_mode==SELECT_SINGLE) { + emit_signal("item_selected",i); + } else + emit_signal("multi_selected",i,true); + + + } + + if (p_event.mouse_button.button_index==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",i,Vector2(mb.x,mb.y)); + } else if (/*select_mode==SELECT_SINGLE &&*/ mb.doubleclick) { + emit_signal("item_activated",i); + + } + } } @@ -690,6 +720,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 +831,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 +976,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 +996,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 +1118,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<StyleBox> bg = get_stylebox("bg"); @@ -1067,7 +1141,7 @@ int ItemList::get_item_at_pos(const Point2& p_pos) const { } float dist = rc.distance_to(pos); - if (dist<closest_dist) { + if (!p_exact && dist<closest_dist) { closest=i; closest_dist=dist; } @@ -1117,6 +1191,16 @@ int ItemList::find_metadata(const Variant& p_metadata) const { } + +void ItemList::set_allow_rmb_select(bool p_allow) { + allow_rmb_select=p_allow; +} + +bool ItemList::get_allow_rmb_select() const { + + return allow_rmb_select; +} + void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Variant()),DEFVAL(true)); @@ -1174,7 +1258,13 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_min_icon_size","size"),&ItemList::set_min_icon_size); ObjectTypeDB::bind_method(_MD("get_min_icon_size"),&ItemList::get_min_icon_size); - ObjectTypeDB::bind_method(_MD("get_item_at_pos","pos"),&ItemList::get_item_at_pos); + ObjectTypeDB::bind_method(_MD("set_max_icon_size","size"),&ItemList::set_max_icon_size); + ObjectTypeDB::bind_method(_MD("get_max_icon_size"),&ItemList::get_max_icon_size); + + ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&ItemList::set_allow_rmb_select); + ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&ItemList::get_allow_rmb_select); + + ObjectTypeDB::bind_method(_MD("get_item_at_pos","pos","exact"),&ItemList::get_item_at_pos,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible); @@ -1187,6 +1277,7 @@ void ItemList::_bind_methods(){ BIND_CONSTANT( SELECT_MULTI ); ADD_SIGNAL( MethodInfo("item_selected",PropertyInfo(Variant::INT,"index"))); + ADD_SIGNAL( MethodInfo("item_rmb_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::VECTOR2,"atpos"))); ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::BOOL,"selected"))); ADD_SIGNAL( MethodInfo("item_activated",PropertyInfo(Variant::INT,"index"))); } @@ -1215,6 +1306,7 @@ ItemList::ItemList() { search_time_msec=0; ensure_selected_visible=false; defer_select_single=-1; + allow_rmb_select=false; } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index fcb4dfae5a..59fa1d8270 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -60,9 +60,11 @@ private: int max_text_lines; int max_columns; Size2 min_icon_size; - + Size2 max_icon_size; int defer_select_single; + bool allow_rmb_select; + void _scroll_changed(double); void _input_event(const InputEvent& p_event); protected: @@ -134,13 +136,19 @@ public: void set_min_icon_size(const Size2& p_size); Size2 get_min_icon_size() const; + void set_max_icon_size(const Size2& p_size); + Size2 get_max_icon_size() const; + + void set_allow_rmb_select(bool p_allow); + bool get_allow_rmb_select() const; + void ensure_current_is_visible(); void sort_items_by_text(); int find_metadata(const Variant& p_metadata) const; virtual String get_tooltip(const Point2& p_pos) const; - int get_item_at_pos(const Point2& p_pos) const; + int get_item_at_pos(const Point2& p_pos,bool p_exact=false) const; ItemList(); ~ItemList(); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 21dee62b38..14dac454bd 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -41,7 +41,15 @@ void LineEdit::_input_event(InputEvent p_event) { const InputEventMouseButton &b = p_event.mouse_button; - if (b.button_index!=1) + if (b.pressed && b.button_index==BUTTON_RIGHT) { + menu->set_pos(get_global_transform().xform(get_local_mouse_pos())); + menu->set_size(Vector2(1,1)); + menu->popup(); + grab_focus(); + return; + } + + if (b.button_index!=BUTTON_LEFT) break; if (b.pressed) { @@ -143,24 +151,10 @@ void LineEdit::_input_event(InputEvent p_event) { if( k.mod.command && editable) { - int old_cursor_pos = cursor_pos; - text = undo_text; - - Ref<Font> font = get_font("font"); - - cached_width = 0; - for (int i = 0; i<text.length(); i++) - cached_width += font->get_char_size(text[i]).width; + undo(); - if(old_cursor_pos > text.length()) { - set_cursor_pos(text.length()); - } else { - set_cursor_pos(old_cursor_pos); - } } - emit_signal("text_changed",text); - _change_notify("text"); } break; @@ -559,6 +553,28 @@ void LineEdit::paste_text() { } +void LineEdit::undo() { + + int old_cursor_pos = cursor_pos; + text = undo_text; + + Ref<Font> font = get_font("font"); + + cached_width = 0; + for (int i = 0; i<text.length(); i++) + cached_width += font->get_char_size(text[i]).width; + + if(old_cursor_pos > text.length()) { + set_cursor_pos(text.length()); + } else { + set_cursor_pos(old_cursor_pos); + } + + emit_signal("text_changed",text); + _change_notify("text"); + +} + void LineEdit::shift_selection_check_pre(bool p_shift) { if (!selection.old_shift && p_shift) { @@ -669,6 +685,8 @@ void LineEdit::set_text(String p_text) { void LineEdit::clear() { clear_internal(); + emit_signal("text_changed",text); + _change_notify("text"); } String LineEdit::get_text() const { @@ -932,6 +950,39 @@ bool LineEdit::is_text_field() const { return true; } +void LineEdit::menu_option(int p_option) { + + switch(p_option) { + case MENU_CUT: { + cut_text(); + } break; + case MENU_COPY: { + + copy_text(); + } break; + case MENU_PASTE: { + + paste_text(); + } break; + case MENU_CLEAR: { + clear(); + } break; + case MENU_SELECT_ALL: { + select_all(); + } break; + case MENU_UNDO: { + + undo(); + } break; + + } + +} + +PopupMenu *LineEdit::get_menu() const { + return menu; +} + void LineEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_align", "align"), &LineEdit::set_align); @@ -952,6 +1003,8 @@ void LineEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_secret","enabled"),&LineEdit::set_secret); ObjectTypeDB::bind_method(_MD("is_secret"),&LineEdit::is_secret); ObjectTypeDB::bind_method(_MD("select","from","to"),&LineEdit::select,DEFVAL(0),DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("menu_option","option"),&LineEdit::menu_option); + ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&LineEdit::get_menu); ADD_SIGNAL( MethodInfo("text_changed", PropertyInfo( Variant::STRING, "text" )) ); ADD_SIGNAL( MethodInfo("text_entered", PropertyInfo( Variant::STRING, "text" )) ); @@ -961,11 +1014,21 @@ void LineEdit::_bind_methods() { BIND_CONSTANT(ALIGN_RIGHT); BIND_CONSTANT(ALIGN_FILL); - ADD_PROPERTY( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") ); + BIND_CONSTANT( MENU_CUT ); + BIND_CONSTANT( MENU_COPY ); + BIND_CONSTANT( MENU_PASTE ); + BIND_CONSTANT( MENU_CLEAR ); + BIND_CONSTANT( MENU_SELECT_ALL ); + BIND_CONSTANT( MENU_UNDO ); + BIND_CONSTANT( MENU_MAX ); + + ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") ); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), _SCS("set_align"), _SCS("get_align")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") ); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") ); + + } LineEdit::LineEdit() { @@ -984,6 +1047,20 @@ LineEdit::LineEdit() { set_stop_mouse(true); + menu = memnew( PopupMenu ); + add_child(menu); + menu->add_item(TTR("Cut"),MENU_CUT,KEY_MASK_CMD|KEY_X); + menu->add_item(TTR("Copy"),MENU_COPY,KEY_MASK_CMD|KEY_C); + menu->add_item(TTR("Paste"),MENU_PASTE,KEY_MASK_CMD|KEY_V); + menu->add_separator(); + menu->add_item(TTR("Select All"),MENU_SELECT_ALL,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Clear"),MENU_CLEAR); + menu->add_separator(); + menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z); + menu->connect("item_pressed",this,"menu_option"); + + + } LineEdit::~LineEdit() { diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 207c6b115b..586a54e950 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -30,6 +30,8 @@ #define LINE_EDIT_H #include "scene/gui/control.h" +#include "scene/gui/popup_menu.h" + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -45,6 +47,18 @@ public: ALIGN_RIGHT, ALIGN_FILL }; + + enum MenuItems { + MENU_CUT, + MENU_COPY, + MENU_PASTE, + MENU_CLEAR, + MENU_SELECT_ALL, + MENU_UNDO, + MENU_MAX + + }; + private: Align align; @@ -54,6 +68,8 @@ private: String undo_text; String text; + PopupMenu *menu; + int cursor_pos; int window_pos; int max_length; // 0 for no maximum @@ -85,14 +101,12 @@ private: void clear_internal(); void changed_internal(); - void copy_text(); - void cut_text(); - void paste_text(); void _input_event(InputEvent p_event); void _notification(int p_what); + protected: static void _bind_methods(); public: @@ -103,6 +117,8 @@ public: virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const; virtual void drop_data(const Point2& p_point,const Variant& p_data); + void menu_option(int p_option); + PopupMenu *get_menu() const; void select_all(); @@ -116,6 +132,10 @@ public: void append_at_cursor(String p_text); void clear(); + void copy_text(); + void cut_text(); + void paste_text(); + void undo(); void set_editable(bool p_editable); bool is_editable() const; @@ -127,7 +147,7 @@ public: virtual Size2 get_minimum_size() const; - virtual bool is_text_field() const; + virtual bool is_text_field() const; LineEdit(); ~LineEdit(); diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index fde5df6b72..5f798f445c 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -31,7 +31,10 @@ Size2 MarginContainer::get_minimum_size() const { - int margin = get_constant("margin"); + int margin_left = get_constant("margin_left"); + int margin_top = get_constant("margin_top"); + int margin_right = get_constant("margin_right"); + int margin_bottom = get_constant("margin_bottom"); Size2 max; @@ -52,9 +55,10 @@ Size2 MarginContainer::get_minimum_size() const { max.height = s.height; } - max.width += margin; - return max; + max.width += (margin_left + margin_right); + max.height += (margin_top + margin_bottom); + return max; } @@ -62,7 +66,10 @@ void MarginContainer::_notification(int p_what) { if (p_what==NOTIFICATION_SORT_CHILDREN) { - int margin = get_constant("margin"); + int margin_left = get_constant("margin_left"); + int margin_top = get_constant("margin_top"); + int margin_right = get_constant("margin_right"); + int margin_bottom = get_constant("margin_bottom"); Size2 s = get_size(); @@ -73,13 +80,10 @@ void MarginContainer::_notification(int p_what) { continue; if (c->is_set_as_toplevel()) continue; - int w; - if (c->get_h_size_flags() & Control::SIZE_EXPAND) - w=s.width-margin; - else - w=c->get_combined_minimum_size().width; - fit_child_in_rect(c,Rect2(margin,0,s.width-margin,s.height)); + int w=s.width-margin_left-margin_right; + int h=s.height-margin_top-margin_bottom; + fit_child_in_rect(c,Rect2(margin_left,margin_top,w,h)); } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 8df0c6d254..1ddf614ec4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1518,6 +1518,15 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { update(); } + + if (mb.button_index==BUTTON_RIGHT) { + + menu->set_pos(get_global_transform().xform(get_local_mouse_pos())); + menu->set_size(Vector2(1,1)); + menu->popup(); + grab_focus(); + + } } else { if (mb.button_index==BUTTON_LEFT) @@ -4146,6 +4155,38 @@ bool TextEdit::is_text_field() const { return true; } + +void TextEdit::menu_option(int p_option) { + + switch( p_option ) { + case MENU_CUT: { + + cut(); + } break; + case MENU_COPY: { + copy(); + } break; + case MENU_PASTE: { + + paste(); + } break; + case MENU_CLEAR: { + clear(); + } break; + case MENU_SELECT_ALL: { + select_all(); + } break; + case MENU_UNDO: { + undo(); + } break; + + }; +} + +PopupMenu *TextEdit::get_menu() const { + return menu; +} + void TextEdit::_bind_methods() { @@ -4215,6 +4256,8 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); + ObjectTypeDB::bind_method(_MD("menu_option"),&TextEdit::menu_option); + ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&TextEdit::get_menu); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));; ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1,10,0.1"), _SCS("cursor_set_blink_speed"),_SCS("cursor_get_blink_speed") ); @@ -4223,6 +4266,15 @@ void TextEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("text_changed")); ADD_SIGNAL(MethodInfo("request_completion")); + BIND_CONSTANT( MENU_CUT ); + BIND_CONSTANT( MENU_COPY ); + BIND_CONSTANT( MENU_PASTE ); + BIND_CONSTANT( MENU_CLEAR ); + BIND_CONSTANT( MENU_SELECT_ALL ); + BIND_CONSTANT( MENU_UNDO ); + BIND_CONSTANT( MENU_MAX ); + + } TextEdit::TextEdit() { @@ -4327,6 +4379,20 @@ TextEdit::TextEdit() { brace_matching_enabled=false; auto_indent=false; insert_mode = false; + + menu = memnew( PopupMenu ); + add_child(menu); + menu->add_item(TTR("Cut"),MENU_CUT,KEY_MASK_CMD|KEY_X); + menu->add_item(TTR("Copy"),MENU_COPY,KEY_MASK_CMD|KEY_C); + menu->add_item(TTR("Paste"),MENU_PASTE,KEY_MASK_CMD|KEY_V); + menu->add_separator(); + menu->add_item(TTR("Select All"),MENU_SELECT_ALL,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Clear"),MENU_CLEAR); + menu->add_separator(); + menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z); + menu->connect("item_pressed",this,"menu_option"); + + } TextEdit::~TextEdit() diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index ea4f148e91..dbe6293240 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -31,6 +31,7 @@ #include "scene/gui/control.h" #include "scene/gui/scroll_bar.h" +#include "scene/gui/popup_menu.h" #include "scene/main/timer.h" @@ -290,6 +291,8 @@ class TextEdit : public Control { DVector<int> _search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const; + PopupMenu *menu; + void _clear(); void _cancel_completion(); void _cancel_code_hint(); @@ -317,6 +320,17 @@ protected: public: + enum MenuItems { + MENU_CUT, + MENU_COPY, + MENU_PASTE, + MENU_CLEAR, + MENU_SELECT_ALL, + MENU_UNDO, + MENU_MAX + + }; + enum SearchFlags { SEARCH_MATCH_CASE=1, @@ -433,6 +447,8 @@ public: uint32_t get_saved_version() const; void tag_saved_version(); + void menu_option(int p_option); + void set_show_line_numbers(bool p_show); void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata); @@ -442,6 +458,8 @@ public: void set_code_hint(const String& p_hint); void query_code_comple(); + PopupMenu *get_menu() const; + String get_text_for_completion(); virtual bool is_text_field() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 062a377cee..2c39aea08c 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1563,10 +1563,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ col_width-=w+cache.button_margin; } - if (p_button==BUTTON_LEFT) { + if (p_button==BUTTON_LEFT || (p_button==BUTTON_RIGHT && allow_rmb_select)) { /* process selection */ - if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON || c.mode==TreeItem::CELL_MODE_CHECK)) { + if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it' s confusing for check emit_signal("item_activated"); return -1; @@ -1574,10 +1574,13 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ if (select_mode==SELECT_MULTI && p_mod.command && c.selectable) { - if (!c.selected) { + if (!c.selected || p_button==BUTTON_RIGHT) { p_item->select(col); emit_signal("multi_selected",p_item,col,true); + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } //p_item->selected_signal.call(col); @@ -1597,15 +1600,25 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ bool inrange=false; select_single_item( p_item, root, col,selected_item,&inrange ); + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } } else { int icount = _count_selected_items(root); - if (select_mode==SELECT_MULTI && icount>1) { + if (select_mode==SELECT_MULTI && icount>1 && p_button!=BUTTON_RIGHT) { single_select_defer=p_item; single_select_defer_column=col; } else { - select_single_item( p_item, root, col ); + + if (p_button!=BUTTON_RIGHT || !c.selected) { + select_single_item( p_item, root, col ); + } + + if (p_button==BUTTON_RIGHT) { + emit_signal("item_rmb_selected",get_local_mouse_pos()); + } } } @@ -1626,7 +1639,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ /* editing */ - bool bring_up_editor=c.selected;// && already_selected; + bool bring_up_editor=force_select_on_already_selected ? (c.selected && already_selected) : c.selected; bool bring_up_value_editor=false; String editor_text=c.text; @@ -2348,12 +2361,13 @@ void Tree::_input_event(InputEvent p_event) { } switch(b.button_index) { + case BUTTON_RIGHT: case BUTTON_LEFT: { Ref<StyleBox> bg = cache.bg; Point2 pos = Point2(b.x,b.y) - bg->get_offset(); cache.click_type=Cache::CLICK_NONE; - if (show_column_titles) { + if (show_column_titles && b.button_index==BUTTON_LEFT) { pos.y-=_get_title_button_height(); if (pos.y<0) { @@ -2375,8 +2389,12 @@ void Tree::_input_event(InputEvent p_event) { } } - if (!root) + if (!root || (!root->get_children() && hide_root)) { + if (b.button_index==BUTTON_RIGHT && allow_rmb_select) { + emit_signal("empty_tree_rmb_selected",get_local_mouse_pos()); + } break; + } click_handled=false; pressing_for_editor=false; @@ -2390,6 +2408,9 @@ void Tree::_input_event(InputEvent p_event) { } + if (b.button_index==BUTTON_RIGHT) + break; + if (drag_touching) { set_fixed_process(false); drag_touching_deaccel=false; @@ -3455,6 +3476,27 @@ int Tree::get_drop_mode_flags() const { return drop_mode_flags; } +void Tree::set_single_select_cell_editing_only_when_already_selected(bool p_enable) { + + force_select_on_already_selected=p_enable; +} + +bool Tree::get_single_select_cell_editing_only_when_already_selected() const { + + return force_select_on_already_selected; +} + + +void Tree::set_allow_rmb_select(bool p_allow) { + + allow_rmb_select=p_allow; +} + +bool Tree::get_allow_rmb_select() const{ + + return allow_rmb_select; +} + void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&Tree::_range_click_timeout); @@ -3505,10 +3547,18 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_drop_mode_flags","flags"),&Tree::set_drop_mode_flags); ObjectTypeDB::bind_method(_MD("get_drop_mode_flags"),&Tree::get_drop_mode_flags); + ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&Tree::set_allow_rmb_select); + ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&Tree::get_allow_rmb_select); + + + ObjectTypeDB::bind_method(_MD("set_single_select_cell_editing_only_when_already_selected","enable"),&Tree::set_single_select_cell_editing_only_when_already_selected); + ObjectTypeDB::bind_method(_MD("get_single_select_cell_editing_only_when_already_selected"),&Tree::get_single_select_cell_editing_only_when_already_selected); ADD_SIGNAL( MethodInfo("item_selected")); ADD_SIGNAL( MethodInfo("cell_selected")); ADD_SIGNAL( MethodInfo("multi_selected",PropertyInfo(Variant::OBJECT,"item"),PropertyInfo(Variant::INT,"column"),PropertyInfo(Variant::BOOL,"selected")) ); + ADD_SIGNAL( MethodInfo("item_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos"))); + ADD_SIGNAL( MethodInfo("empty_tree_rmb_selected",PropertyInfo(Variant::VECTOR2,"pos"))); ADD_SIGNAL( MethodInfo("item_edited")); ADD_SIGNAL( MethodInfo("item_collapsed",PropertyInfo(Variant::OBJECT,"item"))); //ADD_SIGNAL( MethodInfo("item_doubleclicked" ) ); @@ -3610,6 +3660,9 @@ Tree::Tree() { drop_mode_over=NULL; drop_mode_section=0; single_select_defer=NULL; + force_select_on_already_selected=false; + + allow_rmb_select=false; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 43a913392e..1dad26dffe 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -438,6 +438,9 @@ friend class TreeItem; bool drag_touching; bool drag_touching_deaccel; bool click_handled; + bool allow_rmb_select; + + bool force_select_on_already_selected; bool hide_folding; @@ -514,6 +517,12 @@ public: void set_drop_mode_flags(int p_flags); int get_drop_mode_flags() const; + void set_single_select_cell_editing_only_when_already_selected(bool p_enable); + bool get_single_select_cell_editing_only_when_already_selected() const; + + void set_allow_rmb_select(bool p_allow); + bool get_allow_rmb_select() const; + void set_value_evaluator(ValueEvaluator *p_evaluator); Tree(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index ade56c4f49..9feadf91cf 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -837,7 +837,10 @@ void make_default_theme() { t->set_constant("separation","HBoxContainer",4); t->set_constant("separation","VBoxContainer",4); - t->set_constant("margin","MarginContainer",8); + t->set_constant("margin_left","MarginContainer",8); + t->set_constant("margin_top","MarginContainer",0); + t->set_constant("margin_right","MarginContainer",0); + t->set_constant("margin_bottom","MarginContainer",0); t->set_constant("hseparation","GridContainer",4); t->set_constant("vseparation","GridContainer",4); t->set_constant("separation","HSplitContainer",12); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 28834c732d..af28feb63d 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -172,4 +172,6 @@ SceneStringNames::SceneStringNames() { speed=StaticCString::create("speed"); path_pp=NodePath(".."); + + _default=StaticCString::create("default"); } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index f85a858423..da5e45172b 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -182,6 +182,7 @@ public: NodePath path_pp; + StringName _default; }; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index c9cec3b7f4..fc676bda7e 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -2037,7 +2037,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { if (scene) { file->set_current_path(scene->get_filename()); }; - file->set_title(p_option==FILE_OPEN_SCENE?TTR("Open Scene"):"Open Base Scene"); + file->set_title(p_option==FILE_OPEN_SCENE?TTR("Open Scene"):TTR("Open Base Scene")); file->popup_centered_ratio(); } break; @@ -2057,8 +2057,9 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { case FILE_QUICK_OPEN_FILE: { - quick_open->popup("Resource", false, true); - quick_open->set_title(TTR("Quick Search File..")); + //quick_open->popup("Resource", false, true); + //quick_open->set_title(TTR("Quick Search File..")); + scenes_dock->focus_on_filter(); } break; case FILE_RUN_SCRIPT: { @@ -3380,6 +3381,7 @@ Dictionary EditorNode::_get_main_scene_state() { state["scene_tree_offset"]=scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_val(); state["property_edit_offset"]=get_property_editor()->get_scene_tree()->get_vscroll_bar()->get_val(); state["saved_version"]=saved_version; + state["node_filter"]=scene_tree_dock->get_filter(); //print_line(" getting main tab: "+itos(state["main_tab"])); return state; } @@ -3444,6 +3446,8 @@ void EditorNode::_set_main_scene_state(Dictionary p_state) { if (p_state.has("property_edit_offset")) get_property_editor()->get_scene_tree()->get_vscroll_bar()->set_val(p_state["property_edit_offset"]); + if (p_state.has("node_filter")) + scene_tree_dock->set_filter(p_state["node_filter"]); //print_line("set current 8 "); //this should only happen at the very end @@ -3942,12 +3946,6 @@ void EditorNode::_update_recent_scenes() { void EditorNode::_quick_opened() { - if (current_option==FILE_QUICK_OPEN_FILE) { - String res_path = quick_open->get_selected(); - - scenes_dock->open(res_path); - return; - } Vector<String> files = quick_open->get_selected_files(); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index cfec15c383..8fa6cfefcf 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -584,6 +584,7 @@ public: static void add_editor_plugin(EditorPlugin *p_editor); static void remove_editor_plugin(EditorPlugin *p_editor); + void new_inherited_scene() { _menu_option_confirm(FILE_NEW_INHERITED_SCENE,false); } diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index b9b6dc5616..d9351ffa80 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -438,6 +438,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("scenetree_editor/duplicate_node_name_num_separator",0); hints["scenetree_editor/duplicate_node_name_num_separator"]=PropertyInfo(Variant::INT,"scenetree_editor/duplicate_node_name_num_separator",PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"); + set("scenetree_editor/display_old_action_buttons",false); set("gridmap_editor/pick_distance", 5000.0); @@ -537,6 +538,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { }; }; + + + } void EditorSettings::notify_changes() { diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.cpp b/tools/editor/plugins/resource_preloader_editor_plugin.cpp index 01bb82834d..cc9aca1a25 100644 --- a/tools/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/tools/editor/plugins/resource_preloader_editor_plugin.cpp @@ -279,6 +279,106 @@ void ResourcePreloaderEditor::edit(ResourcePreloader* p_preloader) { +Variant ResourcePreloaderEditor::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 = 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<String> 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<String> 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 0bc94079a5..4f0cb4be37 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 0ab45b45c4..8b03c4651d 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<SampleLibrary> 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> sample = r; + + if (sample.is_valid()) { + + return true; + } + } + + + if (String(d["type"])=="files") { + + Vector<String> files = d["files"]; + + if (files.size()==0) + return false; + + for(int i=0;i<files.size();i++) { + String file = files[0]; + String ftype = EditorFileSystem::get_singleton()->get_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> 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<String> 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 b46b9a7f3d..f9fb184b7c 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 796fc23d9a..b2f10ccaae 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<String>& p_path) { +void SpriteFramesEditor::_file_load_request(const DVector<String>& p_path,int p_at_pos) { + ERR_FAIL_COND(!frames->has_animation(edited_anim)); List< Ref<Texture> > resources; @@ -85,28 +89,32 @@ void SpriteFramesEditor::_file_load_request(const DVector<String>& 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<Texture> >::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<Texture> r = frames->get_frame(to_remove); + Ref<Texture> 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<Texture> 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<Texture> 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<Texture> 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<Texture> r = frames->get_frame(to_move); + Ref<Texture> 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<Texture> r = frames->get_frame(to_move); + Ref<Texture> 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() { + + if (updating) + return; + + TreeItem *selected = animations->get_selected(); + ERR_FAIL_COND(!selected); + edited_anim=selected->get_text(0); + _update_library(true); + +} + +void SpriteFramesEditor::_animation_name_edited(){ + + if (updating) + return; + + if (!frames->has_animation(edited_anim)) + return; + + 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<fc;i++) { + Ref<Texture> 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<StringName> anim_names; + + anim_names.sort_custom<StringName::AlphCompare>(); + + frames->get_animation_list(&anim_names); + + anim_names.sort_custom<StringName::AlphCompare>(); + + for(List<StringName>::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(); - tree->set_hide_root(true); - TreeItem *root = tree->create_item(NULL); - if (sel>=frames->get_frame_count()) - sel=frames->get_frame_count()-1; - else if (sel<0 && frames->get_frame_count()) + 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;i<frames->get_frame_count();i++) { + for(int i=0;i<frames->get_frame_count(edited_anim);i++) { + + + String name; + Ref<Texture> icon; - TreeItem *ti = tree->create_item(root); - ti->set_cell_mode(0,TreeItem::CELL_MODE_STRING); - ti->set_selectable(0,true); - if (frames->get_frame(i).is_null()) { + if (frames->get_frame(edited_anim,i).is_null()) { - ti->set_text(0,TTR("Frame ")+itos(i)+" (empty)"); + name=itos(i)+TTR(": (empty)"); } else { - ti->set_text(0,TTR("Frame ")+itos(i)+" ("+frames->get_frame(i)->get_name()+")"); - ti->set_icon(0,frames->get_frame(i)); + name=itos(i)+": "+frames->get_frame(edited_anim,i)->get_name(); + icon=frames->get_frame(edited_anim,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); + + 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) - ti->select(0); + 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<StringName> anim_names; + frames->get_animation_list(&anim_names); + anim_names.sort_custom<StringName::AlphCompare>(); + 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> texture = r; + + if (texture.is_valid()) { + + return true; + } + } + + + if (String(d["type"])=="files") { + + Vector<String> files = d["files"]; + + if (files.size()==0) + return false; + + for(int i=0;i<files.size();i++) { + String file = files[0]; + String ftype = EditorFileSystem::get_singleton()->get_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> 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<String> 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); + + 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); + - vbc->add_child(tree); + + 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 5d0a6cb035..f0aa84c23a 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<String>& p_path); + void _file_load_request(const DVector<String>& 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 6f80910150..c4f54e04cb 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<String> files = drag_data["files"]; diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 2d969ee073..6d0c21d5f8 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -220,11 +220,15 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (!scene) { + EditorNode::get_singleton()->new_inherited_scene(); + + /* should be legal now current_option=-1; //confirmation->get_cancel()->hide(); accept->get_ok()->set_text(TTR("I see..")); accept->set_text("This operation can't be done without a tree root."); accept->popup_centered_minsize(); + */ break; } @@ -629,6 +633,8 @@ void SceneTreeDock::_notification(int p_what) { for(int i=0;i<TOOL_BUTTON_MAX;i++) tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons")); + filter_icon->set_texture(get_icon("Zoom","EditorIcons")); + EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed"); } break; @@ -1271,7 +1277,12 @@ void SceneTreeDock::_update_tool_buttons() { void SceneTreeDock::_selection_changed() { - tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); + if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size()>1) { + //automatically turn on multi-edit + _tool_selected(TOOL_MULTI_EDIT); + } + + //tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); } @@ -1681,9 +1692,81 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) { } +void SceneTreeDock::_tree_rmb(const Vector2& p_menu_pos) { + + + if (!EditorNode::get_singleton()->get_edited_scene()) { + + menu->clear(); + menu->add_item(TTR("New Scene Root"),TOOL_NEW,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Inherit Scene"),TOOL_INSTANCE); + + menu->set_size(Size2(1,1)); + menu->set_pos(p_menu_pos); + menu->popup(); + return; + } + + List<Node*> selection = editor_selection->get_selected_node_list(); + + if (selection.size()==0) + return; + + menu->clear(); + + + if (selection.size()==1) { + menu->add_item(TTR("Add Child Node"),TOOL_NEW,KEY_MASK_CMD|KEY_A); + menu->add_item(TTR("Instance Child Scene"),TOOL_INSTANCE); + menu->add_separator(); + menu->add_item(TTR("Change Type"),TOOL_REPLACE); + menu->add_separator(); + menu->add_item(TTR("Edit Groups"),TOOL_GROUP); + menu->add_item(TTR("Edit Connections"),TOOL_CONNECT); + menu->add_separator(); + menu->add_item(TTR("Add Script"),TOOL_SCRIPT); + menu->add_separator(); + } + + menu->add_item(TTR("Move Up"),TOOL_MOVE_UP,KEY_MASK_CMD|KEY_UP); + menu->add_item(TTR("Move Down"),TOOL_MOVE_DOWN,KEY_MASK_CMD|KEY_DOWN); + menu->add_item(TTR("Duplicate"),TOOL_DUPLICATE,KEY_MASK_CMD|KEY_D); + menu->add_item(TTR("Reparent"),TOOL_REPARENT); + + if (selection.size()==1) { + menu->add_separator(); + menu->add_item(TTR("Save Branch as Scene"),TOOL_NEW_SCENE_FROM); + } + menu->add_separator(); + + menu->add_item(TTR("Delete Node(s)"),TOOL_ERASE,KEY_DELETE); + + menu->set_size(Size2(1,1)); + menu->set_pos(p_menu_pos); + menu->popup(); + +} + + +void SceneTreeDock::_filter_changed(const String& p_filter) { + + scene_tree->set_filter(p_filter); +} + +String SceneTreeDock::get_filter() { + + return filter->get_text(); +} + +void SceneTreeDock::set_filter(const String& p_filter){ + + filter->set_text(p_filter); + scene_tree->set_filter(p_filter); +} + void SceneTreeDock::_bind_methods() { - ObjectTypeDB::bind_method(_MD("_tool_selected"),&SceneTreeDock::_tool_selected); + ObjectTypeDB::bind_method(_MD("_tool_selected"),&SceneTreeDock::_tool_selected,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("_create"),&SceneTreeDock::_create); //ObjectTypeDB::bind_method(_MD("_script_created"),&SceneTreeDock::_script_created); ObjectTypeDB::bind_method(_MD("_node_reparent"),&SceneTreeDock::_node_reparent); @@ -1701,6 +1784,8 @@ void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_new_scene_from"),&SceneTreeDock::_new_scene_from); ObjectTypeDB::bind_method(_MD("_nodes_dragged"),&SceneTreeDock::_nodes_dragged); ObjectTypeDB::bind_method(_MD("_files_dropped"),&SceneTreeDock::_files_dropped); + ObjectTypeDB::bind_method(_MD("_tree_rmb"),&SceneTreeDock::_tree_rmb); + ObjectTypeDB::bind_method(_MD("_filter_changed"),&SceneTreeDock::_filter_changed); ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance); @@ -1761,10 +1846,22 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec hbc_top->add_child(tb); tool_buttons[TOOL_SCRIPT]=tb; + HBoxContainer *filter_hbc = memnew( HBoxContainer ); + vbc->add_child(filter_hbc); + filter = memnew( LineEdit ); + filter->set_h_size_flags(SIZE_EXPAND_FILL); + filter_hbc->add_child(filter); + filter_icon = memnew( TextureFrame ); + filter_hbc->add_child(filter_icon); + filter->connect("text_changed",this,"_filter_changed"); + + + scene_tree = memnew( SceneTreeEditor(false,true,true )); vbc->add_child(scene_tree); scene_tree->set_v_size_flags(SIZE_EXPAND|SIZE_FILL); + scene_tree->connect("rmb_pressed",this,"_tree_rmb"); scene_tree->connect("node_selected", this,"_node_selected",varray(),CONNECT_DEFERRED); scene_tree->connect("node_renamed", this,"_node_renamed",varray(),CONNECT_DEFERRED); @@ -1869,8 +1966,17 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec new_scene_from_dialog->connect("file_selected",this,"_new_scene_from"); - + menu = memnew( PopupMenu ); + add_child(menu); + menu->connect("item_pressed",this,"_tool_selected"); first_enter=true; + if (!EditorSettings::get_singleton()->get("scenetree_editor/display_old_action_buttons")) { + for(int i=0;i<TOOL_BUTTON_MAX;i++) { + tool_buttons[i]->hide(); + } + } + + vbc->add_constant_override("separation",4); } diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index 5dc1e3e12e..d917cae64f 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -35,6 +35,7 @@ #include "scene/gui/button.h" #include "scene/gui/tool_button.h" #include "scene/gui/box_container.h" +#include "scene/gui/popup_menu.h" #include "scene_tree_editor.h" #include "create_dialog.h" #include "editor_data.h" @@ -93,6 +94,11 @@ class SceneTreeDock : public VBoxContainer { EditorSubScene *import_subscene_dialog; EditorFileDialog *new_scene_from_dialog; + LineEdit *filter; + TextureFrame *filter_icon; + + PopupMenu * menu; + bool first_enter; void _create(); @@ -135,12 +141,19 @@ class SceneTreeDock : public VBoxContainer { void _nodes_dragged(Array p_nodes,NodePath p_to,int p_type); void _files_dropped(Vector<String> p_files,NodePath p_to,int p_type); + void _tree_rmb(const Vector2& p_menu_pos); + + void _filter_changed(const String& p_filter); + protected: void _notification(int p_what); static void _bind_methods(); public: + String get_filter(); + void set_filter(const String& p_filter); + void import_subscene(); void set_edited_scene(Node* p_scene); void instance(const String& p_path); diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index fd79460aa8..22b6cdfb5d 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/tools/editor/scene_tree_editor.cpp @@ -210,10 +210,10 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id) } } -void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { +bool SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { if (!p_node) - return; + return false; // only owned nodes are editable, since nodes can create their own (manually owned) child nodes, // which the editor needs not to know about. @@ -227,7 +227,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { part_of_subscene=true; //allow } else { - return; + return false; } } else { part_of_subscene = p_node!=get_scene_node() && get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node))>=0; @@ -345,10 +345,23 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { item->set_as_cursor(0); } + bool keep= ( filter==String() || String(p_node->get_name()).find(filter)!=-1 ); + for (int i=0;i<p_node->get_child_count();i++) { - _add_nodes(p_node->get_child(i),item); + bool child_keep = _add_nodes(p_node->get_child(i),item); + + keep = keep || child_keep; + } + + if (!keep) { + memdelete(item); + return false; + } else { + return true; + } + } @@ -700,6 +713,18 @@ void SceneTreeEditor::set_marked(Node *p_marked,bool p_selectable,bool p_childre } +void SceneTreeEditor::set_filter(const String& p_filter) { + + filter=p_filter; + _update_tree(); +} + +String SceneTreeEditor::get_filter() const { + + return filter; +} + + void SceneTreeEditor::set_display_foreign_nodes(bool p_display) { display_foreign=p_display; @@ -837,6 +862,9 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_da if (!can_rename) return false; //not editable tree + if (filter!=String()) + return false; //can't rearrange tree with filter turned on + Dictionary d=p_data; if (!d.has("type")) @@ -908,6 +936,12 @@ void SceneTreeEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,C } +void SceneTreeEditor::_rmb_select(const Vector2& p_pos) { + + emit_signal("rmb_pressed",tree->get_global_transform().xform(p_pos)); +} + + void SceneTreeEditor::_bind_methods() { @@ -923,6 +957,7 @@ void SceneTreeEditor::_bind_methods() { ObjectTypeDB::bind_method("_cell_button_pressed",&SceneTreeEditor::_cell_button_pressed); ObjectTypeDB::bind_method("_cell_collapsed",&SceneTreeEditor::_cell_collapsed); ObjectTypeDB::bind_method("_subscene_option",&SceneTreeEditor::_subscene_option); + ObjectTypeDB::bind_method("_rmb_select",&SceneTreeEditor::_rmb_select); ObjectTypeDB::bind_method("_node_script_changed",&SceneTreeEditor::_node_script_changed); ObjectTypeDB::bind_method("_node_visibility_changed",&SceneTreeEditor::_node_visibility_changed); @@ -937,6 +972,7 @@ void SceneTreeEditor::_bind_methods() { ADD_SIGNAL( MethodInfo("node_changed") ); ADD_SIGNAL( MethodInfo("nodes_rearranged",PropertyInfo(Variant::ARRAY,"paths"),PropertyInfo(Variant::NODE_PATH,"to_path"),PropertyInfo(Variant::INT,"type") ) ); ADD_SIGNAL( MethodInfo("files_dropped",PropertyInfo(Variant::STRING_ARRAY,"files"),PropertyInfo(Variant::NODE_PATH,"to_path"),PropertyInfo(Variant::INT,"type") ) ); + ADD_SIGNAL( MethodInfo("rmb_pressed",PropertyInfo(Variant::VECTOR2,"pos")) ) ; ADD_SIGNAL( MethodInfo("open") ); ADD_SIGNAL( MethodInfo("open_script") ); @@ -976,6 +1012,11 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open add_child( tree ); tree->set_drag_forwarding(this); + if (p_can_rename) { + tree->set_allow_rmb_select(true); + tree->connect("item_rmb_selected",this,"_rmb_select"); + tree->connect("empty_tree_rmb_selected",this,"_rmb_select"); + } tree->connect("cell_selected", this,"_selected_changed"); tree->connect("item_edited", this,"_renamed",varray(),CONNECT_DEFERRED); diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h index 283db280ed..e88922f73e 100644 --- a/tools/editor/scene_tree_editor.h +++ b/tools/editor/scene_tree_editor.h @@ -66,6 +66,8 @@ class SceneTreeEditor : public Control { PopupMenu *inheritance_menu; ObjectID instance_node; + String filter; + AcceptDialog *error; ConfirmationDialog *clear_inherit_confirm; @@ -73,7 +75,7 @@ class SceneTreeEditor : public Control { void _compute_hash(Node *p_node,uint64_t &hash); - void _add_nodes(Node *p_node,TreeItem *p_parent); + bool _add_nodes(Node *p_node,TreeItem *p_parent); void _test_update_tree(); void _update_tree(); void _tree_changed(); @@ -112,6 +114,7 @@ class SceneTreeEditor : public Control { void _subscene_option(int p_idx); + void _selection_changed(); Node *get_scene_node(); @@ -119,8 +122,12 @@ class SceneTreeEditor : public Control { 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); + void _rmb_select(const Vector2& p_pos); + public: + void set_filter(const String& p_filter); + String get_filter() const; void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo=p_undo_redo; }; void set_display_foreign_nodes(bool p_display); diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index c03142a3e7..e00f470bc4 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -36,7 +36,7 @@ #include "editor_node.h" #include "editor_settings.h" - +#include "scene/main/viewport.h" bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) { @@ -151,6 +151,35 @@ void ScenesDock::_notification(int p_what) { switch(p_what) { + case NOTIFICATION_RESIZED: { + + + bool new_mode = get_size().height < get_viewport_rect().size.height*3/4; + + if (new_mode != split_mode ) { + + split_mode=new_mode; + + //print_line("SPLIT MODE? "+itos(split_mode)); + if (split_mode) { + + file_list_vb->hide(); + tree->set_v_size_flags(SIZE_EXPAND_FILL); + button_back->show(); + } else { + + tree->show(); + file_list_vb->show(); + tree->set_v_size_flags(SIZE_FILL); + button_back->hide(); + if (!EditorFileSystem::get_singleton()->is_scanning()) { + _fs_changed(); + } + } + } + + + } break; case NOTIFICATION_ENTER_TREE: { if (initialized) @@ -163,19 +192,20 @@ void ScenesDock::_notification(int p_what) { button_favorite->set_icon( get_icon("Favorites","EditorIcons")); button_fav_up->set_icon( get_icon("MoveUp","EditorIcons")); button_fav_down->set_icon( get_icon("MoveDown","EditorIcons")); - button_instance->set_icon( get_icon("Add","EditorIcons")); - button_open->set_icon( get_icon("Folder","EditorIcons")); + //button_instance->set_icon( get_icon("Add","EditorIcons")); + //button_open->set_icon( get_icon("Folder","EditorIcons")); button_back->set_icon( get_icon("Filesystem","EditorIcons")); display_mode->set_icon( get_icon("FileList","EditorIcons")); display_mode->connect("pressed",this,"_change_file_display"); - file_options->set_icon( get_icon("Tools","EditorIcons")); + //file_options->set_icon( get_icon("Tools","EditorIcons")); files->connect("item_activated",this,"_select_file"); button_hist_next->connect("pressed",this,"_fw_history"); button_hist_prev->connect("pressed",this,"_bw_history"); + search_button->set_icon( get_icon("Zoom","EditorIcons")); button_hist_next->set_icon( get_icon("Forward","EditorIcons")); button_hist_prev->set_icon( get_icon("Back","EditorIcons")); - file_options->get_popup()->connect("item_pressed",this,"_file_option"); + file_options->connect("item_pressed",this,"_file_option"); button_back->connect("pressed",this,"_go_to_tree",varray(),CONNECT_DEFERRED); @@ -195,6 +225,19 @@ void ScenesDock::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { } break; + case NOTIFICATION_DRAG_BEGIN: { + + Dictionary dd = get_viewport()->gui_get_drag_data(); + if (tree->is_visible() && dd.has("type") && ( + (String(dd["type"])=="files") || (String(dd["type"])=="files_and_dirs") || (String(dd["type"])=="resource"))) { + tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); + } + } break; + case NOTIFICATION_DRAG_END: { + + tree->set_drop_mode_flags(0); + + } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { display_mode->set_pressed(int(EditorSettings::get_singleton()->get("file_dialog/display_mode"))==EditorFileDialog::DISPLAY_LIST); @@ -235,6 +278,11 @@ void ScenesDock::_dir_selected() { button_fav_up->set_disabled(true); button_fav_down->set_disabled(true); + + } + + if (!split_mode) { + _open_pressed(); //go directly to dir } } @@ -355,42 +403,26 @@ String ScenesDock::get_selected_path() const { return "res://"+path; } -void ScenesDock::_instance_pressed() { - if (tree_mode) - { - TreeItem *sel = tree->get_selected(); - if (!sel) - return; - String path = sel->get_metadata(0); - } - else - { - int idx = -1; - for (int i = 0; i<files->get_item_count(); i++) { - if (files->is_selected(i)) - { - idx = i; - break; - } - } +void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) { - if (idx<0) - return; + bool valid=false; - path = files->get_item_metadata(idx); + if (!search_box->is_hidden()) { + valid=true; + } else { + valid=(path==p_path.get_base_dir()); } - emit_signal("instance",path); -} - -void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) { - - if (p_preview.is_valid() && path==p_path.get_base_dir()) { + if (p_preview.is_valid() && valid) { - int idx=p_udata; + Array uarr=p_udata; + int idx=uarr[0]; + String file=uarr[1]; if (idx>=files->get_item_count()) return; + if (files->get_item_text(idx)!=file) + return; String fpath = files->get_item_metadata(idx); if (fpath!=p_path) return; @@ -412,6 +444,34 @@ void ScenesDock::_change_file_display() { _update_files(true); } +void ScenesDock::_search(EditorFileSystemDirectory *p_path,List<FileInfo>* matches,int p_max_items) { + + if (matches->size()>p_max_items) + return; + + for(int i=0;i<p_path->get_subdir_count();i++) { + _search(p_path->get_subdir(i),matches,p_max_items); + + } + + String match = search_box->get_text(); + + for(int i=0;i<p_path->get_file_count();i++) { + String file = p_path->get_file(i); + + if (file.find(match)!=-1) { + + FileInfo fi; + fi.name=file; + fi.type=p_path->get_file_type(i); + fi.path=p_path->get_file_path(i); + matches->push_back(fi); + if (matches->size()>p_max_items) + return; + } + } +} + void ScenesDock::_update_files(bool p_keep_selection) { Set<String> cselection; @@ -427,6 +487,9 @@ void ScenesDock::_update_files(bool p_keep_selection) { files->clear(); + current_path->set_text(path); + + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_path(path); if (!efd) return; @@ -436,6 +499,7 @@ void ScenesDock::_update_files(bool p_keep_selection) { Ref<Texture> file_thumbnail; bool use_thumbnails=!display_mode->is_pressed(); + bool use_folders = !search_box->is_visible() && split_mode; if (use_thumbnails) { //thumbnails @@ -477,59 +541,90 @@ void ScenesDock::_update_files(bool p_keep_selection) { } + if (use_folders) { - if (path!="res://") { + if (path!="res://") { - if (use_thumbnails) { - files->add_item("..",folder_thumbnail,true); - } else { - files->add_item("..",get_icon("folder","FileDialog"),true); + if (use_thumbnails) { + files->add_item("..",folder_thumbnail,true); + } else { + files->add_item("..",get_icon("folder","FileDialog"),true); + } + + String bd = path.get_base_dir(); + if (bd!="res://" && !bd.ends_with("/")) + bd+="/"; + + files->set_item_metadata(files->get_item_count()-1,bd); } - String bd = path.get_base_dir(); - if (bd!="res://" && !bd.ends_with("/")) - bd+="/"; + for(int i=0;i<efd->get_subdir_count();i++) { + + String dname=efd->get_subdir(i)->get_name(); + + + if (use_thumbnails) { + files->add_item(dname,folder_thumbnail,true); + } else { + files->add_item(dname,get_icon("folder","FileDialog"),true); + } - files->set_item_metadata(files->get_item_count()-1,bd); + files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/"); + + if (cselection.has(dname)) + files->select(files->get_item_count()-1,false); + } } - for(int i=0;i<efd->get_subdir_count();i++) { - String dname=efd->get_subdir(i)->get_name(); + List<FileInfo> filelist; + if (search_box->is_visible()) { - if (use_thumbnails) { - files->add_item(dname,folder_thumbnail,true); - } else { - files->add_item(dname,get_icon("folder","FileDialog"),true); + if (search_box->get_text().length()>1) { + _search(EditorFileSystem::get_singleton()->get_filesystem(),&filelist,128); } - files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/"); + filelist.sort(); + } else { - if (cselection.has(dname)) - files->select(files->get_item_count()-1,false); + for(int i=0;i<efd->get_file_count();i++) { + + FileInfo fi; + fi.name=efd->get_file(i); + fi.path=path.plus_file(fi.name); + fi.type=efd->get_file_type(i); + + filelist.push_back(fi); + } } - for(int i=0;i<efd->get_file_count();i++) { + StringName ei="EditorIcons"; //make it faster.. + StringName oi="Object"; - String fname=efd->get_file(i); - String fp = path.plus_file(fname); + for(List<FileInfo>::Element *E=filelist.front();E;E=E->next()) { + String fname=E->get().name; + String fp = E->get().path; + StringName type = E->get().type; - String type = efd->get_file_type(i); Ref<Texture> type_icon; - if (has_icon(type,"EditorIcons")) { - type_icon=get_icon(type,"EditorIcons"); + if (has_icon(type,ei)) { + type_icon=get_icon(type,ei); } else { - type_icon=get_icon("Object","EditorIcons"); + type_icon=get_icon(oi,ei); } if (use_thumbnails) { files->add_item(fname,file_thumbnail,true); files->set_item_metadata(files->get_item_count()-1,fp); files->set_item_tag_icon(files->get_item_count()-1,type_icon); - EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",files->get_item_count()-1); + Array udata; + udata.resize(2); + udata[0]=files->get_item_count()-1; + udata[1]=fname; + EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",udata); } else { files->add_item(fname,type_icon,true); files->set_item_metadata(files->get_item_count()-1,fp); @@ -547,25 +642,21 @@ void ScenesDock::_update_files(bool p_keep_selection) { void ScenesDock::_select_file(int p_idx) { files->select(p_idx,true); - _open_pressed(); + _file_option(FILE_OPEN); } void ScenesDock::_go_to_tree() { tree->show(); - files->hide(); - path_hb->hide(); + file_list_vb->hide(); _update_tree(); tree->grab_focus(); tree->ensure_cursor_is_visible(); button_favorite->show(); button_fav_up->show(); button_fav_down->show(); - button_open->hide(); - button_instance->hide(); - button_open->hide(); - file_options->hide(); - tree_mode=true; + //button_open->hide(); + //file_options->hide(); } void ScenesDock::_go_to_dir(const String& p_dir){ @@ -585,20 +676,18 @@ void ScenesDock::_fs_changed() { button_hist_prev->set_disabled(history_pos==0); button_hist_next->set_disabled(history_pos+1==history.size()); scanning_vb->hide(); + split_box->show(); - if (tree_mode) { - - tree->show(); + if (!tree->is_hidden()) { button_favorite->show(); button_fav_up->show(); button_fav_down->show(); _update_tree(); - } else { - files->show(); - path_hb->show(); - button_instance->show(); - button_open->show(); - file_options->show(); + + } + + if (!file_list_vb->is_hidden()) { + _update_files(true); } @@ -607,18 +696,10 @@ void ScenesDock::_fs_changed() { void ScenesDock::_set_scannig_mode() { - tree->hide(); - button_favorite->hide(); - button_fav_up->hide(); - button_fav_down->hide(); - button_instance->hide(); - button_open->hide(); - file_options->hide(); + split_box->hide(); button_hist_prev->set_disabled(true); button_hist_next->set_disabled(true); scanning_vb->show(); - path_hb->hide(); - files->hide(); set_process(true); if (EditorFileSystem::get_singleton()->is_scanning()) { scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); @@ -635,11 +716,14 @@ void ScenesDock::_fw_history() { path=history[history_pos]; - if (tree_mode) { + if (!tree->is_hidden()) { _update_tree(); tree->grab_focus(); tree->ensure_cursor_is_visible(); - } else { + + } + + if (!file_list_vb->is_hidden()) { _update_files(false); current_path->set_text(path); } @@ -656,11 +740,14 @@ void ScenesDock::_bw_history() { path=history[history_pos]; - if (tree_mode) { + + if (!tree->is_hidden()) { _update_tree(); tree->grab_focus(); tree->ensure_cursor_is_visible(); - } else { + } + + if (!file_list_vb->is_hidden()) { _update_files(false); current_path->set_text(path); } @@ -829,9 +916,17 @@ void ScenesDock::_move_operation(const String& p_to_path) { for(int i=0;i<move_dirs.size();i++) { - String to = p_to_path.plus_file(move_dirs[i].get_file()); - Error err = da->rename(move_dirs[i],to); - print_line("moving dir "+move_dirs[i]+" to "+to); + String mdir = move_dirs[i]; + if (mdir=="res://") + continue; + + if (mdir.ends_with("/")) { + mdir=mdir.substr(0,mdir.length()-1); + } + + String to = p_to_path.plus_file(mdir.get_file()); + Error err = da->rename(mdir,to); + print_line("moving dir "+mdir+" to "+to); if (err!=OK) { EditorNode::get_singleton()->add_io_error("Error moving dir:\n"+move_dirs[i]+"\n"); } @@ -848,6 +943,52 @@ void ScenesDock::_file_option(int p_option) { switch(p_option) { + + case FILE_OPEN: { + int idx=-1; + for(int i=0;i<files->get_item_count();i++) { + if (files->is_selected(i)) { + idx=i; + break; + } + } + + if (idx<0) + return; + + + + String path = files->get_item_metadata(idx); + + if (path.ends_with("/")) { + if (path!="res://") { + path=path.substr(0,path.length()-1); + } + this->path=path; + _update_files(false); + current_path->set_text(path); + _push_to_history(); + } else { + + if (ResourceLoader::get_resource_type(path)=="PackedScene") { + + editor->open_request(path); + } else { + + editor->load_resource(path); + } + } + } break; + case FILE_INSTANCE: { + + for (int i = 0; i<files->get_item_count(); i++) { + + String path =files->get_item_metadata(i); + if (EditorFileSystem::get_singleton()->get_file_type(path)=="PackedScene") { + emit_signal("instance",path); + } + } + } break; case FILE_DEPENDENCIES: { int idx = files->get_current(); @@ -937,77 +1078,63 @@ void ScenesDock::_file_option(int p_option) { void ScenesDock::_open_pressed(){ - if (tree_mode) { - - TreeItem *sel = tree->get_selected(); - if (!sel) { - return; - } - path = sel->get_metadata(0); - /*if (path!="res://" && path.ends_with("/")) { - path=path.substr(0,path.length()-1); - }*/ + TreeItem *sel = tree->get_selected(); + if (!sel) { + return; + } + path = sel->get_metadata(0); + /*if (path!="res://" && path.ends_with("/")) { + path=path.substr(0,path.length()-1); + }*/ - tree_mode=false; + //tree_mode=false; + if (split_mode) { tree->hide(); - files->show(); - path_hb->show(); + file_list_vb->show(); button_favorite->hide(); button_fav_up->hide(); button_fav_down->hide(); - button_instance->show(); - button_open->show(); - file_options->show(); - - _update_files(false); - - current_path->set_text(path); - - _push_to_history(); + } + //file_options->show(); - } else { - - int idx=-1; - for(int i=0;i<files->get_item_count();i++) { - if (files->is_selected(i)) { - idx=i; - break; - } - } + _update_files(false); + current_path->set_text(path); + _push_to_history(); - if (idx<0) - return; +// emit_signal("open",path); +} +void ScenesDock::_search_toggled(){ - String path = files->get_item_metadata(idx); + if (search_button->is_pressed()) { + //search_box->clear(); + search_box->select_all(); + search_box->show(); + current_path->hide(); + search_box->grab_focus(); - if (path.ends_with("/")) { - if (path!="res://") { - path=path.substr(0,path.length()-1); - } - this->path=path; - _update_files(false); - current_path->set_text(path); - _push_to_history(); - } else { + _update_files(false); + } else { - if (ResourceLoader::get_resource_type(path)=="PackedScene") { + //search_box->clear(); + search_box->hide(); + current_path->show(); - editor->open_request(path); - } else { + _update_files(false); - editor->load_resource(path); - } - } } +} -// emit_signal("open",path); +void ScenesDock::_search_changed(const String& p_text) { -} + if (!search_box->is_visible()) + return; //wtf + _update_files(false); +} void ScenesDock::_rescan() { @@ -1020,51 +1147,8 @@ void ScenesDock::fix_dependencies(const String& p_for_file) { deps_editor->edit(p_for_file); } -void ScenesDock::open(const String& p_path) { - - String npath; - String nfile; - - if (p_path.ends_with("/")) { - - if (p_path!="res://") - npath=p_path.substr(0,p_path.length()-1); - else - npath="res://"; - } else { - nfile=p_path.get_file(); - npath=p_path.get_base_dir(); - } - - path=npath; - - if (tree_mode && nfile=="") { - _update_tree(); - tree->grab_focus(); - tree->call_deferred("ensure_cursor_is_visible"); - _push_to_history(); - return; - } else if (tree_mode){ - _update_tree(); - tree->grab_focus(); - tree->ensure_cursor_is_visible(); - _open_pressed(); - current_path->set_text(path); - } else { - _update_files(false); - _push_to_history(); - } - - for(int i=0;i<files->get_item_count();i++) { - - String md = files->get_item_metadata(i); - if (md==p_path) { - files->select(i,true); - files->ensure_current_is_visible(); - break; - } - } +void ScenesDock::focus_on_filter() { } @@ -1076,6 +1160,23 @@ void ScenesDock::set_use_thumbnails(bool p_use) { Variant ScenesDock::get_drag_data_fw(const Point2& p_point,Control* p_from) { + if (p_from==tree) { + + TreeItem *selected = tree->get_selected(); + if (!selected) + return Variant(); + + String path = selected->get_metadata(0); + if (path==String()) + return Variant(); + if (!path.ends_with("/")) + path=path+"/"; + Vector<String> paths; + paths.push_back(path); + return EditorNode::get_singleton()->drag_files(paths,p_from); + + } + if (p_from==files) { List<int> seldirs; @@ -1150,6 +1251,20 @@ bool ScenesDock::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Co return true; } } + + if (p_from==tree) { + + TreeItem *ti = tree->get_item_at_pos(p_point); + if (!ti) + return false; + String path = ti->get_metadata(0); + + if (path==String()) + return false; + + return true; + } + } return false; @@ -1168,53 +1283,150 @@ void ScenesDock::drop_data_fw(const Point2& p_point,const Variant& p_data,Contro return; } - String save_path=path; - int at_pos = files->get_item_at_pos(p_point); - if (at_pos!=-1) { - String to_dir = files->get_item_metadata(at_pos); - if (to_dir.ends_with("/")) { - save_path=to_dir; - if (save_path!="res://") - save_path=save_path.substr(0,save_path.length()-1); - } + if (p_from==tree) { + + TreeItem *ti = tree->get_item_at_pos(p_point); + if (!ti) + return; + String path = ti->get_metadata(0); + + if (path==String()) + return; + + EditorNode::get_singleton()->save_resource_as(res,path); + return; } - EditorNode::get_singleton()->save_resource_as(res,save_path); - return; + if (p_from==files) { + String save_path=path; + + int at_pos = files->get_item_at_pos(p_point); + if (at_pos!=-1) { + String to_dir = files->get_item_metadata(at_pos); + if (to_dir.ends_with("/")) { + save_path=to_dir; + if (save_path!="res://") + save_path=save_path.substr(0,save_path.length()-1); + } + + } + + EditorNode::get_singleton()->save_resource_as(res,save_path); + return; + } } if (drag_data.has("type") && ( String(drag_data["type"])=="files" || String(drag_data["type"])=="files_and_dirs")) { - int at_pos = files->get_item_at_pos(p_point); - ERR_FAIL_COND(at_pos==-1); - String to_dir = files->get_item_metadata(at_pos); - ERR_FAIL_COND(!to_dir.ends_with("/")); + if (p_from==files || p_from==tree) { - Vector<String> fnames = drag_data["files"]; - move_files.clear(); - move_dirs.clear(); - - for(int i=0;i<fnames.size();i++) { - if (fnames[i].ends_with("/")) - move_dirs.push_back(fnames[i]); - else - move_files.push_back(fnames[i]); - } + String to_dir; + + if (p_from==files) { - _move_operation(to_dir); + int at_pos = files->get_item_at_pos(p_point); + ERR_FAIL_COND(at_pos==-1); + String to_dir = files->get_item_metadata(at_pos); + } else { + TreeItem *ti = tree->get_item_at_pos(p_point); + if (!ti) + return; + to_dir = ti->get_metadata(0); + ERR_FAIL_COND(to_dir==String()); + + } + + if (to_dir!="res://" && to_dir.ends_with("/")) { + to_dir=to_dir.substr(0,to_dir.length()-1); + } + + Vector<String> fnames = drag_data["files"]; + move_files.clear(); + move_dirs.clear(); + + for(int i=0;i<fnames.size();i++) { + if (fnames[i].ends_with("/")) + move_dirs.push_back(fnames[i]); + else + move_files.push_back(fnames[i]); + } + + _move_operation(to_dir); + } } } +void ScenesDock::_files_list_rmb_select(int p_item,const Vector2& p_pos) { + + Vector<String> filenames; + + bool all_scenes=true; + + for(int i=0;i<files->get_item_count();i++) { + + if (!files->is_selected(i)) + continue; + + String path = files->get_item_metadata(i); + + if (files->get_item_text(i)=="..") { + // no operate on .. + return; + } + + if (path.ends_with("/")) { + //no operate on dirs + return; + } + + + filenames.push_back(path); + if (EditorFileSystem::get_singleton()->get_file_type(path)!="PackedScene") + all_scenes=false; + } + + + if (filenames.size()==0) + return; + + file_options->clear(); + file_options->set_size(Size2(1,1)); + + file_options->add_item(TTR("Open"),FILE_OPEN); + if (all_scenes) { + file_options->add_item(TTR("Instance"),FILE_INSTANCE); + } + + file_options->add_separator(); + + if (filenames.size()==1) { + file_options->add_item(TTR("Edit Dependencies.."),FILE_DEPENDENCIES); + file_options->add_item(TTR("View Owners.."),FILE_OWNERS); + file_options->add_separator(); + } + + if (filenames.size()==1) { + file_options->add_item(TTR("Rename or Move.."),FILE_MOVE); + } else { + file_options->add_item(TTR("Move To.."),FILE_MOVE); + } + + file_options->add_item(TTR("Delete"),FILE_REMOVE); + //file_options->add_item(TTR("Info"),FILE_INFO); + file_options->set_pos(files->get_global_pos() + p_pos); + file_options->popup(); + +} void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree); ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan); ObjectTypeDB::bind_method(_MD("_favorites_pressed"),&ScenesDock::_favorites_pressed); - ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed); +// ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed); ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed); ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&ScenesDock::_thumbnail_done); @@ -1231,10 +1443,13 @@ void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_file_option"), &ScenesDock::_file_option); ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation); ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation); + ObjectTypeDB::bind_method(_MD("_search_toggled"), &ScenesDock::_search_toggled); + ObjectTypeDB::bind_method(_MD("_search_changed"), &ScenesDock::_search_changed); ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &ScenesDock::get_drag_data_fw); ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &ScenesDock::can_drop_data_fw); ObjectTypeDB::bind_method(_MD("drop_data_fw"), &ScenesDock::drop_data_fw); + ObjectTypeDB::bind_method(_MD("_files_list_rmb_select"),&ScenesDock::_files_list_rmb_select); ADD_SIGNAL(MethodInfo("instance")); ADD_SIGNAL(MethodInfo("open")); @@ -1245,6 +1460,7 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { editor=p_editor; + HBoxContainer *toolbar_hbc = memnew( HBoxContainer ); add_child(toolbar_hbc); @@ -1294,7 +1510,7 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { button_fav_up->set_focus_mode(FOCUS_NONE); button_fav_down->set_focus_mode(FOCUS_NONE); - +/* button_open = memnew( Button ); button_open->set_flat(true); button_open->connect("pressed",this,"_open_pressed"); @@ -1312,26 +1528,23 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { button_instance->set_focus_mode(FOCUS_NONE); button_instance->set_tooltip(TTR("Instance the selected scene(s) as child of the selected node.")); +*/ + file_options = memnew( PopupMenu ); + add_child(file_options); - file_options = memnew( MenuButton ); - toolbar_hbc->add_child(file_options); - file_options->get_popup()->add_item(TTR("Rename or Move"),FILE_MOVE); - file_options->get_popup()->add_item(TTR("Delete"),FILE_REMOVE); - file_options->get_popup()->add_separator(); - file_options->get_popup()->add_item(TTR("Edit Dependencies"),FILE_DEPENDENCIES); - file_options->get_popup()->add_item(TTR("View Owners"),FILE_OWNERS); - //file_options->get_popup()->add_item(TTR("Info"),FILE_INFO); - file_options->hide(); - file_options->set_focus_mode(FOCUS_NONE); - file_options->set_tooltip(TTR("Miscenaneous options related to resources on disk.")); + split_box = memnew( VSplitContainer ); + add_child(split_box); + split_box->set_v_size_flags(SIZE_EXPAND_FILL); tree = memnew( Tree ); tree->set_hide_root(true); - add_child(tree); + split_box->add_child(tree); + tree->set_custom_minimum_size(Size2(0,200)); + tree->set_drag_forwarding(this); - tree->set_v_size_flags(SIZE_EXPAND_FILL); + //tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->connect("item_edited",this,"_favorite_toggled"); tree->connect("item_activated",this,"_open_pressed"); tree->connect("cell_selected",this,"_dir_selected"); @@ -1340,22 +1553,40 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { files->set_v_size_flags(SIZE_EXPAND_FILL); files->set_select_mode(ItemList::SELECT_MULTI); files->set_drag_forwarding(this); + files->connect("item_rmb_selected",this,"_files_list_rmb_select"); + files->set_allow_rmb_select(true); + + file_list_vb = memnew( VBoxContainer ); + split_box->add_child(file_list_vb); + file_list_vb->set_v_size_flags(SIZE_EXPAND_FILL); path_hb = memnew( HBoxContainer ); + file_list_vb->add_child(path_hb); + button_back = memnew( ToolButton ); path_hb->add_child(button_back); + button_back->hide(); current_path=memnew( LineEdit ); current_path->set_h_size_flags(SIZE_EXPAND_FILL); path_hb->add_child(current_path); + + search_box = memnew( LineEdit ); + search_box->set_h_size_flags(SIZE_EXPAND_FILL); + path_hb->add_child(search_box); + search_box->hide(); + search_box->connect("text_changed",this,"_search_changed"); + + search_button = memnew( ToolButton ); + path_hb->add_child(search_button); + search_button->set_toggle_mode(true ); + search_button->connect("pressed",this,"_search_toggled"); + display_mode = memnew( ToolButton ); path_hb->add_child(display_mode); display_mode->set_toggle_mode(true); - add_child(path_hb); - path_hb->hide(); + file_list_vb->add_child(files); - add_child(files); - files->hide(); scanning_vb = memnew( VBoxContainer ); Label *slabel = memnew( Label ); @@ -1393,7 +1624,8 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { history.push_back("res://"); history_pos=0; - tree_mode=true; + + split_mode=false; path="res://"; diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index 86196b7ccd..327e5a25f0 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -39,6 +39,7 @@ #include "scene/gui/menu_button.h" #include "scene/gui/item_list.h" #include "scene/gui/progress_bar.h" +#include "scene/gui/split_container.h" #include "os/dir_access.h" #include "os/thread.h" @@ -54,6 +55,8 @@ class ScenesDock : public VBoxContainer { OBJ_TYPE( ScenesDock, VBoxContainer ); enum FileMenu { + FILE_OPEN, + FILE_INSTANCE, FILE_DEPENDENCIES, FILE_OWNERS, FILE_MOVE, @@ -65,25 +68,28 @@ class ScenesDock : public VBoxContainer { VBoxContainer *scanning_vb; ProgressBar *scanning_progress; + VSplitContainer *split_box; + VBoxContainer *file_list_vb; EditorNode *editor; Set<String> favorites; Button *button_reload; - Button *button_instance; Button *button_favorite; Button *button_fav_up; Button *button_fav_down; - Button *button_open; Button *button_back; Button *display_mode; Button *button_hist_next; Button *button_hist_prev; LineEdit *current_path; + LineEdit *search_box; + Button *search_button; HBoxContainer *path_hb; - MenuButton *file_options; + bool split_mode; + PopupMenu *file_options; DependencyEditor *deps_editor; DependencyEditorOwners *owners_editor; @@ -107,8 +113,6 @@ class ScenesDock : public VBoxContainer { Tree * tree; //directories ItemList *files; - bool tree_mode; - void _go_to_tree(); void _go_to_dir(const String& p_dir); void _select_file(int p_idx); @@ -131,6 +135,7 @@ class ScenesDock : public VBoxContainer { void _bw_history(); void _push_to_history(); + void _fav_up_pressed(); void _fav_down_pressed(); void _dir_selected(); @@ -138,9 +143,27 @@ class ScenesDock : public VBoxContainer { void _rescan(); void _set_scannig_mode(); + void _favorites_pressed(); - void _instance_pressed(); void _open_pressed(); + void _search_toggled(); + void _search_changed(const String& p_text); + + + void _files_list_rmb_select(int p_item,const Vector2& p_pos); + + + struct FileInfo { + String name; + String path; + StringName type; + + bool operator<(const FileInfo& fi) const { + return name < fi.name; + } + }; + + void _search(EditorFileSystemDirectory *p_path, List<FileInfo>* matches, int p_max_items); 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; @@ -152,7 +175,7 @@ protected: public: String get_selected_path() const; - void open(const String& p_path); + void focus_on_filter(); void fix_dependencies(const String& p_for_file); |