diff options
133 files changed, 19181 insertions, 1313 deletions
diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 6204a87054..6770b798f1 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -232,6 +232,20 @@ Error Dictionary::parse_json(const String& p_json) { return OK; } +Dictionary Dictionary::copy() const { + + Dictionary n(is_shared()); + + List<Variant> keys; + get_key_list(&keys); + + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + n[E->get()]=operator[](E->get()); + } + + return n; +} + String Dictionary::to_json() const { return JSON::print(*this); diff --git a/core/dictionary.h b/core/dictionary.h index ae79fab9c3..6a5f4e20e6 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -83,6 +83,8 @@ public: Array keys() const; Array values() const; + Dictionary copy() const; + Dictionary(const Dictionary& p_from); Dictionary(bool p_shared=false); ~Dictionary(); diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/networked_multiplayer_peer.cpp new file mode 100644 index 0000000000..79f3e129e1 --- /dev/null +++ b/core/io/networked_multiplayer_peer.cpp @@ -0,0 +1,29 @@ +#include "networked_multiplayer_peer.h" + + +void NetworkedMultiplayerPeer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_transfer_mode","mode"), &NetworkedMultiplayerPeer::set_transfer_mode ); + ObjectTypeDB::bind_method(_MD("set_target_peer","id"), &NetworkedMultiplayerPeer::set_target_peer ); + ObjectTypeDB::bind_method(_MD("set_channel","id"), &NetworkedMultiplayerPeer::set_channel ); + + ObjectTypeDB::bind_method(_MD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer ); + ObjectTypeDB::bind_method(_MD("get_packet_channel"), &NetworkedMultiplayerPeer::get_packet_channel ); + + ObjectTypeDB::bind_method(_MD("poll"), &NetworkedMultiplayerPeer::poll ); + + + BIND_CONSTANT( TARGET_ALL_PEERS ); + + BIND_CONSTANT( TRANSFER_MODE_UNRELIABLE ); + BIND_CONSTANT( TRANSFER_MODE_RELIABLE ); + BIND_CONSTANT( TRANSFER_MODE_ORDERED ); + + ADD_SIGNAL( MethodInfo("peer_connected",PropertyInfo(Variant::INT,"id"))); + ADD_SIGNAL( MethodInfo("peer_disconnected",PropertyInfo(Variant::INT,"id"))); +} + +NetworkedMultiplayerPeer::NetworkedMultiplayerPeer() { + + +} diff --git a/core/io/networked_multiplayer_peer.h b/core/io/networked_multiplayer_peer.h new file mode 100644 index 0000000000..f140b57b8b --- /dev/null +++ b/core/io/networked_multiplayer_peer.h @@ -0,0 +1,40 @@ +#ifndef NETWORKED_MULTIPLAYER_PEER_H +#define NETWORKED_MULTIPLAYER_PEER_H + +#include "io/packet_peer.h" + +class NetworkedMultiplayerPeer : public PacketPeer { + + OBJ_TYPE(NetworkedMultiplayerPeer,PacketPeer); + +protected: + static void _bind_methods(); +public: + + enum { + TARGET_ALL_PEERS=0xFFFFFF // send to this for all peers + }; + + enum TransferMode { + TRANSFER_MODE_UNRELIABLE, + TRANSFER_MODE_RELIABLE, + TRANSFER_MODE_ORDERED + }; + + virtual void set_transfer_mode(TransferMode p_mode)=0; + virtual void set_target_peer(int p_peer)=0; + virtual void set_channel(int p_channel)=0; + + + virtual int get_packet_peer() const=0; + virtual int get_packet_channel() const=0; + + + virtual void poll()=0; + + NetworkedMultiplayerPeer(); +}; + +VARIANT_ENUM_CAST( NetworkedMultiplayerPeer::TransferMode ) + +#endif // NetworkedMultiplayerPeer_H diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 343a54e0d7..a620dc0fef 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -447,13 +447,17 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case VARIANT_INPUT_EVENT: { + InputEvent ev; + ev.type=f->get_32(); //will only work for null though. + r_v=ev; + } break; case VARIANT_DICTIONARY: { - uint32_t len=f->get_32(); - Dictionary d(len&0x80000000); //last bit means shared - len&=0x7FFFFFFF; - for(uint32_t i=0;i<len;i++) { + uint32_t len=f->get_32(); + Dictionary d(len&0x80000000); //last bit means shared + len&=0x7FFFFFFF; + for(uint32_t i=0;i<len;i++) { Variant key; Error err = parse_variant(key); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); @@ -466,11 +470,11 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case VARIANT_ARRAY: { - uint32_t len=f->get_32(); - Array a(len&0x80000000); //last bit means shared - len&=0x7FFFFFFF; + uint32_t len=f->get_32(); + Array a(len&0x80000000); //last bit means shared + len&=0x7FFFFFFF; a.resize(len); - for(uint32_t i=0;i<len;i++) { + for(uint32_t i=0;i<len;i++) { Variant val; Error err = parse_variant(val); ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); @@ -1725,7 +1729,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property, case Variant::INPUT_EVENT: { f->store_32(VARIANT_INPUT_EVENT); - WARN_PRINT("Can't save InputEvent (maybe it could..)"); + InputEvent event=p_property; + f->store_32(0); //event type none, nothing else suported for now. + } break; case Variant::DICTIONARY: { diff --git a/core/make_binders.py b/core/make_binders.py index c14f07ac83..7584722965 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -62,6 +62,8 @@ public: #else set_argument_count($argc$); #endif + + $ifret _set_returns(true); $ }; }; @@ -140,6 +142,9 @@ public: #else set_argument_count($argc$); #endif + $ifret _set_returns(true); $ + + }; }; diff --git a/core/method_bind.cpp b/core/method_bind.cpp index b41fa33887..a99d0af636 100644 --- a/core/method_bind.cpp +++ b/core/method_bind.cpp @@ -64,6 +64,12 @@ void MethodBind::_set_const(bool p_const) { _const=p_const; } +void MethodBind::_set_returns(bool p_returns) { + + _returns=p_returns; +} + + StringName MethodBind::get_name() const { return name; } @@ -118,6 +124,7 @@ MethodBind::MethodBind() { argument_types=NULL; #endif _const=false; + _returns=false; } MethodBind::~MethodBind() { diff --git a/core/method_bind.h b/core/method_bind.h index 30a848270d..072953743c 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -154,6 +154,9 @@ VARIANT_ENUM_CAST( wchar_t ); VARIANT_ENUM_CAST( Margin ); VARIANT_ENUM_CAST( Orientation ); VARIANT_ENUM_CAST( HAlign ); +VARIANT_ENUM_CAST( Variant::Type ); +VARIANT_ENUM_CAST( Variant::Operator ); +VARIANT_ENUM_CAST( InputEvent::Type ); class MethodBind { @@ -170,11 +173,13 @@ class MethodBind { StringName ret_type; #endif bool _const; + bool _returns; protected: void _set_const(bool p_const); + void _set_returns(bool p_returns); #ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const=0; void _generate_argument_types(int p_count); @@ -261,6 +266,7 @@ public: void set_name(const StringName& p_name); _FORCE_INLINE_ int get_method_id() const { return method_id; } _FORCE_INLINE_ bool is_const() const { return _const; } + _FORCE_INLINE_ bool has_return() const { return _returns; } void set_default_arguments(const Vector<Variant>& p_defargs); @@ -321,7 +327,7 @@ public: virtual bool is_const() const { return false; } virtual String get_instance_type() const { return T::get_type_static(); } - MethodBindNative() { call_method=NULL; } + MethodBindNative() { call_method=NULL; _set_returns(true);} }; diff --git a/core/object.h b/core/object.h index d7b0f09df9..400ab3070e 100644 --- a/core/object.h +++ b/core/object.h @@ -68,6 +68,8 @@ enum PropertyHint { PROPERTY_HINT_IMAGE_COMPRESS_LOSSY, PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS, PROPERTY_HINT_OBJECT_ID, + PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose + PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) PROPERTY_HINT_MAX, }; diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index 4998263961..ba98797a89 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -549,6 +549,23 @@ bool ObjectTypeDB::has_signal(StringName p_type,StringName p_signal) { return false; } +bool ObjectTypeDB::get_signal(StringName p_type,StringName p_signal,MethodInfo *r_signal) { + + TypeInfo *type=types.getptr(p_type); + TypeInfo *check=type; + while(check) { + if (check->signal_map.has(p_signal)) { + if (r_signal) { + *r_signal=check->signal_map[p_signal]; + } + return true; + } + check=check->inherits_ptr; + } + + return false; +} + void ObjectTypeDB::add_property(StringName p_type,const PropertyInfo& p_pinfo, const StringName& p_setter, const StringName& p_getter, int p_index) { diff --git a/core/object_type_db.h b/core/object_type_db.h index 4922e1b67f..3fcd38aa31 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -462,6 +462,7 @@ public: static void add_signal(StringName p_type,const MethodInfo& p_signal); static bool has_signal(StringName p_type,StringName p_signal); + static bool get_signal(StringName p_type,StringName p_signal,MethodInfo *r_signal); 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); diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 4c0a074a07..9710638234 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -429,6 +429,27 @@ static const _KeyCodeReplace _keycode_replace_neo[]={ {0,0} }; +int keycode_get_count() { + + const _KeyCodeText *kct =&_keycodes[0]; + + int count=0; + while(kct->text) { + + count++; + kct++; + } + return count; +} + +int keycode_get_value_by_index(int p_index) { + return _keycodes[p_index].code; +} + +const char* keycode_get_name_by_index(int p_index) { + return _keycodes[p_index].text; +} + int latin_keyboard_keycode_convert(int p_keycode) { diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 80472acc09..fd52d331c8 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -328,6 +328,9 @@ enum KeyModifierMask { String keycode_get_string(uint32_t p_code); bool keycode_has_unicode(uint32_t p_unicode); int find_keycode(const String& p_code); +int keycode_get_count(); +int keycode_get_value_by_index(int p_index); +const char* keycode_get_name_by_index(int p_index); int latin_keyboard_keycode_convert(int p_keycode); #endif diff --git a/core/script_language.h b/core/script_language.h index 6d75b83aaf..0e3f298790 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -98,6 +98,9 @@ public: virtual void set_source_code(const String& p_code)=0; virtual Error reload(bool p_keep_state=false)=0; + virtual bool has_method(const StringName& p_method) const=0; + virtual MethodInfo get_method_info(const StringName& p_method) const=0; + virtual bool is_tool() const=0; virtual String get_node_type() const=0; @@ -110,6 +113,7 @@ public: virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0; virtual void update_exports() {} //editor tool + virtual void get_method_list(List<MethodInfo> *p_list) const=0; Script() {} @@ -177,7 +181,7 @@ public: virtual void get_reserved_words(List<String> *p_words) const=0; virtual void get_comment_delimiters(List<String> *p_delimiters) const=0; virtual void get_string_delimiters(List<String> *p_delimiters) const=0; - virtual String get_template(const String& p_class_name, const String& p_base_class_name) const=0; + virtual Ref<Script> get_template(const String& p_class_name, const String& p_base_class_name) const=0; virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const=0; virtual Script *create_script() const=0; virtual bool has_named_classes() const=0; diff --git a/core/ustring.cpp b/core/ustring.cpp index 6788ada1bb..0d887210c3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -3491,7 +3491,7 @@ bool String::is_valid_integer() const { return false; int from=0; - if (operator[](0)=='+' || operator[](0)=='-') + if (len!=1 && (operator[](0)=='+' || operator[](0)=='-')) from++; for(int i=from;i<len;i++) { diff --git a/core/variant.h b/core/variant.h index 87bf20f8ee..b8b028a760 100644 --- a/core/variant.h +++ b/core/variant.h @@ -395,6 +395,10 @@ public: void get_method_list(List<MethodInfo> *p_list) const; bool has_method(const StringName& p_method) const; + static Vector<Variant::Type> get_method_argument_types(Variant::Type p_type,const StringName& p_method); + static Vector<Variant> get_method_default_arguments(Variant::Type p_type,const StringName& p_method); + static Variant::Type get_method_return_type(Variant::Type p_type,const StringName& p_method,bool* r_has_return=NULL); + static Vector<StringName> get_method_argument_names(Variant::Type p_type,const StringName& p_method); void set_named(const StringName& p_index, const Variant& p_value, bool *r_valid=NULL); Variant get_named(const StringName& p_index, bool *r_valid=NULL) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 7956c14c2c..069c20bc6e 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1173,6 +1173,56 @@ bool Variant::has_method(const StringName& p_method) const { } +Vector<Variant::Type> Variant::get_method_argument_types(Variant::Type p_type,const StringName& p_method) { + + const _VariantCall::TypeFunc &fd = _VariantCall::type_funcs[p_type]; + + const Map<StringName,_VariantCall::FuncData>::Element *E = fd.functions.find(p_method); + if (!E) + return Vector<Variant::Type>(); + + return E->get().arg_types; +} + +Vector<StringName> Variant::get_method_argument_names(Variant::Type p_type,const StringName& p_method) { + + + const _VariantCall::TypeFunc &fd = _VariantCall::type_funcs[p_type]; + + const Map<StringName,_VariantCall::FuncData>::Element *E = fd.functions.find(p_method); + if (!E) + return Vector<StringName>(); + + return E->get().arg_names; + +} + +Variant::Type Variant::get_method_return_type(Variant::Type p_type,const StringName& p_method,bool* r_has_return) { + + const _VariantCall::TypeFunc &fd = _VariantCall::type_funcs[p_type]; + + const Map<StringName,_VariantCall::FuncData>::Element *E = fd.functions.find(p_method); + if (!E) + return Variant::NIL; + + if (r_has_return) + *r_has_return=E->get().return_type; + + return E->get().return_type; +} + +Vector<Variant> Variant::get_method_default_arguments(Variant::Type p_type,const StringName& p_method) { + + const _VariantCall::TypeFunc &fd = _VariantCall::type_funcs[p_type]; + + const Map<StringName,_VariantCall::FuncData>::Element *E = fd.functions.find(p_method); + if (!E) + return Vector<Variant>(); + + return E->get().default_args; + +} + void Variant::get_method_list(List<MethodInfo> *p_list) const { diff --git a/doc/base/classes.xml b/doc/base/classes.xml index b7b0502eaa..7b7430ec13 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -22339,6 +22339,7 @@ <argument index="1" name="title" type="String" default=""Alert!""> </argument> <description> + Displays a modal dialog box utilizing the host OS. </description> </method> <method name="can_draw" qualifiers="const"> @@ -22352,6 +22353,7 @@ <return type="bool"> </return> <description> + Returns if the current host platform is using multiple threads. </description> </method> <method name="delay_msec" qualifiers="const"> @@ -22372,12 +22374,17 @@ <argument index="0" name="file" type="String"> </argument> <description> + Dumps the memory allocation ringlist to a file (only works in debug). + Entry format per line: "Address - Size - Description" </description> </method> <method name="dump_resources_to_file"> <argument index="0" name="file" type="String"> </argument> <description> + Dumps all used resources to file (only works in debug). + Entry format per line: "Resource Type : Resource Location" + At the end of the file is a statistic of all used Resource Types. </description> </method> <method name="execute"> @@ -22401,12 +22408,14 @@ <argument index="0" name="string" type="String"> </argument> <description> + Returns the scancode of the given string (e.g. "Escape") </description> </method> <method name="get_borderless_window" qualifiers="const"> <return type="bool"> </return> <description> + Returns true if the current window is borderless. </description> </method> <method name="get_clipboard" qualifiers="const"> @@ -22434,6 +22443,7 @@ <return type="String"> </return> <description> + Returns the value of the commandline argument "-level". </description> </method> <method name="get_data_dir" qualifiers="const"> @@ -22482,6 +22492,14 @@ <return type="Dictionary"> </return> <description> + Returns the current engine version information in a Dictionary. + + "major" - Holds the major version number as a String + "minor" - Holds the minor version number as a String + "patch" - Holds the patch version number as a String + "status" - Holds the status (e.g. "beta", "rc1", "rc2", ... "stable") as a String + "revision" - Holds the revision (e.g. "custom-build") as a String + "string" - major + minor + patch + status + revision in a single String </description> </method> <method name="get_environment" qualifiers="const"> @@ -22534,6 +22552,8 @@ <return type="String"> </return> <description> + Returns the current latin keyboard variant as a String. + Possible return values are: "QWERTY", "AZERTY", "QZERTY", "DVORAK", "NEO" or "ERROR" </description> </method> <method name="get_locale" qualifiers="const"> @@ -22554,6 +22574,7 @@ <return type="String"> </return> <description> + Returns the model name of the current device. </description> </method> <method name="get_name" qualifiers="const"> @@ -22583,6 +22604,7 @@ <argument index="0" name="code" type="int"> </argument> <description> + Returns the given scancode as a string (e.g. Return values: "Escape", "Shift+Escape"). </description> </method> <method name="get_screen_count" qualifiers="const"> @@ -30627,6 +30649,7 @@ <return type="Vector3"> </return> <description> + Returns collision point. This point is in [b]global[/b] coordinate system. </description> </method> <method name="get_layer_mask" qualifiers="const"> @@ -30669,6 +30692,7 @@ <argument index="0" name="local_point" type="Vector3"> </argument> <description> + Sets to which point ray should be casted. This point is in [b]local[/b] coordinate system. </description> </method> <method name="set_enabled"> diff --git a/main/input_default.cpp b/main/input_default.cpp index 618d0d4f7d..c655b409ff 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -588,7 +588,7 @@ static const char *s_ControllerMappings [] = "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,", "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,", - "030000005e0400008e02000001000000,Microsoft X-Box 360 pad,leftx:a0,lefty:a1,dpdown:h0.1,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:h0.2,lefttrigger:a2,x:b2,dpup:h0.4,back:b6,leftshoulder:b4,y:b3,a:b0,dpright:h0.8,righttrigger:a5,b:b1,", + "030000005e0400008e02000001000000,Microsoft X-Box 360 pad,leftstick:b9,leftx:a0,lefty:a1,dpdown:h0.1,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:h0.2,lefttrigger:a2,x:b2,dpup:h0.4,back:b6,leftshoulder:b4,y:b3,a:b0,dpright:h0.8,righttrigger:a5,b:b1,", "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,", "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", diff --git a/methods.py b/methods.py index 74c282b8cf..e29fd760ba 100755 --- a/methods.py +++ b/methods.py @@ -1213,7 +1213,9 @@ def detect_modules(): register_cpp="" unregister_cpp="" - for x in glob.glob("modules/*"): + files = glob.glob("modules/*") + files.sort() #so register_module_types does not change that often, and also plugins are registered in alphabetic order + for x in files: if (not os.path.isdir(x)): continue x=x.replace("modules/","") # rest of world diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index b02e55cf9d..2e5fb82f37 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -44,7 +44,7 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { } -String GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { +Ref<Script> GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { String _template = String()+ "\nextends %BASE%\n\n"+ @@ -58,7 +58,14 @@ String GDScriptLanguage::get_template(const String& p_class_name, const String& "\n"+ "\n"; - return _template.replace("%BASE%",p_base_class_name); + _template = _template.replace("%BASE%",p_base_class_name); + + Ref<GDScript> script; + script.instance(); + script->set_source_code(_template); + + return script; + } @@ -328,7 +335,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam for(int i=0;i<p_args.size();i++) { if (i>0) s+=", "; - s+=p_args[i]; + s+=p_args[i].get_slice(":",0); } s+=" "; } @@ -2382,7 +2389,24 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base } } } break; + case GDParser::COMPLETION_YIELD: { + + const GDParser::Node *node = p.get_completion_node(); + + GDCompletionIdentifier t; + if (!_guess_expression_type(context,node,p.get_completion_line(),t)) + break; + if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { + + List<MethodInfo> sigs; + ObjectTypeDB::get_signal_list(t.obj_type,&sigs); + for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) { + options.insert("\""+E->get().name+"\""); + } + } + + } break; } diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index de86eb2ab9..47d8f0b40f 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -372,8 +372,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language()==GDScriptLanguage::get_singleton()) { - GDInstance *ins = static_cast<GDInstance*>(obj_A->get_script_instance()); - GDScript *cmp = ins->script.ptr(); + GDScript *cmp = static_cast<GDScript*>(obj_A->get_script_instance()->get_script().ptr()); //bool found=false; while(cmp) { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index e829fa86b4..a6794564db 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -378,6 +378,21 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ tokenizer->advance(); + if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) { + + + completion_cursor=StringName(); + completion_node=object; + completion_type=COMPLETION_YIELD; + completion_class=current_class; + completion_function=current_function; + completion_line=tokenizer->get_token_line(); + completion_argument=0; + completion_block=current_block; + completion_found=true; + tokenizer->advance(); + } + Node *signal = _parse_and_reduce_expression(p_parent,p_static); if (!signal) return NULL; diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 4afc534a8c..2d6b52c473 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -375,7 +375,8 @@ public: COMPLETION_METHOD, COMPLETION_CALL_ARGUMENTS, COMPLETION_INDEX, - COMPLETION_VIRTUAL_FUNC + COMPLETION_VIRTUAL_FUNC, + COMPLETION_YIELD, }; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index db11974d0d..2b8d6e86e2 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -249,6 +249,50 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { }*/ #endif + +void GDScript::get_method_list(List<MethodInfo> *p_list) const { + + for (const Map<StringName,GDFunction*>::Element *E=member_functions.front();E;E=E->next()) { + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get()->get_argument_count();i++) { + PropertyInfo arg; + arg.type=Variant::NIL; //variant + arg.name=E->get()->get_argument_name(i); + mi.arguments.push_back(arg); + } + + mi.return_val.name="Variant"; + p_list->push_back(mi); + } +} + +bool GDScript::has_method(const StringName& p_method) const { + + return member_functions.has(p_method); +} + +MethodInfo GDScript::get_method_info(const StringName& p_method) const { + + const Map<StringName,GDFunction*>::Element *E=member_functions.find(p_method); + if (!E) + return MethodInfo(); + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get()->get_argument_count();i++) { + PropertyInfo arg; + arg.type=Variant::NIL; //variant + arg.name=E->get()->get_argument_name(i); + mi.arguments.push_back(arg); + } + + mi.return_val.name="Variant"; + return mi; + +} + + bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const { #ifdef TOOLS_ENABLED @@ -1222,6 +1266,8 @@ void GDInstance::call_multilevel_reversed(const StringName& p_method,const Varia } } + + void GDInstance::notification(int p_notification) { //notification is not virutal, it gets called at ALL levels just like in C. diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index f0b6b7103c..28a0df1efd 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -181,6 +181,10 @@ public: bool get_property_default_value(const StringName& p_property,Variant& r_value) const; + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName& p_method) const; + virtual MethodInfo get_method_info(const StringName& p_method) const; + virtual ScriptLanguage *get_language() const; GDScript(); @@ -373,7 +377,7 @@ public: virtual void get_reserved_words(List<String> *p_words) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; - virtual String get_template(const String& p_class_name, const String& p_base_class_name) const; + virtual Ref<Script> get_template(const String& p_class_name, const String& p_base_class_name) const; virtual bool validate(const String& p_script,int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 37a3fb2b25..6e73244b57 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -1808,6 +1808,7 @@ bool GridMap::is_using_baked_light() const{ } + GridMap::GridMap() { cell_size=2; diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub new file mode 100644 index 0000000000..403fe68f66 --- /dev/null +++ b/modules/visual_script/SCsub @@ -0,0 +1,5 @@ +Import('env') + +env.add_source_files(env.modules_sources,"*.cpp") + +Export('env') diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py new file mode 100644 index 0000000000..ea7e83378a --- /dev/null +++ b/modules/visual_script/config.py @@ -0,0 +1,11 @@ + + +def can_build(platform): + return True + + +def configure(env): + pass + + + diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp new file mode 100644 index 0000000000..1360e546f3 --- /dev/null +++ b/modules/visual_script/register_types.cpp @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "visual_script.h" +#include "visual_script_editor.h" +#include "io/resource_loader.h" +#include "visual_script_nodes.h" +#include "visual_script_func_nodes.h" +#include "visual_script_builtin_funcs.h" +#include "visual_script_flow_control.h" +#include "visual_script_yield_nodes.h" + + +VisualScriptLanguage *visual_script_language=NULL; + + +void register_visual_script_types() { + + ObjectTypeDB::register_type<VisualScript>(); + ObjectTypeDB::register_virtual_type<VisualScriptNode>(); + ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>(); + ObjectTypeDB::register_type<VisualScriptFunction>(); + ObjectTypeDB::register_type<VisualScriptOperator>(); + ObjectTypeDB::register_type<VisualScriptVariableSet>(); + ObjectTypeDB::register_type<VisualScriptVariableGet>(); + ObjectTypeDB::register_type<VisualScriptConstant>(); + ObjectTypeDB::register_type<VisualScriptIndexGet>(); + ObjectTypeDB::register_type<VisualScriptIndexSet>(); + ObjectTypeDB::register_type<VisualScriptGlobalConstant>(); + ObjectTypeDB::register_type<VisualScriptMathConstant>(); + ObjectTypeDB::register_type<VisualScriptEngineSingleton>(); + ObjectTypeDB::register_type<VisualScriptSceneNode>(); + ObjectTypeDB::register_type<VisualScriptSceneTree>(); + ObjectTypeDB::register_type<VisualScriptResourcePath>(); + ObjectTypeDB::register_type<VisualScriptSelf>(); + ObjectTypeDB::register_type<VisualScriptCustomNode>(); + ObjectTypeDB::register_type<VisualScriptSubCall>(); + + ObjectTypeDB::register_type<VisualScriptFunctionCall>(); + ObjectTypeDB::register_type<VisualScriptPropertySet>(); + ObjectTypeDB::register_type<VisualScriptPropertyGet>(); + ObjectTypeDB::register_type<VisualScriptScriptCall>(); + ObjectTypeDB::register_type<VisualScriptEmitSignal>(); + + ObjectTypeDB::register_type<VisualScriptReturn>(); + ObjectTypeDB::register_type<VisualScriptCondition>(); + ObjectTypeDB::register_type<VisualScriptWhile>(); + ObjectTypeDB::register_type<VisualScriptIterator>(); + ObjectTypeDB::register_type<VisualScriptSequence>(); + ObjectTypeDB::register_type<VisualScriptInputFilter>(); + ObjectTypeDB::register_type<VisualScriptInputSelector>(); + + ObjectTypeDB::register_type<VisualScriptYield>(); + ObjectTypeDB::register_type<VisualScriptYieldSignal>(); + + ObjectTypeDB::register_type<VisualScriptBuiltinFunc>(); + + visual_script_language=memnew( VisualScriptLanguage ); + //script_language_gd->init(); + ScriptServer::register_language(visual_script_language); + + register_visual_script_nodes(); + register_visual_script_func_nodes(); + register_visual_script_builtin_func_node(); + register_visual_script_flow_control_nodes(); + register_visual_script_yield_nodes(); + +#ifdef TOOLS_ENABLED + VisualScriptEditor::register_editor(); +#endif + + +} + +void unregister_visual_script_types() { + + + ScriptServer::unregister_language(visual_script_language); + + if (visual_script_language) + memdelete( visual_script_language ); + +} diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h new file mode 100644 index 0000000000..0a5805eb0b --- /dev/null +++ b/modules/visual_script/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_visual_script_types(); +void unregister_visual_script_types(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp new file mode 100644 index 0000000000..425436d907 --- /dev/null +++ b/modules/visual_script/visual_script.cpp @@ -0,0 +1,2617 @@ +#include "visual_script.h" +#include "visual_script_nodes.h" +#include "scene/main/node.h" + +#include "globals.h" +#define SCRIPT_VARIABLES_PREFIX "script_variables/" + + +//used by editor, this is not really saved +void VisualScriptNode::set_breakpoint(bool p_breakpoint) { + breakpoint=p_breakpoint; +} + +bool VisualScriptNode::is_breakpoint() const { + + return breakpoint; +} + +void VisualScriptNode::_notification(int p_what) { + + if (p_what==NOTIFICATION_POSTINITIALIZE) { + + int dvc = get_input_value_port_count(); + for(int i=0;i<dvc;i++) { + Variant::Type expected = get_input_value_port_info(i).type; + Variant::CallError ce; + default_input_values.push_back(Variant::construct(expected,NULL,0,ce,false)); + } + } +} + +void VisualScriptNode::ports_changed_notify(){ + + default_input_values.resize( MAX(default_input_values.size(),get_input_value_port_count()) ); //let it grow as big as possible, we don't want to lose values on resize + emit_signal("ports_changed"); +} + +void VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) { + + ERR_FAIL_INDEX(p_port,default_input_values.size()); + + default_input_values[p_port]=p_value; +} + +Variant VisualScriptNode::get_default_input_value(int p_port) const { + + ERR_FAIL_INDEX_V(p_port,default_input_values.size(),Variant()); + return default_input_values[p_port]; +} + +void VisualScriptNode::_set_default_input_values(Array p_values) { + + + default_input_values=p_values; +} + +Array VisualScriptNode::_get_default_input_values() const { + + //validate on save, since on load there is little info about this + + Array saved_values; + + //actually validate on save + for(int i=0;i<get_input_value_port_count();i++) { + + Variant::Type expected = get_input_value_port_info(i).type; + + if (i>=default_input_values.size()) { + + Variant::CallError ce; + saved_values.push_back(Variant::construct(expected,NULL,0,ce,false)); + } else { + + if (expected==Variant::NIL || expected==default_input_values[i].get_type()) { + saved_values.push_back(default_input_values[i]); + } else { + //not the same, reconvert + Variant::CallError ce; + Variant existing = default_input_values[i]; + const Variant *existingp=&existing; + saved_values.push_back( Variant::construct(expected,&existingp,1,ce,false) ); + } + } + } + return saved_values; +} + + + +void VisualScriptNode::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script); + ObjectTypeDB::bind_method(_MD("set_default_input_value","port_idx","value:Variant"),&VisualScriptNode::set_default_input_value); + ObjectTypeDB::bind_method(_MD("get_default_input_value:Variant","port_idx"),&VisualScriptNode::get_default_input_value); + ObjectTypeDB::bind_method(_MD("_set_default_input_values","values"),&VisualScriptNode::_set_default_input_values); + ObjectTypeDB::bind_method(_MD("_get_default_input_values"),&VisualScriptNode::_get_default_input_values); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY,"_default_input_values",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_default_input_values"),_SCS("_get_default_input_values")); + ADD_SIGNAL(MethodInfo("ports_changed")); +} + + +Ref<VisualScript> VisualScriptNode::get_visual_script() const { + + if (scripts_used.size()) + return Ref<VisualScript>(scripts_used.front()->get()); + + return Ref<VisualScript>(); + +} + +VisualScriptNode::VisualScriptNode() { + breakpoint=false; +} + +//////////////// + +///////////////////// + +VisualScriptNodeInstance::VisualScriptNodeInstance() { + + sequence_outputs=NULL; + input_ports=NULL; +} + +VisualScriptNodeInstance::~VisualScriptNodeInstance() { + + if (sequence_outputs) { + memdelete(sequence_outputs); + } + + if (input_ports) { + memdelete(input_ports); + } + + if (output_ports) { + memdelete(output_ports); + } + +} + +void VisualScript::add_function(const StringName& p_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(functions.has(p_name)); + + functions[p_name]=Function(); + functions[p_name].scroll=Vector2(-50,-100); +} + +bool VisualScript::has_function(const StringName& p_name) const { + + return functions.has(p_name); + +} +void VisualScript::remove_function(const StringName& p_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_name)); + + for (Map<int,Function::NodeData>::Element *E=functions[p_name].nodes.front();E;E=E->next()) { + + E->get().node->disconnect("ports_changed",this,"_node_ports_changed"); + E->get().node->scripts_used.erase(this); + } + + functions.erase(p_name); + +} + +void VisualScript::rename_function(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + functions[p_new_name]=functions[p_name]; + functions.erase(p_name); + +} + +void VisualScript::set_function_scroll(const StringName& p_name, const Vector2& p_scroll) { + + ERR_FAIL_COND(!functions.has(p_name)); + functions[p_name].scroll=p_scroll; + +} + +Vector2 VisualScript::get_function_scroll(const StringName& p_name) const { + + ERR_FAIL_COND_V(!functions.has(p_name),Vector2()); + return functions[p_name].scroll; + +} + + +void VisualScript::get_function_list(List<StringName> *r_functions) const { + + for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + r_functions->push_back(E->key()); + } + + r_functions->sort_custom<StringName::AlphCompare>(); + +} + +int VisualScript::get_function_node_id(const StringName& p_name) const { + + ERR_FAIL_COND_V(!functions.has(p_name),-1); + + return functions[p_name].function_id; + +} + + +void VisualScript::_node_ports_changed(int p_id) { + + + StringName function; + + for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + + if (E->get().nodes.has(p_id)) { + function=E->key(); + break; + } + } + + ERR_FAIL_COND(function==StringName()); + + Function &func = functions[function]; + Ref<VisualScriptNode> vsn = func.nodes[p_id].node; + + //must revalidate all the functions + + { + List<SequenceConnection> to_remove; + + for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id && E->get().from_output>=vsn->get_output_sequence_port_count()) { + + to_remove.push_back(E->get()); + } + if (E->get().to_node==p_id && !vsn->has_input_sequence_port()) { + + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.sequence_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + { + + List<DataConnection> to_remove; + + + for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id && E->get().from_port>=vsn->get_output_value_port_count()) { + to_remove.push_back(E->get()); + } + if (E->get().to_node==p_id && E->get().to_port>=vsn->get_input_value_port_count()) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.data_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + set_edited(true); //something changed, let's set as edited + emit_signal("node_ports_changed",function,p_id); + +} + +void VisualScript::add_node(const StringName& p_func,int p_id, const Ref<VisualScriptNode>& p_node, const Point2 &p_pos) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_func)); + + + for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + + ERR_FAIL_COND(E->get().nodes.has(p_id)); //id can exist only one in script, even for different functions + } + + Function &func = functions[p_func]; + + + if (p_node->cast_to<VisualScriptFunction>()) { + //the function indeed + ERR_EXPLAIN("A function node already has been set here."); + ERR_FAIL_COND(func.function_id>=0); + + func.function_id=p_id; + } + + Function::NodeData nd; + nd.node=p_node; + nd.pos=p_pos; + + Ref<VisualScriptNode> vsn = p_node; + vsn->connect("ports_changed",this,"_node_ports_changed",varray(p_id)); + vsn->scripts_used.insert(this); + + + + func.nodes[p_id]=nd; +} + +void VisualScript::remove_node(const StringName& p_func,int p_id){ + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + ERR_FAIL_COND(!func.nodes.has(p_id)); + { + List<SequenceConnection> to_remove; + + for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id || E->get().to_node==p_id) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.sequence_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + { + + List<DataConnection> to_remove; + + + for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id || E->get().to_node==p_id) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.data_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + if (func.nodes[p_id].node->cast_to<VisualScriptFunction>()) { + func.function_id=-1; //revert to invalid + } + + func.nodes[p_id].node->disconnect("ports_changed",this,"_node_ports_changed"); + func.nodes[p_id].node->scripts_used.erase(this); + + func.nodes.erase(p_id); + + +} + + +bool VisualScript::has_node(const StringName& p_func,int p_id) const { + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + return func.nodes.has(p_id); +} + +Ref<VisualScriptNode> VisualScript::get_node(const StringName& p_func,int p_id) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),Ref<VisualScriptNode>()); + const Function &func = functions[p_func]; + + ERR_FAIL_COND_V(!func.nodes.has(p_id),Ref<VisualScriptNode>()); + + return func.nodes[p_id].node; +} + +void VisualScript::set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + ERR_FAIL_COND(!func.nodes.has(p_id)); + func.nodes[p_id].pos=p_pos; +} + +Point2 VisualScript::get_node_pos(const StringName& p_func,int p_id) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),Point2()); + const Function &func = functions[p_func]; + + ERR_FAIL_COND_V(!func.nodes.has(p_id),Point2()); + return func.nodes[p_id].pos; +} + + +void VisualScript::get_node_list(const StringName& p_func,List<int> *r_nodes) const{ + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Map<int,Function::NodeData>::Element *E=func.nodes.front();E;E=E->next()) { + r_nodes->push_back(E->key()); + } + +} + + +void VisualScript::sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){ + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + ERR_FAIL_COND(func.sequence_connections.has(sc)); + + func.sequence_connections.insert(sc); + +} + +void VisualScript::sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){ + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + ERR_FAIL_COND(!func.sequence_connections.has(sc)); + + func.sequence_connections.erase(sc); + +} + +bool VisualScript::has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + + return func.sequence_connections.has(sc); +} + +void VisualScript::get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const { + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) { + r_connection->push_back(E->get()); + } +} + + +void VisualScript::data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + ERR_FAIL_COND( func.data_connections.has(dc)); + + func.data_connections.insert(dc); +} + +void VisualScript::data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) { + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + ERR_FAIL_COND( !func.data_connections.has(dc)); + + func.data_connections.erase(dc); + +} + +bool VisualScript::has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const { + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + return func.data_connections.has(dc); + +} + +bool VisualScript::is_input_value_port_connected(const StringName& p_func,int p_node,int p_port) const { + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().to_node==p_node && E->get().to_port==p_port) + return true; + } + + return false; +} + +void VisualScript::get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const { + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) { + r_connection->push_back(E->get()); + } +} + +void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(variables.has(p_name)); + + Variable v; + v.default_value=p_default_value; + v.info.type=p_default_value.get_type(); + v.info.name=p_name; + v.info.hint=PROPERTY_HINT_NONE; + + variables[p_name]=v; + script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name; + + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif + +} + +bool VisualScript::has_variable(const StringName& p_name) const { + + return variables.has(p_name); +} + +void VisualScript::remove_variable(const StringName& p_name) { + + ERR_FAIL_COND(!variables.has(p_name)); + variables.erase(p_name); + script_variable_remap.erase(SCRIPT_VARIABLES_PREFIX+String(p_name)); + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif +} + +void VisualScript::set_variable_default_value(const StringName& p_name,const Variant& p_value){ + + ERR_FAIL_COND(!variables.has(p_name)); + + variables[p_name].default_value=p_value; + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif + +} +Variant VisualScript::get_variable_default_value(const StringName& p_name) const{ + + ERR_FAIL_COND_V(!variables.has(p_name),Variant()); + return variables[p_name].default_value; + +} +void VisualScript::set_variable_info(const StringName& p_name,const PropertyInfo& p_info){ + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!variables.has(p_name)); + variables[p_name].info=p_info; + variables[p_name].info.name=p_name; + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif + + +} +PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{ + + ERR_FAIL_COND_V(!variables.has(p_name),PropertyInfo()); + return variables[p_name].info; +} + +void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) { + + PropertyInfo pinfo; + if (p_info.has("type")) + pinfo.type=Variant::Type(int(p_info["type"])); + if (p_info.has("name")) + pinfo.name=p_info["name"]; + if (p_info.has("hint")) + pinfo.hint=PropertyHint(int(p_info["hint"])); + if (p_info.has("hint_string")) + pinfo.hint_string=p_info["hint_string"]; + if (p_info.has("usage")) + pinfo.usage=p_info["usage"]; + + set_variable_info(p_name,pinfo); +} + +Dictionary VisualScript::_get_variable_info(const StringName& p_name) const{ + + PropertyInfo pinfo=get_variable_info(p_name); + Dictionary d; + d["type"]=pinfo.type; + d["name"]=pinfo.name; + d["hint"]=pinfo.hint; + d["hint_string"]=pinfo.hint_string; + d["usage"]=pinfo.usage; + + return d; +} + +void VisualScript::get_variable_list(List<StringName> *r_variables){ + + + for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + r_variables->push_back(E->key()); + } + + r_variables->sort_custom<StringName::AlphCompare>(); +} + + +void VisualScript::set_instance_base_type(const StringName& p_type) { + + ERR_FAIL_COND( instances.size() ); + base_type=p_type; +} + + +void VisualScript::rename_variable(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!variables.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + variables[p_new_name]=variables[p_name]; + variables.erase(p_name); + +} + +void VisualScript::add_custom_signal(const StringName& p_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(custom_signals.has(p_name)); + + custom_signals[p_name]=Vector<Argument>(); +} + +bool VisualScript::has_custom_signal(const StringName& p_name) const { + + return custom_signals.has(p_name); + +} +void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_func)); + Argument arg; + arg.type=p_type; + arg.name=p_name; + if (p_index<0) + custom_signals[p_func].push_back(arg); + else + custom_signals[p_func].insert(0,arg); + +} +void VisualScript::custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func][p_argidx].type=p_type; +} +Variant::Type VisualScript::custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),Variant::NIL); + ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),Variant::NIL); + return custom_signals[p_func][p_argidx].type; +} +void VisualScript::custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name) { + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func][p_argidx].name=p_name; + +} +String VisualScript::custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),String()); + ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),String()); + return custom_signals[p_func][p_argidx].name; + +} +void VisualScript::custom_signal_remove_argument(const StringName& p_func,int p_argidx) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func].remove(p_argidx); + +} + +int VisualScript::custom_signal_get_argument_count(const StringName& p_func) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),0); + return custom_signals[p_func].size(); + +} +void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + ERR_FAIL_INDEX(p_with_argidx,custom_signals[p_func].size()); + + SWAP( custom_signals[p_func][p_argidx], custom_signals[p_func][p_with_argidx] ); + +} +void VisualScript::remove_custom_signal(const StringName& p_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_name)); + custom_signals.erase(p_name); + +} + +void VisualScript::rename_custom_signal(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND( instances.size() ); + ERR_FAIL_COND(!custom_signals.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + custom_signals[p_new_name]=custom_signals[p_name]; + custom_signals.erase(p_name); + +} + +void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const { + + for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) { + r_custom_signals->push_back(E->key()); + } + + r_custom_signals->sort_custom<StringName::AlphCompare>(); + +} + +int VisualScript::get_available_id() const { + + int max_id=0; + for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + if (E->get().nodes.empty()) + continue; + + int last_id = E->get().nodes.back()->key(); + max_id=MAX(max_id,last_id+1); + } + + return max_id; +} + +///////////////////////////////// + + +bool VisualScript::can_instance() const { + + return true;//ScriptServer::is_scripting_enabled(); + +} + + +StringName VisualScript::get_instance_base_type() const { + + return base_type; +} + + +#ifdef TOOLS_ENABLED +void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + + + placeholders.erase(p_placeholder); +} + + +void VisualScript::_update_placeholders() { + + if (placeholders.size()==0) + return; //no bother if no placeholders + List<PropertyInfo> pinfo; + Map<StringName,Variant> values; + + for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + pinfo.push_back(p); + values[p.name]=E->get().default_value; + } + + for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + + E->get()->update(pinfo,values); + } + +} + +#endif + + +ScriptInstance* VisualScript::instance_create(Object *p_this) { + + + +#ifdef TOOLS_ENABLED + + if (!ScriptServer::is_scripting_enabled()) { + + + PlaceHolderScriptInstance *sins = memnew( PlaceHolderScriptInstance(VisualScriptLanguage::singleton,Ref<Script>((Script*)this),p_this)); + placeholders.insert(sins); + + List<PropertyInfo> pinfo; + Map<StringName,Variant> values; + + for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + pinfo.push_back(p); + values[p.name]=E->get().default_value; + } + + sins->update(pinfo,values); + + return sins; + } +#endif + + + VisualScriptInstance *instance=memnew( VisualScriptInstance ); + instance->create(Ref<VisualScript>(this),p_this); + + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->lock(); + + instances[p_this]=instance; + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->unlock(); + + return instance; +} + +bool VisualScript::instance_has(const Object *p_this) const { + + return instances.has((Object*)p_this); +} + +bool VisualScript::has_source_code() const { + + return false; +} + +String VisualScript::get_source_code() const { + + return String(); +} + +void VisualScript::set_source_code(const String& p_code) { + +} + +Error VisualScript::reload(bool p_keep_state) { + + return OK; +} + + +bool VisualScript::is_tool() const { + + return false; +} + + +String VisualScript::get_node_type() const { + + return String(); +} + + +ScriptLanguage *VisualScript::get_language() const { + + return VisualScriptLanguage::singleton; +} + + +bool VisualScript::has_script_signal(const StringName& p_signal) const { + + return custom_signals.has(p_signal); +} + +void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + + for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get().size();i++) { + PropertyInfo arg; + arg.type=E->get()[i].type; + arg.name=E->get()[i].name; + mi.arguments.push_back(arg); + } + + + r_signals->push_back(mi); + } + + +} + + +bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const { + + if (!script_variable_remap.has(p_property)) + return false; + + r_value=variables[ script_variable_remap[p_property] ].default_value; + return true; +} +void VisualScript::get_method_list(List<MethodInfo> *p_list) const { + + for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + if (E->get().function_id>=0) { + + Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node; + if (func.is_valid()) { + + for(int i=0;i<func->get_argument_count();i++) { + PropertyInfo arg; + arg.name=func->get_argument_name(i); + arg.type=func->get_argument_type(i); + mi.arguments.push_back(arg); + } + } + } + + p_list->push_back(mi); + } +} + +bool VisualScript::has_method(const StringName& p_method) const { + + return functions.has(p_method); +} +MethodInfo VisualScript::get_method_info(const StringName& p_method) const{ + + const Map<StringName,Function>::Element *E=functions.find(p_method); + if (!E) + return MethodInfo(); + + MethodInfo mi; + mi.name=E->key(); + if (E->get().function_id>=0) { + + Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node; + if (func.is_valid()) { + + for(int i=0;i<func->get_argument_count();i++) { + PropertyInfo arg; + arg.name=func->get_argument_name(i); + arg.type=func->get_argument_type(i); + mi.arguments.push_back(arg); + } + } + } + + return mi; +} + + +void VisualScript::_set_data(const Dictionary& p_data) { + + Dictionary d = p_data; + if (d.has("base_type")) + base_type=d["base_type"]; + + variables.clear(); + Array vars=d["variables"]; + for (int i=0;i<vars.size();i++) { + + Dictionary v=vars[i]; + StringName name = v["name"]; + add_variable(name); + _set_variable_info(name,v); + set_variable_default_value(name,v["default_value"]); + + } + + + custom_signals.clear(); + Array sigs=d["signals"]; + for (int i=0;i<sigs.size();i++) { + + Dictionary cs=sigs[i]; + add_custom_signal(cs["name"]); + + Array args=cs["arguments"]; + for(int j=0;j<args.size();j+=2) { + custom_signal_add_argument(cs["name"],Variant::Type(int(args[j+1])),args[j]); + } + } + + Array funcs=d["functions"]; + functions.clear(); + + for (int i=0;i<funcs.size();i++) { + + Dictionary func=funcs[i]; + + + StringName name=func["name"]; + //int id=func["function_id"]; + add_function(name); + + set_function_scroll(name,func["scroll"]); + + Array nodes = func["nodes"]; + + for(int i=0;i<nodes.size();i+=3) { + + add_node(name,nodes[i],nodes[i+2],nodes[i+1]); + } + + + Array sequence_connections=func["sequence_connections"]; + + for (int j=0;j<sequence_connections.size();j+=3) { + + sequence_connect(name,sequence_connections[j+0],sequence_connections[j+1],sequence_connections[j+2]); + } + + + Array data_connections=func["data_connections"]; + + for (int j=0;j<data_connections.size();j+=4) { + + data_connect(name,data_connections[j+0],data_connections[j+1],data_connections[j+2],data_connections[j+3]); + + } + + + } + +} + +Dictionary VisualScript::_get_data() const{ + + Dictionary d; + d["base_type"]=base_type; + Array vars; + for (const Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + + Dictionary var = _get_variable_info(E->key()); + var["name"]=E->key(); //make sure it's the right one + var["default_value"]=E->get().default_value; + vars.push_back(var); + } + d["variables"]=vars; + + Array sigs; + for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) { + + Dictionary cs; + cs["name"]=E->key(); + Array args; + for(int i=0;i<E->get().size();i++) { + args.push_back(E->get()[i].name); + args.push_back(E->get()[i].type); + } + cs["arguments"]=args; + + sigs.push_back(cs); + } + + d["signals"]=sigs; + + Array funcs; + + for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + + Dictionary func; + func["name"]=E->key(); + func["function_id"]=E->get().function_id; + func["scroll"]=E->get().scroll; + + Array nodes; + + for (const Map<int,Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + + nodes.push_back(F->key()); + nodes.push_back(F->get().pos); + nodes.push_back(F->get().node); + + } + + func["nodes"]=nodes; + + Array sequence_connections; + + for (const Set<SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) { + + sequence_connections.push_back(F->get().from_node); + sequence_connections.push_back(F->get().from_output); + sequence_connections.push_back(F->get().to_node); + + } + + + func["sequence_connections"]=sequence_connections; + + Array data_connections; + + for (const Set<DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) { + + data_connections.push_back(F->get().from_node); + data_connections.push_back(F->get().from_port); + data_connections.push_back(F->get().to_node); + data_connections.push_back(F->get().to_port); + + } + + + func["data_connections"]=data_connections; + + funcs.push_back(func); + + } + + d["functions"]=funcs; + + + return d; + +} + +void VisualScript::_bind_methods() { + + + + ObjectTypeDB::bind_method(_MD("_node_ports_changed"),&VisualScript::_node_ports_changed); + + ObjectTypeDB::bind_method(_MD("add_function","name"),&VisualScript::add_function); + ObjectTypeDB::bind_method(_MD("has_function","name"),&VisualScript::has_function); + ObjectTypeDB::bind_method(_MD("remove_function","name"),&VisualScript::remove_function); + ObjectTypeDB::bind_method(_MD("rename_function","name","new_name"),&VisualScript::rename_function); + ObjectTypeDB::bind_method(_MD("set_function_scroll","ofs"),&VisualScript::set_function_scroll); + ObjectTypeDB::bind_method(_MD("get_function_scroll"),&VisualScript::get_function_scroll); + + ObjectTypeDB::bind_method(_MD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2())); + ObjectTypeDB::bind_method(_MD("remove_node","func","id"),&VisualScript::remove_node); + ObjectTypeDB::bind_method(_MD("get_function_node_id","name"),&VisualScript::get_function_node_id); + + ObjectTypeDB::bind_method(_MD("get_node","func","id"),&VisualScript::get_node); + ObjectTypeDB::bind_method(_MD("has_node","func","id"),&VisualScript::has_node); + ObjectTypeDB::bind_method(_MD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos); + ObjectTypeDB::bind_method(_MD("get_node_pos","func","id"),&VisualScript::get_node_pos); + + ObjectTypeDB::bind_method(_MD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect); + ObjectTypeDB::bind_method(_MD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect); + ObjectTypeDB::bind_method(_MD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection); + + ObjectTypeDB::bind_method(_MD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect); + ObjectTypeDB::bind_method(_MD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect); + ObjectTypeDB::bind_method(_MD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection); + + ObjectTypeDB::bind_method(_MD("add_variable","name","default_value"),&VisualScript::add_variable,DEFVAL(Variant())); + ObjectTypeDB::bind_method(_MD("has_variable","name"),&VisualScript::has_variable); + ObjectTypeDB::bind_method(_MD("remove_variable","name"),&VisualScript::remove_variable); + ObjectTypeDB::bind_method(_MD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value); + ObjectTypeDB::bind_method(_MD("get_variable_default_value","name"),&VisualScript::get_variable_default_value); + ObjectTypeDB::bind_method(_MD("set_variable_info","name","value"),&VisualScript::_set_variable_info); + ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VisualScript::_get_variable_info); + ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable); + + ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal); + ObjectTypeDB::bind_method(_MD("has_custom_signal","name"),&VisualScript::has_custom_signal); + ObjectTypeDB::bind_method(_MD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type); + ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name); + ObjectTypeDB::bind_method(_MD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count); + ObjectTypeDB::bind_method(_MD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument); + ObjectTypeDB::bind_method(_MD("remove_custom_signal","name"),&VisualScript::remove_custom_signal); + ObjectTypeDB::bind_method(_MD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal); + + //ObjectTypeDB::bind_method(_MD("set_variable_info","name","info"),&VScript::set_variable_info); + //ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VScript::set_variable_info); + + ObjectTypeDB::bind_method(_MD("set_instance_base_type","type"),&VisualScript::set_instance_base_type); + + ObjectTypeDB::bind_method(_MD("_set_data","data"),&VisualScript::_set_data); + ObjectTypeDB::bind_method(_MD("_get_data"),&VisualScript::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data")); + + ADD_SIGNAL(MethodInfo("node_ports_changed",PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::INT,"id"))); +} + +VisualScript::VisualScript() { + + base_type="Object"; + +} + +VisualScript::~VisualScript() { + + while(!functions.empty()) { + remove_function(functions.front()->key()); + } + +} + +//////////////////////////////////////////// + + + +bool VisualScriptInstance::set(const StringName& p_name, const Variant& p_value) { + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) + return false; + + Map<StringName,Variant>::Element *E=variables.find(remap->get()); + ERR_FAIL_COND_V(!E,false); + + E->get()=p_value; + + return true; +} + + +bool VisualScriptInstance::get(const StringName& p_name, Variant &r_ret) const { + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) + return false; + + const Map<StringName,Variant>::Element *E=variables.find(remap->get()); + ERR_FAIL_COND_V(!E,false); + + return E->get(); +} +void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{ + + for (const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + p_properties->push_back(p); + + } +} +Variant::Type VisualScriptInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const{ + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) { + if (r_is_valid) + *r_is_valid=false; + return Variant::NIL; + } + + const Map<StringName,VisualScript::Variable>::Element *E=script->variables.find(remap->get()); + if (!E) { + if (r_is_valid) + *r_is_valid=false; + ERR_FAIL_V(Variant::NIL); + } + + if (r_is_valid) + *r_is_valid=true; + + return E->get().info.type; + +} + +void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const{ + + for (const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + if (E->get().function_id>=0 && E->get().nodes.has(E->get().function_id)) { + + Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node; + if (vsf.is_valid()) { + + for(int i=0;i<vsf->get_argument_count();i++) { + PropertyInfo arg; + arg.name=vsf->get_argument_name(i); + arg.type=vsf->get_argument_type(i); + + mi.arguments.push_back(arg); + } + + //vsf->Get_ for now at least it does not return.. + } + } + + p_list->push_back(mi); + } + +} +bool VisualScriptInstance::has_method(const StringName& p_method) const{ + + return script->functions.has(p_method); +} + + +//#define VSDEBUG(m_text) print_line(m_text) +#define VSDEBUG(m_text) + +Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p_stack, int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield, Variant::CallError &r_error) { + + Map<StringName,Function>::Element *F = functions.find(p_method); + ERR_FAIL_COND_V(!F,Variant()); + Function *f=&F->get(); + + //this call goes separate, so it can e yielded and suspended + Variant *variant_stack=(Variant*)p_stack; + bool *sequence_bits = (bool*)(variant_stack + f->max_stack); + const Variant **input_args=(const Variant**)(sequence_bits+f->node_count); + Variant **output_args=(Variant**)(input_args + max_input_args); + int flow_max = f->flow_stack_size; + int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL; + + String error_str; + + VisualScriptNodeInstance* node=p_node; + bool error=false; + int current_node_id=f->node; + Variant return_value; + Variant *working_mem=NULL; + + int flow_stack_pos=p_flow_stack_pos; + +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) { + VisualScriptLanguage::singleton->enter_function(this,&p_method,variant_stack,&working_mem,¤t_node_id); + } +#endif + + while(true) { + + current_node_id=node->get_id(); + + VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type()); + VSDEBUG("AT STACK POS: "+itos(flow_stack_pos)); + + + //setup working mem + working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL; + + VSDEBUG("WORKING MEM: "+itos(node->working_mem_idx)); + + if (current_node_id==f->node) { + //if function node, set up function arguments from begining of stack + + for(int i=0;i<f->argument_count;i++) { + input_args[i]=&variant_stack[i]; + } + } else { + //setup input pointers normally + VSDEBUG("INPUT PORTS: "+itos(node->input_port_count)); + + for(int i=0 ; i<node->input_port_count ; i++) { + + + int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK; + + if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { + //is a default value (unassigned input port) + input_args[i]=&default_values[index]; + VSDEBUG("\tPORT "+itos(i)+" DEFAULT VAL"); + } else if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) { + //from a node that requires read + Function::UnsequencedGet *ug = &f->unsequenced_gets[index]; + + bool ok = ug->from->get_output_port_unsequenced(i,&variant_stack[ug->to_stack],working_mem,error_str); + if (!ok) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + current_node_id=ug->from->get_id(); + error=true; + working_mem=NULL; + break; + } + + VSDEBUG("\tPORT "+itos(i)+" UNSEQ READ TO STACK: " + itos(ug->to_stack)); + input_args[i]=&variant_stack[ug->to_stack]; + } else { + //regular temporary in stack + input_args[i]=&variant_stack[index]; + VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(index)); + + } + } + } + + if (error) + break; + + //setup output pointers + + VSDEBUG("OUTPUT PORTS: "+itos(node->output_port_count)); + for(int i=0 ; i<node->output_port_count ; i++) { + output_args[i] = &variant_stack[ node->output_ports[i] ]; + VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(node->output_ports[i])); + } + + //do step + + VisualScriptNodeInstance::StartMode start_mode; + { + if (p_resuming_yield) + start_mode=VisualScriptNodeInstance::START_MODE_RESUME_YIELD; + else if (flow_stack && !(flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT)) //if there is a push bit, it means we are continuing a sequence + start_mode=VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE; + else + start_mode=VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE; + } + + VSDEBUG("STEP - STARTSEQ: "+itos(start_sequence)); + + int ret = node->step(input_args,output_args,start_mode,working_mem,r_error,error_str); + + if (r_error.error!=Variant::CallError::CALL_OK) { + //use error from step + error=true; + break; + } + + if (ret&VisualScriptNodeInstance::STEP_YIELD_BIT) { + //yielded! + if (node->get_working_memory_size()==0) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("A node yielded without working memory, please read the docs on how to yield properly!"); + error=true; + break; + + } else { + Ref<VisualScriptFunctionState> state = *working_mem; + if (!state.is_valid()) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Node yielded, but did not return a function state in the first working memory."); + error=true; + break; + + } + + //step 1, capture all state + state->instance_id=get_owner_ptr()->get_instance_ID(); + state->script_id=get_script()->get_instance_ID(); + state->instance=this; + state->function=p_method; + state->working_mem_index=node->working_mem_idx; + state->variant_stack_size=f->max_stack; + state->node=node; + state->flow_stack_pos=flow_stack_pos; + state->stack.resize(p_stack_size); + copymem(state->stack.ptr(),p_stack,p_stack_size); + //step 2, run away, return directly + r_error.error=Variant::CallError::CALL_OK; + + +#ifdef DEBUG_ENABLED + //will re-enter later, so exiting + if (ScriptDebugger::get_singleton()) { + VisualScriptLanguage::singleton->exit_function(); + } +#endif + + return state; + + } + } + +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) { + // line + bool do_break=false; + + if (ScriptDebugger::get_singleton()->get_lines_left()>0) { + + if (ScriptDebugger::get_singleton()->get_depth()<=0) + ScriptDebugger::get_singleton()->set_lines_left( ScriptDebugger::get_singleton()->get_lines_left() -1 ); + if (ScriptDebugger::get_singleton()->get_lines_left()<=0) + do_break=true; + } + + if (ScriptDebugger::get_singleton()->is_breakpoint(current_node_id,source)) + do_break=true; + + if (do_break) { + VisualScriptLanguage::singleton->debug_break("Breakpoint",true); + } + + ScriptDebugger::get_singleton()->line_poll(); + + } +#endif + int output = ret & VisualScriptNodeInstance::STEP_MASK; + + VSDEBUG("STEP RETURN: "+itos(ret)); + + if (ret & VisualScriptNodeInstance::STEP_EXIT_FUNCTION_BIT) { + if (node->get_working_memory_size()==0) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Return value must be assigned to first element of node working memory! Fix your node please."); + error=true; + } else { + //assign from working memory, first element + return_value=*working_mem; + } + + VSDEBUG("EXITING FUNCTION - VALUE "+String(return_value)); + break; //exit function requested, bye + } + + VisualScriptNodeInstance *next=NULL; //next node + + if ( (ret==output || ret&VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) { + //if no exit bit was set, and has sequence outputs, guess next node + if (output<0 || output>=node->sequence_output_count) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Node returned an invalid sequence output: ")+itos(output); + error=true; + break; + } + + next = node->sequence_outputs[output]; + if (next) { + VSDEBUG("GOT NEXT NODE - "+itos(next->get_id())); + } else { + VSDEBUG("GOT NEXT NODE - NULL"); + } + } + + if (flow_stack) { + + //update flow stack pos (may have changed) + flow_stack[flow_stack_pos] = current_node_id; + + //add stack push bit if requested + if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) { + + flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT; + sequence_bits[ node ->sequence_index ]=true; //remember sequence bit + VSDEBUG("NEXT SEQ - FLAG BIT"); + } else { + sequence_bits[ node ->sequence_index ]=false; //forget sequence bit + VSDEBUG("NEXT SEQ - NORMAL"); + } + + + if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) { + //go back request + + if (flow_stack_pos>0) { + flow_stack_pos--; + node = instances[ flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_MASK ]; + VSDEBUG("NEXT IS GO BACK"); + } else { + VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT"); + break; //simply exit without value or error + } + } else if (next) { + + + if (sequence_bits[next->sequence_index]) { + // what happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front + // because each node has a working memory, we can't really do a sub-sequence + // as a result, the sequence will be restarted and the stack will roll back to find where this node + // started the sequence + + bool found = false; + + for(int i=flow_stack_pos;i>=0;i--) { + + + if ( (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ) == next->get_id() ) { + flow_stack_pos=i; //roll back and remove bit + flow_stack[i]=next->get_id(); + sequence_bits[next->sequence_index]=false; + found=true; + } + } + + if (!found) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Found sequence bit but not the node in the stack, report bug!"); + error=true; + break; + } + + node=next; + VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - "+itos(flow_stack_pos)); + + } else { + // check for stack overflow + if (flow_stack_pos+1 >= flow_max) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Stack overflow with stack depth: ")+itos(output); + error=true; + break; + } + + node = next; + + flow_stack_pos++; + flow_stack[flow_stack_pos]=node->get_id(); + + VSDEBUG("INCREASE FLOW STACK"); + + } + + } else { + //no next node, try to go back in stack to pushed bit + + bool found = false; + + for(int i=flow_stack_pos;i>=0;i--) { + + VSDEBUG("FS "+itos(i)+" - "+itos(flow_stack[i])); + if (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT) { + + node = instances[ flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ]; + flow_stack_pos=i; + found=true; + } + } + + if (!found) { + VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING"); + break; //done, couldn't find a push stack bit + } + + VSDEBUG("NO NEXT NODE, GO BACK TO: "+itos(flow_stack_pos)); + + } + } else { + + node=next; //stackless mode, simply assign next node + } + + } + + + + if (error) { + + //error + // function, file, line, error, explanation + String err_file = script->get_path(); + String err_func = p_method; + int err_line=current_node_id; //not a line but it works as one + + + //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { + // debugger break did not happen + + if (!VisualScriptLanguage::singleton->debug_break(error_str,false)) { + + _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,error_str.utf8().get_data(),ERR_HANDLER_SCRIPT); + } + + //} + } else { + + + //return_value= + } + +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) { + VisualScriptLanguage::singleton->exit_function(); + } +#endif + + //clean up variant stack + for(int i=0;i<f->max_stack;i++) { + variant_stack[i].~Variant(); + } + + + return return_value; +} + + +Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error){ + + r_error.error=Variant::CallError::CALL_OK; //ok by default + + Map<StringName,Function>::Element *F = functions.find(p_method); + if (!F) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); + } + + VSDEBUG("CALLING: "+String(p_method)); + + Function *f=&F->get(); + + int total_stack_size=0; + + total_stack_size+=f->max_stack*sizeof(Variant); //variants + total_stack_size+=f->node_count*sizeof(bool); + total_stack_size+=(max_input_args+max_output_args)*sizeof(Variant*); //arguments + total_stack_size+=f->flow_stack_size*sizeof(int); //flow + + VSDEBUG("STACK SIZE: "+itos(total_stack_size)); + VSDEBUG("STACK VARIANTS: : "+itos(f->max_stack)); + VSDEBUG("SEQBITS: : "+itos(f->node_count)); + VSDEBUG("MAX INPUT: "+itos(max_input_args)); + VSDEBUG("MAX OUTPUT: "+itos(max_output_args)); + VSDEBUG("FLOW STACK SIZE: "+itos(f->flow_stack_size)); + + void *stack = alloca(total_stack_size); + + Variant *variant_stack=(Variant*)stack; + bool *sequence_bits = (bool*)(variant_stack + f->max_stack); + const Variant **input_args=(const Variant**)(sequence_bits+f->node_count); + Variant **output_args=(Variant**)(input_args + max_input_args); + int flow_max = f->flow_stack_size; + int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL; + + for(int i=0;i<f->node_count;i++) { + sequence_bits[i]=false; //all starts as false + } + + + Map<int,VisualScriptNodeInstance*>::Element *E = instances.find(f->node); + if (!E) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + + ERR_EXPLAIN("No VisualScriptFunction node in function!"); + ERR_FAIL_V(Variant()); + } + + VisualScriptNodeInstance *node = E->get(); + + + if (flow_stack) { + flow_stack[0]=node->get_id(); + } + + VSDEBUG("ARGUMENTS: "+itos(f->argument_count)=" RECEIVED: "+itos(p_argcount)); + + if (p_argcount<f->argument_count) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=node->get_input_port_count(); + + return Variant(); + } + + if (p_argcount>f->argument_count) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument=node->get_input_port_count(); + + return Variant(); + } + + //allocate variant stack + for(int i=0;i<f->max_stack;i++) { + memnew_placement(&variant_stack[i],Variant); + } + + //allocate function arguments (must be copied for yield to work properly) + for(int i=0;i<p_argcount;i++) { + variant_stack[i]=*p_args[i]; + } + + return _call_internal(p_method,stack,total_stack_size,node,0,false,r_error); + + +} + +void VisualScriptInstance::notification(int p_notification){ + + //do nothing as this is called using virtual + + Variant what=p_notification; + const Variant*whatp=&what; + Variant::CallError ce; + call(VisualScriptLanguage::singleton->notification,&whatp,1,ce); //do as call + +} + +Ref<Script> VisualScriptInstance::get_script() const{ + + return script; +} + + +void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_owner) { + + script=p_script; + owner=p_owner; + source=p_script->get_path(); + + max_input_args = 0; + max_output_args = 0; + + if (p_owner->cast_to<Node>()) { + //turn on these if they exist and base is a node + Node* node = p_owner->cast_to<Node>(); + if (p_script->functions.has("_process")) + node->set_process(true); + if (p_script->functions.has("_fixed_process")) + node->set_fixed_process(true); + if (p_script->functions.has("_input")) + node->set_process_input(true); + if (p_script->functions.has("_unhandled_input")) + node->set_process_unhandled_input(true); + if (p_script->functions.has("_unhandled_key_input")) + node->set_process_unhandled_key_input(true); + } + + for(const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) { + variables[E->key()]=E->get().default_value; + } + + + for(const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) { + + Function function; + function.node=E->get().function_id; + function.max_stack=0; + function.flow_stack_size=0; + function.node_count=0; + + if (function.node<0) { + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No start node in function: "+String(E->key())); + + ERR_CONTINUE( function.node < 0 ); + } + + { + Ref<VisualScriptFunction> func_node = script->get_node(E->key(),E->get().function_id); + + if (func_node.is_null()) { + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No VisualScriptFunction typed start node in function: "+String(E->key())); + } + + ERR_CONTINUE( !func_node.is_valid() ); + + function.argument_count=func_node->get_argument_count(); + function.max_stack+=function.argument_count; + function.flow_stack_size= func_node->is_stack_less() ? 0 : func_node->get_stack_size(); + + } + + //multiple passes are required to set up this complex thing.. + + + + + //first create the nodes + for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + + Ref<VisualScriptNode> node = F->get().node; + VisualScriptNodeInstance *instance = node->instance(this); //create instance + ERR_FAIL_COND(!instance); + + instance->base=node.ptr(); + + instance->id=F->key(); + instance->input_port_count = node->get_input_value_port_count(); + instance->output_port_count = node->get_output_value_port_count(); + instance->sequence_output_count = node->get_output_sequence_port_count(); + instance->sequence_index=function.node_count++; + + if (instance->input_port_count) { + instance->input_ports = memnew_arr(int,instance->input_port_count); + for(int i=0;i<instance->input_port_count;i++) { + instance->input_ports[i]=-1; //if not assigned, will become default value + } + } + + if (instance->output_port_count) { + instance->output_ports = memnew_arr(int,instance->output_port_count); + for(int i=0;i<instance->output_port_count;i++) { + instance->output_ports[i]=-1; //if not assigned, will output to trash + } + } + + if (instance->sequence_output_count) { + instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance*,instance->sequence_output_count); + for(int i=0;i<instance->sequence_output_count;i++) { + instance->sequence_outputs[i]=NULL; //if it remains null, flow ends here + } + } + + if (instance->get_working_memory_size()) { + instance->working_mem_idx = function.max_stack; + function.max_stack+=instance->get_working_memory_size(); + } else { + instance->working_mem_idx=-1; //no working mem + } + + max_input_args = MAX( max_input_args, instance->input_port_count ); + max_output_args = MAX( max_output_args, instance->output_port_count ); + + instances[F->key()]=instance; + + + } + + function.trash_pos = function.max_stack++; //create pos for trash + + //second pass, do data connections + + for(const Set<VisualScript::DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) { + + VisualScript::DataConnection dc = F->get(); + ERR_CONTINUE(!instances.has(dc.from_node)); + VisualScriptNodeInstance *from = instances[dc.from_node]; + ERR_CONTINUE(!instances.has(dc.to_node)); + VisualScriptNodeInstance *to = instances[dc.to_node]; + ERR_CONTINUE(dc.from_port >= from->output_port_count); + ERR_CONTINUE(dc.to_port >= to->input_port_count); + + if (from->output_ports[dc.from_port]==-1) { + + int stack_pos = function.max_stack++; + from->output_ports[dc.from_port] = stack_pos; + } + + + if (from->is_output_port_unsequenced(dc.from_node)) { + + //prepare an unsequenced read (must actually get the value from the output) + int stack_pos = function.max_stack++; + + Function::UnsequencedGet uget; + uget.from=from; + uget.from_port=dc.from_port; + uget.to_stack=stack_pos; + + to->input_ports[dc.to_port] = function.unsequenced_gets.size() | VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT; + function.unsequenced_gets.push_back(uget); + + } else { + + to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is + } + + } + + //third pass, do sequence connections + + for(const Set<VisualScript::SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) { + + VisualScript::SequenceConnection sc = F->get(); + ERR_CONTINUE(!instances.has(sc.from_node)); + VisualScriptNodeInstance *from = instances[sc.from_node]; + ERR_CONTINUE(!instances.has(sc.to_node)); + VisualScriptNodeInstance *to = instances[sc.to_node]; + ERR_CONTINUE(sc.from_output >= from->sequence_output_count); + + from->sequence_outputs[sc.from_output]=to; + + } + + //fourth pass: + // 1) unassigned input ports to default values + // 2) connect unassigned output ports to trash + + + for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + + ERR_CONTINUE(!instances.has(F->key())); + + Ref<VisualScriptNode> node = F->get().node; + VisualScriptNodeInstance *instance = instances[F->key()]; + + // conect to default values + for(int i=0;i<instance->input_port_count;i++) { + if (instance->input_ports[i]==-1) { + + //unassigned, connect to default val + instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT; + default_values.push_back( node->get_default_input_value(i) ); + } + } + + // conect to trash + for(int i=0;i<instance->output_port_count;i++) { + if (instance->output_ports[i]==-1) { + instance->output_ports[i] = function.trash_pos; //trash is same for all + } + } + } + + + functions[E->key()]=function; + } +} + +ScriptLanguage *VisualScriptInstance::get_language(){ + + return VisualScriptLanguage::singleton; +} + + +VisualScriptInstance::VisualScriptInstance() { + + +} + +VisualScriptInstance::~VisualScriptInstance() { + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->lock(); + + script->instances.erase(owner); + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->unlock(); + + for (Map<int,VisualScriptNodeInstance*>::Element *E=instances.front();E;E=E->next()) { + memdelete(E->get()); + } +} + + + +///////////////////////////////////////////// + + +///////////////////// + + +Variant VisualScriptFunctionState::_signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + ERR_FAIL_COND_V(function==StringName(),Variant()); + +#ifdef DEBUG_ENABLED + if (instance_id && !ObjectDB::get_instance(instance_id)) { + ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_FAIL_V(Variant()); + } + + if (script_id && !ObjectDB::get_instance(script_id)) { + ERR_EXPLAIN("Resumed after yield, but script is gone"); + ERR_FAIL_V(Variant()); + } +#endif + + r_error.error=Variant::CallError::CALL_OK; + + Array args; + + if (p_argcount==0) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } else if (p_argcount==1) { + //noooneee, reserved for me, me and only me. + } else { + + for(int i=0;i<p_argcount-1;i++) { + args.push_back(*p_args[i]); + } + } + + Ref<VisualScriptFunctionState> self = *p_args[p_argcount-1]; //hi, I'm myself, needed this to remain alive. + + if (self.is_null()) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=p_argcount-1; + r_error.expected=Variant::OBJECT; + return Variant(); + } + + r_error.error=Variant::CallError::CALL_OK; + + Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index; + + *working_mem=args; //arguments go to working mem. + + Variant ret = instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error); + function=StringName(); //invalidate + return ret; +} + +void VisualScriptFunctionState::connect_to_signal(Object* p_obj, const String& p_signal, Array p_binds) { + + Vector<Variant> binds; + for(int i=0;i<p_binds.size();i++) { + binds.push_back(p_binds[i]); + } + binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing + p_obj->connect(p_signal,this,"_signal_callback",binds); +} + +bool VisualScriptFunctionState::is_valid() const { + + return function!=StringName(); +} + +Variant VisualScriptFunctionState::resume(Array p_args) { + + ERR_FAIL_COND_V(function==StringName(),Variant()); +#ifdef DEBUG_ENABLED + if (instance_id && !ObjectDB::get_instance(instance_id)) { + ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_FAIL_V(Variant()); + } + + if (script_id && !ObjectDB::get_instance(script_id)) { + ERR_EXPLAIN("Resumed after yield, but script is gone"); + ERR_FAIL_V(Variant()); + } +#endif + + Variant::CallError r_error; + r_error.error=Variant::CallError::CALL_OK; + + Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index; + + *working_mem=p_args; //arguments go to working mem. + + Variant ret= instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error); + function=StringName(); //invalidate + return ret; +} + + +void VisualScriptFunctionState::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal); + ObjectTypeDB::bind_method(_MD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant())); + ObjectTypeDB::bind_method(_MD("is_valid"),&VisualScriptFunctionState::is_valid); + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); +} + +VisualScriptFunctionState::VisualScriptFunctionState() { + +} + +VisualScriptFunctionState::~VisualScriptFunctionState() { + + if (function!=StringName()) { + Variant *s = ((Variant*)stack.ptr()); + for(int i=0;i<variant_stack_size;i++) { + s[i].~Variant(); + } + } +} + + + + + +/////////////////////////////////////////////// + +String VisualScriptLanguage::get_name() const { + + return "VisualScript"; +} + +/* LANGUAGE FUNCTIONS */ +void VisualScriptLanguage::init() { + + +} +String VisualScriptLanguage::get_type() const { + + return "VisualScript"; +} +String VisualScriptLanguage::get_extension() const { + + return "vs"; +} +Error VisualScriptLanguage::execute_file(const String& p_path) { + + return OK; +} +void VisualScriptLanguage::finish() { + + +} + +/* EDITOR FUNCTIONS */ +void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const { + + +} +void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { + + +} +void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { + + +} +Ref<Script> VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { + + Ref<VisualScript> script; + script.instance(); + script->set_instance_base_type(p_base_class_name); + return script; +} +bool VisualScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List<String> *r_functions) const { + + return false; +} +Script *VisualScriptLanguage::create_script() const { + + return memnew( VisualScript ); +} +bool VisualScriptLanguage::has_named_classes() const { + + return false; +} +int VisualScriptLanguage::find_function(const String& p_function,const String& p_code) const { + + return -1; +} +String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { + + return String(); +} + +void VisualScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const { + + +} +void VisualScriptLanguage::add_global_constant(const StringName& p_variable,const Variant& p_value) { + + +} + + +/* DEBUGGER FUNCTIONS */ + + + +bool VisualScriptLanguage::debug_break_parse(const String& p_file, int p_node,const String& p_error) { + //break because of parse error + + if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) { + + _debug_parse_err_node=p_node; + _debug_parse_err_file=p_file; + _debug_error=p_error; + ScriptDebugger::get_singleton()->debug(this,false); + return true; + } else { + return false; + } + +} + +bool VisualScriptLanguage::debug_break(const String& p_error,bool p_allow_continue) { + + if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) { + + _debug_parse_err_node=-1; + _debug_parse_err_file=""; + _debug_error=p_error; + ScriptDebugger::get_singleton()->debug(this,p_allow_continue); + return true; + } else { + return false; + } + +} + + +String VisualScriptLanguage::debug_get_error() const { + + return _debug_error; +} + +int VisualScriptLanguage::debug_get_stack_level_count() const { + + if (_debug_parse_err_node>=0) + return 1; + + + return _debug_call_stack_pos; +} +int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const { + + if (_debug_parse_err_node>=0) + return _debug_parse_err_node; + + ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,-1); + + int l = _debug_call_stack_pos - p_level -1; + + return *(_call_stack[l].current_id); + +} +String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const { + + if (_debug_parse_err_node>=0) + return ""; + + ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,""); + int l = _debug_call_stack_pos - p_level -1; + return *_call_stack[l].function; +} +String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const { + + if (_debug_parse_err_node>=0) + return _debug_parse_err_file; + + ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,""); + int l = _debug_call_stack_pos - p_level -1; + return _call_stack[l].instance->get_script_ptr()->get_path(); + +} +void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) { + + if (_debug_parse_err_node>=0) + return; + + ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); + + int l = _debug_call_stack_pos - p_level -1; + const StringName *f = _call_stack[l].function; + + ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f)); + VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f]; + + VisualScriptNodeInstance *node =_call_stack[l].instance->instances[*_call_stack[l].current_id]; + ERR_FAIL_COND(!node); + + p_locals->push_back("node_name"); + p_values->push_back(node->get_base_node()->get_text()); + + for(int i=0;i<node->input_port_count;i++) { + String name = node->get_base_node()->get_input_value_port_info(i).name; + if (name==String()) { + name="in_"+itos(i); + } + + p_locals->push_back("input/"+name); + + //value is trickier + + int in_from = node->input_ports[i]; + int in_value = in_from&VisualScriptNodeInstance::INPUT_MASK; + + if (in_from&VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { + p_values->push_back(_call_stack[l].instance->default_values[in_value]); + } else if (in_from&VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) { + p_values->push_back( _call_stack[l].stack[ func->unsequenced_gets[ in_value ].to_stack ] ); + } else { + p_values->push_back( _call_stack[l].stack[ in_value] ); + } + } + + for(int i=0;i<node->output_port_count;i++) { + + String name = node->get_base_node()->get_output_value_port_info(i).name; + if (name==String()) { + name="out_"+itos(i); + } + + p_locals->push_back("output/"+name); + + //value is trickier + + int in_from = node->output_ports[i]; + p_values->push_back( _call_stack[l].stack[ in_from] ); + + } + + for(int i=0;i<node->get_working_memory_size();i++) { + p_locals->push_back("working_mem/mem_"+itos(i)); + p_values->push_back( (*_call_stack[l].work_mem)[i]); + } + +/* + ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); + + + VisualFunction *f = _call_stack[l].function; + + List<Pair<StringName,int> > locals; + + f->debug_get_stack_member_state(*_call_stack[l].line,&locals); + for( List<Pair<StringName,int> >::Element *E = locals.front();E;E=E->next() ) { + + p_locals->push_back(E->get().first); + p_values->push_back(_call_stack[l].stack[E->get().second]); + } +*/ +} +void VisualScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems,int p_max_depth) { + + if (_debug_parse_err_node>=0) + return; + + ERR_FAIL_INDEX(p_level,_debug_call_stack_pos); + int l = _debug_call_stack_pos - p_level -1; + + + Ref<VisualScript> vs = _call_stack[l].instance->get_script(); + if (vs.is_null()) + return; + + List<StringName> vars; + vs->get_variable_list(&vars); + for (List<StringName>::Element *E=vars.front();E;E=E->next()) { + Variant v; + if (_call_stack[l].instance->get_variable(E->get(),&v)) { + p_members->push_back("variables/"+E->get()); + p_values->push_back(v); + } + } +} + +void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) { + + //no globals are really reachable in gdscript +} +String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) { + + if (_debug_parse_err_node>=0) + return ""; + return ""; +} + + + +void VisualScriptLanguage::reload_all_scripts() { + + +} +void VisualScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload) { + + +} +/* LOADER FUNCTIONS */ + +void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("vs"); + +} +void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const { + + +} +void VisualScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_constants) const { + + +} + +void VisualScriptLanguage::profiling_start() { + + +} +void VisualScriptLanguage::profiling_stop() { + + +} + +int VisualScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max) { + + return 0; +} + +int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max) { + + return 0; +} + + +VisualScriptLanguage* VisualScriptLanguage::singleton=NULL; + + +void VisualScriptLanguage::add_register_func(const String& p_name,VisualScriptNodeRegisterFunc p_func) { + + ERR_FAIL_COND(register_funcs.has(p_name)); + register_funcs[p_name]=p_func; +} + +Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String& p_name) { + + ERR_FAIL_COND_V(!register_funcs.has(p_name),Ref<VisualScriptNode>()); + + return register_funcs[p_name](p_name); +} + +void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) { + + for (Map<String,VisualScriptNodeRegisterFunc>::Element *E=register_funcs.front();E;E=E->next()) { + r_names->push_back(E->key()); + } +} + + +VisualScriptLanguage::VisualScriptLanguage() { + + notification="_notification"; + _get_output_port_unsequenced="_get_output_port_unsequenced"; + _step="_step"; + _subcall="_subcall"; + singleton=this; +#ifndef NO_THREADS + lock = Mutex::create(); +#endif + + + _debug_parse_err_node=-1; + _debug_parse_err_file=""; + _debug_call_stack_pos=0; + int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); + if (ScriptDebugger::get_singleton()) { + //debugging enabled! + _debug_max_call_stack = dmcs; + if (_debug_max_call_stack<1024) + _debug_max_call_stack=1024; + _call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 ); + + } else { + _debug_max_call_stack=0; + _call_stack=NULL; + } + +} + +VisualScriptLanguage::~VisualScriptLanguage() { + + if (lock) + memdelete(lock); + + if (_call_stack) { + memdelete_arr(_call_stack); + } + singleton=NULL; +} diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h new file mode 100644 index 0000000000..786b9b873e --- /dev/null +++ b/modules/visual_script/visual_script.h @@ -0,0 +1,600 @@ +#ifndef VSCRIPT_H +#define VSCRIPT_H + +#include "script_language.h" +#include "os/thread.h" + +class VisualScriptInstance; +class VisualScriptNodeInstance; +class VisualScript; + +class VisualScriptNode : public Resource { + OBJ_TYPE(VisualScriptNode,Resource) + +friend class VisualScript; + + Set<VisualScript*> scripts_used; + + Array default_input_values; + bool breakpoint; + + void _set_default_input_values(Array p_values); + Array _get_default_input_values() const; +protected: + + virtual bool _use_builtin_script() const { return false; } + + void _notification(int p_what); + void ports_changed_notify(); + static void _bind_methods(); +public: + + Ref<VisualScript> get_visual_script() const; + + virtual int get_output_sequence_port_count() const=0; + virtual bool has_input_sequence_port() const=0; + + virtual String get_output_sequence_port_text(int p_port) const=0; + + virtual int get_input_value_port_count() const=0; + virtual int get_output_value_port_count() const=0; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const=0; + virtual PropertyInfo get_output_value_port_info(int p_idx) const=0; + + void set_default_input_value(int p_port,const Variant& p_value); + Variant get_default_input_value(int p_port) const; + + virtual String get_caption() const=0; + virtual String get_text() const=0; + virtual String get_category() const=0; + + //used by editor, this is not really saved + void set_breakpoint(bool p_breakpoint); + bool is_breakpoint() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0; + + VisualScriptNode(); +}; + + +class VisualScriptNodeInstance { +friend class VisualScriptInstance; +friend class VisualScriptLanguage; //for debugger + + + enum { //input argument addressing + INPUT_SHIFT=1<<24, + INPUT_MASK=INPUT_SHIFT-1, + INPUT_DEFAULT_VALUE_BIT=INPUT_SHIFT, // from unassigned input port, using default value (edited by user) + INPUT_UNSEQUENCED_READ_BIT=INPUT_SHIFT<<1, //from unsequenced read (requires calling a function, used for constants, variales, etc). + }; + + + int id; + int sequence_index; + VisualScriptNodeInstance **sequence_outputs; + int sequence_output_count; + int *input_ports; + int input_port_count; + int *output_ports; + int output_port_count; + int working_mem_idx; + + VisualScriptNode *base; + +public: + + enum StartMode { + START_MODE_BEGIN_SEQUENCE, + START_MODE_CONTINUE_SEQUENCE, + START_MODE_RESUME_YIELD + }; + + enum { + STEP_SHIFT=1<<24, + STEP_MASK=STEP_SHIFT-1, + STEP_FLAG_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack + STEP_FLAG_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node + STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node + STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function + STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory) + + FLOW_STACK_PUSHED_BIT=1<<30, //in flow stack, means bit was pushed (must go back here if end of sequence) + FLOW_STACK_MASK=FLOW_STACK_PUSHED_BIT-1 + + }; + + _FORCE_INLINE_ int get_input_port_count() const { return input_port_count; } + _FORCE_INLINE_ int get_output_port_count() const { return output_port_count; } + _FORCE_INLINE_ int get_sequence_output_count() const { return sequence_output_count; } + + _FORCE_INLINE_ int get_id() const { return id; } + + virtual int get_working_memory_size() const { return 0; } + + //unsequenced ports are those that can return a value even if no sequence happened through them, used for constants, variables, etc. + virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str)=0; //do a step, return which sequence port to go out + + Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>( base ); } + + VisualScriptNodeInstance(); + virtual ~VisualScriptNodeInstance(); +}; + + +class VisualScript : public Script { + + OBJ_TYPE( VisualScript, Script ) + + RES_BASE_EXTENSION("vs"); + +public: + + struct SequenceConnection { + + union { + + struct { + uint64_t from_node : 24; + uint64_t from_output : 16; + uint64_t to_node : 24; + }; + uint64_t id; + }; + + bool operator<(const SequenceConnection& p_connection) const { + + return id<p_connection.id; + } + }; + + struct DataConnection { + + union { + + struct { + uint64_t from_node : 24; + uint64_t from_port : 8; + uint64_t to_node : 24; + uint64_t to_port : 8; + }; + uint64_t id; + }; + + bool operator<(const DataConnection& p_connection) const { + + return id<p_connection.id; + } + }; + + +private: +friend class VisualScriptInstance; + + StringName base_type; + struct Argument { + String name; + Variant::Type type; + }; + + struct Function { + struct NodeData { + Point2 pos; + Ref<VisualScriptNode> node; + }; + + Map<int,NodeData> nodes; + + Set<SequenceConnection> sequence_connections; + + Set<DataConnection> data_connections; + + int function_id; + + Vector2 scroll; + + + Function() { function_id=-1; } + + }; + + struct Variable { + PropertyInfo info; + Variant default_value; + }; + + + + Map<StringName,Function> functions; + Map<StringName,Variable> variables; + Map<StringName,StringName> script_variable_remap; + Map<StringName,Vector<Argument> > custom_signals; + + Map<Object*,VisualScriptInstance*> instances; + +#ifdef TOOLS_ENABLED + Set<PlaceHolderScriptInstance*> placeholders; + //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); + void _update_placeholders(); +#endif + + void _set_variable_info(const StringName& p_name,const Dictionary& p_info); + Dictionary _get_variable_info(const StringName& p_name) const; + + + void _set_data(const Dictionary& p_data); + Dictionary _get_data() const; + +protected: + + void _node_ports_changed(int p_id); + static void _bind_methods(); +public: + + + void add_function(const StringName& p_name); + bool has_function(const StringName& p_name) const; + void remove_function(const StringName& p_name); + void rename_function(const StringName& p_name,const StringName& p_new_name); + void set_function_scroll(const StringName& p_name, const Vector2& p_scroll); + Vector2 get_function_scroll(const StringName& p_name) const; + void get_function_list(List<StringName> *r_functions) const; + int get_function_node_id(const StringName& p_name) const; + + + void add_node(const StringName& p_func,int p_id,const Ref<VisualScriptNode>& p_node,const Point2& p_pos=Point2()); + void remove_node(const StringName& p_func,int p_id); + bool has_node(const StringName& p_func,int p_id) const; + Ref<VisualScriptNode> get_node(const StringName& p_func,int p_id) const; + void set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos); + Point2 get_node_pos(const StringName& p_func,int p_id) const; + void get_node_list(const StringName& p_func,List<int> *r_nodes) const; + + void sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node); + void sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node); + bool has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const; + void get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const; + + void data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port); + void data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port); + bool has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const; + void get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const; + bool is_input_value_port_connected(const StringName& p_name,int p_node,int p_port) const; + + void add_variable(const StringName& p_name,const Variant& p_default_value=Variant()); + bool has_variable(const StringName& p_name) const; + void remove_variable(const StringName& p_name); + void set_variable_default_value(const StringName& p_name,const Variant& p_value); + Variant get_variable_default_value(const StringName& p_name) const; + void set_variable_info(const StringName& p_name,const PropertyInfo& p_info); + PropertyInfo get_variable_info(const StringName& p_name) const; + void get_variable_list(List<StringName> *r_variables); + void rename_variable(const StringName& p_name,const StringName& p_new_name); + + + void add_custom_signal(const StringName& p_name); + bool has_custom_signal(const StringName& p_name) const; + void custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index=-1); + void custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type); + Variant::Type custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const; + void custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name); + String custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const; + void custom_signal_remove_argument(const StringName& p_func,int p_argidx); + int custom_signal_get_argument_count(const StringName& p_func) const; + void custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx); + void remove_custom_signal(const StringName& p_name); + void rename_custom_signal(const StringName& p_name,const StringName& p_new_name); + + void get_custom_signal_list(List<StringName> *r_custom_signals) const; + + int get_available_id() const; + + void set_instance_base_type(const StringName& p_type); + + virtual bool can_instance() const; + + virtual StringName get_instance_base_type() const; + virtual ScriptInstance* instance_create(Object *p_this); + virtual bool instance_has(const Object *p_this) const; + + + virtual bool has_source_code() const; + virtual String get_source_code() const; + virtual void set_source_code(const String& p_code); + virtual Error reload(bool p_keep_state=false); + + virtual bool is_tool() const; + + virtual String get_node_type() const; + + virtual ScriptLanguage *get_language() const; + + virtual bool has_script_signal(const StringName& p_signal) const; + virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; + + virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const; + virtual void get_method_list(List<MethodInfo> *p_list) const; + + virtual bool has_method(const StringName& p_method) const; + virtual MethodInfo get_method_info(const StringName& p_method) const; + + + + VisualScript(); + ~VisualScript(); +}; + + +class VisualScriptInstance : public ScriptInstance { + Object *owner; + Ref<VisualScript> script; + + Map<StringName,Variant> variables; //using variable path, not script + Map<int,VisualScriptNodeInstance*> instances; + + struct Function { + int node; + int max_stack; + int trash_pos; + int return_pos; + int flow_stack_size; + int node_count; + int argument_count; + bool valid; + + struct UnsequencedGet { + VisualScriptNodeInstance* from; + int from_port; + int to_stack; + }; + + Vector<UnsequencedGet> unsequenced_gets; + + }; + + Map<StringName,Function> functions; + + Vector<Variant> default_values; + int max_input_args,max_output_args; + + StringName source; + + Variant _call_internal(const StringName& p_method, void* p_stack,int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield,Variant::CallError &r_error); + + + //Map<StringName,Function> functions; +friend class VisualScriptFunctionState; //for yield +friend class VisualScriptLanguage; //for debugger +public: + virtual bool set(const StringName& p_name, const Variant& p_value); + virtual bool get(const StringName& p_name, Variant &r_ret) const; + virtual void get_property_list(List<PropertyInfo> *p_properties) const; + virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const; + + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName& p_method) const; + virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error); + virtual void notification(int p_notification); + + bool set_variable(const StringName& p_variable,const Variant& p_value) { + + Map<StringName,Variant>::Element *E=variables.find(p_variable); + if (!E) + return false; + + E->get()=p_value; + return true; + } + + bool get_variable(const StringName& p_variable,Variant* r_variable) const { + + const Map<StringName,Variant>::Element *E=variables.find(p_variable); + if (!E) + return false; + + *r_variable=E->get(); + return true; + + } + + virtual Ref<Script> get_script() const; + + _FORCE_INLINE_ VisualScript *get_script_ptr() { return script.ptr(); } + _FORCE_INLINE_ Object *get_owner_ptr() { return owner; } + + void create(const Ref<VisualScript>& p_script,Object *p_owner); + + virtual ScriptLanguage *get_language(); + + VisualScriptInstance(); + ~VisualScriptInstance(); +}; + + +class VisualScriptFunctionState : public Reference { + + OBJ_TYPE(VisualScriptFunctionState,Reference); +friend class VisualScriptInstance; + + ObjectID instance_id; + ObjectID script_id; + VisualScriptInstance *instance; + StringName function; + Vector<uint8_t> stack; + int working_mem_index; + int variant_stack_size; + VisualScriptNodeInstance *node; + int flow_stack_pos; + + Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error); +protected: + static void _bind_methods(); +public: + + void connect_to_signal(Object* p_obj,const String& p_signal,Array p_binds); + bool is_valid() const; + Variant resume(Array p_args); + VisualScriptFunctionState(); + ~VisualScriptFunctionState(); +}; + + +typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String& p_type); + +class VisualScriptLanguage : public ScriptLanguage { + + Map<String,VisualScriptNodeRegisterFunc> register_funcs; + + struct CallLevel { + + Variant *stack; + Variant **work_mem; + const StringName *function; + VisualScriptInstance *instance; + int *current_id; + + }; + + + int _debug_parse_err_node; + String _debug_parse_err_file; + String _debug_error; + int _debug_call_stack_pos; + int _debug_max_call_stack; + CallLevel *_call_stack; + +public: + StringName notification; + StringName _get_output_port_unsequenced; + StringName _step; + StringName _subcall; + + static VisualScriptLanguage* singleton; + + Mutex *lock; + + bool debug_break(const String& p_error,bool p_allow_continue=true); + bool debug_break_parse(const String& p_file, int p_node,const String& p_error); + + _FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance,const StringName* p_function, Variant *p_stack, Variant **p_work_mem,int *current_id) { + + if (Thread::get_main_ID()!=Thread::get_caller_ID()) + return; //no support for other threads than main for now + + if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0) + ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() +1 ); + + if (_debug_call_stack_pos >= _debug_max_call_stack) { + //stack overflow + _debug_error="Stack Overflow (Stack Size: "+itos(_debug_max_call_stack)+")"; + ScriptDebugger::get_singleton()->debug(this); + return; + } + + _call_stack[_debug_call_stack_pos].stack=p_stack; + _call_stack[_debug_call_stack_pos].instance=p_instance; + _call_stack[_debug_call_stack_pos].function=p_function; + _call_stack[_debug_call_stack_pos].work_mem=p_work_mem; + _call_stack[_debug_call_stack_pos].current_id=current_id; + _debug_call_stack_pos++; + } + + _FORCE_INLINE_ void exit_function() { + + if (Thread::get_main_ID()!=Thread::get_caller_ID()) + return; //no support for other threads than main for now + + if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0) + ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() -1 ); + + if (_debug_call_stack_pos==0) { + + _debug_error="Stack Underflow (Engine Bug)"; + ScriptDebugger::get_singleton()->debug(this); + return; + } + + _debug_call_stack_pos--; + } + + ////////////////////////////////////// + + virtual String get_name() const; + + /* LANGUAGE FUNCTIONS */ + virtual void init(); + virtual String get_type() const; + virtual String get_extension() const; + virtual Error execute_file(const String& p_path) ; + virtual void finish(); + + /* EDITOR FUNCTIONS */ + virtual void get_reserved_words(List<String> *p_words) const; + virtual void get_comment_delimiters(List<String> *p_delimiters) const; + virtual void get_string_delimiters(List<String> *p_delimiters) const; + virtual Ref<Script> get_template(const String& p_class_name, const String& p_base_class_name) const; + virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const; + virtual Script *create_script() const; + virtual bool has_named_classes() const; + virtual int find_function(const String& p_function,const String& p_code) const; + virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const; + virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const; + virtual void add_global_constant(const StringName& p_variable,const Variant& p_value); + + + /* DEBUGGER FUNCTIONS */ + + virtual String debug_get_error() const; + virtual int debug_get_stack_level_count() const; + virtual int debug_get_stack_level_line(int p_level) const; + virtual String debug_get_stack_level_function(int p_level) const; + virtual String debug_get_stack_level_source(int p_level) const; + virtual void debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1); + virtual void debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1); + virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1); + virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1); + + + virtual void reload_all_scripts(); + virtual void reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload); + /* LOADER FUNCTIONS */ + + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual void get_public_functions(List<MethodInfo> *p_functions) const; + virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const; + + virtual void profiling_start(); + virtual void profiling_stop(); + + virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max); + virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max); + + void add_register_func(const String& p_name,VisualScriptNodeRegisterFunc p_func); + Ref<VisualScriptNode> create_node_from_name(const String& p_name); + void get_registered_node_names(List<String> *r_names); + + + VisualScriptLanguage(); + ~VisualScriptLanguage(); + +}; + +//aid for registering +template<class T> +static Ref<VisualScriptNode> create_node_generic(const String& p_name) { + + Ref<T> node; + node.instance(); + return node; +} + + + +#endif // VSCRIPT_H diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp new file mode 100644 index 0000000000..e813d9ea84 --- /dev/null +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -0,0 +1,1186 @@ +#include "visual_script_builtin_funcs.h" +#include "math_funcs.h" +#include "object_type_db.h" +#include "reference.h" +#include "func_ref.h" +#include "os/os.h" +#include "variant_parser.h" +#include "io/marshalls.h" + +const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX]={ + "sin", + "cos", + "tan", + "sinh", + "cosh", + "tanh", + "asin", + "acos", + "atan", + "atan2", + "sqrt", + "fmod", + "fposmod", + "floor", + "ceil", + "round", + "abs", + "sign", + "pow", + "log", + "exp", + "is_nan", + "is_inf", + "ease", + "decimals", + "stepify", + "lerp", + "dectime", + "randomize", + "randi", + "randf", + "rand_range", + "seed", + "rand_seed", + "deg2rad", + "rad2deg", + "linear2db", + "db2linear", + "max", + "min", + "clamp", + "nearest_po2", + "weakref", + "funcref", + "convert", + "typeof", + "type_exists", + "str", + "print", + "printerr", + "printraw", + "var2str", + "str2var", + "var2bytes", + "bytes2var", +}; + + + +int VisualScriptBuiltinFunc::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptBuiltinFunc::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptBuiltinFunc::get_input_value_port_count() const{ + + + switch(func) { + + case MATH_RANDOMIZE: + case MATH_RAND: + case MATH_RANDF: + return 0; + case MATH_SIN: + case MATH_COS: + case MATH_TAN: + case MATH_SINH: + case MATH_COSH: + case MATH_TANH: + case MATH_ASIN: + case MATH_ACOS: + case MATH_ATAN: + case MATH_SQRT: + case MATH_FLOOR: + case MATH_CEIL: + case MATH_ROUND: + case MATH_ABS: + case MATH_SIGN: + case MATH_LOG: + case MATH_EXP: + case MATH_ISNAN: + case MATH_ISINF: + case MATH_DECIMALS: + case MATH_SEED: + case MATH_RANDSEED: + case MATH_DEG2RAD: + case MATH_RAD2DEG: + case MATH_LINEAR2DB: + case MATH_DB2LINEAR: + case LOGIC_NEAREST_PO2: + case OBJ_WEAKREF: + case TYPE_OF: + case TEXT_STR: + case TEXT_PRINT: + case TEXT_PRINTERR: + case TEXT_PRINTRAW: + case VAR_TO_STR: + case STR_TO_VAR: + case VAR_TO_BYTES: + case BYTES_TO_VAR: + case TYPE_EXISTS: + return 1; + case MATH_ATAN2: + case MATH_FMOD: + case MATH_FPOSMOD: + case MATH_POW: + case MATH_EASE: + case MATH_STEPIFY: + case MATH_RANDOM: + case LOGIC_MAX: + case LOGIC_MIN: + case FUNC_FUNCREF: + case TYPE_CONVERT: + return 2; + case MATH_LERP: + case MATH_DECTIME: + case LOGIC_CLAMP: + return 3; + case FUNC_MAX:{} + + } + return 0; +} +int VisualScriptBuiltinFunc::get_output_value_port_count() const{ + + switch(func) { + case MATH_RANDOMIZE: + case TEXT_PRINT: + case TEXT_PRINTERR: + case TEXT_PRINTRAW: + case MATH_SEED: + return 0; + case MATH_RANDSEED: + return 2; + default: + return 1; + } + + return 1; +} + +String VisualScriptBuiltinFunc::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const{ + + switch(func) { + + case MATH_SIN: + case MATH_COS: + case MATH_TAN: + case MATH_SINH: + case MATH_COSH: + case MATH_TANH: + case MATH_ASIN: + case MATH_ACOS: + case MATH_ATAN: + case MATH_ATAN2: + case MATH_SQRT: { + return PropertyInfo(Variant::REAL,"num"); + } break; + case MATH_FMOD: + case MATH_FPOSMOD: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"x"); + else + return PropertyInfo(Variant::REAL,"y"); + } break; + case MATH_FLOOR: + case MATH_CEIL: + case MATH_ROUND: + case MATH_ABS: + case MATH_SIGN: { + return PropertyInfo(Variant::REAL,"num"); + + } break; + + case MATH_POW: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"x"); + else + return PropertyInfo(Variant::REAL,"y"); + } break; + case MATH_LOG: + case MATH_EXP: + case MATH_ISNAN: + case MATH_ISINF: { + return PropertyInfo(Variant::REAL,"num"); + } break; + case MATH_EASE: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"s"); + else + return PropertyInfo(Variant::REAL,"curve"); + } break; + case MATH_DECIMALS: { + return PropertyInfo(Variant::REAL,"step"); + } break; + case MATH_STEPIFY: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"s"); + else + return PropertyInfo(Variant::REAL,"steps"); + } break; + case MATH_LERP: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"from"); + else if (p_idx==1) + return PropertyInfo(Variant::REAL,"to"); + else + return PropertyInfo(Variant::REAL,"weight"); + + } break; + case MATH_DECTIME: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"value"); + else if (p_idx==1) + return PropertyInfo(Variant::REAL,"amount"); + else + return PropertyInfo(Variant::REAL,"step"); + } break; + case MATH_RANDOMIZE: { + + } break; + case MATH_RAND: { + + } break; + case MATH_RANDF: { + + } break; + case MATH_RANDOM: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"from"); + else + return PropertyInfo(Variant::REAL,"to"); + } break; + case MATH_SEED: { + return PropertyInfo(Variant::INT,"seed"); + } break; + case MATH_RANDSEED: { + return PropertyInfo(Variant::INT,"seed"); + } break; + case MATH_DEG2RAD: { + return PropertyInfo(Variant::REAL,"deg"); + } break; + case MATH_RAD2DEG: { + return PropertyInfo(Variant::REAL,"rad"); + } break; + case MATH_LINEAR2DB: { + return PropertyInfo(Variant::REAL,"nrg"); + } break; + case MATH_DB2LINEAR: { + return PropertyInfo(Variant::REAL,"db"); + } break; + case LOGIC_MAX: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"a"); + else + return PropertyInfo(Variant::REAL,"b"); + } break; + case LOGIC_MIN: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"a"); + else + return PropertyInfo(Variant::REAL,"b"); + } break; + case LOGIC_CLAMP: { + if (p_idx==0) + return PropertyInfo(Variant::REAL,"a"); + else if (p_idx==0) + return PropertyInfo(Variant::REAL,"min"); + else + return PropertyInfo(Variant::REAL,"max"); + } break; + case LOGIC_NEAREST_PO2: { + return PropertyInfo(Variant::INT,"num"); + } break; + case OBJ_WEAKREF: { + + return PropertyInfo(Variant::OBJECT,"source"); + + } break; + case FUNC_FUNCREF: { + + if (p_idx==0) + return PropertyInfo(Variant::OBJECT,"instance"); + else + return PropertyInfo(Variant::STRING,"funcname"); + + } break; + case TYPE_CONVERT: { + + if (p_idx==0) + return PropertyInfo(Variant::NIL,"what"); + else + return PropertyInfo(Variant::STRING,"type"); + } break; + case TYPE_OF: { + return PropertyInfo(Variant::NIL,"what"); + + } break; + case TYPE_EXISTS: { + + return PropertyInfo(Variant::STRING,"type"); + + } break; + case TEXT_STR: { + + return PropertyInfo(Variant::NIL,"value"); + + + } break; + case TEXT_PRINT: { + + return PropertyInfo(Variant::NIL,"value"); + + } break; + case TEXT_PRINTERR: { + return PropertyInfo(Variant::NIL,"value"); + + } break; + case TEXT_PRINTRAW: { + + return PropertyInfo(Variant::NIL,"value"); + + } break; + case VAR_TO_STR: { + return PropertyInfo(Variant::NIL,"var"); + + } break; + case STR_TO_VAR: { + + return PropertyInfo(Variant::STRING,"string"); + } break; + case VAR_TO_BYTES: { + return PropertyInfo(Variant::NIL,"var"); + + } break; + case BYTES_TO_VAR: { + + return PropertyInfo(Variant::RAW_ARRAY,"bytes"); + } break; + case FUNC_MAX:{} + } + + return PropertyInfo(); +} + +PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) const{ + + Variant::Type t=Variant::NIL; + switch(func) { + + case MATH_SIN: + case MATH_COS: + case MATH_TAN: + case MATH_SINH: + case MATH_COSH: + case MATH_TANH: + case MATH_ASIN: + case MATH_ACOS: + case MATH_ATAN: + case MATH_ATAN2: + case MATH_SQRT: + case MATH_FMOD: + case MATH_FPOSMOD: + case MATH_FLOOR: + case MATH_CEIL: { + t=Variant::REAL; + } break; + case MATH_ROUND: { + t=Variant::INT; + } break; + case MATH_ABS: { + t=Variant::NIL; + } break; + case MATH_SIGN: { + t=Variant::NIL; + } break; + case MATH_POW: + case MATH_LOG: + case MATH_EXP: { + t=Variant::REAL; + } break; + case MATH_ISNAN: + case MATH_ISINF: { + t=Variant::BOOL; + } break; + case MATH_EASE: { + t=Variant::REAL; + } break; + case MATH_DECIMALS: { + t=Variant::INT; + } break; + case MATH_STEPIFY: + case MATH_LERP: + case MATH_DECTIME: { + t=Variant::REAL; + + } break; + case MATH_RANDOMIZE: { + + } break; + case MATH_RAND: { + + t=Variant::INT; + } break; + case MATH_RANDF: + case MATH_RANDOM: { + t=Variant::REAL; + } break; + case MATH_SEED: { + + } break; + case MATH_RANDSEED: { + + if (p_idx==0) + return PropertyInfo(Variant::INT,"rnd"); + else + return PropertyInfo(Variant::INT,"seed"); + } break; + case MATH_DEG2RAD: + case MATH_RAD2DEG: + case MATH_LINEAR2DB: + case MATH_DB2LINEAR: { + t=Variant::REAL; + } break; + case LOGIC_MAX: + case LOGIC_MIN: + case LOGIC_CLAMP: { + + + } break; + + case LOGIC_NEAREST_PO2: { + t=Variant::NIL; + } break; + case OBJ_WEAKREF: { + + t=Variant::OBJECT; + + } break; + case FUNC_FUNCREF: { + + t=Variant::OBJECT; + + } break; + case TYPE_CONVERT: { + + + + } break; + case TYPE_OF: { + t=Variant::INT; + + } break; + case TYPE_EXISTS: { + + t=Variant::BOOL; + + } break; + case TEXT_STR: { + + t=Variant::STRING; + + } break; + case TEXT_PRINT: { + + + } break; + case TEXT_PRINTERR: { + + } break; + case TEXT_PRINTRAW: { + + } break; + case VAR_TO_STR: { + t=Variant::STRING; + } break; + case STR_TO_VAR: { + + } break; + case VAR_TO_BYTES: { + t=Variant::RAW_ARRAY; + + } break; + case BYTES_TO_VAR: { + + + } break; + case FUNC_MAX:{} + } + + return PropertyInfo(t,""); +} + +String VisualScriptBuiltinFunc::get_caption() const { + + return "BuiltinFunc"; +} + +String VisualScriptBuiltinFunc::get_text() const { + + return func_name[func]; +} + +void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) { + + ERR_FAIL_INDEX(p_which,FUNC_MAX); + func=p_which; + _change_notify(); + ports_changed_notify(); +} + +VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() { + return func; +} + + +#define VALIDATE_ARG_NUM(m_arg) \ + if (!p_inputs[m_arg]->is_num()) {\ + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ + r_error.argument=m_arg;\ + r_error.expected=Variant::REAL;\ + return 0;\ + } + +class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { +public: + + VisualScriptBuiltinFunc *node; + VisualScriptInstance *instance; + + VisualScriptBuiltinFunc::BuiltinFunc func; + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + switch(func) { + case VisualScriptBuiltinFunc::MATH_SIN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::cos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::tan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_SINH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sinh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COSH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::cosh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TANH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::tanh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ASIN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::asin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ACOS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::acos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::atan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN2: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SQRT: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sqrt(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_FMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FPOSMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FLOOR: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::floor(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_CEIL: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::ceil(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ROUND: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::round(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ABS: { + + if (p_inputs[0]->get_type()==Variant::INT) { + + int64_t i = *p_inputs[0]; + *p_outputs[0]=ABS(i); + } else if (p_inputs[0]->get_type()==Variant::REAL) { + + real_t r = *p_inputs[0]; + *p_outputs[0]=Math::abs(r); + } else { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::REAL; + + } + } break; + case VisualScriptBuiltinFunc::MATH_SIGN: { + + if (p_inputs[0]->get_type()==Variant::INT) { + + int64_t i = *p_inputs[0]; + *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0); + } else if (p_inputs[0]->get_type()==Variant::REAL) { + + real_t r = *p_inputs[0]; + *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); + } else { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::REAL; + + } + } break; + case VisualScriptBuiltinFunc::MATH_POW: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LOG: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::log(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EXP: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::exp(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISNAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::is_nan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISINF: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::is_inf(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EASE: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_DECIMALS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::step_decimals(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_STEPIFY: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_DECTIME: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { + Math::randomize(); + + } break; + case VisualScriptBuiltinFunc::MATH_RAND: { + *p_outputs[0]=Math::rand(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDF: { + *p_outputs[0]=Math::randf(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOM: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SEED: { + + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_inputs[0]; + Math::seed(seed); + + } break; + case VisualScriptBuiltinFunc::MATH_RANDSEED: { + + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_inputs[0]; + int ret = Math::rand_from_seed(&seed); + Array reta; + reta.push_back(ret); + reta.push_back(seed); + *p_outputs[0]=reta; + + } break; + case VisualScriptBuiltinFunc::MATH_DEG2RAD: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::deg2rad(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::rad2deg(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::linear2db(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::db2linear(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::LOGIC_MAX: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *p_outputs[0]=MAX(a,b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *p_outputs[0]=MAX(a,b); + } + + } break; + case VisualScriptBuiltinFunc::LOGIC_MIN: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *p_outputs[0]=MIN(a,b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *p_outputs[0]=MIN(a,b); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_CLAMP: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + int64_t c = *p_inputs[2]; + *p_outputs[0]=CLAMP(a,b,c); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + real_t c = *p_inputs[2]; + + *p_outputs[0]=CLAMP(a,b,c); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { + + VALIDATE_ARG_NUM(0); + int64_t num = *p_inputs[0]; + *p_outputs[0] = nearest_power_of_2(num); + } break; + case VisualScriptBuiltinFunc::OBJ_WEAKREF: { + + if (p_inputs[0]->get_type()!=Variant::OBJECT) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; + + return 0; + + } + + if (p_inputs[0]->is_ref()) { + + REF r = *p_inputs[0]; + if (!r.is_valid()) { + + return 0; + } + + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_ref(r); + *p_outputs[0]=wref; + } else { + Object *obj = *p_inputs[0]; + if (!obj) { + + return 0; + } + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_obj(obj); + *p_outputs[0]=wref; + } + + + + + } break; + case VisualScriptBuiltinFunc::FUNC_FUNCREF: { + + if (p_inputs[0]->get_type()!=Variant::OBJECT) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; + + return 0; + + } + if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=1; + r_error.expected=Variant::STRING; + + return 0; + + } + + Ref<FuncRef> fr = memnew( FuncRef); + + fr->set_instance(*p_inputs[0]); + fr->set_function(*p_inputs[1]); + + *p_outputs[0]=fr; + + } break; + case VisualScriptBuiltinFunc::TYPE_CONVERT: { + + VALIDATE_ARG_NUM(1); + int type=*p_inputs[1]; + if (type<0 || type>=Variant::VARIANT_MAX) { + + *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::INT; + return 0; + + } else { + + + *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); + } + } break; + case VisualScriptBuiltinFunc::TYPE_OF: { + + + *p_outputs[0] = p_inputs[0]->get_type(); + + } break; + case VisualScriptBuiltinFunc::TYPE_EXISTS: { + + + *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); + + } break; + case VisualScriptBuiltinFunc::TEXT_STR: { + + String str = *p_inputs[0]; + + *p_outputs[0]=str; + + } break; + case VisualScriptBuiltinFunc::TEXT_PRINT: { + + String str = *p_inputs[0]; + print_line(str); + + + } break; + + case VisualScriptBuiltinFunc::TEXT_PRINTERR: { + + String str = *p_inputs[0]; + + //str+="\n"; + OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); + + + } break; + case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { + String str = *p_inputs[0]; + + //str+="\n"; + OS::get_singleton()->print("%s",str.utf8().get_data()); + + + } break; + case VisualScriptBuiltinFunc::VAR_TO_STR: { + + String vars; + VariantWriter::write_to_string(*p_inputs[0],vars); + *p_outputs[0]=vars; + } break; + case VisualScriptBuiltinFunc::STR_TO_VAR: { + + if (p_inputs[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + + return 0; + } + + VariantParser::StreamString ss; + ss.s=*p_inputs[0]; + + String errs; + int line; + Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); + + if (err!=OK) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; + return 0; + } + + } break; + case VisualScriptBuiltinFunc::VAR_TO_BYTES: { + + + ByteArray barr; + int len; + Error err = encode_variant(*p_inputs[0],NULL,len); + if (err) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::NIL; + *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; + return 0; + } + + barr.resize(len); + { + ByteArray::Write w = barr.write(); + encode_variant(*p_inputs[0],w.ptr(),len); + + } + *p_outputs[0]=barr; + } break; + case VisualScriptBuiltinFunc::BYTES_TO_VAR: { + + if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + + return 0; + } + + ByteArray varr=*p_inputs[0]; + Variant ret; + { + ByteArray::Read r=varr.read(); + Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); + if (err!=OK) { + *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + return 0; + } + + } + + *p_outputs[0]=ret; + + } break; + default: {} + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceBuiltinFunc * instance = memnew(VisualScriptNodeInstanceBuiltinFunc ); + instance->node=this; + instance->instance=p_instance; + instance->func=func; + return instance; +} + + +void VisualScriptBuiltinFunc::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_func","which"),&VisualScriptBuiltinFunc::set_func); + ObjectTypeDB::bind_method(_MD("get_func"),&VisualScriptBuiltinFunc::get_func); + + String cc; + + for(int i=0;i<FUNC_MAX;i++) { + + if (i>0) + cc+=","; + cc+=func_name[i]; + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"function",PROPERTY_HINT_ENUM,cc),_SCS("set_func"),_SCS("get_func")); +} + +VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() { + + func=MATH_SIN; +} + +template<VisualScriptBuiltinFunc::BuiltinFunc func> +static Ref<VisualScriptNode> create_builtin_func_node(const String& p_name) { + + Ref<VisualScriptBuiltinFunc> node; + node.instance(); + node->set_func(func); + return node; +} + +void register_visual_script_builtin_func_node() { + + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/cos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/tan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sinh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/cosh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/tanh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/asin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/acos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan2",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/round",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/abs",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sign",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/pow",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/log",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/exp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/isnan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/isinf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/random",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/deg2rad",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/max",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/min",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/clamp",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref",create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/funcref",create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); + +} diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h new file mode 100644 index 0000000000..ebf227a192 --- /dev/null +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -0,0 +1,110 @@ +#ifndef VISUAL_SCRIPT_BUILTIN_FUNCS_H +#define VISUAL_SCRIPT_BUILTIN_FUNCS_H + +#include "visual_script.h" + + +class VisualScriptBuiltinFunc : public VisualScriptNode { + + OBJ_TYPE(VisualScriptBuiltinFunc,VisualScriptNode) +public: + + enum BuiltinFunc { + MATH_SIN, + MATH_COS, + MATH_TAN, + MATH_SINH, + MATH_COSH, + MATH_TANH, + MATH_ASIN, + MATH_ACOS, + MATH_ATAN, + MATH_ATAN2, + MATH_SQRT, + MATH_FMOD, + MATH_FPOSMOD, + MATH_FLOOR, + MATH_CEIL, + MATH_ROUND, + MATH_ABS, + MATH_SIGN, + MATH_POW, + MATH_LOG, + MATH_EXP, + MATH_ISNAN, + MATH_ISINF, + MATH_EASE, + MATH_DECIMALS, + MATH_STEPIFY, + MATH_LERP, + MATH_DECTIME, + MATH_RANDOMIZE, + MATH_RAND, + MATH_RANDF, + MATH_RANDOM, + MATH_SEED, + MATH_RANDSEED, + MATH_DEG2RAD, + MATH_RAD2DEG, + MATH_LINEAR2DB, + MATH_DB2LINEAR, + LOGIC_MAX, + LOGIC_MIN, + LOGIC_CLAMP, + LOGIC_NEAREST_PO2, + OBJ_WEAKREF, + FUNC_FUNCREF, + TYPE_CONVERT, + TYPE_OF, + TYPE_EXISTS, + TEXT_STR, + TEXT_PRINT, + TEXT_PRINTERR, + TEXT_PRINTRAW, + VAR_TO_STR, + STR_TO_VAR, + VAR_TO_BYTES, + BYTES_TO_VAR, + FUNC_MAX + }; + +private: + static const char* func_name[FUNC_MAX]; + BuiltinFunc func; +protected: + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_func(BuiltinFunc p_which); + BuiltinFunc get_func(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptBuiltinFunc(); +}; + +VARIANT_ENUM_CAST(VisualScriptBuiltinFunc::BuiltinFunc) + + +void register_visual_script_builtin_func_node(); + + +#endif // VISUAL_SCRIPT_BUILTIN_FUNCS_H diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp new file mode 100644 index 0000000000..0d97126e0a --- /dev/null +++ b/modules/visual_script/visual_script_editor.cpp @@ -0,0 +1,2622 @@ +#include "visual_script_editor.h" +#include "tools/editor/editor_node.h" +#include "visual_script_nodes.h" +#include "visual_script_flow_control.h" +#include "visual_script_func_nodes.h" +#include "os/input.h" +#include "os/keyboard.h" + +class VisualScriptEditorSignalEdit : public Object { + + OBJ_TYPE(VisualScriptEditorSignalEdit,Object) + + StringName sig; +public: + UndoRedo *undo_redo; + Ref<VisualScript> script; + + +protected: + + static void _bind_methods() { + ObjectTypeDB::bind_method("_sig_changed",&VisualScriptEditorSignalEdit::_sig_changed); + } + + void _sig_changed() { + + _change_notify(); + } + + bool _set(const StringName& p_name, const Variant& p_value) { + + if (sig==StringName()) + return false; + + if (p_name=="argument_count") { + + int new_argc=p_value; + int argc = script->custom_signal_get_argument_count(sig); + if (argc==new_argc) + return true; + + undo_redo->create_action("Change Signal Arguments"); + + + + if (new_argc < argc) { + for(int i=new_argc;i<argc;i++) { + undo_redo->add_do_method(script.ptr(),"custom_signal_remove_argument",sig,new_argc); + undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",sig,script->custom_signal_get_argument_name(sig,i),script->custom_signal_get_argument_type(sig,i),-1); + } + } else if (new_argc>argc) { + + for(int i=argc;i<new_argc;i++) { + + undo_redo->add_do_method(script.ptr(),"custom_signal_add_argument",sig,Variant::NIL,"arg"+itos(i+1),-1); + undo_redo->add_undo_method(script.ptr(),"custom_signal_remove_argument",sig,argc); + } + } + + undo_redo->add_do_method(this,"_sig_changed"); + undo_redo->add_undo_method(this,"_sig_changed"); + + undo_redo->commit_action(); + + return true; + } + if (String(p_name).begins_with("argument/")) { + int idx = String(p_name).get_slice("/",1).to_int()-1; + ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false); + String what = String(p_name).get_slice("/",2); + if (what=="type") { + + int old_type = script->custom_signal_get_argument_type(sig,idx); + int new_type=p_value; + undo_redo->create_action("Change Argument Type"); + undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,new_type); + undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,old_type); + undo_redo->commit_action(); + + return true; + } + + if (what=="name") { + + String old_name = script->custom_signal_get_argument_name(sig,idx); + String new_name=p_value; + undo_redo->create_action("Change Argument name"); + undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,new_name); + undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,old_name); + undo_redo->commit_action(); + return true; + } + + + } + + + return false; + } + + bool _get(const StringName& p_name,Variant &r_ret) const { + + if (sig==StringName()) + return false; + + if (p_name=="argument_count") { + r_ret = script->custom_signal_get_argument_count(sig); + return true; + } + if (String(p_name).begins_with("argument/")) { + int idx = String(p_name).get_slice("/",1).to_int()-1; + ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false); + String what = String(p_name).get_slice("/",2); + if (what=="type") { + r_ret = script->custom_signal_get_argument_type(sig,idx); + return true; + } + if (what=="name") { + r_ret = script->custom_signal_get_argument_name(sig,idx); + return true; + } + + + + } + + return false; + } + void _get_property_list( List<PropertyInfo> *p_list) const { + + if (sig==StringName()) + return; + + p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256")); + String argt="Variant"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + for(int i=0;i<script->custom_signal_get_argument_count(sig);i++) { + p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt)); + p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name")); + } + } + +public: + + + void edit(const StringName& p_sig) { + + sig=p_sig; + _change_notify(); + } + + VisualScriptEditorSignalEdit() { undo_redo=NULL; } +}; + +class VisualScriptEditorVariableEdit : public Object { + + OBJ_TYPE(VisualScriptEditorVariableEdit,Object) + + StringName var; +public: + UndoRedo *undo_redo; + Ref<VisualScript> script; + + +protected: + + static void _bind_methods() { + ObjectTypeDB::bind_method("_var_changed",&VisualScriptEditorVariableEdit::_var_changed); + ObjectTypeDB::bind_method("_var_value_changed",&VisualScriptEditorVariableEdit::_var_value_changed); + } + + void _var_changed() { + + _change_notify(); + } + void _var_value_changed() { + + _change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general + } + + bool _set(const StringName& p_name, const Variant& p_value) { + + if (var==StringName()) + return false; + + + + if (String(p_name)=="value") { + undo_redo->create_action("Set Variable Default Value"); + Variant current=script->get_variable_default_value(var); + undo_redo->add_do_method(script.ptr(),"set_variable_default_value",var,p_value); + undo_redo->add_undo_method(script.ptr(),"set_variable_default_value",var,current); + undo_redo->add_do_method(this,"_var_value_changed"); + undo_redo->add_undo_method(this,"_var_value_changed"); + undo_redo->commit_action(); + return true; + } + + Dictionary d = script->call("get_variable_info",var); + + if (String(p_name)=="type") { + + Dictionary dc=d.copy(); + dc["type"]=p_value; + undo_redo->create_action("Set Variable Type"); + undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc); + undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d); + undo_redo->add_do_method(this,"_var_changed"); + undo_redo->add_undo_method(this,"_var_changed"); + undo_redo->commit_action(); + return true; + } + + if (String(p_name)=="hint") { + + Dictionary dc=d.copy(); + dc["hint"]=p_value; + undo_redo->create_action("Set Variable Type"); + undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc); + undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d); + undo_redo->add_do_method(this,"_var_changed"); + undo_redo->add_undo_method(this,"_var_changed"); + undo_redo->commit_action(); + return true; + } + + if (String(p_name)=="hint_string") { + + Dictionary dc=d.copy(); + dc["hint_string"]=p_value; + undo_redo->create_action("Set Variable Type"); + undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc); + undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d); + undo_redo->add_do_method(this,"_var_changed"); + undo_redo->add_undo_method(this,"_var_changed"); + undo_redo->commit_action(); + return true; + } + + + return false; + } + + bool _get(const StringName& p_name,Variant &r_ret) const { + + if (var==StringName()) + return false; + + if (String(p_name)=="value") { + r_ret=script->get_variable_default_value(var); + return true; + } + + PropertyInfo pinfo = script->get_variable_info(var); + + if (String(p_name)=="type") { + r_ret=pinfo.type; + return true; + } + if (String(p_name)=="hint") { + r_ret=pinfo.hint; + return true; + } + if (String(p_name)=="hint_string") { + r_ret=pinfo.hint_string; + return true; + } + + return false; + } + void _get_property_list( List<PropertyInfo> *p_list) const { + + if (var==StringName()) + return; + + String argt="Variant"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + p_list->push_back(PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt)); + p_list->push_back(PropertyInfo(script->get_variable_info(var).type,"value",script->get_variable_info(var).hint,script->get_variable_info(var).hint_string,PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::INT,"hint",PROPERTY_HINT_ENUM,"None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,BitFlags,AllFlags,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText")); + p_list->push_back(PropertyInfo(Variant::STRING,"hint_string")); + + } + +public: + + + void edit(const StringName& p_var) { + + var=p_var; + _change_notify(); + } + + VisualScriptEditorVariableEdit() { undo_redo=NULL; } +}; + +static Color _color_from_type(Variant::Type p_type) { + + Color color; + color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7); + return color; +} + + + +void VisualScriptEditor::_update_graph_connections() { + + graph->clear_connections(); + + List<VisualScript::SequenceConnection> sequence_conns; + script->get_sequence_connection_list(edited_func,&sequence_conns); + + + for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) { + + graph->connect_node(itos(E->get().from_node),E->get().from_output,itos(E->get().to_node),0); + } + + List<VisualScript::DataConnection> data_conns; + script->get_data_connection_list(edited_func,&data_conns); + + for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) { + + VisualScript::DataConnection dc=E->get(); + + + Ref<VisualScriptNode> from_node = script->get_node(edited_func,E->get().from_node); + Ref<VisualScriptNode> to_node = script->get_node(edited_func,E->get().to_node); + + if (to_node->has_input_sequence_port()) { + dc.to_port++; + } + + dc.from_port+=from_node->get_output_sequence_port_count(); + + graph->connect_node(itos(E->get().from_node),dc.from_port,itos(E->get().to_node),dc.to_port); + } + +} + + +void VisualScriptEditor::_update_graph(int p_only_id) { + + + updating_graph=true; + + //byebye all nodes + if (p_only_id>=0) { + if (graph->has_node(itos(p_only_id))) { + Node* gid = graph->get_node(itos(p_only_id)); + if (gid) + memdelete(gid); + } + } else { + + for(int i=0;i<graph->get_child_count();i++) { + + if (graph->get_child(i)->cast_to<GraphNode>()) { + memdelete(graph->get_child(i)); + i--; + } + } + } + + if (!script->has_function(edited_func)) { + graph->hide(); + select_func_text->show(); + updating_graph=false; + return; + } + + graph->show(); + select_func_text->hide(); + + Ref<Texture> type_icons[Variant::VARIANT_MAX]={ + Control::get_icon("MiniVariant","EditorIcons"), + Control::get_icon("MiniBoolean","EditorIcons"), + Control::get_icon("MiniInteger","EditorIcons"), + Control::get_icon("MiniFloat","EditorIcons"), + Control::get_icon("MiniString","EditorIcons"), + Control::get_icon("MiniVector2","EditorIcons"), + Control::get_icon("MiniRect2","EditorIcons"), + Control::get_icon("MiniVector3","EditorIcons"), + Control::get_icon("MiniMatrix2","EditorIcons"), + Control::get_icon("MiniPlane","EditorIcons"), + Control::get_icon("MiniQuat","EditorIcons"), + Control::get_icon("MiniAabb","EditorIcons"), + Control::get_icon("MiniMatrix3","EditorIcons"), + Control::get_icon("MiniTransform","EditorIcons"), + Control::get_icon("MiniColor","EditorIcons"), + Control::get_icon("MiniImage","EditorIcons"), + Control::get_icon("MiniPath","EditorIcons"), + Control::get_icon("MiniRid","EditorIcons"), + Control::get_icon("MiniObject","EditorIcons"), + Control::get_icon("MiniInput","EditorIcons"), + Control::get_icon("MiniDictionary","EditorIcons"), + Control::get_icon("MiniArray","EditorIcons"), + Control::get_icon("MiniRawArray","EditorIcons"), + Control::get_icon("MiniIntArray","EditorIcons"), + Control::get_icon("MiniFloatArray","EditorIcons"), + Control::get_icon("MiniStringArray","EditorIcons"), + Control::get_icon("MiniVector2Array","EditorIcons"), + Control::get_icon("MiniVector3Array","EditorIcons"), + Control::get_icon("MiniColorArray","EditorIcons") + }; + + + + Ref<Texture> seq_port = Control::get_icon("VisualShaderPort","EditorIcons"); + + List<int> ids; + script->get_node_list(edited_func,&ids); + StringName editor_icons="EditorIcons"; + + for(List<int>::Element *E=ids.front();E;E=E->next()) { + + if (p_only_id>=0 && p_only_id!=E->get()) + continue; + + Ref<VisualScriptNode> node = script->get_node(edited_func,E->get()); + Vector2 pos = script->get_node_pos(edited_func,E->get()); + + GraphNode *gnode = memnew( GraphNode ); + gnode->set_title(node->get_caption()); + if (error_line==E->get()) { + gnode->set_overlay(GraphNode::OVERLAY_POSITION); + } else if (node->is_breakpoint()) { + gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT); + } + + if (EditorSettings::get_singleton()->has("visual_script_editor/color_"+node->get_category())) { + gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script_editor/color_"+node->get_category())); + } + + gnode->set_meta("__vnode",node); + gnode->set_name(itos(E->get())); + gnode->connect("dragged",this,"_node_moved",varray(E->get())); + gnode->connect("close_request",this,"_remove_node",varray(E->get()),CONNECT_DEFERRED); + + + if (E->get()!=script->get_function_node_id(edited_func)) { + //function can't be erased + gnode->set_show_close_button(true); + } + + Label *text = memnew( Label ); + text->set_text(node->get_text()); + gnode->add_child(text); + + int slot_idx=0; + + bool single_seq_output = node->get_output_sequence_port_count()==1 && node->get_output_sequence_port_text(0)==String(); + gnode->set_slot(0,node->has_input_sequence_port(),TYPE_SEQUENCE,Color(1,1,1,1),single_seq_output,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port); + gnode->set_offset(pos*EDSCALE); + slot_idx++; + + if (!single_seq_output) { + for(int i=0;i<node->get_output_sequence_port_count();i++) { + + Label *text2 = memnew( Label ); + text2->set_text(node->get_output_sequence_port_text(i)); + text2->set_align(Label::ALIGN_RIGHT); + gnode->add_child(text2); + gnode->set_slot(slot_idx,false,0,Color(),true,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port); + slot_idx++; + } + } + + for(int i=0;i<MAX(node->get_output_value_port_count(),node->get_input_value_port_count());i++) { + + bool left_ok=false; + Variant::Type left_type=Variant::NIL; + String left_name; + + if (i<node->get_input_value_port_count()) { + PropertyInfo pi = node->get_input_value_port_info(i); + left_ok=true; + left_type=pi.type; + left_name=pi.name; + } + + bool right_ok=false; + Variant::Type right_type=Variant::NIL; + String right_name; + + if (i<node->get_output_value_port_count()) { + PropertyInfo pi = node->get_output_value_port_info(i); + right_ok=true; + right_type=pi.type; + right_name=pi.name; + } + + HBoxContainer *hbc = memnew( HBoxContainer); + + if (left_ok) { + + Ref<Texture> t; + if (left_type>=0 && left_type<Variant::VARIANT_MAX) { + t=type_icons[left_type]; + } + if (t.is_valid()) { + TextureFrame *tf = memnew(TextureFrame); + tf->set_texture(t); + tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + hbc->add_child(tf); + } + + hbc->add_child(memnew(Label(left_name))); + + if (left_type!=Variant::NIL && !script->is_input_value_port_connected(edited_func,E->get(),i)) { + Button *button = memnew( Button ); + Variant value = node->get_default_input_value(i); + if (value.get_type()!=left_type) { + //different type? for now convert + //not the same, reconvert + Variant::CallError ce; + const Variant *existingp=&value; + value = Variant::construct(left_type,&existingp,1,ce,false); + } + + button->set_text(value); + button->connect("pressed",this,"_default_value_edited",varray(button,E->get(),i)); + hbc->add_child(button); + } + } else { + Control *c = memnew(Control); + c->set_custom_minimum_size(Size2(10,0)*EDSCALE); + hbc->add_child(c); + } + + hbc->add_spacer(); + + if (right_ok) { + + hbc->add_child(memnew(Label(right_name))); + + Ref<Texture> t; + if (right_type>=0 && right_type<Variant::VARIANT_MAX) { + t=type_icons[right_type]; + } + if (t.is_valid()) { + TextureFrame *tf = memnew(TextureFrame); + tf->set_texture(t); + tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + hbc->add_child(tf); + } + + } + + gnode->add_child(hbc); + + gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),right_ok,right_type,_color_from_type(right_type)); + + slot_idx++; + } + + graph->add_child(gnode); + } + + _update_graph_connections(); + graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)*EDSCALE); //may need to adapt a bit, let it do so + updating_graph=false; + +} + +void VisualScriptEditor::_update_members() { + + + updating_members=true; + + members->clear(); + TreeItem *root = members->create_item(); + + TreeItem *functions = members->create_item(root); + functions->set_selectable(0,false); + functions->set_text(0,TTR("Functions:")); + functions->add_button(0,Control::get_icon("Override","EditorIcons"),1); + functions->add_button(0,Control::get_icon("Add","EditorIcons"),0); + functions->set_custom_bg_color(0,Control::get_color("prop_section","Editor")); + + List<StringName> func_names; + script->get_function_list(&func_names); + for (List<StringName>::Element *E=func_names.front();E;E=E->next()) { + TreeItem *ti = members->create_item(functions) ; + ti->set_text(0,E->get()); + ti->set_selectable(0,true); + ti->set_editable(0,true); + //ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now + ti->add_button(0,Control::get_icon("Del","EditorIcons"),1); + ti->set_metadata(0,E->get()); + if (E->get()==edited_func) { + ti->set_custom_bg_color(0,get_color("prop_category","Editor")); + ti->set_custom_color(0,Color(1,1,1,1)); + } + if (selected==E->get()) + ti->select(0); + } + + TreeItem *variables = members->create_item(root); + variables->set_selectable(0,false); + variables->set_text(0,TTR("Variables:")); + variables->add_button(0,Control::get_icon("Add","EditorIcons")); + variables->set_custom_bg_color(0,Control::get_color("prop_section","Editor")); + + + List<StringName> var_names; + script->get_variable_list(&var_names); + for (List<StringName>::Element *E=var_names.front();E;E=E->next()) { + TreeItem *ti = members->create_item(variables); + ti->set_text(0,E->get()); + ti->set_selectable(0,true); + ti->set_editable(0,true); + ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); + ti->add_button(0,Control::get_icon("Del","EditorIcons"),1); + ti->set_metadata(0,E->get()); + if (selected==E->get()) + ti->select(0); + } + + TreeItem *_signals = members->create_item(root); + _signals->set_selectable(0,false); + _signals->set_text(0,TTR("Signals:")); + _signals->add_button(0,Control::get_icon("Add","EditorIcons")); + _signals->set_custom_bg_color(0,Control::get_color("prop_section","Editor")); + + List<StringName> signal_names; + script->get_custom_signal_list(&signal_names); + for (List<StringName>::Element *E=signal_names.front();E;E=E->next()) { + TreeItem *ti = members->create_item(_signals); + ti->set_text(0,E->get()); + ti->set_selectable(0,true); + ti->set_editable(0,true); + ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); + ti->add_button(0,Control::get_icon("Del","EditorIcons"),1); + ti->set_metadata(0,E->get()); + if (selected==E->get()) + ti->select(0); + } + + String base_type=script->get_instance_base_type(); + String icon_type=base_type; + if (!Control::has_icon(base_type,"EditorIcons")) { + icon_type="Object"; + } + + base_type_select->set_text(base_type); + base_type_select->set_icon(Control::get_icon(icon_type,"EditorIcons")); + + updating_members=false; + +} + +void VisualScriptEditor::_member_selected() { + + if (updating_members) + return; + + TreeItem *ti=members->get_selected(); + ERR_FAIL_COND(!ti); + + + selected=ti->get_metadata(0); +// print_line("selected: "+String(selected)); + + + if (ti->get_parent()==members->get_root()->get_children()) { + + if (edited_func!=selected) { + + revert_on_drag=edited_func; + edited_func=selected; + _update_members(); + _update_graph(); + } + + return; //or crash because it will become invalid + + } + + + +} + +void VisualScriptEditor::_member_edited() { + + if (updating_members) + return; + + TreeItem *ti=members->get_edited(); + ERR_FAIL_COND(!ti); + + String name = ti->get_metadata(0); + String new_name = ti->get_text(0); + + if (name==new_name) + return; + + if (!new_name.is_valid_identifier()) { + + EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:")+" "+new_name); + updating_members=true; + ti->set_text(0,name); + updating_members=false; + return; + + } + + if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) { + + EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:")+" "+new_name); + updating_members=true; + ti->set_text(0,name); + updating_members=false; + return; + } + + TreeItem *root=members->get_root(); + + if (ti->get_parent()==root->get_children()) { + + if (edited_func==selected) { + edited_func=new_name; + } + selected=new_name; + + + _update_graph(); + + undo_redo->create_action(TTR("Rename Function")); + undo_redo->add_do_method(script.ptr(),"rename_function",name,new_name); + undo_redo->add_undo_method(script.ptr(),"rename_function",new_name,name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + + return; //or crash because it will become invalid + + } + + if (ti->get_parent()==root->get_children()->get_next()) { + + selected=new_name; + undo_redo->create_action(TTR("Rename Variable")); + undo_redo->add_do_method(script.ptr(),"rename_variable",name,new_name); + undo_redo->add_undo_method(script.ptr(),"rename_variable",new_name,name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + + return; //or crash because it will become invalid + } + + if (ti->get_parent()==root->get_children()->get_next()->get_next()) { + + selected=new_name; + undo_redo->create_action(TTR("Rename Signal")); + undo_redo->add_do_method(script.ptr(),"rename_custom_signal",name,new_name); + undo_redo->add_undo_method(script.ptr(),"rename_custom_signal",new_name,name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + + return; //or crash because it will become invalid + } +} + +void VisualScriptEditor::_override_pressed(int p_id) { + + //override a virtual function or method from base type + + ERR_FAIL_COND(!virtuals_in_menu.has(p_id)); + + VirtualInMenu vim=virtuals_in_menu[p_id]; + + String name = _validate_name(vim.name); + selected=name; + edited_func=selected; + Ref<VisualScriptFunction> func_node; + func_node.instance(); + func_node->set_name(vim.name); + + undo_redo->create_action(TTR("Add Function")); + undo_redo->add_do_method(script.ptr(),"add_function",name); + for(int i=0;i<vim.args.size();i++) { + func_node->add_argument(vim.args[i].first,vim.args[i].second); + } + + + undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node); + if (vim.ret!=Variant::NIL || vim.ret_variant) { + Ref<VisualScriptReturn> ret_node; + ret_node.instance(); + ret_node->set_return_type(vim.ret); + ret_node->set_enable_return_value(true); + ret_node->set_name(vim.name); + undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id()+1,ret_node,Vector2(500,0)); + + } + + undo_redo->add_undo_method(script.ptr(),"remove_function",name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); + + + _update_graph(); +} + +void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) { + + TreeItem *ti=p_item->cast_to<TreeItem>(); + + TreeItem *root=members->get_root(); + + if (ti->get_parent()==root) { + //main buttons + if (ti==root->get_children()) { + //add function, this one uses menu + + if (p_button==1) { + new_function_menu->clear(); + new_function_menu->set_size(Size2(0,0)); + int idx=0; + + virtuals_in_menu.clear(); + + List<MethodInfo> mi; + ObjectTypeDB::get_method_list(script->get_instance_base_type(),&mi); + for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { + MethodInfo mi=E->get(); + if (mi.flags&METHOD_FLAG_VIRTUAL) { + + VirtualInMenu vim; + vim.name=mi.name; + vim.ret=mi.return_val.type; + if (mi.return_val.name!=String()) + vim.ret_variant=true; + else + vim.ret_variant=false; + + String desc; + + if (mi.return_val.type==Variant::NIL) + desc="var"; + else + desc=Variant::get_type_name(mi.return_val.type); + desc+=" "+mi.name+" ( "; + + + for(int i=0;i<mi.arguments.size();i++) { + + if (i>0) + desc+=", "; + + if (mi.arguments[i].type==Variant::NIL) + desc+="var "; + else + desc+=Variant::get_type_name(mi.arguments[i].type)+" "; + + desc+=mi.arguments[i].name; + + Pair<Variant::Type,String> p; + p.first=mi.arguments[i].type; + p.second=mi.arguments[i].name; + vim.args.push_back( p ); + + } + + desc+=" )"; + + virtuals_in_menu[idx]=vim; + + new_function_menu->add_item(desc,idx); + idx++; + } + } + + Rect2 pos = members->get_item_rect(ti); + new_function_menu->set_pos(members->get_global_pos()+pos.pos+Vector2(0,pos.size.y)); + new_function_menu->popup(); + return; + } else if (p_button==0) { + + + String name = _validate_name("new_function"); + selected=name; + edited_func=selected; + + Ref<VisualScriptFunction> func_node; + func_node.instance(); + func_node->set_name(name); + + undo_redo->create_action(TTR("Add Function")); + undo_redo->add_do_method(script.ptr(),"add_function",name); + undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node); + undo_redo->add_undo_method(script.ptr(),"remove_function",name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); + + _update_graph(); + } + + return; //or crash because it will become invalid + + } + + if (ti==root->get_children()->get_next()) { + //add variable + String name = _validate_name("new_variable"); + selected=name; + + undo_redo->create_action(TTR("Add Variable")); + undo_redo->add_do_method(script.ptr(),"add_variable",name); + undo_redo->add_undo_method(script.ptr(),"remove_variable",name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + return; //or crash because it will become invalid + + } + + if (ti==root->get_children()->get_next()->get_next()) { + //add variable + String name = _validate_name("new_signal"); + selected=name; + + undo_redo->create_action(TTR("Add Signal")); + undo_redo->add_do_method(script.ptr(),"add_custom_signal",name); + undo_redo->add_undo_method(script.ptr(),"remove_custom_signal",name); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + return; //or crash because it will become invalid + + } + + } else { + + if (ti->get_parent()==root->get_children()) { + //edit/remove function + String name = ti->get_metadata(0); + + if (p_button==1) { + //delete the function + undo_redo->create_action(TTR("Remove Function")); + undo_redo->add_do_method(script.ptr(),"remove_function",name); + undo_redo->add_undo_method(script.ptr(),"add_function",name); + List<int> nodes; + script->get_node_list(name,&nodes); + for (List<int>::Element *E=nodes.front();E;E=E->next()) { + undo_redo->add_undo_method(script.ptr(),"add_node",name,E->get(),script->get_node(name,E->get()),script->get_node_pos(name,E->get())); + } + + List<VisualScript::SequenceConnection> seq_connections; + + script->get_sequence_connection_list(name,&seq_connections); + + for (List<VisualScript::SequenceConnection>::Element *E=seq_connections.front();E;E=E->next()) { + undo_redo->add_undo_method(script.ptr(),"sequence_connect",name,E->get().from_node,E->get().from_output,E->get().to_node); + } + + List<VisualScript::DataConnection> data_connections; + + script->get_data_connection_list(name,&data_connections); + + for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) { + undo_redo->add_undo_method(script.ptr(),"data_connect",name,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port); + } + + //for(int i=0;i<script->function_get_argument_count(name);i++) { + //// undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i)); + //} + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + } else if (p_button==0) { + + } + return; //or crash because it will become invalid + + } + + if (ti->get_parent()==root->get_children()->get_next()) { + //edit/remove variable + + String name = ti->get_metadata(0); + + if (p_button==1) { + + + undo_redo->create_action(TTR("Remove Variable")); + undo_redo->add_do_method(script.ptr(),"remove_variable",name); + undo_redo->add_undo_method(script.ptr(),"add_variable",name,script->get_variable_default_value(name)); + undo_redo->add_undo_method(script.ptr(),"set_variable_info",name,script->call("get_variable_info",name)); //return as dict + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + return; //or crash because it will become invalid + } else if (p_button==0) { + + variable_editor->edit(name); + edit_variable_dialog->set_title(TTR("Editing Variable:")+" "+name); + edit_variable_dialog->popup_centered_minsize(Size2(400,200)*EDSCALE); + } + + } + + if (ti->get_parent()==root->get_children()->get_next()->get_next()) { + //edit/remove variable + String name = ti->get_metadata(0); + + if (p_button==1) { + + undo_redo->create_action(TTR("Remove Signal")); + undo_redo->add_do_method(script.ptr(),"remove_custom_signal",name); + undo_redo->add_undo_method(script.ptr(),"add_custom_signal",name); + + for(int i=0;i<script->custom_signal_get_argument_count(name);i++) { + undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",name,script->custom_signal_get_argument_name(name,i),script->custom_signal_get_argument_type(name,i)); + } + + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + } else if (p_button==0) { + + signal_editor->edit(name); + edit_signal_dialog->set_title(TTR("Editing Signal:")+" "+name); + edit_signal_dialog->popup_centered_minsize(Size2(400,300)*EDSCALE); + } + + return; //or crash because it will become invalid + + } + + + } +} + +void VisualScriptEditor::_available_node_doubleclicked() { + + TreeItem *item = nodes->get_selected(); + + if (!item) + return; + + String which = item->get_metadata(0); + if (which==String()) + return; + + Vector2 ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5; + + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + while(true) { + bool exists=false; + List<int> existing; + script->get_node_list(edited_func,&existing); + for (List<int>::Element *E=existing.front();E;E=E->next()) { + Point2 pos = script->get_node_pos(edited_func,E->get()); + if (pos.distance_to(ofs)<15) { + ofs+=Vector2(graph->get_snap(),graph->get_snap()); + exists=true; + break; + } + } + + if (exists) + continue; + break; + + } + + + Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(which); + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + +} + +void VisualScriptEditor::_update_available_nodes() { + + nodes->clear(); + + TreeItem *root = nodes->create_item(); + + Map<String,TreeItem*> path_cache; + + String filter = node_filter->get_text(); + + List<String> fnodes; + VisualScriptLanguage::singleton->get_registered_node_names(&fnodes); + + for (List<String>::Element *E=fnodes.front();E;E=E->next()) { + + + Vector<String> path = E->get().split("/"); + + if (filter!=String() && path.size() && path[path.size()-1].findn(filter)==-1) + continue; + + String sp; + TreeItem* parent=root; + + for(int i=0;i<path.size()-1;i++) { + + if (i>0) + sp+=","; + sp+=path[i]; + if (!path_cache.has(sp)) { + TreeItem* pathn = nodes->create_item(parent); + pathn->set_selectable(0,false); + pathn->set_text(0,path[i].capitalize()); + path_cache[sp]=pathn; + parent=pathn; + if (filter==String()) { + pathn->set_collapsed(true); //should remember state + } + } else { + parent=path_cache[sp]; + } + } + + TreeItem *item = nodes->create_item(parent); + item->set_text(0,path[path.size()-1].capitalize()); + item->set_selectable(0,true); + item->set_metadata(0,E->get()); + } + +} + +String VisualScriptEditor::_validate_name(const String& p_name) const { + + String valid=p_name; + + int counter=1; + while(true) { + + bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid); + + if (exists) { + counter++; + valid=p_name+"_"+itos(counter); + continue; + } + + break; + } + + return valid; +} + +void VisualScriptEditor::_on_nodes_delete() { + + + List<int> to_erase; + + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_erase.push_back(gn->get_name().operator String().to_int()); + } + } + } + + if (to_erase.empty()) + return; + + undo_redo->create_action("Remove VisualScript Nodes"); + + for(List<int>::Element*F=to_erase.front();F;F=F->next()) { + + + undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,F->get()); + undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,F->get(),script->get_node(edited_func,F->get()),script->get_node_pos(edited_func,F->get())); + + + List<VisualScript::SequenceConnection> sequence_conns; + script->get_sequence_connection_list(edited_func,&sequence_conns); + + + for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) { + + if (E->get().from_node==F->get() || E->get().to_node==F->get()) { + undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node); + } + } + + List<VisualScript::DataConnection> data_conns; + script->get_data_connection_list(edited_func,&data_conns); + + for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) { + + if (E->get().from_node==F->get() || E->get().to_node==F->get()) { + undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port); + } + } + + } + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); +} + + +void VisualScriptEditor::_on_nodes_duplicate() { + + + List<int> to_duplicate; + + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_duplicate.push_back(gn->get_name().operator String().to_int()); + } + } + } + + if (to_duplicate.empty()) + return; + + undo_redo->create_action("Duplicate VisualScript Nodes"); + int idc=script->get_available_id()+1; + + Set<int> to_select; + + for(List<int>::Element*F=to_duplicate.front();F;F=F->next()) { + + Ref<VisualScriptNode> node = script->get_node(edited_func,F->get()); + + Ref<VisualScriptNode> dupe = node->duplicate(); + + int new_id = idc++; + to_select.insert(new_id); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,dupe,script->get_node_pos(edited_func,F->get())+Vector2(20,20)); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + + } + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); + + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + int id = gn->get_name().operator String().to_int(); + gn->set_selected(to_select.has(id)); + + } + } + + if (to_select.size()) { + EditorNode::get_singleton()->push_item(script->get_node(edited_func,to_select.front()->get()).ptr()); + } + +} + +void VisualScriptEditor::_input(const InputEvent& p_event) { + + if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { + revert_on_drag=String(); //so we can still drag functions + } +} + +Variant VisualScriptEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) { + + + if (p_from==nodes) { + + TreeItem *it = nodes->get_item_at_pos(p_point); + if (!it) + return Variant(); + String type=it->get_metadata(0); + if (type==String()) + return Variant(); + + Dictionary dd; + dd["type"]="visual_script_node_drag"; + dd["node_type"]=type; + + Label *label = memnew(Label); + label->set_text(it->get_text(0)); + set_drag_preview(label); + return dd; + } + + if (p_from==members) { + + + TreeItem *it = members->get_item_at_pos(p_point); + if (!it) + return Variant(); + + String type=it->get_metadata(0); + + if (type==String()) + return Variant(); + + + Dictionary dd; + TreeItem *root=members->get_root(); + + if (it->get_parent()==root->get_children()) { + + dd["type"]="visual_script_function_drag"; + dd["function"]=type; + if (revert_on_drag!=String()) { + edited_func=revert_on_drag; //revert so function does not change + revert_on_drag=String(); + _update_graph(); + } + } else if (it->get_parent()==root->get_children()->get_next()) { + + dd["type"]="visual_script_variable_drag"; + dd["variable"]=type; + } else if (it->get_parent()==root->get_children()->get_next()->get_next()) { + + dd["type"]="visual_script_signal_drag"; + dd["signal"]=type; + + } else { + return Variant(); + } + + + + + + + Label *label = memnew(Label); + label->set_text(it->get_text(0)); + set_drag_preview(label); + return dd; + } + return Variant(); +} + +bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{ + + if (p_from==graph) { + + + Dictionary d = p_data; + if (d.has("type") && + ( + String(d["type"])=="visual_script_node_drag" || + String(d["type"])=="visual_script_function_drag" || + String(d["type"])=="visual_script_variable_drag" || + String(d["type"])=="visual_script_signal_drag" || + String(d["type"])=="obj_property" || + String(d["type"])=="nodes" + ) ) { + + + if (String(d["type"])=="obj_property") { + +#ifdef OSX_ENABLED + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Meta to drop a Setter, Shift+Meta to drop a Setter and copy the value."); +#else + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Setter, Shift+Ctrl to drop a Setter and copy the value."); +#endif + } + + if (String(d["type"])=="visual_script_variable_drag") { + +#ifdef OSX_ENABLED + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Meta to drop a Variable Setter."); +#else + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Variable Setter."); +#endif + } + + return true; + + } + + + + } + + + return false; +} + +#ifdef TOOLS_ENABLED + +static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { + + if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) + return NULL; + + Ref<Script> scr = p_current_node->get_script(); + + if (scr.is_valid() && scr==script) + return p_current_node; + + for(int i=0;i<p_current_node->get_child_count();i++) { + Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); + if (n) + return n; + } + + return NULL; +} + +#endif + +void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){ + + if (p_from==graph) { + + Dictionary d = p_data; + if (d.has("type") && String(d["type"])=="visual_script_node_drag") { + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + + ofs/=EDSCALE; + + Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(d["node_type"]); + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + } + + if (d.has("type") && String(d["type"])=="visual_script_variable_drag") { + +#ifdef OSX_ENABLED + bool use_set = Input::get_singleton()->is_key_pressed(KEY_META); +#else + bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL); +#endif + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + Ref<VisualScriptNode> vnode; + if (use_set) { + Ref<VisualScriptVariableSet> vnodes; + vnodes.instance(); + vnodes->set_variable(d["variable"]); + vnode=vnodes; + } else { + + Ref<VisualScriptVariableGet> vnodeg; + vnodeg.instance(); + vnodeg->set_variable(d["variable"]); + vnode=vnodeg; + } + + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + } + + if (d.has("type") && String(d["type"])=="visual_script_function_drag") { + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + Ref<VisualScriptScriptCall> vnode; + vnode.instance(); + vnode->set_call_mode(VisualScriptScriptCall::CALL_MODE_SELF); + vnode->set_function(d["function"]); + + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + } + + + if (d.has("type") && String(d["type"])=="visual_script_signal_drag") { + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + Ref<VisualScriptEmitSignal> vnode; + vnode.instance(); + vnode->set_signal(d["signal"]); + + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + } + if (d.has("type") && String(d["type"])=="nodes") { + + Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script); + + + if (!sn) { + EditorNode::get_singleton()->show_warning("Can't drop nodes because script '"+get_name()+"' is not used in this scene."); + return; + } + + Array nodes = d["nodes"]; + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + ofs/=EDSCALE; + + undo_redo->create_action(TTR("Add Node(s) From Tree")); + int base_id = script->get_available_id(); + + for(int i=0;i<nodes.size();i++) { + + NodePath np = nodes[i]; + Node *node = get_node(np); + if (!node) { + continue; + } + + Ref<VisualScriptSceneNode> scene_node; + scene_node.instance(); + scene_node->set_node_path(sn->get_path_to(node)); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,scene_node,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); + + base_id++; + ofs+=Vector2(25,25); + } + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + + } + + if (d.has("type") && String(d["type"])=="obj_property") { + + Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script); + + + if (!sn) { + //EditorNode::get_singleton()->show_warning("Can't drop properties because script '"+get_name()+"' is not used in this scene."); + //return; + } + + Object *obj=d["object"]; + + if (!obj) + return; + + Node *node = obj->cast_to<Node>(); + Vector2 ofs = graph->get_scroll_ofs() + p_point; + + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; +#ifdef OSX_ENABLED + bool use_set = Input::get_singleton()->is_key_pressed(KEY_META); +#else + bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL); +#endif + + bool use_value = Input::get_singleton()->is_key_pressed(KEY_SHIFT); + + if (!node) { + + + if (use_set) + undo_redo->create_action(TTR("Add Setter Property")); + else + undo_redo->create_action(TTR("Add Getter Property")); + + int base_id = script->get_available_id(); + + Ref<VisualScriptNode> vnode; + + if (use_set) { + + Ref<VisualScriptPropertySet> pset; + pset.instance(); + pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + pset->set_base_type(obj->get_type()); + pset->set_property(d["property"]); + if (use_value) { + pset->set_use_builtin_value(true); + pset->set_builtin_value(d["value"]); + } + vnode=pset; + } else { + + Ref<VisualScriptPropertyGet> pget; + pget.instance(); + pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + pget->set_base_type(obj->get_type()); + pget->set_property(d["property"]); + vnode=pget; + + } + + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); + + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + } else { + + + + if (use_set) + undo_redo->create_action(TTR("Add Setter Property")); + else + undo_redo->create_action(TTR("Add Getter Property")); + + int base_id = script->get_available_id(); + + Ref<VisualScriptNode> vnode; + + if (use_set) { + + Ref<VisualScriptPropertySet> pset; + pset.instance(); + pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); + pset->set_base_path(sn->get_path_to(sn)); + pset->set_property(d["property"]); + if (use_value) { + pset->set_use_builtin_value(true); + pset->set_builtin_value(d["value"]); + } + + vnode=pset; + } else { + + Ref<VisualScriptPropertyGet> pget; + pget.instance(); + pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); + pget->set_base_path(sn->get_path_to(sn)); + pget->set_property(d["property"]); + vnode=pget; + + } + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); + + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + } + + + } + + + } + + +} + + +///////////////////////// + + + +void VisualScriptEditor::apply_code() { + + +} + +Ref<Script> VisualScriptEditor::get_edited_script() const{ + + return script; +} + +Vector<String> VisualScriptEditor::get_functions(){ + + return Vector<String>(); +} + +void VisualScriptEditor::set_edited_script(const Ref<Script>& p_script){ + + script=p_script; + signal_editor->script=p_script; + signal_editor->undo_redo=undo_redo; + variable_editor->script=p_script; + variable_editor->undo_redo=undo_redo; + + + script->connect("node_ports_changed",this,"_node_ports_changed"); + + _update_members(); + _update_available_nodes(); +} + +void VisualScriptEditor::reload_text(){ + + +} + +String VisualScriptEditor::get_name(){ + + String name; + + if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) { + name=script->get_path().get_file(); + if (is_unsaved()) { + name+="(*)"; + } + } else if (script->get_name()!="") + name=script->get_name(); + else + name=script->get_type()+"("+itos(script->get_instance_ID())+")"; + + return name; + +} + +Ref<Texture> VisualScriptEditor::get_icon(){ + + return Control::get_icon("VisualScript","EditorIcons"); +} + +bool VisualScriptEditor::is_unsaved(){ +#ifdef TOOLS_ENABLED + return script->is_edited(); +#else + return false; +#endif +} + +Variant VisualScriptEditor::get_edit_state(){ + + Dictionary d; + d["function"]=edited_func; + d["scroll"]=graph->get_scroll_ofs(); + d["zoom"]=graph->get_zoom(); + d["using_snap"]=graph->is_using_snap(); + d["snap"]=graph->get_snap(); + return d; +} + +void VisualScriptEditor::set_edit_state(const Variant& p_state){ + + Dictionary d = p_state; + if (d.has("function")) { + edited_func=p_state; + selected=edited_func; + + } + + _update_graph(); + _update_members(); + + if (d.has("scroll")) { + graph->set_scroll_ofs(d["scroll"]); + } + if (d.has("zoom")) { + graph->set_zoom(d["zoom"]); + } + if (d.has("snap")) { + graph->set_snap(d["snap"]); + } + if (d.has("snap_enabled")) { + graph->set_use_snap(d["snap_enabled"]); + } + +} + + +void VisualScriptEditor::_center_on_node(int p_id) { + + Node *n = graph->get_node(itos(p_id)); + if (!n) + return; + GraphNode *gn = n->cast_to<GraphNode>(); + if (gn) { + gn->set_selected(true); + Vector2 new_scroll = gn->get_offset() - graph->get_size()*0.5 + gn->get_size()*0.5; + graph->set_scroll_ofs( new_scroll ); + script->set_function_scroll(edited_func,new_scroll/EDSCALE); + script->set_edited(true); //so it's saved + + } +} + +void VisualScriptEditor::goto_line(int p_line, bool p_with_error){ + + p_line+=1; //add one because script lines begin from 0. + + if (p_with_error) + error_line=p_line; + + List<StringName> functions; + script->get_function_list(&functions); + for (List<StringName>::Element *E=functions.front();E;E=E->next()) { + + if (script->has_node(E->get(),p_line)) { + + edited_func=E->get(); + selected=edited_func; + _update_graph(); + _update_members(); + + call_deferred("_center_on_node",p_line); //editor might be just created and size might not exist yet + + return; + } + } +} + +void VisualScriptEditor::trim_trailing_whitespace(){ + + +} + +void VisualScriptEditor::ensure_focus(){ + + graph->grab_focus(); +} + +void VisualScriptEditor::tag_saved_version(){ + + +} + +void VisualScriptEditor::reload(bool p_soft){ + + +} + +void VisualScriptEditor::get_breakpoints(List<int> *p_breakpoints){ + + List<StringName> functions; + script->get_function_list(&functions); + for (List<StringName>::Element *E=functions.front();E;E=E->next()) { + + List<int> nodes; + script->get_node_list(E->get(),&nodes); + for (List<int>::Element *F=nodes.front();F;F=F->next()) { + + Ref<VisualScriptNode> vsn = script->get_node(E->get(),F->get()); + if (vsn->is_breakpoint()) { + p_breakpoints->push_back(F->get()-1); //subtract 1 because breakpoints in text start from zero + } + } + } +} + +bool VisualScriptEditor::goto_method(const String& p_method){ + + if (!script->has_function(p_method)) + return false; + + edited_func=p_method; + selected=edited_func; + _update_members(); + _update_graph(); + return true; +} + +void VisualScriptEditor::add_callback(const String& p_function,StringArray p_args){ + + if (script->has_function(p_function)) { + edited_func=p_function; + selected=edited_func; + _update_members(); + _update_graph(); + return; + } + + Ref<VisualScriptFunction> func; + func.instance(); + for(int i=0;i<p_args.size();i++) { + + String name = p_args[i]; + Variant::Type type=Variant::NIL; + + if (name.find(":")!=-1) { + String tt = name.get_slice(":",1); + name=name.get_slice(":",0); + for(int j=0;j<Variant::VARIANT_MAX;j++) { + + String tname = Variant::get_type_name(Variant::Type(j)); + if (tname==tt) { + type=Variant::Type(j); + break; + } + } + } + + func->add_argument(type,name); + } + + func->set_name(p_function); + script->add_function(p_function); + script->add_node(p_function,script->get_available_id(),func); + + edited_func=p_function; + selected=edited_func; + _update_members(); + _update_graph(); + graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)); //for first time it might need to be later + + //undo_redo->clear_history(); + +} + +void VisualScriptEditor::update_settings(){ + + _update_graph(); +} + +void VisualScriptEditor::set_debugger_active(bool p_active) { + if (!p_active) { + error_line=-1; + _update_graph(); //clear line break + } +} + +void VisualScriptEditor::set_tooltip_request_func(String p_method,Object* p_obj){ + + +} + +Control *VisualScriptEditor::get_edit_menu(){ + + return edit_menu; +} + +void VisualScriptEditor::_change_base_type() { + + select_base_type->popup(true); +} + +void VisualScriptEditor::_change_base_type_callback() { + + String bt = select_base_type->get_selected_type(); + + ERR_FAIL_COND(bt==String()); + undo_redo->create_action("Change Base Type"); + undo_redo->add_do_method(script.ptr(),"set_instance_base_type",bt); + undo_redo->add_undo_method(script.ptr(),"set_instance_base_type",script->get_instance_base_type()); + undo_redo->add_do_method(this,"_update_members"); + undo_redo->add_undo_method(this,"_update_members"); + undo_redo->commit_action(); + +} + +void VisualScriptEditor::_node_selected(Node* p_node) { + + Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode"); + if (vnode.is_null()) + return; + + EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector +} + +static bool _get_out_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) { + + if (p_slot<p_node->get_output_sequence_port_count()) { + r_sequence=true; + r_real_slot=p_slot; + + return true; + } + + r_real_slot=p_slot-p_node->get_output_sequence_port_count(); + r_sequence=false; + + return (r_real_slot<p_node->get_output_value_port_count()); + +} + +static bool _get_in_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) { + + if (p_slot==0 && p_node->has_input_sequence_port()) { + r_sequence=true; + r_real_slot=0; + return true; + } + + + r_real_slot=p_slot-(p_node->has_input_sequence_port()?1:0); + r_sequence=false; + + return r_real_slot<p_node->get_input_value_port_count(); + +} + + +void VisualScriptEditor::_begin_node_move() { + + undo_redo->create_action("Move Node(s)"); +} + +void VisualScriptEditor::_end_node_move() { + + undo_redo->commit_action(); +} + +void VisualScriptEditor::_move_node(String func,int p_id,const Vector2& p_to) { + + + + if (func==String(edited_func)) { + Node* node = graph->get_node(itos(p_id)); + if (node && node->cast_to<GraphNode>()) + node->cast_to<GraphNode>()->set_offset(p_to); + } + script->set_node_pos(edited_func,p_id,p_to/EDSCALE); +} + +void VisualScriptEditor::_node_moved(Vector2 p_from,Vector2 p_to, int p_id) { + + undo_redo->add_do_method(this,"_move_node",String(edited_func),p_id,p_to); + undo_redo->add_undo_method(this,"_move_node",String(edited_func),p_id,p_from); +} + +void VisualScriptEditor::_remove_node(int p_id) { + + + undo_redo->create_action("Remove VisualScript Node"); + + undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,p_id); + undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,p_id,script->get_node(edited_func,p_id),script->get_node_pos(edited_func,p_id)); + + + List<VisualScript::SequenceConnection> sequence_conns; + script->get_sequence_connection_list(edited_func,&sequence_conns); + + + for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) { + + if (E->get().from_node==p_id || E->get().to_node==p_id) { + undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node); + } + } + + List<VisualScript::DataConnection> data_conns; + script->get_data_connection_list(edited_func,&data_conns); + + for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) { + + if (E->get().from_node==p_id || E->get().to_node==p_id) { + undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port); + } + } + + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); +} + + +void VisualScriptEditor::_node_ports_changed(const String& p_func,int p_id) { + + if (p_func!=String(edited_func)) + return; + + _update_graph(p_id); +} + +void VisualScriptEditor::_graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot) { + + Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int()); + ERR_FAIL_COND(!from_node.is_valid()); + + bool from_seq; + int from_port; + + if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq)) + return; //can't connect this, it' s invalid + + Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int()); + ERR_FAIL_COND(!to_node.is_valid()); + + bool to_seq; + int to_port; + + if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq)) + return; //can't connect this, it' s invalid + + + ERR_FAIL_COND(from_seq!=to_seq); + + + undo_redo->create_action("Connect Nodes"); + + if (from_seq) { + undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int()); + undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int()); + } else { + undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port); + undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port); + //update nodes in sgraph + undo_redo->add_do_method(this,"_update_graph",p_from.to_int()); + undo_redo->add_do_method(this,"_update_graph",p_to.to_int()); + undo_redo->add_undo_method(this,"_update_graph",p_from.to_int()); + undo_redo->add_undo_method(this,"_update_graph",p_to.to_int()); + } + + undo_redo->add_do_method(this,"_update_graph_connections"); + undo_redo->add_undo_method(this,"_update_graph_connections"); + + undo_redo->commit_action(); + +} + +void VisualScriptEditor::_graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot){ + + Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int()); + ERR_FAIL_COND(!from_node.is_valid()); + + bool from_seq; + int from_port; + + if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq)) + return; //can't connect this, it' s invalid + + Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int()); + ERR_FAIL_COND(!to_node.is_valid()); + + bool to_seq; + int to_port; + + if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq)) + return; //can't connect this, it' s invalid + + + ERR_FAIL_COND(from_seq!=to_seq); + + + undo_redo->create_action("Connect Nodes"); + + if (from_seq) { + undo_redo->add_do_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int()); + undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int()); + } else { + undo_redo->add_do_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port); + undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port); + //update nodes in sgraph + undo_redo->add_do_method(this,"_update_graph",p_from.to_int()); + undo_redo->add_do_method(this,"_update_graph",p_to.to_int()); + undo_redo->add_undo_method(this,"_update_graph",p_from.to_int()); + undo_redo->add_undo_method(this,"_update_graph",p_to.to_int()); + } + undo_redo->add_do_method(this,"_update_graph_connections"); + undo_redo->add_undo_method(this,"_update_graph_connections"); + + undo_redo->commit_action(); +} + + +void VisualScriptEditor::_default_value_changed() { + + + Ref<VisualScriptNode> vsn = script->get_node(edited_func,editing_id); + if (vsn.is_null()) + return; + + undo_redo->create_action("Change Input Value"); + undo_redo->add_do_method(vsn.ptr(),"set_default_input_value",editing_input,default_value_edit->get_variant()); + undo_redo->add_undo_method(vsn.ptr(),"set_default_input_value",editing_input,vsn->get_default_input_value(editing_input)); + + undo_redo->add_do_method(this,"_update_graph",editing_id); + undo_redo->add_undo_method(this,"_update_graph",editing_id); + undo_redo->commit_action(); + +} + +void VisualScriptEditor::_default_value_edited(Node * p_button,int p_id,int p_input_port) { + + Ref<VisualScriptNode> vsn = script->get_node(edited_func,p_id); + if (vsn.is_null()) + return; + + PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port); + Variant existing = vsn->get_default_input_value(p_input_port); + if (pinfo.type!=Variant::NIL && existing.get_type()!=pinfo.type) { + + Variant::CallError ce; + const Variant *existingp=&existing; + existing = Variant::construct(pinfo.type,&existingp,1,ce,false); + + } + + default_value_edit->set_pos(p_button->cast_to<Control>()->get_global_pos()+Vector2(0,p_button->cast_to<Control>()->get_size().y)); + default_value_edit->set_size(Size2(1,1)); + if (default_value_edit->edit(NULL,pinfo.name,pinfo.type,existing,pinfo.hint,pinfo.hint_string)) + default_value_edit->popup(); + + editing_id = p_id; + editing_input=p_input_port; + +} + +void VisualScriptEditor::_show_hint(const String& p_hint) { + + hint_text->set_text(p_hint); + hint_text->show(); + hint_text_timer->start(); +} + +void VisualScriptEditor::_hide_timer() { + + hint_text->hide(); +} + +void VisualScriptEditor::_node_filter_changed(const String& p_text) { + + _update_available_nodes(); +} + +void VisualScriptEditor::_notification(int p_what) { + + if (p_what==NOTIFICATION_READY) { + node_filter_icon->set_texture(Control::get_icon("Zoom","EditorIcons")); + } +} + +void VisualScriptEditor::_graph_ofs_changed(const Vector2& p_ofs) { + + if (updating_graph) + return; + + updating_graph=true; + + if (script->has_function(edited_func)) { + script->set_function_scroll(edited_func,graph->get_scroll_ofs()/EDSCALE); + script->set_edited(true); + } + updating_graph=false; +} + +void VisualScriptEditor::_menu_option(int p_what) { + + switch(p_what) { + case EDIT_DELETE_NODES: { + _on_nodes_delete(); + } break; + case EDIT_TOGGLE_BREAKPOINT: { + + List<String> reselect; + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + if (gn->is_selected()) { + int id = String(gn->get_name()).to_int(); + Ref<VisualScriptNode> vsn = script->get_node(edited_func,id); + if (vsn.is_valid()) { + vsn->set_breakpoint(!vsn->is_breakpoint()); + reselect.push_back(gn->get_name()); + } + } + } + } + + _update_graph(); + + for(List<String>::Element *E=reselect.front();E;E=E->next()) { + GraphNode *gn = graph->get_node(E->get())->cast_to<GraphNode>(); + gn->set_selected(true); + } + + } break; + case EDIT_FIND_NODE_TYPE: { + //popup disappearing grabs focus to owner, so use call deferred + node_filter->call_deferred("grab_focus"); + node_filter->call_deferred("select_all"); + } break; + + } +} + +void VisualScriptEditor::_bind_methods() { + + ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button); + ObjectTypeDB::bind_method("_member_edited",&VisualScriptEditor::_member_edited); + ObjectTypeDB::bind_method("_member_selected",&VisualScriptEditor::_member_selected); + ObjectTypeDB::bind_method("_update_members",&VisualScriptEditor::_update_members); + ObjectTypeDB::bind_method("_change_base_type",&VisualScriptEditor::_change_base_type); + ObjectTypeDB::bind_method("_change_base_type_callback",&VisualScriptEditor::_change_base_type_callback); + ObjectTypeDB::bind_method("_override_pressed",&VisualScriptEditor::_override_pressed); + ObjectTypeDB::bind_method("_node_selected",&VisualScriptEditor::_node_selected); + ObjectTypeDB::bind_method("_node_moved",&VisualScriptEditor::_node_moved); + ObjectTypeDB::bind_method("_move_node",&VisualScriptEditor::_move_node); + ObjectTypeDB::bind_method("_begin_node_move",&VisualScriptEditor::_begin_node_move); + ObjectTypeDB::bind_method("_end_node_move",&VisualScriptEditor::_end_node_move); + ObjectTypeDB::bind_method("_remove_node",&VisualScriptEditor::_remove_node); + ObjectTypeDB::bind_method("_update_graph",&VisualScriptEditor::_update_graph,DEFVAL(-1)); + ObjectTypeDB::bind_method("_node_ports_changed",&VisualScriptEditor::_node_ports_changed); + ObjectTypeDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked); + ObjectTypeDB::bind_method("_default_value_edited",&VisualScriptEditor::_default_value_edited); + ObjectTypeDB::bind_method("_default_value_changed",&VisualScriptEditor::_default_value_changed); + ObjectTypeDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option); + ObjectTypeDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed); + ObjectTypeDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node); + + + + ObjectTypeDB::bind_method("get_drag_data_fw",&VisualScriptEditor::get_drag_data_fw); + ObjectTypeDB::bind_method("can_drop_data_fw",&VisualScriptEditor::can_drop_data_fw); + ObjectTypeDB::bind_method("drop_data_fw",&VisualScriptEditor::drop_data_fw); + + ObjectTypeDB::bind_method("_input",&VisualScriptEditor::_input); + ObjectTypeDB::bind_method("_on_nodes_delete",&VisualScriptEditor::_on_nodes_delete); + ObjectTypeDB::bind_method("_on_nodes_duplicate",&VisualScriptEditor::_on_nodes_duplicate); + + ObjectTypeDB::bind_method("_hide_timer",&VisualScriptEditor::_hide_timer); + + ObjectTypeDB::bind_method("_graph_connected",&VisualScriptEditor::_graph_connected); + ObjectTypeDB::bind_method("_graph_disconnected",&VisualScriptEditor::_graph_disconnected); + ObjectTypeDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections); + ObjectTypeDB::bind_method("_node_filter_changed",&VisualScriptEditor::_node_filter_changed); + + +} + + + +VisualScriptEditor::VisualScriptEditor() { + + updating_graph=false; + + edit_menu = memnew( MenuButton ); + edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE); + edit_menu->get_popup()->connect("item_pressed",this,"_menu_option"); + + main_hsplit = memnew( HSplitContainer ); + add_child(main_hsplit); + main_hsplit->set_area_as_parent_rect(); + + left_vsplit = memnew( VSplitContainer ); + main_hsplit->add_child(left_vsplit); + + VBoxContainer *left_vb = memnew( VBoxContainer ); + left_vsplit->add_child(left_vb); + left_vb->set_v_size_flags(SIZE_EXPAND_FILL); + left_vb->set_custom_minimum_size(Size2(180,1)*EDSCALE); + + base_type_select = memnew( Button ); + left_vb->add_margin_child(TTR("Base Type:"),base_type_select); + base_type_select->connect("pressed",this,"_change_base_type"); + + members = memnew( Tree ); + left_vb->add_margin_child(TTR("Members:"),members,true); + members->set_hide_root(true); + members->connect("button_pressed",this,"_member_button"); + members->connect("item_edited",this,"_member_edited"); + members->connect("cell_selected",this,"_member_selected",varray(),CONNECT_DEFERRED); + members->set_single_select_cell_editing_only_when_already_selected(true); + members->set_hide_folding(true); + members->set_drag_forwarding(this); + + + VBoxContainer *left_vb2 = memnew( VBoxContainer ); + left_vsplit->add_child(left_vb2); + left_vb2->set_v_size_flags(SIZE_EXPAND_FILL); + + + VBoxContainer *vbc_nodes = memnew( VBoxContainer ); + HBoxContainer *hbc_nodes = memnew( HBoxContainer ); + node_filter = memnew (LineEdit); + node_filter->connect("text_changed",this,"_node_filter_changed"); + hbc_nodes->add_child(node_filter); + node_filter->set_h_size_flags(SIZE_EXPAND_FILL); + node_filter_icon = memnew( TextureFrame ); + node_filter_icon->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED); + hbc_nodes->add_child(node_filter_icon); + vbc_nodes->add_child(hbc_nodes); + + nodes = memnew( Tree ); + vbc_nodes->add_child(nodes); + nodes->set_v_size_flags(SIZE_EXPAND_FILL); + + left_vb2->add_margin_child(TTR("Available Nodes:"),vbc_nodes,true); + + nodes->set_hide_root(true); + nodes->connect("item_activated",this,"_available_node_doubleclicked"); + nodes->set_drag_forwarding(this); + + graph = memnew( GraphEdit ); + main_hsplit->add_child(graph); + graph->set_h_size_flags(SIZE_EXPAND_FILL); + graph->connect("node_selected",this,"_node_selected"); + graph->connect("_begin_node_move",this,"_begin_node_move"); + graph->connect("_end_node_move",this,"_end_node_move"); + graph->connect("delete_nodes_request",this,"_on_nodes_delete"); + graph->connect("duplicate_nodes_request",this,"_on_nodes_duplicate"); + graph->set_drag_forwarding(this); + graph->hide(); + graph->connect("scroll_offset_changed",this,"_graph_ofs_changed"); + + select_func_text = memnew( Label ); + select_func_text->set_text(TTR("Select or create a function to edit graph")); + select_func_text->set_align(Label::ALIGN_CENTER); + select_func_text->set_valign(Label::VALIGN_CENTER); + select_func_text->set_h_size_flags(SIZE_EXPAND_FILL); + main_hsplit->add_child(select_func_text); + + + hint_text = memnew( Label ); + hint_text->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,100); + hint_text->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + hint_text->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + hint_text->set_align(Label::ALIGN_CENTER); + hint_text->set_valign(Label::VALIGN_CENTER); + graph->add_child(hint_text); + + hint_text_timer = memnew( Timer ); + hint_text_timer->set_wait_time(4); + hint_text_timer->connect("timeout",this,"_hide_timer"); + add_child(hint_text_timer); + + //allowed casts (connections) + for(int i=0;i<Variant::VARIANT_MAX;i++) { + graph->add_valid_connection_type(Variant::NIL,i); + graph->add_valid_connection_type(i,Variant::NIL); + for(int j=0;j<Variant::VARIANT_MAX;j++) { + if (Variant::can_convert(Variant::Type(i),Variant::Type(j))) { + graph->add_valid_connection_type(i,j); + } + } + + graph->add_valid_right_disconnect_type(i); + } + + graph->add_valid_left_disconnect_type(TYPE_SEQUENCE); + + graph->connect("connection_request",this,"_graph_connected"); + graph->connect("disconnection_request",this,"_graph_disconnected"); + + edit_signal_dialog = memnew( AcceptDialog ); + edit_signal_dialog->get_ok()->set_text(TTR("Close")); + add_child(edit_signal_dialog); + edit_signal_dialog->set_title(TTR("Edit Signal Arguments:")); + + signal_editor = memnew( VisualScriptEditorSignalEdit ); + edit_signal_edit = memnew( PropertyEditor ); + edit_signal_edit->hide_top_label(); + edit_signal_dialog->add_child(edit_signal_edit); + edit_signal_dialog->set_child_rect(edit_signal_edit); + edit_signal_edit->edit(signal_editor); + + edit_variable_dialog = memnew( AcceptDialog ); + edit_variable_dialog->get_ok()->set_text(TTR("Close")); + add_child(edit_variable_dialog); + edit_variable_dialog->set_title(TTR("Edit Variable:")); + + variable_editor = memnew( VisualScriptEditorVariableEdit ); + edit_variable_edit = memnew( PropertyEditor ); + edit_variable_edit->hide_top_label(); + edit_variable_dialog->add_child(edit_variable_edit); + edit_variable_dialog->set_child_rect(edit_variable_edit); + edit_variable_edit->edit(variable_editor); + + select_base_type=memnew(CreateDialog); + select_base_type->set_base_type("Object"); //anything goes + select_base_type->connect("create",this,"_change_base_type_callback"); + select_base_type->get_ok()->set_text(TTR("Change")); + add_child(select_base_type); + + undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + new_function_menu = memnew( PopupMenu ); + new_function_menu->connect("item_pressed",this,"_override_pressed"); + add_child(new_function_menu); + updating_members=false; + + set_process_input(true); //for revert on drag + set_process_unhandled_input(true); //for revert on drag + + default_value_edit= memnew( CustomPropertyEditor); + add_child(default_value_edit); + default_value_edit->connect("variant_changed",this,"_default_value_changed"); + + error_line=-1; +} + +VisualScriptEditor::~VisualScriptEditor() { + + undo_redo->clear_history(); //avoid crashes + memdelete(signal_editor); + memdelete(variable_editor); +} + +static ScriptEditorBase * create_editor(const Ref<Script>& p_script) { + + if (p_script->cast_to<VisualScript>()) { + return memnew( VisualScriptEditor ); + } + + return NULL; +} + +static void register_editor_callback() { + + ScriptEditor::register_create_script_editor_function(create_editor); + EditorSettings::get_singleton()->set("visual_script_editor/color_functions",Color(1,0.9,0.9)); + EditorSettings::get_singleton()->set("visual_script_editor/color_data",Color(0.9,1.0,0.9)); + EditorSettings::get_singleton()->set("visual_script_editor/color_operators",Color(0.9,0.9,1.0)); + EditorSettings::get_singleton()->set("visual_script_editor/color_flow_control",Color(1.0,1.0,0.8)); + EditorSettings::get_singleton()->set("visual_script_editor/color_custom",Color(0.8,1.0,1.0)); + + + ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected")); + ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9); + ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Tyoe"), KEY_MASK_CMD+KEY_F); + +} + +void VisualScriptEditor::register_editor() { + + //too early to register stuff here, request a callback + EditorNode::add_plugin_init_callback(register_editor_callback); + + + +} + diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h new file mode 100644 index 0000000000..bd33f35739 --- /dev/null +++ b/modules/visual_script/visual_script_editor.h @@ -0,0 +1,184 @@ +#ifndef VisualSCRIPT_EDITOR_H +#define VisualSCRIPT_EDITOR_H + +#include "tools/editor/plugins/script_editor_plugin.h" +#include "visual_script.h" +#include "tools/editor/property_editor.h" +#include "scene/gui/graph_edit.h" +#include "tools/editor/create_dialog.h" + +class VisualScriptEditorSignalEdit; +class VisualScriptEditorVariableEdit; + + + +class VisualScriptEditor : public ScriptEditorBase { + OBJ_TYPE(VisualScriptEditor,ScriptEditorBase) + + enum { + TYPE_SEQUENCE=1000, + INDEX_BASE_SEQUENCE=1024 + + + }; + + enum { + EDIT_DELETE_NODES, + EDIT_TOGGLE_BREAKPOINT, + EDIT_FIND_NODE_TYPE, + }; + + MenuButton *edit_menu; + + Ref<VisualScript> script; + + Button *base_type_select; + + HSplitContainer *main_hsplit; + VSplitContainer *left_vsplit; + + GraphEdit *graph; + + LineEdit *node_filter; + TextureFrame *node_filter_icon; + + VisualScriptEditorSignalEdit *signal_editor; + + AcceptDialog *edit_signal_dialog; + PropertyEditor *edit_signal_edit; + + + VisualScriptEditorVariableEdit *variable_editor; + + AcceptDialog *edit_variable_dialog; + PropertyEditor *edit_variable_edit; + + CustomPropertyEditor *default_value_edit; + + UndoRedo *undo_redo; + + Tree *members; + Tree *nodes; + + Label *hint_text; + Timer *hint_text_timer; + + Label *select_func_text; + + bool updating_graph; + + void _show_hint(const String& p_hint); + void _hide_timer(); + + CreateDialog *select_base_type; + + struct VirtualInMenu { + String name; + Variant::Type ret; + bool ret_variant; + Vector< Pair<Variant::Type,String> > args; + }; + + Map<int,VirtualInMenu> virtuals_in_menu; + + PopupMenu *new_function_menu; + + + StringName edited_func; + + void _update_graph_connections(); + void _update_graph(int p_only_id=-1); + + bool updating_members; + + void _update_members(); + + StringName selected; + + String _validate_name(const String& p_name) const; + + + int error_line; + + void _node_selected(Node* p_node); + void _center_on_node(int p_id); + + void _node_filter_changed(const String& p_text); + void _change_base_type_callback(); + void _change_base_type(); + void _member_selected(); + void _member_edited(); + void _override_pressed(int p_id); + + void _begin_node_move(); + void _end_node_move(); + void _move_node(String func,int p_id,const Vector2& p_to); + + void _node_moved(Vector2 p_from,Vector2 p_to, int p_id); + void _remove_node(int p_id); + void _graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot); + void _graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot); + void _node_ports_changed(const String& p_func,int p_id); + void _available_node_doubleclicked(); + + void _update_available_nodes(); + + void _member_button(Object *p_item, int p_column, int p_button); + + + String revert_on_drag; + + void _input(const InputEvent& p_event); + void _on_nodes_delete(); + void _on_nodes_duplicate(); + + 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); + + + int editing_id; + int editing_input; + + void _default_value_changed(); + void _default_value_edited(Node * p_button,int p_id,int p_input_port); + + void _menu_option(int p_what); + + void _graph_ofs_changed(const Vector2& p_ofs); +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + virtual void apply_code(); + virtual Ref<Script> get_edited_script() const; + virtual Vector<String> get_functions(); + virtual void set_edited_script(const Ref<Script>& p_script); + virtual void reload_text(); + virtual String get_name(); + virtual Ref<Texture> get_icon(); + virtual bool is_unsaved(); + virtual Variant get_edit_state(); + virtual void set_edit_state(const Variant& p_state); + virtual void goto_line(int p_line,bool p_with_error=false); + virtual void trim_trailing_whitespace(); + virtual void ensure_focus(); + virtual void tag_saved_version(); + virtual void reload(bool p_soft); + virtual void get_breakpoints(List<int> *p_breakpoints); + virtual bool goto_method(const String& p_method); + virtual void add_callback(const String& p_function,StringArray p_args); + virtual void update_settings(); + virtual void set_debugger_active(bool p_active); + virtual void set_tooltip_request_func(String p_method,Object* p_obj); + virtual Control *get_edit_menu(); + + static void register_editor(); + + VisualScriptEditor(); + ~VisualScriptEditor(); +}; + +#endif // VisualSCRIPT_EDITOR_H diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp new file mode 100644 index 0000000000..cb0ff4086c --- /dev/null +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -0,0 +1,1678 @@ +#include "visual_script_flow_control.h" +#include "os/keyboard.h" +#include "globals.h" + +////////////////////////////////////////// +////////////////RETURN//////////////////// +////////////////////////////////////////// + +int VisualScriptReturn::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptReturn::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptReturn::get_input_value_port_count() const{ + + return with_value?1:0; +} +int VisualScriptReturn::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptReturn::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="result"; + pinfo.type=type; + return pinfo; +} +PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const{ + return PropertyInfo(); +} + +String VisualScriptReturn::get_caption() const { + + return "Return"; +} + +String VisualScriptReturn::get_text() const { + + return get_name(); +} + +void VisualScriptReturn::set_return_type(Variant::Type p_type) { + + if (type==p_type) + return; + type=p_type; + ports_changed_notify(); + +} + +Variant::Type VisualScriptReturn::get_return_type() const{ + + return type; +} + +void VisualScriptReturn::set_enable_return_value(bool p_enable) { + if (with_value==p_enable) + return; + + with_value=p_enable; + ports_changed_notify(); +} + +bool VisualScriptReturn::is_return_value_enabled() const { + + return with_value; +} + +void VisualScriptReturn::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_return_type","type"),&VisualScriptReturn::set_return_type); + ObjectTypeDB::bind_method(_MD("get_return_type"),&VisualScriptReturn::get_return_type); + ObjectTypeDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value); + ObjectTypeDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled); + + String argt="Variant"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),_SCS("set_enable_return_value"),_SCS("is_return_value_enabled")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),_SCS("set_return_type"),_SCS("get_return_type")); + +} + +class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { +public: + + VisualScriptReturn *node; + VisualScriptInstance *instance; + bool with_value; + + virtual int get_working_memory_size() const { return 1; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (with_value) { + *p_working_mem = *p_inputs[0]; + } else { + *p_working_mem = Variant(); + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptReturn::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceReturn * instance = memnew(VisualScriptNodeInstanceReturn ); + instance->node=this; + instance->instance=p_instance; + instance->with_value=with_value; + return instance; +} + +VisualScriptReturn::VisualScriptReturn() { + + with_value=false; + type=Variant::NIL; +} + +template<bool with_value> +static Ref<VisualScriptNode> create_return_node(const String& p_name) { + + Ref<VisualScriptReturn> node; + node.instance(); + node->set_enable_return_value(with_value); + return node; +} + + + +////////////////////////////////////////// +////////////////CONDITION///////////////// +////////////////////////////////////////// + +int VisualScriptCondition::get_output_sequence_port_count() const { + + return 2; +} + +bool VisualScriptCondition::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptCondition::get_input_value_port_count() const{ + + return 1; +} +int VisualScriptCondition::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptCondition::get_output_sequence_port_text(int p_port) const { + + if (p_port==0) + return "true"; + else + return "false"; +} + +PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="cond"; + pinfo.type=Variant::BOOL; + return pinfo; +} +PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const{ + return PropertyInfo(); +} + +String VisualScriptCondition::get_caption() const { + + return "Condition"; +} + +String VisualScriptCondition::get_text() const { + + return "if (cond) is: "; +} + + +void VisualScriptCondition::_bind_methods() { + + + +} + +class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance { +public: + + VisualScriptCondition *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 1; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_inputs[0]->operator bool()) + return 0; + else + return 1; + } + + +}; + +VisualScriptNodeInstance* VisualScriptCondition::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceCondition * instance = memnew(VisualScriptNodeInstanceCondition ); + instance->node=this; + instance->instance=p_instance; + return instance; +} + +VisualScriptCondition::VisualScriptCondition() { + +} + + + +////////////////////////////////////////// +////////////////WHILE///////////////// +////////////////////////////////////////// + +int VisualScriptWhile::get_output_sequence_port_count() const { + + return 2; +} + +bool VisualScriptWhile::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptWhile::get_input_value_port_count() const{ + + return 1; +} +int VisualScriptWhile::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptWhile::get_output_sequence_port_text(int p_port) const { + + if (p_port==0) + return "repeat"; + else + return "exit"; +} + +PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="cond"; + pinfo.type=Variant::BOOL; + return pinfo; +} +PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const{ + return PropertyInfo(); +} + +String VisualScriptWhile::get_caption() const { + + return "While"; +} + +String VisualScriptWhile::get_text() const { + + return "while (cond): "; +} + + +void VisualScriptWhile::_bind_methods() { + + + +} + +class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance { +public: + + VisualScriptWhile *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 1; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + bool keep_going = p_inputs[0]->operator bool(); + + if (keep_going) + return 0|STEP_FLAG_PUSH_STACK_BIT; + else + return 1; + } + + +}; + +VisualScriptNodeInstance* VisualScriptWhile::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceWhile * instance = memnew(VisualScriptNodeInstanceWhile ); + instance->node=this; + instance->instance=p_instance; + return instance; +} +VisualScriptWhile::VisualScriptWhile() { + +} + + + +////////////////////////////////////////// +////////////////ITERATOR///////////////// +////////////////////////////////////////// + +int VisualScriptIterator::get_output_sequence_port_count() const { + + return 2; +} + +bool VisualScriptIterator::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptIterator::get_input_value_port_count() const{ + + return 1; +} +int VisualScriptIterator::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptIterator::get_output_sequence_port_text(int p_port) const { + + if (p_port==0) + return "each"; + else + return "exit"; +} + +PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="input"; + pinfo.type=Variant::NIL; + return pinfo; +} +PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const{ + PropertyInfo pinfo; + pinfo.name="elem"; + pinfo.type=Variant::NIL; + return pinfo; +} +String VisualScriptIterator::get_caption() const { + + return "Iterator"; +} + +String VisualScriptIterator::get_text() const { + + return "for (elem) in (input): "; +} + + +void VisualScriptIterator::_bind_methods() { + + + +} + +class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance { +public: + + VisualScriptIterator *node; + VisualScriptInstance *instance; + + virtual int get_working_memory_size() const { return 2; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_start_mode==START_MODE_BEGIN_SEQUENCE) { + p_working_mem[0]=*p_inputs[0]; + bool valid; + bool can_iter = p_inputs[0]->iter_init(p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Input type not iterable: ")+Variant::get_type_name(p_inputs[0]->get_type()); + return 0; + } + + if (!can_iter) + return 1; //nothing to iterate + + + *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid"); + return 0; + } + + + } else { //continue sequence + + bool valid; + bool can_iter = p_working_mem[0].iter_next(p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid: ")+Variant::get_type_name(p_inputs[0]->get_type()); + return 0; + } + + if (!can_iter) + return 1; //nothing to iterate + + + *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid"); + return 0; + } + + } + + return 0|STEP_FLAG_PUSH_STACK_BIT; //go around + } + + +}; + +VisualScriptNodeInstance* VisualScriptIterator::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIterator * instance = memnew(VisualScriptNodeInstanceIterator ); + instance->node=this; + instance->instance=p_instance; + return instance; +} + +VisualScriptIterator::VisualScriptIterator() { + +} + + + +////////////////////////////////////////// +////////////////SEQUENCE///////////////// +////////////////////////////////////////// + +int VisualScriptSequence::get_output_sequence_port_count() const { + + return steps; +} + +bool VisualScriptSequence::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptSequence::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptSequence::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSequence::get_output_sequence_port_text(int p_port) const { + + return itos(p_port+1); +} + +PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const{ + return PropertyInfo(); +} +PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const{ + return PropertyInfo(Variant::INT,"current"); +} +String VisualScriptSequence::get_caption() const { + + return "Sequence"; +} + +String VisualScriptSequence::get_text() const { + + return "in order: "; +} + +void VisualScriptSequence::set_steps(int p_steps) { + + ERR_FAIL_COND(p_steps<1); + if (steps==p_steps) + return; + + steps=p_steps; + ports_changed_notify(); + +} + +int VisualScriptSequence::get_steps() const { + + return steps; +} + +void VisualScriptSequence::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_steps","steps"),&VisualScriptSequence::set_steps); + ObjectTypeDB::bind_method(_MD("get_steps"),&VisualScriptSequence::get_steps); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),_SCS("set_steps"),_SCS("get_steps")); + +} + +class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance { +public: + + VisualScriptSequence *node; + VisualScriptInstance *instance; + int steps; + + virtual int get_working_memory_size() const { return 1; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_start_mode==START_MODE_BEGIN_SEQUENCE) { + + p_working_mem[0]=0; + } + + int step = p_working_mem[0]; + + *p_outputs[0]=step; + + if (step+1==steps) + return step; + else { + p_working_mem[0]=step+1; + return step|STEP_FLAG_PUSH_STACK_BIT; + } + + } + + +}; + +VisualScriptNodeInstance* VisualScriptSequence::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSequence * instance = memnew(VisualScriptNodeInstanceSequence ); + instance->node=this; + instance->instance=p_instance; + instance->steps=steps; + return instance; +} +VisualScriptSequence::VisualScriptSequence() { + + steps=1; +} + + +////////////////////////////////////////// +////////////////EVENT TYPE FILTER/////////// +////////////////////////////////////////// + +static const char* event_type_names[InputEvent::TYPE_MAX]={ + "None", + "Key", + "MouseMotion", + "MouseButton", + "JoystickMotion", + "JoystickButton", + "ScreenTouch", + "ScreenDrag", + "Action" +}; + +int VisualScriptInputSelector::get_output_sequence_port_count() const { + + return InputEvent::TYPE_MAX; +} + +bool VisualScriptInputSelector::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptInputSelector::get_input_value_port_count() const{ + + + return 1; +} +int VisualScriptInputSelector::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptInputSelector::get_output_sequence_port_text(int p_port) const { + + return event_type_names[p_port]; +} + +PropertyInfo VisualScriptInputSelector::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,"event"); +} + +PropertyInfo VisualScriptInputSelector::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,""); +} + + +String VisualScriptInputSelector::get_caption() const { + + return "InputSelector"; +} + +String VisualScriptInputSelector::get_text() const { + + return ""; +} + + +class VisualScriptNodeInstanceInputSelector : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + InputEvent::Type type; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) { + r_error_str="Input value not of type event"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + InputEvent event = *p_inputs[0]; + + *p_outputs[0] = event; + + return event.type; + } + + +}; + +VisualScriptNodeInstance* VisualScriptInputSelector::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceInputSelector * instance = memnew(VisualScriptNodeInstanceInputSelector ); + instance->instance=p_instance; + return instance; +} + + + +void VisualScriptInputSelector::_bind_methods() { + + +} + +VisualScriptInputSelector::VisualScriptInputSelector() { + + +} + +////////////////////////////////////////// +////////////////EVENT ACTION FILTER/////////// +////////////////////////////////////////// + + +int VisualScriptInputFilter::get_output_sequence_port_count() const { + + return filters.size(); +} + +bool VisualScriptInputFilter::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptInputFilter::get_input_value_port_count() const{ + + + return 1; +} +int VisualScriptInputFilter::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const { + + String text; + + switch(filters[p_port].type) { + case InputEvent::NONE: { + text="None"; + } break; + case InputEvent::KEY: { + + InputEventKey k = filters[p_port].key; + + if (k.scancode==0 && k.unicode==0) { + text="No Key"; + } else { + if (k.scancode!=0) { + text="KeyCode: "+keycode_get_string(k.scancode); + } else if (k.unicode!=0) { + text="Uniode: "+String::chr(k.unicode); + } + + if (k.pressed) + text+=", Pressed"; + else + text+=", Released"; + + if (k.echo) + text+=", Echo"; + if (k.mod.alt) + text="Alt+"+text; + if (k.mod.shift) + text="Shift+"+text; + if (k.mod.control) + text="Ctrl+"+text; + if (k.mod.meta) + text="Meta+"+text; + } + + } break; + case InputEvent::MOUSE_MOTION: { + InputEventMouseMotion mm = filters[p_port].mouse_motion; + text="Mouse Motion"; + + String b = "Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"; + + for(int i=0;i<7;i++) { + if (mm.button_mask&(1<<i)) { + text=b.get_slice(",",i)+"+"+text; + } + } + if (mm.mod.alt) + text="Alt+"+text; + if (mm.mod.shift) + text="Shift+"+text; + if (mm.mod.control) + text="Ctrl+"+text; + if (mm.mod.meta) + text="Meta+"+text; + } break; + case InputEvent::MOUSE_BUTTON: { + + InputEventMouseButton mb = filters[p_port].mouse_button; + + String b = "Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"; + + text=b.get_slice(",",mb.button_index)+" Mouse Button"; + + if (mb.pressed) + text+=", Pressed"; + else + text+=", Released"; + + if (mb.doubleclick) + text+=", DblClick"; + if (mb.mod.alt) + text="Alt+"+text; + if (mb.mod.shift) + text="Shift+"+text; + if (mb.mod.control) + text="Ctrl+"+text; + if (mb.mod.meta) + text="Meta+"+text; + + + } break; + case InputEvent::JOYSTICK_MOTION: { + + InputEventJoystickMotion jm = filters[p_port].joy_motion; + + text="JoyMotion Axis "+itos(jm.axis>>1); + if (jm.axis&1) + text+=" > "+rtos(jm.axis_value); + else + text+=" < "+rtos(-jm.axis_value); + + } break; + case InputEvent::JOYSTICK_BUTTON: { + InputEventJoystickButton jb = filters[p_port].joy_button; + + text="JoyButton "+itos(jb.button_index); + if (jb.pressed) + text+=", Pressed"; + else + text+=", Released"; + } break; + case InputEvent::SCREEN_TOUCH: { + InputEventScreenTouch sd = filters[p_port].screen_touch; + + text="Touch Finger "+itos(sd.index); + if (sd.pressed) + text+=", Pressed"; + else + text+=", Released"; + } break; + case InputEvent::SCREEN_DRAG: { + InputEventScreenDrag sd = filters[p_port].screen_drag; + text="Drag Finger "+itos(sd.index); + } break; + case InputEvent::ACTION: { + + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + text="No Action"; + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + + if (filters[p_port].action.action==index) { + text="Action "+pi.name.substr(pi.name.find("/")+1,pi.name.length()); + break; + } + index++; + } + + if (filters[p_port].action.pressed) + text+=", Pressed"; + else + text+=", Released"; + + + } break; + } + + + + return text+" - "+itos(p_port); +} + +PropertyInfo VisualScriptInputFilter::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,"event"); +} + +PropertyInfo VisualScriptInputFilter::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,""); +} + + +String VisualScriptInputFilter::get_caption() const { + + return "InputFilter"; +} + +String VisualScriptInputFilter::get_text() const { + + return ""; +} + + + +bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name=="filter_count") { + filters.resize(p_value); + _change_notify(); + ports_changed_notify(); + return true; + } + + + if (String(p_name).begins_with("filter_")) { + + int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int(); + + ERR_FAIL_INDEX_V(idx,filters.size(),false); + + String what = String(p_name).get_slice("/",1); + + + if (what=="type") { + filters[idx]=InputEvent(); + filters[idx].type=InputEvent::Type(int(p_value)); + if (filters[idx].type==InputEvent::JOYSTICK_MOTION) { + filters[idx].joy_motion.axis_value=0.5; //for treshold + } else if (filters[idx].type==InputEvent::KEY) { + filters[idx].key.pressed=true; //put these as true to make it more user friendly + } else if (filters[idx].type==InputEvent::MOUSE_BUTTON) { + filters[idx].mouse_button.pressed=true; + } else if (filters[idx].type==InputEvent::JOYSTICK_BUTTON) { + filters[idx].joy_button.pressed=true; + } else if (filters[idx].type==InputEvent::SCREEN_TOUCH) { + filters[idx].screen_touch.pressed=true; + } else if (filters[idx].type==InputEvent::ACTION) { + filters[idx].action.pressed=true; + } + _change_notify(); + ports_changed_notify(); + + return true; + } + if (what=="device") { + filters[idx].device=p_value; + ports_changed_notify(); + return true; + } + + switch(filters[idx].type) { + + case InputEvent::KEY: { + + if (what=="scancode") { + String sc = p_value; + if (sc==String()) { + filters[idx].key.scancode=0; + } else { + filters[idx].key.scancode=find_keycode(p_value); + } + + } else if (what=="unicode") { + + String uc = p_value; + + if (uc==String()) { + filters[idx].key.unicode=0; + } else { + filters[idx].key.unicode=uc[0]; + } + + } else if (what=="pressed") { + + filters[idx].key.pressed=p_value; + } else if (what=="echo") { + + filters[idx].key.echo=p_value; + + } else if (what=="mod_alt") { + filters[idx].key.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].key.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].key.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].key.mod.meta=p_value; + } else { + return false; + } + ports_changed_notify(); + + return true; + } break; + case InputEvent::MOUSE_MOTION: { + + + if (what=="button_mask") { + filters[idx].mouse_motion.button_mask=p_value; + + } else if (what=="mod_alt") { + filters[idx].mouse_motion.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].mouse_motion.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].mouse_motion.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].mouse_motion.mod.meta=p_value; + } else { + return false; + } + + ports_changed_notify(); + return true; + + } break; + case InputEvent::MOUSE_BUTTON: { + + if (what=="button_index") { + filters[idx].mouse_button.button_index=p_value; + } else if (what=="pressed") { + filters[idx].mouse_button.pressed=p_value; + } else if (what=="doubleclicked") { + filters[idx].mouse_button.doubleclick=p_value; + + } else if (what=="mod_alt") { + filters[idx].mouse_button.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].mouse_button.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].mouse_button.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].mouse_button.mod.meta=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + } break; + case InputEvent::JOYSTICK_MOTION: { + + if (what=="axis") { + filters[idx].joy_motion.axis=int(p_value)<<1|filters[idx].joy_motion.axis; + } else if (what=="mode") { + filters[idx].joy_motion.axis|=int(p_value); + } else if (what=="treshold") { + filters[idx].joy_motion.axis_value=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + if (what=="button_index") { + filters[idx].joy_button.button_index=p_value; + } else if (what=="pressed") { + filters[idx].joy_button.pressed=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + } break; + case InputEvent::SCREEN_TOUCH: { + + if (what=="finger_index") { + filters[idx].screen_touch.index=p_value; + } else if (what=="pressed") { + filters[idx].screen_touch.pressed=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + } break; + case InputEvent::SCREEN_DRAG: { + if (what=="finger_index") { + filters[idx].screen_drag.index=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + } break; + case InputEvent::ACTION: { + + + if (what=="action_name") { + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + String name = pi.name.substr(pi.name.find("/")+1,pi.name.length()); + if (name==String(p_value)) { + + filters[idx].action.action=index; + ports_changed_notify(); + return true; + } + + index++; + } + + filters[idx].action.action=0; + ports_changed_notify(); + + return false; + + } else if (what=="pressed") { + + filters[idx].action.pressed=p_value; + ports_changed_notify(); + return true; + } + + + } break; + + } + } + return false; +} + +bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) const{ + + if (p_name=="filter_count") { + r_ret=filters.size(); + return true; + } + + + if (String(p_name).begins_with("filter_")) { + + int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int(); + + ERR_FAIL_INDEX_V(idx,filters.size(),false); + + String what = String(p_name).get_slice("/",1); + + + if (what=="type") { + r_ret=filters[idx].type; + return true; + } + if (what=="device") { + r_ret=filters[idx].device; + return true; + } + + switch(filters[idx].type) { + + case InputEvent::KEY: { + + if (what=="scancode") { + if (filters[idx].key.scancode==0) + r_ret=String(); + else { + + r_ret=keycode_get_string(filters[idx].key.scancode); + } + + } else if (what=="unicode") { + + + if (filters[idx].key.unicode==0) { + r_ret=String(); + } else { + CharType str[2]={ (CharType)filters[idx].key.unicode, 0}; + r_ret=String(str); + } + + } else if (what=="pressed") { + + r_ret=filters[idx].key.pressed; + } else if (what=="echo") { + + r_ret=filters[idx].key.echo; + + } else if (what=="mod_alt") { + r_ret=filters[idx].key.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].key.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].key.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].key.mod.meta; + } else { + return false; + } + + return true; + } break; + case InputEvent::MOUSE_MOTION: { + + + if (what=="button_mask") { + r_ret=filters[idx].mouse_motion.button_mask; + + } else if (what=="mod_alt") { + r_ret=filters[idx].mouse_motion.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].mouse_motion.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].mouse_motion.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].mouse_motion.mod.meta; + } else { + return false; + } + + return true; + + } break; + case InputEvent::MOUSE_BUTTON: { + + if (what=="button_index") { + r_ret=filters[idx].mouse_button.button_index; + } else if (what=="pressed") { + r_ret=filters[idx].mouse_button.pressed; + } else if (what=="doubleclicked") { + r_ret=filters[idx].mouse_button.doubleclick; + + } else if (what=="mod_alt") { + r_ret=filters[idx].mouse_button.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].mouse_button.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].mouse_button.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].mouse_button.mod.meta; + } else { + return false; + } + return true; + + } break; + case InputEvent::JOYSTICK_MOTION: { + + if (what=="axis_index") { + r_ret=filters[idx].joy_motion.axis>>1; + } else if (what=="mode") { + r_ret=filters[idx].joy_motion.axis&1; + } else if (what=="treshold") { + r_ret=filters[idx].joy_motion.axis_value; + } else { + return false; + } + return true; + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + if (what=="button_index") { + r_ret=filters[idx].joy_button.button_index; + } else if (what=="pressed") { + r_ret=filters[idx].joy_button.pressed; + } else { + return false; + } + return true; + + } break; + case InputEvent::SCREEN_TOUCH: { + + if (what=="finger_index") { + r_ret=filters[idx].screen_touch.index; + } else if (what=="pressed") { + r_ret=filters[idx].screen_touch.pressed; + } else { + return false; + } + return true; + } break; + case InputEvent::SCREEN_DRAG: { + if (what=="finger_index") { + r_ret=filters[idx].screen_drag.index; + } else { + return false; + } + return true; + } break; + case InputEvent::ACTION: { + + + if (what=="action_name") { + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + + if (filters[idx].action.action==index) { + r_ret=pi.name.substr(pi.name.find("/")+1,pi.name.length()); + return true; + } + index++; + } + + r_ret="None"; //no index + return false; + + } else if (what=="pressed") { + + r_ret=filters[idx].action.pressed; + return true; + } + + + } break; + + } + } + return false; +} +void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64")); + + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + + String kc; + String actions; + + + + for(int i=0;i<filters.size();i++) { + + String base = "filter_"+itos(i)+"/"; + p_list->push_back(PropertyInfo(Variant::INT,base+"type",PROPERTY_HINT_ENUM,et)); + p_list->push_back(PropertyInfo(Variant::INT,base+"device")); + switch(filters[i].type) { + + case InputEvent::NONE: { + + } break; + case InputEvent::KEY: { + if (kc==String()) { + int kcc = keycode_get_count(); + kc="None"; + for(int i=0;i<kcc;i++) { + kc+=","; + kc+=String(keycode_get_name_by_index(i)); + } + } + p_list->push_back(PropertyInfo(Variant::STRING,base+"scancode",PROPERTY_HINT_ENUM,kc)); + p_list->push_back(PropertyInfo(Variant::STRING,base+"unicode")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"echo")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + + } break; + case InputEvent::MOUSE_MOTION: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_mask",PROPERTY_HINT_FLAGS,"Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + } break; + case InputEvent::MOUSE_BUTTON: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_index",PROPERTY_HINT_ENUM,"Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"doubleclicked")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + } break; + case InputEvent::JOYSTICK_MOTION: { + + p_list->push_back(PropertyInfo(Variant::INT,base+"axis_index")); + p_list->push_back(PropertyInfo(Variant::INT,base+"mode",PROPERTY_HINT_ENUM,"Min,Max")); + p_list->push_back(PropertyInfo(Variant::REAL,base+"treshold",PROPERTY_HINT_RANGE,"0,1,0.01")); + } break; + case InputEvent::JOYSTICK_BUTTON: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_index")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + case InputEvent::SCREEN_TOUCH: { + p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + case InputEvent::SCREEN_DRAG: { + p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index")); + } break; + case InputEvent::ACTION: { + + + + if (actions==String()) { + + actions="None"; + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + Vector<String> al; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + String name = pi.name.substr(pi.name.find("/")+1,pi.name.length()); + + + al.push_back(name); + } + + for(int i=0;i<al.size();i++) { + actions+=","; + actions+=al[i]; + } + } + + p_list->push_back(PropertyInfo(Variant::STRING,base+"action_name",PROPERTY_HINT_ENUM,actions)); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + + } + } +} + +class VisualScriptNodeInstanceInputFilter : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + Vector<InputEvent> filters; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) { + r_error_str="Input value not of type event"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + InputEvent event = *p_inputs[0]; + + + for(int i=0;i<filters.size();i++) { + + const InputEvent &ie = filters[i]; + if (ie.type!=event.type) + continue; + + bool match=false; + + switch(ie.type) { + + case InputEvent::NONE: { + + match=true; + } break; + case InputEvent::KEY: { + + InputEventKey k = ie.key; + InputEventKey k2 = event.key; + + if (k.scancode==0 && k.unicode==0 && k2.scancode==0 && k2.unicode==0) { + match=true; + + } else { + + if ( (k.scancode!=0 && k.scancode==k2.scancode) || (k.unicode!=0 && k.unicode==k2.unicode)) { + //key valid + + if ( + k.pressed==k2.pressed && + k.echo==k2.echo && + k.mod == k2.mod + ) { + match=true; + } + } + + } + + } break; + case InputEvent::MOUSE_MOTION: { + InputEventMouseMotion mm = ie.mouse_motion; + InputEventMouseMotion mm2 = event.mouse_motion; + + if ( mm.button_mask==mm2.button_mask && + mm.mod==mm2.mod + ) { + match=true; + } + + } break; + case InputEvent::MOUSE_BUTTON: { + + InputEventMouseButton mb = ie.mouse_button; + InputEventMouseButton mb2 = event.mouse_button; + + if ( mb.button_index==mb2.button_index && + mb.pressed==mb2.pressed && + mb.doubleclick==mb2.doubleclick && + mb.mod==mb2.mod) { + match=true; + } + + + } break; + case InputEvent::JOYSTICK_MOTION: { + + InputEventJoystickMotion jm = ie.joy_motion; + InputEventJoystickMotion jm2 = event.joy_motion; + + int axis = jm.axis>>1; + + if (axis==jm2.axis) { + + if (jm.axis&1) { + //greater + if (jm2.axis_value > jm.axis_value) { + match=true; + } + } else { + //less + if (jm2.axis_value < -jm.axis_value) { + match=true; + } + } + } + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + InputEventJoystickButton jb = ie.joy_button; + InputEventJoystickButton jb2 = event.joy_button; + + if ( jb.button_index==jb2.button_index && + jb.pressed == jb2.pressed + ) { + match=true; + } + } break; + case InputEvent::SCREEN_TOUCH: { + InputEventScreenTouch st = ie.screen_touch; + InputEventScreenTouch st2 = event.screen_touch; + + if ( st.index==st2.index && + st.pressed==st2.pressed) { + match=true; + } + + } break; + case InputEvent::SCREEN_DRAG: { + InputEventScreenDrag sd = ie.screen_drag; + InputEventScreenDrag sd2 = event.screen_drag; + + if (sd.index==sd2.index) { + match=true; + } + } break; + case InputEvent::ACTION: { + + InputEventAction ia = ie.action; + InputEventAction ia2 = event.action; + + if ( ia.action==ia2.action && + ia.pressed==ia2.pressed) { + match=true; + } + } break; + + } + + *p_outputs[0] = event; + + if (match) + return i; //go through match output + + } + + return STEP_NO_ADVANCE_BIT; //none found, don't advance + + + } + + +}; + + +VisualScriptNodeInstance* VisualScriptInputFilter::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceInputFilter * instance = memnew(VisualScriptNodeInstanceInputFilter ); + instance->instance=p_instance; + instance->filters=filters; + return instance; +} + + + + +VisualScriptInputFilter::VisualScriptInputFilter() { + + +} + + + + +void register_visual_script_flow_control_nodes() { + + VisualScriptLanguage::singleton->add_register_func("flow_control/return",create_return_node<false>); + VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value",create_return_node<true>); + VisualScriptLanguage::singleton->add_register_func("flow_control/condition",create_node_generic<VisualScriptCondition>); + VisualScriptLanguage::singleton->add_register_func("flow_control/while",create_node_generic<VisualScriptWhile>); + VisualScriptLanguage::singleton->add_register_func("flow_control/iterator",create_node_generic<VisualScriptIterator>); + VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>); + VisualScriptLanguage::singleton->add_register_func("flow_control/input_select",create_node_generic<VisualScriptInputSelector>); + VisualScriptLanguage::singleton->add_register_func("flow_control/input_filter",create_node_generic<VisualScriptInputFilter>); + + + +} diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h new file mode 100644 index 0000000000..ed0e328629 --- /dev/null +++ b/modules/visual_script/visual_script_flow_control.h @@ -0,0 +1,280 @@ +#ifndef VISUAL_SCRIPT_FLOW_CONTROL_H +#define VISUAL_SCRIPT_FLOW_CONTROL_H + +#include "visual_script.h" + +class VisualScriptReturn : public VisualScriptNode { + + OBJ_TYPE(VisualScriptReturn,VisualScriptNode) + + + Variant::Type type; + bool with_value; +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + void set_return_type(Variant::Type); + Variant::Type get_return_type() const; + + void set_enable_return_value(bool p_enable); + bool is_return_value_enabled() const; + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptReturn(); +}; + + +class VisualScriptCondition : public VisualScriptNode { + + OBJ_TYPE(VisualScriptCondition,VisualScriptNode) + + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptCondition(); +}; + + +class VisualScriptWhile : public VisualScriptNode { + + OBJ_TYPE(VisualScriptWhile,VisualScriptNode) + + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptWhile(); +}; + + + +class VisualScriptIterator : public VisualScriptNode { + + OBJ_TYPE(VisualScriptIterator,VisualScriptNode) + + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptIterator(); +}; + + + +class VisualScriptSequence : public VisualScriptNode { + + OBJ_TYPE(VisualScriptSequence,VisualScriptNode) + + + int steps; + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + void set_steps(int p_steps); + int get_steps() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSequence(); +}; + + + + +class VisualScriptInputSelector : public VisualScriptNode { + + OBJ_TYPE(VisualScriptInputSelector,VisualScriptNode) + + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + + VisualScriptInputSelector(); +}; + + + + +class VisualScriptInputFilter : public VisualScriptNode { + + OBJ_TYPE(VisualScriptInputFilter,VisualScriptNode) + + Vector<InputEvent> filters; + + +protected: + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + + VisualScriptInputFilter(); +}; + +void register_visual_script_flow_control_nodes(); + + + +#endif // VISUAL_SCRIPT_FLOW_CONTROL_H diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp new file mode 100644 index 0000000000..4006dab4a5 --- /dev/null +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -0,0 +1,2511 @@ +#include "visual_script_func_nodes.h" +#include "scene/main/scene_main_loop.h" +#include "os/os.h" +#include "scene/main/node.h" +#include "visual_script_nodes.h" + +////////////////////////////////////////// +////////////////CALL////////////////////// +////////////////////////////////////////// + +int VisualScriptFunctionCall::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptFunctionCall::has_input_sequence_port() const{ + + return true; +} +#ifdef TOOLS_ENABLED + +static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { + + if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) + return NULL; + + Ref<Script> scr = p_current_node->get_script(); + + if (scr.is_valid() && scr==script) + return p_current_node; + + for(int i=0;i<p_current_node->get_child_count();i++) { + Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); + if (n) + return n; + } + + return NULL; +} + +#endif +Node *VisualScriptFunctionCall::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + +StringName VisualScriptFunctionCall::_get_base_type() const { + + if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { + Node *path = _get_base_node(); + if (path) + return path->get_type(); + + } + + return base_type; +} + +int VisualScriptFunctionCall::get_input_value_port_count() const{ + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + + Vector<StringName> names = Variant::get_method_argument_names(basic_type,function); + return names.size()+1; + + } else { + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (!mb) + return 0; + + return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) - use_default_args; + } + +} +int VisualScriptFunctionCall::get_output_value_port_count() const{ + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + bool returns=false; + Variant::get_method_return_type(basic_type,function,&returns); + return returns?1:0; + + } else { + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (!mb) + return 0; + + return mb->has_return() ? 1 : 0; + } +} + +String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { + if (p_idx==0) { + PropertyInfo pi; + pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); + pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); + return pi; + } else { + p_idx--; + } + } + +#ifdef DEBUG_METHODS_ENABLED + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + + Vector<StringName> names = Variant::get_method_argument_names(basic_type,function); + Vector<Variant::Type> types = Variant::get_method_argument_types(basic_type,function); + return PropertyInfo(types[p_idx],names[p_idx]); + + } else { + + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (!mb) + return PropertyInfo(); + + return mb->get_argument_info(p_idx); + } +#else + return PropertyInfo(); +#endif + +} + +PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const{ + + +#ifdef DEBUG_METHODS_ENABLED + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + + return PropertyInfo(Variant::get_method_return_type(basic_type,function),""); + } else { + + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (!mb) + return PropertyInfo(); + + PropertyInfo pi = mb->get_argument_info(-1); + pi.name=""; + return pi; + } +#else + return PropertyInfo(); +#endif +} + + +String VisualScriptFunctionCall::get_caption() const { + + static const char*cname[4]= { + "CallSelf", + "CallNode", + "CallInstance", + "CallBasic" + }; + + return cname[call_mode]; +} + +String VisualScriptFunctionCall::get_text() const { + + if (call_mode==CALL_MODE_SELF) + return " "+String(function)+"()"; + else if (call_mode==CALL_MODE_BASIC_TYPE) + return Variant::get_type_name(basic_type)+"."+String(function)+"()"; + else + return " "+base_type+"."+String(function)+"()"; + +} + +void VisualScriptFunctionCall::_update_defargs() { + + //save base type if accessible + + if (call_mode==CALL_MODE_NODE_PATH) { + + Node* node=_get_base_node(); + if (node) { + base_type=node->get_type(); + } + } else if (call_mode==CALL_MODE_SELF) { + + if (get_visual_script().is_valid()) { + base_type=get_visual_script()->get_instance_base_type(); + } + } + + + if (call_mode==CALL_MODE_BASIC_TYPE) { + use_default_args = Variant::get_method_default_arguments(basic_type,function).size(); + } else { + if (!get_visual_script().is_valid()) + return; //do not change if not valid yet + + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (!mb) + return; + + use_default_args=mb->get_default_argument_count(); + } + +} + +void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) { + + if (basic_type==p_type) + return; + basic_type=p_type; + + _update_defargs(); + _change_notify(); + ports_changed_notify(); +} + +Variant::Type VisualScriptFunctionCall::get_basic_type() const{ + + return basic_type; +} + +void VisualScriptFunctionCall::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + _update_defargs(); + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptFunctionCall::get_base_type() const{ + + return base_type; +} + +void VisualScriptFunctionCall::set_function(const StringName& p_type){ + + if (function==p_type) + return; + + function=p_type; + _update_defargs(); + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptFunctionCall::get_function() const { + + + return function; +} + +void VisualScriptFunctionCall::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + _update_defargs(); + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptFunctionCall::get_base_path() const { + + return base_path; +} + + +void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + _update_defargs(); + _change_notify(); + ports_changed_notify(); + +} +VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const { + + return call_mode; +} + +void VisualScriptFunctionCall::set_use_default_args(int p_amount) { + + if (use_default_args==p_amount) + return; + + use_default_args=p_amount; + ports_changed_notify(); + + +} + +int VisualScriptFunctionCall::get_use_default_args() const{ + + return use_default_args; +} +void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const { + + if (property.name=="function/base_type") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + if (property.name=="function/basic_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE) { + property.usage=0; + } + } + + if (property.name=="function/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="function/function") { + property.hint=PROPERTY_HINT_ENUM; + + + List<MethodInfo> methods; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + if (basic_type==Variant::NIL) { + property.usage=0; + return; //nothing for nil + } + Variant::CallError ce; + Variant v = Variant::construct(basic_type,NULL,0,ce); + v.get_method_list(&methods); + + + } else { + + StringName base = _get_base_type(); + ObjectTypeDB::get_method_list(base,&methods); + + + } + + List<String> mstring; + for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + mstring.push_back(E->get().name.get_slice(":",0)); + } + + mstring.sort(); + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + property.hint_string=ml; + } + + if (property.name=="function/use_default_args") { + + property.hint=PROPERTY_HINT_RANGE; + + int mc=0; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + mc = Variant::get_method_default_arguments(basic_type,function).size(); + } else { + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (mb) { + + mc=mb->get_default_argument_count(); + } + } + + if (mc==0) { + property.usage=0; //do not show + } else { + + property.hint_string="0,"+itos(mc)+",1"; + } + } +} + + +void VisualScriptFunctionCall::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type); + + ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type); + ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type); + + ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function); + ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptFunctionCall::get_base_path); + + ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args); + ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args); + + + String bt; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (i>0) + bt+=","; + + bt+=Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args")); + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + BIND_CONSTANT( CALL_MODE_INSTANCE); + BIND_CONSTANT( CALL_MODE_BASIC_TYPE ); +} + +class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance { +public: + + + VisualScriptFunctionCall::CallMode call_mode; + NodePath node_path; + int input_args; + bool returns; + StringName function; + + VisualScriptFunctionCall *node; + VisualScriptInstance *instance; + + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + switch(call_mode) { + + case VisualScriptFunctionCall::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + if (returns) { + *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); + } else { + object->call(function,p_inputs,input_args,r_error); + } + } break; + case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + if (returns) { + *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); + } else { + another->call(function,p_inputs,input_args,r_error); + } + + } break; + case VisualScriptFunctionCall::CALL_MODE_INSTANCE: + case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: { + + Variant v = *p_inputs[0]; + + if (returns) { + *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error); + } else { + v.call(function,p_inputs+1,input_args,r_error); + } + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceFunctionCall * instance = memnew(VisualScriptNodeInstanceFunctionCall ); + instance->node=this; + instance->instance=p_instance; + instance->function=function; + instance->call_mode=call_mode; + instance->returns=get_output_value_port_count(); + instance->node_path=base_path; + instance->input_args = get_input_value_port_count() - ( (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1: 0 ); + return instance; +} +VisualScriptFunctionCall::VisualScriptFunctionCall() { + + call_mode=CALL_MODE_INSTANCE; + basic_type=Variant::NIL; + use_default_args=0; + base_type="Object"; + +} + +template<VisualScriptFunctionCall::CallMode cmode> +static Ref<VisualScriptNode> create_function_call_node(const String& p_name) { + + Ref<VisualScriptFunctionCall> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + + +////////////////////////////////////////// +////////////////SET////////////////////// +////////////////////////////////////////// + +static const char* event_type_names[InputEvent::TYPE_MAX]={ + "None", + "Key", + "MouseMotion", + "MouseButton", + "JoystickMotion", + "JoystickButton", + "ScreenTouch", + "ScreenDrag", + "Action" +}; + + +int VisualScriptPropertySet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptPropertySet::has_input_sequence_port() const{ + + return true; +} + +Node *VisualScriptPropertySet::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + +StringName VisualScriptPropertySet::_get_base_type() const { + + if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { + Node *path = _get_base_node(); + if (path) + return path->get_type(); + + } + + return base_type; +} + +int VisualScriptPropertySet::get_input_value_port_count() const{ + + int pc = (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0; + + if (!use_builtin_value) + pc++; + + return pc; +} +int VisualScriptPropertySet::get_output_value_port_count() const{ + + return call_mode==CALL_MODE_BASIC_TYPE? 1 : 0; +} + +String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { + if (p_idx==0) { + PropertyInfo pi; + pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); + pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); + return pi; + } else { + p_idx--; + } + } + +#ifdef DEBUG_METHODS_ENABLED + + //not very efficient but.. + + + List<PropertyInfo> pinfo; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + Variant::CallError ce; + v = Variant::construct(basic_type,NULL,0,ce); + } + v.get_property_list(&pinfo); + + } else if (call_mode==CALL_MODE_NODE_PATH) { + + Node *n = _get_base_node(); + if (n) { + n->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==property) { + + PropertyInfo info=E->get(); + info.name="value"; + return info; + } + } + + +#endif + + return PropertyInfo(Variant::NIL,"value"); + +} + +PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{ + if (call_mode==CALL_MODE_BASIC_TYPE) { + return PropertyInfo(basic_type,"out"); + } else { + return PropertyInfo(); + } + +} + + +String VisualScriptPropertySet::get_caption() const { + + static const char*cname[4]= { + "SelfSet", + "NodeSet", + "InstanceSet", + "BasicSet" + }; + + return cname[call_mode]; +} + +String VisualScriptPropertySet::get_text() const { + + String prop; + + if (call_mode==CALL_MODE_BASIC_TYPE) + prop=Variant::get_type_name(basic_type)+"."+property; + else + prop=property; + + if (use_builtin_value) { + String bit = builtin_value.get_construct_string(); + if (bit.length()>40) { + bit=bit.substr(0,40); + bit+="..."; + } + + prop+="\n "+bit; + } + + return prop; + +} + +void VisualScriptPropertySet::_update_base_type() { + //cache it because this information may not be available on load + if (call_mode==CALL_MODE_NODE_PATH) { + + Node* node=_get_base_node(); + if (node) { + base_type=node->get_type(); + } + } else if (call_mode==CALL_MODE_SELF) { + + if (get_visual_script().is_valid()) { + base_type=get_visual_script()->get_instance_base_type(); + } + } + +} +void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) { + + if (basic_type==p_type) + return; + basic_type=p_type; + + + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +Variant::Type VisualScriptPropertySet::get_basic_type() const{ + + return basic_type; +} + +void VisualScriptPropertySet::set_event_type(InputEvent::Type p_type) { + + if (event_type==p_type) + return; + event_type=p_type; + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +InputEvent::Type VisualScriptPropertySet::get_event_type() const{ + + return event_type; +} + + +void VisualScriptPropertySet::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertySet::get_base_type() const{ + + return base_type; +} + +void VisualScriptPropertySet::set_property(const StringName& p_type){ + + if (property==p_type) + return; + + property=p_type; + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptPropertySet::get_property() const { + + + return property; +} + +void VisualScriptPropertySet::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + _update_base_type(); + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptPropertySet::get_base_path() const { + + return base_path; +} + + +void VisualScriptPropertySet::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + _update_base_type(); + _change_notify(); + ports_changed_notify(); + +} +VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const { + + return call_mode; +} + + +void VisualScriptPropertySet::set_use_builtin_value(bool p_use) { + + if (use_builtin_value==p_use) + return; + + use_builtin_value=p_use; + _change_notify(); + ports_changed_notify(); + +} + +bool VisualScriptPropertySet::is_using_builtin_value() const{ + + return use_builtin_value; +} + +void VisualScriptPropertySet::set_builtin_value(const Variant& p_value){ + + if (builtin_value==p_value) + return; + + builtin_value=p_value; + +} +Variant VisualScriptPropertySet::get_builtin_value() const{ + + return builtin_value; +} +void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { + + if (property.name=="property/base_type") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + + if (property.name=="property/basic_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE) { + property.usage=0; + } + } + + if (property.name=="property/event_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { + property.usage=0; + } + } + + if (property.name=="property/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="property/property") { + property.hint=PROPERTY_HINT_ENUM; + + + List<PropertyInfo> pinfo; + + + if (call_mode==CALL_MODE_BASIC_TYPE) { + Variant::CallError ce; + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + v = Variant::construct(basic_type,NULL,0,ce); + } + v.get_property_list(&pinfo); + + } else if (call_mode==CALL_MODE_NODE_PATH) { + + Node *n = _get_base_node(); + if (n) { + n->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + } else { + + + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + + } + + List<String> mstring; + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().usage&PROPERTY_USAGE_EDITOR) { + mstring.push_back(E->get().name); + } + } + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + if (ml==String()) { + property.usage=PROPERTY_USAGE_NOEDITOR; //do not show for editing if empty + } else { + property.hint_string=ml; + } + } + + if (property.name=="value/builtin") { + + if (!use_builtin_value) { + property.usage=0; + } else { + List<PropertyInfo> pinfo; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + Variant::CallError ce; + Variant v = Variant::construct(basic_type,NULL,0,ce); + v.get_property_list(&pinfo); + + } else if (call_mode==CALL_MODE_NODE_PATH) { + + Node *n = _get_base_node(); + if (n) { + n->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==this->property) { + + property.hint=E->get().hint; + property.type=E->get().type; + property.hint_string=E->get().hint_string; + } + } + } + + } +} + +void VisualScriptPropertySet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type); + + + ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type); + ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertySet::get_basic_type); + + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); + ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type); + + ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property); + ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertySet::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path); + + ObjectTypeDB::bind_method(_MD("set_builtin_value","value"),&VisualScriptPropertySet::set_builtin_value); + ObjectTypeDB::bind_method(_MD("get_builtin_value"),&VisualScriptPropertySet::get_builtin_value); + + ObjectTypeDB::bind_method(_MD("set_use_builtin_value","enable"),&VisualScriptPropertySet::set_use_builtin_value); + ObjectTypeDB::bind_method(_MD("is_using_builtin_value"),&VisualScriptPropertySet::is_using_builtin_value); + + String bt; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (i>0) + bt+=","; + + bt+=Variant::get_type_name(Variant::Type(i)); + } + + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"value/use_builtin"),_SCS("set_use_builtin_value"),_SCS("is_using_builtin_value")); + ADD_PROPERTY(PropertyInfo(Variant::NIL,"value/builtin"),_SCS("set_builtin_value"),_SCS("get_builtin_value")); + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + BIND_CONSTANT( CALL_MODE_INSTANCE); + +} + +class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance { +public: + + + VisualScriptPropertySet::CallMode call_mode; + NodePath node_path; + StringName property; + bool use_builtin; + Variant builtin_val; + + VisualScriptPropertySet *node; + VisualScriptInstance *instance; + + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + switch(call_mode) { + + case VisualScriptPropertySet::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + bool valid; + + if (use_builtin) { + object->set(property,builtin_val,&valid); + } else { + object->set(property,*p_inputs[0],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + } break; + case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + bool valid; + + if (use_builtin) { + another->set(property,builtin_val,&valid); + } else { + another->set(property,*p_inputs[0],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + + } break; + case VisualScriptPropertySet::CALL_MODE_INSTANCE: + case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: { + + Variant v = *p_inputs[0]; + + bool valid; + + if (use_builtin) { + v.set(property,builtin_val,&valid); + } else { + v.set(property,p_inputs[1],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + + if (call_mode==VisualScriptPropertySet::CALL_MODE_BASIC_TYPE) { + *p_outputs[0]=v; + } + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstancePropertySet * instance = memnew(VisualScriptNodeInstancePropertySet ); + instance->node=this; + instance->instance=p_instance; + instance->property=property; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->use_builtin=use_builtin_value; + instance->builtin_val=builtin_value; + return instance; +} + +VisualScriptPropertySet::VisualScriptPropertySet() { + + call_mode=CALL_MODE_INSTANCE; + base_type="Object"; + basic_type=Variant::NIL; + event_type=InputEvent::NONE; + +} + +template<VisualScriptPropertySet::CallMode cmode> +static Ref<VisualScriptNode> create_property_set_node(const String& p_name) { + + Ref<VisualScriptPropertySet> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + + +////////////////////////////////////////// +////////////////GET////////////////////// +////////////////////////////////////////// + +int VisualScriptPropertyGet::get_output_sequence_port_count() const { + + return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; +} + +bool VisualScriptPropertyGet::has_input_sequence_port() const{ + + return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true; +} +void VisualScriptPropertyGet::_update_base_type() { + //cache it because this information may not be available on load + if (call_mode==CALL_MODE_NODE_PATH) { + + Node* node=_get_base_node(); + if (node) { + base_type=node->get_type(); + } + } else if (call_mode==CALL_MODE_SELF) { + + if (get_visual_script().is_valid()) { + base_type=get_visual_script()->get_instance_base_type(); + } + } + +} +Node *VisualScriptPropertyGet::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + +StringName VisualScriptPropertyGet::_get_base_type() const { + + if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { + Node *path = _get_base_node(); + if (path) + return path->get_type(); + + } + + return base_type; +} + +int VisualScriptPropertyGet::get_input_value_port_count() const{ + + return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0; + +} +int VisualScriptPropertyGet::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_INSTANCE || call_mode==CALL_MODE_BASIC_TYPE) { + if (p_idx==0) { + PropertyInfo pi; + pi.type=(call_mode==CALL_MODE_INSTANCE?Variant::OBJECT:basic_type); + pi.name=(call_mode==CALL_MODE_INSTANCE?String("instance"):Variant::get_type_name(basic_type).to_lower()); + return pi; + } else { + p_idx--; + } + } + return PropertyInfo(); + +} + +PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const{ + + + +#ifdef DEBUG_METHODS_ENABLED + + //not very efficient but.. + + + List<PropertyInfo> pinfo; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + Variant::CallError ce; + v = Variant::construct(basic_type,NULL,0,ce); + } + v.get_property_list(&pinfo); + } else if (call_mode==CALL_MODE_NODE_PATH) { + + Node *n = _get_base_node(); + if (n) { + n->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==property) { + + PropertyInfo info=E->get(); + info.name=""; + return info; + } + } + + +#endif + + return PropertyInfo(Variant::NIL,""); +} + + +String VisualScriptPropertyGet::get_caption() const { + + static const char*cname[4]= { + "SelfGet", + "NodeGet", + "InstanceGet", + "BasicGet" + }; + + return cname[call_mode]; +} + +String VisualScriptPropertyGet::get_text() const { + + + if (call_mode==CALL_MODE_BASIC_TYPE) + return Variant::get_type_name(basic_type)+"."+property; + else + return property; + +} + +void VisualScriptPropertyGet::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertyGet::get_base_type() const{ + + return base_type; +} + +void VisualScriptPropertyGet::set_property(const StringName& p_type){ + + if (property==p_type) + return; + + property=p_type; + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptPropertyGet::get_property() const { + + + return property; +} + +void VisualScriptPropertyGet::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +NodePath VisualScriptPropertyGet::get_base_path() const { + + return base_path; +} + + +void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + _change_notify(); + _update_base_type(); + ports_changed_notify(); + +} +VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const { + + return call_mode; +} + + + +void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) { + + if (basic_type==p_type) + return; + basic_type=p_type; + + + _change_notify(); + ports_changed_notify(); +} + +Variant::Type VisualScriptPropertyGet::get_basic_type() const{ + + return basic_type; +} + + +void VisualScriptPropertyGet::set_event_type(InputEvent::Type p_type) { + + if (event_type==p_type) + return; + event_type=p_type; + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +InputEvent::Type VisualScriptPropertyGet::get_event_type() const{ + + return event_type; +} + +void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { + + if (property.name=="property/base_type") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + + if (property.name=="property/basic_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE) { + property.usage=0; + } + } + if (property.name=="property/event_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { + property.usage=0; + } + } + + if (property.name=="property/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="property/property") { + property.hint=PROPERTY_HINT_ENUM; + + + List<PropertyInfo> pinfo; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + Variant::CallError ce; + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + v = Variant::construct(basic_type,NULL,0,ce); + } + v.get_property_list(&pinfo); + + } else if (call_mode==CALL_MODE_NODE_PATH) { + + Node *n = _get_base_node(); + if (n) { + n->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + } else { + ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + } + + List<String> mstring; + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().usage&PROPERTY_USAGE_EDITOR) + mstring.push_back(E->get().name); + } + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + if (ml==String()) { + property.usage=PROPERTY_USAGE_NOEDITOR; //do not show for editing if empty + } else { + property.hint_string=ml; + } + + } + +} + +void VisualScriptPropertyGet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type); + + + ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type); + ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type); + + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); + ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type); + + + ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property); + ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertyGet::get_base_path); + + String bt; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (i>0) + bt+=","; + + bt+=Variant::get_type_name(Variant::Type(i)); + } + + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + BIND_CONSTANT( CALL_MODE_INSTANCE); +} + +class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance { +public: + + + VisualScriptPropertyGet::CallMode call_mode; + NodePath node_path; + StringName property; + + VisualScriptPropertyGet *node; + VisualScriptInstance *instance; + + + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return (call_mode==VisualScriptPropertyGet::CALL_MODE_SELF || call_mode==VisualScriptPropertyGet::CALL_MODE_NODE_PATH); } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + //these two modes can be get directly, so they use unsequenced mode + switch(call_mode) { + + case VisualScriptPropertyGet::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + bool valid; + + *r_value = object->get(property,&valid); + + if (!valid) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Invalid index property name."); + return false; + } + } break; + case VisualScriptPropertyGet::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Base object is not a Node!"); + return false; + } + + Node* another = node->get_node(node_path); + if (!node) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Path does not lead Node!"); + return false; + } + + bool valid; + + + *r_value = another->get(property,&valid); + + if (!valid) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=vformat(RTR("Invalid index property name '%s' in node %s."),String(property),another->get_name()); + return false; + } + + } break; + default: {}; + } + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + bool valid; + Variant v = *p_inputs[0]; + + *p_outputs[0] = v.get(property,&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Invalid index property name."); + + } + + + return 0; + } + + + + +}; + +VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstancePropertyGet * instance = memnew(VisualScriptNodeInstancePropertyGet ); + instance->node=this; + instance->instance=p_instance; + instance->property=property; + instance->call_mode=call_mode; + instance->node_path=base_path; + + return instance; +} + +VisualScriptPropertyGet::VisualScriptPropertyGet() { + + call_mode=CALL_MODE_INSTANCE; + base_type="Object"; + basic_type=Variant::NIL; + event_type=InputEvent::NONE; + +} + +template<VisualScriptPropertyGet::CallMode cmode> +static Ref<VisualScriptNode> create_property_get_node(const String& p_name) { + + Ref<VisualScriptPropertyGet> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + + +////////////////////////////////////////// +////////////////SCRIPT CALL////////////////////// +////////////////////////////////////////// + +int VisualScriptScriptCall::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptScriptCall::has_input_sequence_port() const{ + + return true; +} + +Node *VisualScriptScriptCall::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + + +int VisualScriptScriptCall::get_input_value_port_count() const{ + +#if 1 + return argument_count; +#else + if (call_mode==CALL_MODE_SELF) { + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_function(function)) + return 0; + + int id = vs->get_function_node_id(function); + if (id<0) + return 0; + + Ref<VisualScriptFunction> func = vs->get_node(function,id); + + return func->get_argument_count(); + } + } else { + + Node*base = _get_base_node(); + if (!base) + return 0; + Ref<Script> script = base->get_script(); + if (!script.is_valid()) + return 0; + + List<MethodInfo> functions; + script->get_method_list(&functions); + for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) { + if (E->get().name==function) { + return E->get().arguments.size(); + } + } + + } + + + return 0; +#endif + +} +int VisualScriptScriptCall::get_output_value_port_count() const{ + return 1; +} + +String VisualScriptScriptCall::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptScriptCall::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_SELF) { + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_function(function)) + return PropertyInfo(); + + int id = vs->get_function_node_id(function); + if (id<0) + return PropertyInfo(); + + Ref<VisualScriptFunction> func = vs->get_node(function,id); + + if (p_idx>=func->get_argument_count()) + return PropertyInfo(); + return PropertyInfo(func->get_argument_type(p_idx),func->get_argument_name(p_idx)); + } + } else { + + Node*base = _get_base_node(); + if (!base) + return PropertyInfo(); + Ref<Script> script = base->get_script(); + if (!script.is_valid()) + return PropertyInfo(); + + List<MethodInfo> functions; + script->get_method_list(&functions); + for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) { + if (E->get().name==function) { + if (p_idx<0 || p_idx>=E->get().arguments.size()) + return PropertyInfo(); + return E->get().arguments[p_idx]; + } + } + + } + + return PropertyInfo(); + +} + +PropertyInfo VisualScriptScriptCall::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptScriptCall::get_caption() const { + + return "ScriptCall"; +} + +String VisualScriptScriptCall::get_text() const { + + return " "+String(function)+"()"; +} + +void VisualScriptScriptCall::_update_argument_count() { + + //try to remember the amount of arguments in the function, because if loaded from scratch + //this information will not be available + + if (call_mode==CALL_MODE_SELF) { + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_function(function)) + return ; + + int id = vs->get_function_node_id(function); + if (id<0) + return; + + Ref<VisualScriptFunction> func = vs->get_node(function,id); + + argument_count=func->get_argument_count(); + } + } else { + + Node*base = _get_base_node(); + if (!base) + return; + + Ref<Script> script = base->get_script(); + if (!script.is_valid()) + return ; + + List<MethodInfo> functions; + script->get_method_list(&functions); + for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) { + if (E->get().name==function) { + argument_count=E->get().arguments.size(); + return; + } + } + + } +} + + +void VisualScriptScriptCall::set_function(const StringName& p_type){ + + if (function==p_type) + return; + + function=p_type; + _update_argument_count(); + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptScriptCall::get_function() const { + + + return function; +} + +void VisualScriptScriptCall::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + _update_argument_count(); + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptScriptCall::get_base_path() const { + + return base_path; +} + + +void VisualScriptScriptCall::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + _update_argument_count(); + _change_notify(); + ports_changed_notify(); + +} + +void VisualScriptScriptCall::set_argument_count(int p_count) { + + argument_count=p_count; + _change_notify(); + ports_changed_notify(); + +} + +int VisualScriptScriptCall::get_argument_count() const { + + return argument_count; +} + +VisualScriptScriptCall::CallMode VisualScriptScriptCall::get_call_mode() const { + + return call_mode; +} + +void VisualScriptScriptCall::_validate_property(PropertyInfo& property) const { + + + + if (property.name=="function/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="function/function") { + property.hint=PROPERTY_HINT_ENUM; + + + List<MethodInfo> methods; + + if (call_mode==CALL_MODE_SELF) { + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + vs->get_method_list(&methods); + + } + } else { + + Node*base = _get_base_node(); + if (!base) + return; + Ref<Script> script = base->get_script(); + if (!script.is_valid()) + return; + + script->get_method_list(&methods); + + } + + List<String> mstring; + for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + mstring.push_back(E->get().name.get_slice(":",0)); + } + + mstring.sort(); + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + property.hint_string=ml; + } + +} + + +void VisualScriptScriptCall::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptScriptCall::set_function); + ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptScriptCall::get_function); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptScriptCall::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptScriptCall::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptScriptCall::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptScriptCall::get_base_path); + + ObjectTypeDB::bind_method(_MD("set_argument_count","argument_count"),&VisualScriptScriptCall::set_argument_count); + ObjectTypeDB::bind_method(_MD("get_argument_count"),&VisualScriptScriptCall::get_argument_count); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path"),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/argument_count"),_SCS("set_argument_count"),_SCS("get_argument_count")); + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + +} + +class VisualScriptNodeInstanceScriptCall : public VisualScriptNodeInstance { +public: + + + VisualScriptScriptCall::CallMode call_mode; + NodePath node_path; + int input_args; + bool returns; + StringName function; + + VisualScriptScriptCall *node; + VisualScriptInstance *instance; + + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + switch(call_mode) { + + case VisualScriptScriptCall::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); + + } break; + case VisualScriptScriptCall::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + + *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptScriptCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceScriptCall * instance = memnew(VisualScriptNodeInstanceScriptCall ); + instance->node=this; + instance->instance=p_instance; + instance->function=function; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->input_args = argument_count; + return instance; +} + +VisualScriptScriptCall::VisualScriptScriptCall() { + + call_mode=CALL_MODE_SELF; + argument_count=0; + + +} + +template<VisualScriptScriptCall::CallMode cmode> +static Ref<VisualScriptNode> create_script_call_node(const String& p_name) { + + Ref<VisualScriptScriptCall> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + + +////////////////////////////////////////// +////////////////EMIT////////////////////// +////////////////////////////////////////// + +int VisualScriptEmitSignal::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptEmitSignal::has_input_sequence_port() const{ + + return true; +} + + +int VisualScriptEmitSignal::get_input_value_port_count() const{ + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_custom_signal(name)) + return 0; + + return vs->custom_signal_get_argument_count(name); + } + + return 0; + +} +int VisualScriptEmitSignal::get_output_value_port_count() const{ + return 0; +} + +String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const{ + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_custom_signal(name)) + return PropertyInfo(); + + return PropertyInfo(vs->custom_signal_get_argument_type(name,p_idx),vs->custom_signal_get_argument_name(name,p_idx)); + } + + return PropertyInfo(); + +} + +PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptEmitSignal::get_caption() const { + + return "EmitSignal"; +} + +String VisualScriptEmitSignal::get_text() const { + + return "emit "+String(name); +} + + + +void VisualScriptEmitSignal::set_signal(const StringName& p_type){ + + if (name==p_type) + return; + + name=p_type; + + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptEmitSignal::get_signal() const { + + + return name; +} + + +void VisualScriptEmitSignal::_validate_property(PropertyInfo& property) const { + + + + if (property.name=="signal/signal") { + property.hint=PROPERTY_HINT_ENUM; + + + List<StringName> sigs; + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + vs->get_custom_signal_list(&sigs); + + } + + String ml; + for (List<StringName>::Element *E=sigs.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + property.hint_string=ml; + } + +} + + +void VisualScriptEmitSignal::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_signal","name"),&VisualScriptEmitSignal::set_signal); + ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptEmitSignal::get_signal); + + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); + + +} + +class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { +public: + + VisualScriptEmitSignal *node; + VisualScriptInstance *instance; + int argcount; + StringName name; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + Object *obj = instance->get_owner_ptr(); + + obj->emit_signal(name,p_inputs,argcount); + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceEmitSignal * instance = memnew(VisualScriptNodeInstanceEmitSignal ); + instance->node=this; + instance->instance=p_instance; + instance->name=name; + instance->argcount=get_input_value_port_count(); + return instance; +} + +VisualScriptEmitSignal::VisualScriptEmitSignal() { +} + + + +static Ref<VisualScriptNode> create_basic_type_call_node(const String& p_name) { + + Vector<String> path = p_name.split("/"); + ERR_FAIL_COND_V(path.size()<4,Ref<VisualScriptNode>()); + String base_type = path[2]; + String method = path[3]; + + Ref<VisualScriptFunctionCall> node; + node.instance(); + + Variant::Type type=Variant::VARIANT_MAX; + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + if (Variant::get_type_name(Variant::Type(i))==base_type) { + type=Variant::Type(i); + break; + } + } + + ERR_FAIL_COND_V(type==Variant::VARIANT_MAX,Ref<VisualScriptNode>()); + + + node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + node->set_basic_type(type); + node->set_function(method); + + return node; +} + + +void register_visual_script_func_nodes() { + + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_instance",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_basic_type",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_self",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_node",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_NODE_PATH>); + + VisualScriptLanguage::singleton->add_register_func("functions/property_set/instace_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/basic_type_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/self_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/node_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_NODE_PATH>); + + VisualScriptLanguage::singleton->add_register_func("functions/property_get/instance_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/basic_type_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/self_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/node_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_NODE_PATH>); + + VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); + VisualScriptLanguage::singleton->add_register_func("functions/call_script/emit_signal",create_node_generic<VisualScriptEmitSignal>); + + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + Variant::Type t = Variant::Type(i); + String type_name = Variant::get_type_name(t); + Variant::CallError ce; + Variant vt = Variant::construct(t,NULL,0,ce); + List<MethodInfo> ml; + vt.get_method_list(&ml); + + for (List<MethodInfo>::Element *E=ml.front();E;E=E->next()) { + VisualScriptLanguage::singleton->add_register_func("functions/by_type/"+type_name+"/"+E->get().name,create_basic_type_call_node); + } + } +} diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h new file mode 100644 index 0000000000..2ccc61242a --- /dev/null +++ b/modules/visual_script/visual_script_func_nodes.h @@ -0,0 +1,361 @@ +#ifndef VISUAL_SCRIPT_FUNC_NODES_H +#define VISUAL_SCRIPT_FUNC_NODES_H + +#include "visual_script.h" + + +class VisualScriptFunctionCall : public VisualScriptNode { + + OBJ_TYPE(VisualScriptFunctionCall,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + CALL_MODE_INSTANCE, + CALL_MODE_BASIC_TYPE, + }; +private: + + CallMode call_mode; + StringName base_type; + Variant::Type basic_type; + NodePath base_path; + StringName function; + int use_default_args; + + Node *_get_base_node() const; + StringName _get_base_type() const; + + void _update_defargs(); +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_basic_type(Variant::Type p_type); + Variant::Type get_basic_type() const; + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_function(const StringName& p_type); + StringName get_function() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + void set_use_default_args(int p_amount); + int get_use_default_args() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptFunctionCall(); +}; + +VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode ); + + +class VisualScriptPropertySet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptPropertySet,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + CALL_MODE_INSTANCE, + CALL_MODE_BASIC_TYPE, + + + }; +private: + + CallMode call_mode; + Variant::Type basic_type; + StringName base_type; + NodePath base_path; + StringName property; + bool use_builtin_value; + Variant builtin_value; + InputEvent::Type event_type; + + Node *_get_base_node() const; + StringName _get_base_type() const; + + void _update_base_type(); + +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_basic_type(Variant::Type p_type); + Variant::Type get_basic_type() const; + + void set_event_type(InputEvent::Type p_type); + InputEvent::Type get_event_type() const; + + void set_property(const StringName& p_type); + StringName get_property() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + void set_use_builtin_value(bool p_use); + bool is_using_builtin_value() const; + + void set_builtin_value(const Variant &p_value); + Variant get_builtin_value() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptPropertySet(); +}; + +VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode ); + + +class VisualScriptPropertyGet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptPropertyGet,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + CALL_MODE_INSTANCE, + CALL_MODE_BASIC_TYPE + + }; +private: + + CallMode call_mode; + Variant::Type basic_type; + StringName base_type; + NodePath base_path; + StringName property; + InputEvent::Type event_type; + + void _update_base_type(); + Node *_get_base_node() const; + StringName _get_base_type() const; + + +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_basic_type(Variant::Type p_type); + Variant::Type get_basic_type() const; + + void set_event_type(InputEvent::Type p_type); + InputEvent::Type get_event_type() const; + + void set_property(const StringName& p_type); + StringName get_property() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptPropertyGet(); +}; + + + + + +VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode ); + + + +class VisualScriptScriptCall : public VisualScriptNode { + + OBJ_TYPE(VisualScriptScriptCall,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + }; +private: + + CallMode call_mode; + NodePath base_path; + StringName function; + int argument_count; + + + Node *_get_base_node() const; + + + void _update_argument_count(); +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_function(const StringName& p_type); + StringName get_function() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + void set_argument_count(int p_count); + int get_argument_count() const; + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptScriptCall(); +}; + +VARIANT_ENUM_CAST(VisualScriptScriptCall::CallMode ); + + + + +class VisualScriptEmitSignal : public VisualScriptNode { + + OBJ_TYPE(VisualScriptEmitSignal,VisualScriptNode) + +private: + + StringName name; + + +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_signal(const StringName& p_type); + StringName get_signal() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptEmitSignal(); +}; + + + +void register_visual_script_func_nodes(); + +#endif // VISUAL_SCRIPT_FUNC_NODES_H diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp new file mode 100644 index 0000000000..d205a40f76 --- /dev/null +++ b/modules/visual_script/visual_script_nodes.cpp @@ -0,0 +1,2485 @@ +#include "visual_script_nodes.h" +#include "global_constants.h" +#include "globals.h" +#include "scene/main/scene_main_loop.h" +#include "os/os.h" +#include "scene/main/node.h" + +////////////////////////////////////////// +////////////////FUNCTION////////////////// +////////////////////////////////////////// + + +bool VisualScriptFunction::_set(const StringName& p_name, const Variant& p_value) { + + + if (p_name=="argument_count") { + + int new_argc=p_value; + int argc = arguments.size(); + if (argc==new_argc) + return true; + + arguments.resize(new_argc); + + for(int i=argc;i<new_argc;i++) { + arguments[i].name="arg"+itos(i+1); + arguments[i].type=Variant::NIL; + } + ports_changed_notify(); + _change_notify(); + return true; + } + if (String(p_name).begins_with("argument/")) { + int idx = String(p_name).get_slice("/",1).to_int()-1; + ERR_FAIL_INDEX_V(idx,arguments.size(),false); + String what = String(p_name).get_slice("/",2); + if (what=="type") { + + Variant::Type new_type = Variant::Type(int(p_value)); + arguments[idx].type=new_type; + ports_changed_notify(); + + return true; + } + + if (what=="name") { + + arguments[idx].name=p_value; + ports_changed_notify(); + return true; + } + + + } + + if (p_name=="stack/stackless") { + set_stack_less(p_value); + return true; + } + + if (p_name=="stack/size") { + stack_size=p_value; + return true; + } + return false; +} + +bool VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const { + + + if (p_name=="argument_count") { + r_ret = arguments.size(); + return true; + } + if (String(p_name).begins_with("argument/")) { + int idx = String(p_name).get_slice("/",1).to_int()-1; + ERR_FAIL_INDEX_V(idx,arguments.size(),false); + String what = String(p_name).get_slice("/",2); + if (what=="type") { + r_ret = arguments[idx].type; + return true; + } + if (what=="name") { + r_ret = arguments[idx].name; + return true; + } + + + + } + + if (p_name=="stack/stackless") { + r_ret=stack_less; + return true; + } + + if (p_name=="stack/size") { + r_ret=stack_size; + return true; + } + + return false; +} +void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const { + + + p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256")); + String argt="Variant"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + for(int i=0;i<arguments.size();i++) { + p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt)); + p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name")); + } + if (!stack_less) { + p_list->push_back(PropertyInfo(Variant::INT,"stack/size",PROPERTY_HINT_RANGE,"1,100000")); + } + p_list->push_back(PropertyInfo(Variant::BOOL,"stack/stackless")); + +} + + +int VisualScriptFunction::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptFunction::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptFunction::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptFunction::get_output_value_port_count() const{ + + return arguments.size(); +} + +String VisualScriptFunction::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const{ + + ERR_FAIL_V(PropertyInfo()); + return PropertyInfo(); +} +PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,arguments.size(),PropertyInfo()); + PropertyInfo out; + out.type=arguments[p_idx].type; + out.name=arguments[p_idx].name; + return out; +} + +String VisualScriptFunction::get_caption() const { + + return "Function"; +} + +String VisualScriptFunction::get_text() const { + + return get_name(); //use name as function name I guess +} + +void VisualScriptFunction::add_argument(Variant::Type p_type,const String& p_name,int p_index){ + + Argument arg; + arg.name=p_name; + arg.type=p_type; + if (p_index>=0) + arguments.insert(p_index,arg); + else + arguments.push_back(arg); + + ports_changed_notify(); + +} +void VisualScriptFunction::set_argument_type(int p_argidx,Variant::Type p_type){ + + ERR_FAIL_INDEX(p_argidx,arguments.size()); + + arguments[p_argidx].type=p_type; + ports_changed_notify(); +} +Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const { + + ERR_FAIL_INDEX_V(p_argidx,arguments.size(),Variant::NIL); + return arguments[p_argidx].type; + +} +void VisualScriptFunction::set_argument_name(int p_argidx,const String& p_name) { + + ERR_FAIL_INDEX(p_argidx,arguments.size()); + + arguments[p_argidx].name=p_name; + ports_changed_notify(); + +} +String VisualScriptFunction::get_argument_name(int p_argidx) const { + + ERR_FAIL_INDEX_V(p_argidx,arguments.size(),String()); + return arguments[p_argidx].name; + +} +void VisualScriptFunction::remove_argument(int p_argidx) { + + ERR_FAIL_INDEX(p_argidx,arguments.size()); + + arguments.remove(p_argidx); + ports_changed_notify(); + +} + +int VisualScriptFunction::get_argument_count() const { + + return arguments.size(); +} + +class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { +public: + + VisualScriptFunction *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + int ac = node->get_argument_count(); + + for(int i=0;i<ac;i++) { +#ifdef DEBUG_ENABLED + Variant::Type expected = node->get_argument_type(i); + if (expected!=Variant::NIL) { + if (!Variant::can_convert_strict(p_inputs[i]->get_type(),expected)) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.expected=expected; + r_error.argument=i; + return 0; + } + } +#endif + + *p_outputs[i]=*p_inputs[i]; + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptFunction::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceFunction * instance = memnew(VisualScriptNodeInstanceFunction ); + instance->node=this; + instance->instance=p_instance; + return instance; +} + +VisualScriptFunction::VisualScriptFunction() { + + stack_size=256; + stack_less=false; +} + + +void VisualScriptFunction::set_stack_less(bool p_enable) { + stack_less=p_enable; + _change_notify(); +} + +bool VisualScriptFunction::is_stack_less() const { + return stack_less; +} + +void VisualScriptFunction::set_stack_size(int p_size) { + + ERR_FAIL_COND(p_size <1 || p_size>100000); + stack_size=p_size; +} + +int VisualScriptFunction::get_stack_size() const { + + return stack_size; +} + + +////////////////////////////////////////// +////////////////OPERATOR////////////////// +////////////////////////////////////////// + +int VisualScriptOperator::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptOperator::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptOperator::get_input_value_port_count() const{ + + return (op==Variant::OP_BIT_NEGATE || op==Variant::OP_NOT || op==Variant::OP_NEGATE) ? 1 : 2; +} +int VisualScriptOperator::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptOperator::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const{ + + static const Variant::Type port_types[Variant::OP_MAX][2]={ + {Variant::NIL,Variant::NIL}, //OP_EQUAL, + {Variant::NIL,Variant::NIL}, //OP_NOT_EQUAL, + {Variant::NIL,Variant::NIL}, //OP_LESS, + {Variant::NIL,Variant::NIL}, //OP_LESS_EQUAL, + {Variant::NIL,Variant::NIL}, //OP_GREATER, + {Variant::NIL,Variant::NIL}, //OP_GREATER_EQUAL, + //mathematic + {Variant::NIL,Variant::NIL}, //OP_ADD, + {Variant::NIL,Variant::NIL}, //OP_SUBSTRACT, + {Variant::NIL,Variant::NIL}, //OP_MULTIPLY, + {Variant::NIL,Variant::NIL}, //OP_DIVIDE, + {Variant::NIL,Variant::NIL}, //OP_NEGATE, + {Variant::INT,Variant::INT}, //OP_MODULE, + {Variant::STRING,Variant::STRING}, //OP_STRING_CONCAT, + //bitwise + {Variant::INT,Variant::INT}, //OP_SHIFT_LEFT, + {Variant::INT,Variant::INT}, //OP_SHIFT_RIGHT, + {Variant::INT,Variant::INT}, //OP_BIT_AND, + {Variant::INT,Variant::INT}, //OP_BIT_OR, + {Variant::INT,Variant::INT}, //OP_BIT_XOR, + {Variant::INT,Variant::INT}, //OP_BIT_NEGATE, + //logic + {Variant::BOOL,Variant::BOOL}, //OP_AND, + {Variant::BOOL,Variant::BOOL}, //OP_OR, + {Variant::BOOL,Variant::BOOL}, //OP_XOR, + {Variant::BOOL,Variant::BOOL}, //OP_NOT, + //containment + {Variant::NIL,Variant::NIL} //OP_IN, + }; + + ERR_FAIL_INDEX_V(p_idx,Variant::OP_MAX,PropertyInfo()); + + PropertyInfo pinfo; + pinfo.name=p_idx==0?"A":"B"; + pinfo.type=port_types[op][p_idx]; + return pinfo; +} +PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{ + static const Variant::Type port_types[Variant::OP_MAX]={ + //comparation + Variant::BOOL, //OP_EQUAL, + Variant::BOOL, //OP_NOT_EQUAL, + Variant::BOOL, //OP_LESS, + Variant::BOOL, //OP_LESS_EQUAL, + Variant::BOOL, //OP_GREATER, + Variant::BOOL, //OP_GREATER_EQUAL, + //mathematic + Variant::NIL, //OP_ADD, + Variant::NIL, //OP_SUBSTRACT, + Variant::NIL, //OP_MULTIPLY, + Variant::NIL, //OP_DIVIDE, + Variant::NIL, //OP_NEGATE, + Variant::INT, //OP_MODULE, + Variant::STRING, //OP_STRING_CONCAT, + //bitwise + Variant::INT, //OP_SHIFT_LEFT, + Variant::INT, //OP_SHIFT_RIGHT, + Variant::INT, //OP_BIT_AND, + Variant::INT, //OP_BIT_OR, + Variant::INT, //OP_BIT_XOR, + Variant::INT, //OP_BIT_NEGATE, + //logic + Variant::BOOL, //OP_AND, + Variant::BOOL, //OP_OR, + Variant::BOOL, //OP_XOR, + Variant::BOOL, //OP_NOT, + //containment + Variant::BOOL //OP_IN, + }; + + PropertyInfo pinfo; + pinfo.name=""; + pinfo.type=port_types[op]; + return pinfo; + +} + +static const char* op_names[]={ + //comparation + "Equal", //OP_EQUAL, + "NotEqual", //OP_NOT_EQUAL, + "Less", //OP_LESS, + "LessEqual", //OP_LESS_EQUAL, + "Greater", //OP_GREATER, + "GreaterEq", //OP_GREATER_EQUAL, + //mathematic + "Add", //OP_ADD, + "Subtract", //OP_SUBSTRACT, + "Multiply", //OP_MULTIPLY, + "Divide", //OP_DIVIDE, + "Negate", //OP_NEGATE, + "Remainder", //OP_MODULE, + "Concat", //OP_STRING_CONCAT, + //bitwise + "ShiftLeft", //OP_SHIFT_LEFT, + "ShiftRight", //OP_SHIFT_RIGHT, + "BitAnd", //OP_BIT_AND, + "BitOr", //OP_BIT_OR, + "BitXor", //OP_BIT_XOR, + "BitNeg", //OP_BIT_NEGATE, + //logic + "And", //OP_AND, + "Or", //OP_OR, + "Xor", //OP_XOR, + "Not", //OP_NOT, + //containment + "In", //OP_IN, +}; + +String VisualScriptOperator::get_caption() const { + + + + return op_names[op]; +} + +String VisualScriptOperator::get_text() const { + + static const wchar_t* op_names[]={ + //comparation + L"A = B", //OP_EQUAL, + L"A \u2260 B", //OP_NOT_EQUAL, + L"A < B", //OP_LESS, + L"A \u2264 B", //OP_LESS_EQUAL, + L"A > B", //OP_GREATER, + L"A \u2265 B", //OP_GREATER_EQUAL, + //mathematic + L"A + B", //OP_ADD, + L"A - B", //OP_SUBSTRACT, + L"A x B", //OP_MULTIPLY, + L"A \u00F7 B", //OP_DIVIDE, + L"\u00AC A", //OP_NEGATE, + L"A mod B", //OP_MODULE, + L"A .. B", //OP_STRING_CONCAT, + //bitwise + L"A << B", //OP_SHIFT_LEFT, + L"A >> B", //OP_SHIFT_RIGHT, + L"A & B", //OP_BIT_AND, + L"A | B", //OP_BIT_OR, + L"A ^ B", //OP_BIT_XOR, + L"~A", //OP_BIT_NEGATE, + //logic + L"A and B", //OP_AND, + L"A or B", //OP_OR, + L"A xor B", //OP_XOR, + L"not A", //OP_NOT, + + }; + return op_names[op]; +} + +void VisualScriptOperator::set_operator(Variant::Operator p_op) { + + if (op==p_op) + return; + op=p_op; + ports_changed_notify(); + +} + +Variant::Operator VisualScriptOperator::get_operator() const{ + + return op; +} + + +void VisualScriptOperator::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_operator","op"),&VisualScriptOperator::set_operator); + ObjectTypeDB::bind_method(_MD("get_operator"),&VisualScriptOperator::get_operator); + + String types; + for(int i=0;i<Variant::OP_MAX;i++) { + if (i>0) + types+=","; + types+=op_names[i]; + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types),_SCS("set_operator"),_SCS("get_operator")); + +} + +class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { +public: + + bool unary; + Variant::Operator op; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + bool valid; + if (unary) { + + Variant::evaluate(op,*p_inputs[0],Variant(),*p_outputs[0],valid); + } else { + Variant::evaluate(op,*p_inputs[0],*p_inputs[1],*p_outputs[0],valid); + } + + if (!valid) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + if (p_outputs[0]->get_type()==Variant::STRING) { + r_error_str=*p_outputs[0]; + } else { + if (unary) + r_error_str=String(op_names[op])+RTR(": Invalid argument of type: ")+Variant::get_type_name(p_inputs[0]->get_type()); + else + r_error_str=String(op_names[op])+RTR(": Invalid arguments: ")+"A: "+Variant::get_type_name(p_inputs[0]->get_type())+" B: "+Variant::get_type_name(p_inputs[1]->get_type()); + } + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptOperator::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceOperator * instance = memnew(VisualScriptNodeInstanceOperator ); + instance->unary=get_input_value_port_count()==1; + instance->op=op; + return instance; +} + +VisualScriptOperator::VisualScriptOperator() { + + op=Variant::OP_ADD; +} + + + +template<Variant::Operator OP> +static Ref<VisualScriptNode> create_op_node(const String& p_name) { + + Ref<VisualScriptOperator> node; + node.instance(); + node->set_operator(OP); + return node; +} + +////////////////////////////////////////// +////////////////VARIABLE GET////////////////// +////////////////////////////////////////// + +int VisualScriptVariableGet::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptVariableGet::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptVariableGet::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptVariableGet::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="value"; + if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { + PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); + pinfo.type=vinfo.type; + pinfo.hint=vinfo.hint; + pinfo.hint_string=vinfo.hint_string; + } + return pinfo; +} + + +String VisualScriptVariableGet::get_caption() const { + + return "Variable"; +} + +String VisualScriptVariableGet::get_text() const { + + return variable; +} + +void VisualScriptVariableGet::set_variable(StringName p_variable) { + + if (variable==p_variable) + return; + variable=p_variable; + ports_changed_notify(); + +} + +StringName VisualScriptVariableGet::get_variable() const{ + + return variable; +} + +void VisualScriptVariableGet::_validate_property(PropertyInfo& property) const { + + if (property.name=="variable/name" && get_visual_script().is_valid()) { + Ref<VisualScript> vs = get_visual_script(); + List<StringName> vars; + vs->get_variable_list(&vars); + + String vhint; + for (List<StringName>::Element *E=vars.front();E;E=E->next()) { + if (vhint!=String()) + vhint+=","; + + vhint+=E->get().operator String(); + } + + property.hint=PROPERTY_HINT_ENUM; + property.hint_string=vhint; + } +} + +void VisualScriptVariableGet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableGet::set_variable); + ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableGet::get_variable); + + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); + +} + +class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { +public: + + VisualScriptVariableGet *node; + VisualScriptInstance *instance; + StringName variable; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + if (instance->get_variable(variable,r_value)==false) { + r_error=RTR("VariableGet not found in script: ")+"'"+String(variable)+"'"; + return false; + } else { + return true; + } + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptVariableGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceVariableGet * instance = memnew(VisualScriptNodeInstanceVariableGet ); + instance->node=this; + instance->instance=p_instance; + instance->variable=variable; + return instance; +} +VisualScriptVariableGet::VisualScriptVariableGet() { + + +} + + +////////////////////////////////////////// +////////////////VARIABLE GET////////////////// +////////////////////////////////////////// + +int VisualScriptVariableSet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptVariableSet::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptVariableSet::get_input_value_port_count() const{ + + return 1; +} +int VisualScriptVariableSet::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="set"; + if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { + PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); + pinfo.type=vinfo.type; + pinfo.hint=vinfo.hint; + pinfo.hint_string=vinfo.hint_string; + } + return pinfo; +} + +PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptVariableSet::get_caption() const { + + return "VariableSet"; +} + +String VisualScriptVariableSet::get_text() const { + + return variable; +} + +void VisualScriptVariableSet::set_variable(StringName p_variable) { + + if (variable==p_variable) + return; + variable=p_variable; + ports_changed_notify(); + +} + +StringName VisualScriptVariableSet::get_variable() const{ + + return variable; +} + +void VisualScriptVariableSet::_validate_property(PropertyInfo& property) const { + + if (property.name=="variable/name" && get_visual_script().is_valid()) { + Ref<VisualScript> vs = get_visual_script(); + List<StringName> vars; + vs->get_variable_list(&vars); + + String vhint; + for (List<StringName>::Element *E=vars.front();E;E=E->next()) { + if (vhint!=String()) + vhint+=","; + + vhint+=E->get().operator String(); + } + + property.hint=PROPERTY_HINT_ENUM; + property.hint_string=vhint; + } +} + +void VisualScriptVariableSet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableSet::set_variable); + ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableSet::get_variable); + + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); + +} + +class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { +public: + + VisualScriptVariableSet *node; + VisualScriptInstance *instance; + StringName variable; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (instance->set_variable(variable,*p_inputs[0])==false) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD ; + r_error_str=RTR("VariableSet not found in script: ")+"'"+String(variable)+"'"; + } + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptVariableSet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceVariableSet * instance = memnew(VisualScriptNodeInstanceVariableSet ); + instance->node=this; + instance->instance=p_instance; + instance->variable=variable; + return instance; +} +VisualScriptVariableSet::VisualScriptVariableSet() { + + +} + + + +////////////////////////////////////////// +////////////////CONSTANT////////////////// +////////////////////////////////////////// + +int VisualScriptConstant::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptConstant::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptConstant::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptConstant::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptConstant::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const{ + + PropertyInfo pinfo; + pinfo.name="get"; + pinfo.type=type; + return pinfo; +} + + +String VisualScriptConstant::get_caption() const { + + return "Constant"; +} + +String VisualScriptConstant::get_text() const { + + return String(value); +} + +void VisualScriptConstant::set_constant_type(Variant::Type p_type) { + + if (type==p_type) + return; + + type=p_type; + ports_changed_notify(); + Variant::CallError ce; + value=Variant::construct(type,NULL,0,ce); + _change_notify(); + +} + +Variant::Type VisualScriptConstant::get_constant_type() const{ + + return type; +} + +void VisualScriptConstant::set_constant_value(Variant p_value){ + + if (value==p_value) + return; + + value=p_value; + ports_changed_notify(); +} +Variant VisualScriptConstant::get_constant_value() const{ + + return value; +} + +void VisualScriptConstant::_validate_property(PropertyInfo& property) const { + + + if (property.name=="constant/value") { + property.type=type; + if (type==Variant::NIL) + property.usage=0; //do not save if nil + } +} + +void VisualScriptConstant::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_constant_type","type"),&VisualScriptConstant::set_constant_type); + ObjectTypeDB::bind_method(_MD("get_constant_type"),&VisualScriptConstant::get_constant_type); + + ObjectTypeDB::bind_method(_MD("set_constant_value","value"),&VisualScriptConstant::set_constant_value); + ObjectTypeDB::bind_method(_MD("get_constant_value"),&VisualScriptConstant::get_constant_value); + + String argt="Null"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant/type",PROPERTY_HINT_ENUM,argt),_SCS("set_constant_type"),_SCS("get_constant_type")); + ADD_PROPERTY(PropertyInfo(Variant::NIL,"constant/value"),_SCS("set_constant_value"),_SCS("get_constant_value")); + +} + +class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { +public: + + Variant constant; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value=constant; + + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceConstant * instance = memnew(VisualScriptNodeInstanceConstant ); + instance->constant=value; + return instance; +} + +VisualScriptConstant::VisualScriptConstant() { + + type=Variant::NIL; + +} + + + +////////////////////////////////////////// +////////////////INDEX//////////////////// +////////////////////////////////////////// + +int VisualScriptIndexGet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptIndexGet::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptIndexGet::get_input_value_port_count() const{ + + return 2; +} +int VisualScriptIndexGet::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const{ + + if (p_idx==0) { + return PropertyInfo(Variant::NIL,"base"); + } else { + return PropertyInfo(Variant::NIL,"index"); + + } +} + +PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptIndexGet::get_caption() const { + + return "IndexGet"; +} + +String VisualScriptIndexGet::get_text() const { + + return String("get"); +} + + +class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { +public: + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + bool valid; + *p_outputs[0] = p_inputs[0]->get(*p_inputs[1],&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid get: "+p_inputs[0]->get_construct_string(); + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptIndexGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIndexGet * instance = memnew(VisualScriptNodeInstanceIndexGet ); + return instance; +} +VisualScriptIndexGet::VisualScriptIndexGet() { + + + +} + +////////////////////////////////////////// +////////////////INDEXSET////////////////// +////////////////////////////////////////// + +int VisualScriptIndexSet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptIndexSet::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptIndexSet::get_input_value_port_count() const{ + + return 3; +} +int VisualScriptIndexSet::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const{ + + if (p_idx==0) { + return PropertyInfo(Variant::NIL,"base"); + } else if (p_idx==1){ + return PropertyInfo(Variant::NIL,"index"); + + } else { + return PropertyInfo(Variant::NIL,"value"); + + } +} + +PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptIndexSet::get_caption() const { + + return "IndexSet"; +} + +String VisualScriptIndexSet::get_text() const { + + return String("set"); +} + + +class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { +public: + + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + bool valid; + *p_outputs[0]=*p_inputs[0]; + p_outputs[0]->set(*p_inputs[1],*p_inputs[2],&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid set: "+p_inputs[1]->get_construct_string(); + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptIndexSet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIndexSet * instance = memnew(VisualScriptNodeInstanceIndexSet ); + return instance; +} +VisualScriptIndexSet::VisualScriptIndexSet() { + + + +} + + +////////////////////////////////////////// +////////////////GLOBALCONSTANT/////////// +////////////////////////////////////////// + +int VisualScriptGlobalConstant::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptGlobalConstant::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptGlobalConstant::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptGlobalConstant::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::REAL,"value"); +} + + +String VisualScriptGlobalConstant::get_caption() const { + + return "GlobalConst"; +} + +String VisualScriptGlobalConstant::get_text() const { + + return GlobalConstants::get_global_constant_name(index); +} + +void VisualScriptGlobalConstant::set_global_constant(int p_which) { + + index=p_which; + _change_notify(); + ports_changed_notify(); +} + +int VisualScriptGlobalConstant::get_global_constant() { + return index; +} + + +class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { +public: + + int index; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value = GlobalConstants::get_global_constant_value(index); + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptGlobalConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceGlobalConstant * instance = memnew(VisualScriptNodeInstanceGlobalConstant ); + instance->index=index; + return instance; +} + +void VisualScriptGlobalConstant::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_global_constant","index"),&VisualScriptGlobalConstant::set_global_constant); + ObjectTypeDB::bind_method(_MD("get_global_constant"),&VisualScriptGlobalConstant::get_global_constant); + + String cc; + + for(int i=0;i<GlobalConstants::get_global_constant_count();i++) { + + if (i>0) + cc+=","; + cc+=GlobalConstants::get_global_constant_name(i); + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_global_constant"),_SCS("get_global_constant")); +} + +VisualScriptGlobalConstant::VisualScriptGlobalConstant() { + + index=0; +} + + + +////////////////////////////////////////// +////////////////MATHCONSTANT/////////// +////////////////////////////////////////// + + +const char* VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX]={ + "One", + "PI", + "PIx2", + "PI/2", + "E", + "Sqrt2", +}; + +double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX]={ + 1.0, + Math_PI, + Math_PI*2, + Math_PI*0.5, + 2.71828182845904523536, + Math::sqrt(2.0) +}; + + +int VisualScriptMathConstant::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptMathConstant::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptMathConstant::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptMathConstant::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::REAL,"value"); +} + + +String VisualScriptMathConstant::get_caption() const { + + return "MathConst"; +} + +String VisualScriptMathConstant::get_text() const { + + return const_name[constant]; +} + +void VisualScriptMathConstant::set_math_constant(MathConstant p_which) { + + constant=p_which; + _change_notify(); + ports_changed_notify(); +} + +VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() { + return constant; +} + +class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { +public: + + float value; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value = value; + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptMathConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceMathConstant * instance = memnew(VisualScriptNodeInstanceMathConstant ); + instance->value=const_value[constant]; + return instance; +} + + +void VisualScriptMathConstant::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant); + ObjectTypeDB::bind_method(_MD("get_math_constant"),&VisualScriptMathConstant::get_math_constant); + + String cc; + + for(int i=0;i<MATH_CONSTANT_MAX;i++) { + + if (i>0) + cc+=","; + cc+=const_name[i]; + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_math_constant"),_SCS("get_math_constant")); +} + +VisualScriptMathConstant::VisualScriptMathConstant() { + + constant=MATH_CONSTANT_ONE; +} + + + +////////////////////////////////////////// +////////////////GLOBALSINGLETON/////////// +////////////////////////////////////////// + +int VisualScriptEngineSingleton::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptEngineSingleton::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptEngineSingleton::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptEngineSingleton::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptEngineSingleton::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptEngineSingleton::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"instance"); +} + + +String VisualScriptEngineSingleton::get_caption() const { + + return "EngineSingleton"; +} + +String VisualScriptEngineSingleton::get_text() const { + + return singleton; +} + +void VisualScriptEngineSingleton::set_singleton(const String& p_string) { + + singleton=p_string; + + _change_notify(); + ports_changed_notify(); +} + +String VisualScriptEngineSingleton::get_singleton() { + return singleton; +} + + + +class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance { +public: + + Object* singleton; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value=singleton; + return true; + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + return 0; + } + +}; + +VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceEngineSingleton * instance = memnew(VisualScriptNodeInstanceEngineSingleton ); + instance->singleton=Globals::get_singleton()->get_singleton_object(singleton); + return instance; +} + + +void VisualScriptEngineSingleton::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_singleton","name"),&VisualScriptEngineSingleton::set_singleton); + ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptEngineSingleton::get_singleton); + + String cc; + + List<Globals::Singleton> singletons; + + Globals::get_singleton()->get_singletons(&singletons); + + for (List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) { + if (E->get().name=="VS" || E->get().name=="PS" || E->get().name=="PS2D" || E->get().name=="AS" || E->get().name=="TS" || E->get().name=="SS" || E->get().name=="SS2D") + continue; //skip these, too simple named + + if (cc!=String()) + cc+=","; + cc+=E->get().name; + } + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_singleton"),_SCS("get_singleton")); +} + +VisualScriptEngineSingleton::VisualScriptEngineSingleton() { + + singleton=String(); +} + + + +////////////////////////////////////////// +////////////////GETNODE/////////// +////////////////////////////////////////// + +int VisualScriptSceneNode::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSceneNode::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptSceneNode::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptSceneNode::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"node"); +} + + +String VisualScriptSceneNode::get_caption() const { + + return "SceneNode"; +} + +String VisualScriptSceneNode::get_text() const { + + return path.simplified(); +} + +void VisualScriptSceneNode::set_node_path(const NodePath& p_path) { + + path=p_path; + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptSceneNode::get_node_path() { + return path; +} + + +class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance { +public: + + VisualScriptSceneNode *node; + VisualScriptInstance *instance; + NodePath path; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error="Base object is not a Node!"; + return false; + } + + + + Node* another = node->get_node(path); + if (!node) { + r_error="Path does not lead Node!"; + return false; + } + + *r_value=another; + return true; + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptSceneNode::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSceneNode * instance = memnew(VisualScriptNodeInstanceSceneNode ); + instance->node=this; + instance->instance=p_instance; + instance->path=path; + return instance; +} + + +#ifdef TOOLS_ENABLED + +static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { + + if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) + return NULL; + + Ref<Script> scr = p_current_node->get_script(); + + if (scr.is_valid() && scr==script) + return p_current_node; + + for(int i=0;i<p_current_node->get_child_count();i++) { + Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); + if (n) + return n; + } + + return NULL; +} + +#endif + +void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const { + +#ifdef TOOLS_ENABLED + if (property.name=="node_path") { + + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return; + + property.hint_string=script_node->get_path(); + } +#endif +} + +void VisualScriptSceneNode::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_node_path","path"),&VisualScriptSceneNode::set_node_path); + ObjectTypeDB::bind_method(_MD("get_node_path"),&VisualScriptSceneNode::get_node_path); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_node_path"),_SCS("get_node_path")); +} + +VisualScriptSceneNode::VisualScriptSceneNode() { + + path=String("."); +} + + +////////////////////////////////////////// +////////////////SceneTree/////////// +////////////////////////////////////////// + +int VisualScriptSceneTree::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSceneTree::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptSceneTree::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptSceneTree::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSceneTree::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"instance"); +} + + +String VisualScriptSceneTree::get_caption() const { + + return "SceneTree"; +} + +String VisualScriptSceneTree::get_text() const { + + return ""; +} + + +class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance { +public: + + VisualScriptSceneTree *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error="Base object is not a Node!"; + return false; + } + + SceneTree* tree = node->get_tree(); + if (!tree) { + r_error="Attempt to get SceneTree while node is not in the active tree."; + return false; + } + + *r_value=tree; + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptSceneTree::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSceneTree * instance = memnew(VisualScriptNodeInstanceSceneTree ); + instance->node=this; + instance->instance=p_instance; + return instance; +} + + +void VisualScriptSceneTree::_validate_property(PropertyInfo& property) const { + +} + +void VisualScriptSceneTree::_bind_methods() { + +} + +VisualScriptSceneTree::VisualScriptSceneTree() { + +} + + +////////////////////////////////////////// +////////////////RESPATH/////////// +////////////////////////////////////////// + +int VisualScriptResourcePath::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptResourcePath::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptResourcePath::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptResourcePath::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptResourcePath::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptResourcePath::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::STRING,"path"); +} + + +String VisualScriptResourcePath::get_caption() const { + + return "ResourcePath"; +} + +String VisualScriptResourcePath::get_text() const { + + return path; +} + +void VisualScriptResourcePath::set_resource_path(const String& p_path) { + + path=p_path; + _change_notify(); + ports_changed_notify(); +} + +String VisualScriptResourcePath::get_resource_path() { + return path; +} + + +class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance { +public: + + String path; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + *r_value = path; + return true; + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptResourcePath::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceResourcePath * instance = memnew(VisualScriptNodeInstanceResourcePath ); + instance->path=path; + return instance; +} + + + +void VisualScriptResourcePath::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_resource_path","path"),&VisualScriptResourcePath::set_resource_path); + ObjectTypeDB::bind_method(_MD("get_resource_path"),&VisualScriptResourcePath::get_resource_path); + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"path",PROPERTY_HINT_FILE),_SCS("set_resource_path"),_SCS("get_resource_path")); +} + +VisualScriptResourcePath::VisualScriptResourcePath() { + + path=""; +} + + + +////////////////////////////////////////// +////////////////SELF/////////// +////////////////////////////////////////// + +int VisualScriptSelf::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSelf::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptSelf::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptSelf::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSelf::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"instance"); +} + + +String VisualScriptSelf::get_caption() const { + + return "Self"; +} + +String VisualScriptSelf::get_text() const { + + if (get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else + return ""; +} + + +class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value = instance->get_owner_ptr(); + return true; + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptSelf::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSelf * instance = memnew(VisualScriptNodeInstanceSelf ); + instance->instance=p_instance; + return instance; +} + + + +void VisualScriptSelf::_bind_methods() { + +} + +VisualScriptSelf::VisualScriptSelf() { + + +} + +////////////////////////////////////////// +////////////////CUSTOM (SCRIPTED)/////////// +////////////////////////////////////////// + +int VisualScriptCustomNode::get_output_sequence_port_count() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_count")) { + return get_script_instance()->call("_get_output_sequence_port_count"); + } + return 0; +} + +bool VisualScriptCustomNode::has_input_sequence_port() const{ + + if (get_script_instance() && get_script_instance()->has_method("_has_input_sequence_port")) { + return get_script_instance()->call("_has_input_sequence_port"); + } + return false; +} + +int VisualScriptCustomNode::get_input_value_port_count() const{ + + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_count")) { + return get_script_instance()->call("_get_input_value_port_count"); + } + return 0; +} +int VisualScriptCustomNode::get_output_value_port_count() const{ + + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_count")) { + return get_script_instance()->call("_get_output_value_port_count"); + } + return 0; +} + +String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const { + + if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_text")) { + return get_script_instance()->call("_get_output_sequence_port_text",p_port); + } + + return String(); +} + +PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const{ + + PropertyInfo info; + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_type")) { + info.type=Variant::Type(int(get_script_instance()->call("_get_input_value_port_type",p_idx))); + } + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_name")) { + info.name=get_script_instance()->call("_get_input_value_port_name",p_idx); + } + return info; +} + +PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const{ + + PropertyInfo info; + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_type")) { + info.type=Variant::Type(int(get_script_instance()->call("_get_output_value_port_type",p_idx))); + } + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_name")) { + info.name=get_script_instance()->call("_get_output_value_port_name",p_idx); + } + return info; +} + + +String VisualScriptCustomNode::get_caption() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_caption")) { + return get_script_instance()->call("_get_caption"); + } + return "CustomNode"; +} + +String VisualScriptCustomNode::get_text() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_text")) { + return get_script_instance()->call("_get_text"); + } + return ""; +} + +String VisualScriptCustomNode::get_category() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_category")) { + return get_script_instance()->call("_get_category"); + } + return "custom"; +} + +class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + VisualScriptCustomNode *node; + int in_count; + int out_count; + int work_mem_size; + Vector<bool> out_unsequenced; + + virtual int get_working_memory_size() const { return work_mem_size; } + virtual bool is_output_port_unsequenced(int p_idx) const { return out_unsequenced[p_idx]; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + if (!node->get_script_instance() || !node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_get_output_port_unsequenced)) { +#ifdef DEBUG_ENABLED + r_error=RTR("Custom node has no _get_output_port_unsequenced(idx,wmem), but unsequenced ports were specified."); + return false; + } +#endif + + Array work_mem(true); + work_mem.resize(work_mem_size); + + *r_value = node->get_script_instance()->call(VisualScriptLanguage::singleton->_get_output_port_unsequenced,p_idx,work_mem); + + + for(int i=0;i<work_mem_size;i++) { + if (i<work_mem.size()) { + p_working_mem[i]=work_mem[i]; + } + } + + return true; + + } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (node->get_script_instance()) { +#ifdef DEBUG_ENABLED + if (!node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_step)) { + r_error_str=RTR("Custom node has no _step() method, can't process graph."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } +#endif + Array in_values(true); + Array out_values(true); + Array work_mem(true); + + in_values.resize(in_count); + + for(int i=0;i<in_count;i++) { + in_values[i]=p_inputs[i]; + } + + out_values.resize(in_count); + + work_mem.resize(work_mem_size); + + for(int i=0;i<work_mem_size;i++) { + work_mem[i]=p_working_mem[i]; + } + + int ret_out; + + Variant ret = node->get_script_instance()->call(VisualScriptLanguage::singleton->_step,in_values,out_values,p_start_mode,work_mem); + if (ret.get_type()==Variant::STRING) { + r_error_str=ret; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } else if (ret.is_num()) { + ret_out=ret; + } else { + r_error_str=RTR("Invalid return value from _step(), must be integer (seq out), or string (error)."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + for(int i=0;i<out_count;i++) { + if (i<out_values.size()) { + *p_outputs[i]=out_values[i]; + } + } + + for(int i=0;i<work_mem_size;i++) { + if (i<work_mem.size()) { + p_working_mem[i]=work_mem[i]; + } + } + + return ret_out; + + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceCustomNode * instance = memnew(VisualScriptNodeInstanceCustomNode ); + instance->instance=p_instance; + instance->in_count=get_input_value_port_count(); + instance->out_count=get_output_value_port_count(); + + for(int i=0;i<instance->out_count;i++) { + bool unseq = get_script_instance() && get_script_instance()->has_method("_is_output_port_unsequenced") && bool(get_script_instance()->call("_is_output_port_unsequenced",i)); + instance->out_unsequenced.push_back(unseq); + } + + if (get_script_instance() && get_script_instance()->has_method("_get_working_memory_size")) { + instance->work_mem_size = get_script_instance()->call("_get_working_memory_size"); + } else { + instance->work_mem_size=0; + } + + return instance; +} + + + +void VisualScriptCustomNode::_bind_methods() { + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_sequence_port_count") ); + BIND_VMETHOD( MethodInfo(Variant::BOOL,"_has_input_sequence_port") ); + + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_sequence_port_text",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_count") ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_count") ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_type",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_input_value_port_name",PropertyInfo(Variant::INT,"idx")) ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_type",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_value_port_name",PropertyInfo(Variant::INT,"idx")) ); + + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_caption") ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_text") ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_category") ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_working_memory_size") ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_is_output_port_unsequenced",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_port_unsequenced",PropertyInfo(Variant::INT,"idx"),PropertyInfo(Variant::ARRAY,"work_mem")) ); + BIND_VMETHOD( MethodInfo(Variant::NIL,"_step:Variant",PropertyInfo(Variant::ARRAY,"inputs"),PropertyInfo(Variant::ARRAY,"outputs"),PropertyInfo(Variant::INT,"start_mode"),PropertyInfo(Variant::ARRAY,"working_mem")) ); + + BIND_CONSTANT( START_MODE_BEGIN_SEQUENCE ); + BIND_CONSTANT( START_MODE_CONTINUE_SEQUENCE ); + BIND_CONSTANT( START_MODE_RESUME_YIELD ); + + BIND_CONSTANT( STEP_PUSH_STACK_BIT ); + BIND_CONSTANT( STEP_GO_BACK_BIT ); + BIND_CONSTANT( STEP_NO_ADVANCE_BIT ); + BIND_CONSTANT( STEP_EXIT_FUNCTION_BIT ); + BIND_CONSTANT( STEP_YIELD_BIT ); + +} + +VisualScriptCustomNode::VisualScriptCustomNode() { + + +} + +////////////////////////////////////////// +////////////////SUBCALL/////////// +////////////////////////////////////////// + +int VisualScriptSubCall::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptSubCall::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptSubCall::get_input_value_port_count() const{ + + Ref<Script> script = get_script(); + + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.arguments.size(); + } + + return 0; +} +int VisualScriptSubCall::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSubCall::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSubCall::get_input_value_port_info(int p_idx) const{ + + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.arguments[p_idx]; + } + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const{ + + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.return_val; + } + return PropertyInfo(); +} + + +String VisualScriptSubCall::get_caption() const { + + return "SubCall"; +} + + +String VisualScriptSubCall::get_text() const { + + Ref<Script> script = get_script(); + if (script.is_valid()) { + if (script->get_name()!=String()) + return script->get_name(); + if (script->get_path().is_resource_file()) + return script->get_path().get_file(); + return script->get_type(); + } + return ""; +} + +String VisualScriptSubCall::get_category() const { + + return "custom"; +} + +class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + VisualScriptSubCall *subcall; + int input_args; + bool valid; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }; + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (!valid) { + r_error_str="Node requires a script with a _subcall(<args>) method to work."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + *p_outputs[0]=subcall->call(VisualScriptLanguage::singleton->_subcall,p_inputs,input_args,r_error_str); + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptSubCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSubCall * instance = memnew(VisualScriptNodeInstanceSubCall ); + instance->instance=p_instance; + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + instance->valid=true; + instance->input_args=get_input_value_port_count(); + } else { + instance->valid=false; + } + return instance; +} + + + +void VisualScriptSubCall::_bind_methods() { + + BIND_VMETHOD( MethodInfo(Variant::NIL,"_subcall",PropertyInfo(Variant::NIL,"arguments:Variant")) ); + +} + +VisualScriptSubCall::VisualScriptSubCall() { + + +} + + +void register_visual_script_nodes() { + + VisualScriptLanguage::singleton->add_register_func("data/set_variable",create_node_generic<VisualScriptVariableGet>); + VisualScriptLanguage::singleton->add_register_func("data/get_variable",create_node_generic<VisualScriptVariableSet>); + VisualScriptLanguage::singleton->add_register_func("data/constant",create_node_generic<VisualScriptConstant>); + VisualScriptLanguage::singleton->add_register_func("data/global_constant",create_node_generic<VisualScriptGlobalConstant>); + VisualScriptLanguage::singleton->add_register_func("data/math_constant",create_node_generic<VisualScriptMathConstant>); + VisualScriptLanguage::singleton->add_register_func("data/engine_singleton",create_node_generic<VisualScriptEngineSingleton>); + VisualScriptLanguage::singleton->add_register_func("data/scene_node",create_node_generic<VisualScriptSceneNode>); + VisualScriptLanguage::singleton->add_register_func("data/scene_tree",create_node_generic<VisualScriptSceneTree>); + VisualScriptLanguage::singleton->add_register_func("data/resource_path",create_node_generic<VisualScriptResourcePath>); + VisualScriptLanguage::singleton->add_register_func("data/self",create_node_generic<VisualScriptSelf>); + VisualScriptLanguage::singleton->add_register_func("custom/custom_node",create_node_generic<VisualScriptCustomNode>); + VisualScriptLanguage::singleton->add_register_func("custom/sub_call",create_node_generic<VisualScriptSubCall>); + + + VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>); + VisualScriptLanguage::singleton->add_register_func("index/set_index",create_node_generic<VisualScriptIndexSet>); + + + VisualScriptLanguage::singleton->add_register_func("operators/compare/equal",create_op_node<Variant::OP_EQUAL>); + VisualScriptLanguage::singleton->add_register_func("operators/compare/not_equal",create_op_node<Variant::OP_NOT_EQUAL>); + VisualScriptLanguage::singleton->add_register_func("operators/compare/less",create_op_node<Variant::OP_LESS>); + VisualScriptLanguage::singleton->add_register_func("operators/compare/less_equal",create_op_node<Variant::OP_LESS_EQUAL>); + VisualScriptLanguage::singleton->add_register_func("operators/compare/greater",create_op_node<Variant::OP_GREATER>); + VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal",create_op_node<Variant::OP_GREATER_EQUAL>); + //mathematic + VisualScriptLanguage::singleton->add_register_func("operators/math/add",create_op_node<Variant::OP_ADD>); + VisualScriptLanguage::singleton->add_register_func("operators/math/subtract",create_op_node<Variant::OP_SUBSTRACT>); + VisualScriptLanguage::singleton->add_register_func("operators/math/multiply",create_op_node<Variant::OP_MULTIPLY>); + VisualScriptLanguage::singleton->add_register_func("operators/math/divide",create_op_node<Variant::OP_DIVIDE>); + VisualScriptLanguage::singleton->add_register_func("operators/math/negate",create_op_node<Variant::OP_NEGATE>); + VisualScriptLanguage::singleton->add_register_func("operators/math/remainder",create_op_node<Variant::OP_MODULE>); + VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat",create_op_node<Variant::OP_STRING_CONCAT>); + //bitwise + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left",create_op_node<Variant::OP_SHIFT_LEFT>); + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right",create_op_node<Variant::OP_SHIFT_RIGHT>); + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_and",create_op_node<Variant::OP_BIT_AND>); + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_or",create_op_node<Variant::OP_BIT_OR>); + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_xor",create_op_node<Variant::OP_BIT_XOR>); + VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_negate",create_op_node<Variant::OP_BIT_NEGATE>); + //logic + VisualScriptLanguage::singleton->add_register_func("operators/logic/and",create_op_node<Variant::OP_AND>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/or",create_op_node<Variant::OP_OR>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/xor",create_op_node<Variant::OP_XOR>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/not",create_op_node<Variant::OP_NOT>); + VisualScriptLanguage::singleton->add_register_func("operators/logic/in",create_op_node<Variant::OP_IN>); + + +} diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h new file mode 100644 index 0000000000..50f61ecfcc --- /dev/null +++ b/modules/visual_script/visual_script_nodes.h @@ -0,0 +1,651 @@ +#ifndef VISUAL_SCRIPT_NODES_H +#define VISUAL_SCRIPT_NODES_H + +#include "visual_script.h" + +class VisualScriptFunction : public VisualScriptNode { + + OBJ_TYPE(VisualScriptFunction,VisualScriptNode) + + + struct Argument { + String name; + Variant::Type type; + }; + + Vector<Argument> arguments; + + bool stack_less; + int stack_size; + + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + void add_argument(Variant::Type p_type,const String& p_name,int p_index=-1); + void set_argument_type(int p_argidx,Variant::Type p_type); + Variant::Type get_argument_type(int p_argidx) const; + void set_argument_name(int p_argidx,const String& p_name); + String get_argument_name(int p_argidx) const; + void remove_argument(int p_argidx); + int get_argument_count() const; + + + void set_stack_less(bool p_enable); + bool is_stack_less() const; + + void set_stack_size(int p_size); + int get_stack_size() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptFunction(); +}; + + +class VisualScriptOperator : public VisualScriptNode { + + OBJ_TYPE(VisualScriptOperator,VisualScriptNode) + + + Variant::Operator op; +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "operators"; } + + void set_operator(Variant::Operator p_op); + Variant::Operator get_operator() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptOperator(); +}; + + +class VisualScriptVariableGet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptVariableGet,VisualScriptNode) + + + StringName variable; +protected: + + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_variable(StringName p_var); + StringName get_variable() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptVariableGet(); +}; + + +class VisualScriptVariableSet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptVariableSet,VisualScriptNode) + + + StringName variable; +protected: + + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_variable(StringName p_var); + StringName get_variable() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptVariableSet(); +}; + + +class VisualScriptConstant : public VisualScriptNode { + + OBJ_TYPE(VisualScriptConstant,VisualScriptNode) + + + Variant::Type type; + Variant value; +protected: + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_constant_type(Variant::Type p_type); + Variant::Type get_constant_type() const; + + void set_constant_value(Variant p_value); + Variant get_constant_value() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptConstant(); +}; + + +class VisualScriptIndexGet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptIndexGet,VisualScriptNode) + + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "operators"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptIndexGet(); +}; + + +class VisualScriptIndexSet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptIndexSet,VisualScriptNode) + + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "operators"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptIndexSet(); +}; + + + +class VisualScriptGlobalConstant : public VisualScriptNode { + + OBJ_TYPE(VisualScriptGlobalConstant,VisualScriptNode) + + int index; + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_global_constant(int p_which); + int get_global_constant(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptGlobalConstant(); +}; + + + +class VisualScriptMathConstant : public VisualScriptNode { + + OBJ_TYPE(VisualScriptMathConstant,VisualScriptNode) +public: + + enum MathConstant { + MATH_CONSTANT_ONE, + MATH_CONSTANT_PI, + MATH_CONSTANT_2PI, + MATH_CONSTANT_HALF_PI, + MATH_CONSTANT_E, + MATH_CONSTANT_SQRT2, + MATH_CONSTANT_MAX, + }; + +private: + static const char* const_name[MATH_CONSTANT_MAX]; + static double const_value[MATH_CONSTANT_MAX]; + MathConstant constant; +protected: + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_math_constant(MathConstant p_which); + MathConstant get_math_constant(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptMathConstant(); +}; + +VARIANT_ENUM_CAST( VisualScriptMathConstant::MathConstant ) + +class VisualScriptEngineSingleton : public VisualScriptNode { + + OBJ_TYPE(VisualScriptEngineSingleton,VisualScriptNode) + + String singleton; + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_singleton(const String &p_string); + String get_singleton(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptEngineSingleton(); +}; + + + + +class VisualScriptSceneNode : public VisualScriptNode { + + OBJ_TYPE(VisualScriptSceneNode,VisualScriptNode) + + NodePath path; +protected: + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_node_path(const NodePath &p_path); + NodePath get_node_path(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSceneNode(); +}; + + + + +class VisualScriptSceneTree : public VisualScriptNode { + + OBJ_TYPE(VisualScriptSceneTree,VisualScriptNode) + + +protected: + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSceneTree(); +}; + + + +class VisualScriptResourcePath : public VisualScriptNode { + + OBJ_TYPE(VisualScriptResourcePath,VisualScriptNode) + + String path; +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_resource_path(const String &p_path); + String get_resource_path(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptResourcePath(); +}; + + +class VisualScriptSelf : public VisualScriptNode { + + OBJ_TYPE(VisualScriptSelf,VisualScriptNode) + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSelf(); +}; + + +class VisualScriptCustomNode: public VisualScriptNode { + + OBJ_TYPE(VisualScriptCustomNode,VisualScriptNode) + + +protected: + + virtual bool _use_builtin_script() const { return true; } + + static void _bind_methods(); +public: + + enum StartMode { //replicated for step + START_MODE_BEGIN_SEQUENCE, + START_MODE_CONTINUE_SEQUENCE, + START_MODE_RESUME_YIELD + }; + + enum { //replicated for step + STEP_SHIFT=1<<24, + STEP_MASK=STEP_SHIFT-1, + STEP_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack + STEP_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node + STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node + STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function + STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory) + }; + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptCustomNode(); +}; + +class VisualScriptSubCall: public VisualScriptNode { + + OBJ_TYPE(VisualScriptSubCall,VisualScriptNode) + + +protected: + + virtual bool _use_builtin_script() const { return true; } + + static void _bind_methods(); +public: + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSubCall(); +}; + + +void register_visual_script_nodes(); + +#endif // VISUAL_SCRIPT_NODES_H diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp new file mode 100644 index 0000000000..a6f84a97d9 --- /dev/null +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -0,0 +1,622 @@ +#include "visual_script_yield_nodes.h" +#include "scene/main/scene_main_loop.h" +#include "os/os.h" +#include "scene/main/node.h" +#include "visual_script_nodes.h" + +////////////////////////////////////////// +////////////////YIELD/////////// +////////////////////////////////////////// + +int VisualScriptYield::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptYield::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptYield::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptYield::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptYield::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptYield::get_caption() const { + + return "Wait"; +} + +String VisualScriptYield::get_text() const { + + switch (yield_mode) { + case YIELD_FRAME: return "Next Frame"; break; + case YIELD_FIXED_FRAME: return "Next Fixed Frame"; break; + case YIELD_WAIT: return rtos(wait_time)+" sec(s)"; break; + } + + return String(); +} + + +class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance { +public: + + VisualScriptYield::YieldMode mode; + float wait_time; + + virtual int get_working_memory_size() const { return 1; } //yield needs at least 1 + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_start_mode==START_MODE_RESUME_YIELD) { + return 0; //resuming yield + } else { + //yield + + + SceneTree *tree = OS::get_singleton()->get_main_loop()->cast_to<SceneTree>(); + if (!tree) { + r_error_str="Main Loop is not SceneTree"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + Ref<VisualScriptFunctionState> state; + state.instance(); + + switch(mode) { + + case VisualScriptYield::YIELD_FRAME: state->connect_to_signal(tree,"idle_frame",Array()); break; + case VisualScriptYield::YIELD_FIXED_FRAME: state->connect_to_signal(tree,"fixed_frame",Array()); break; + case VisualScriptYield::YIELD_WAIT: state->connect_to_signal(tree->create_timer(wait_time).ptr(),"timeout",Array()); break; + + } + + *p_working_mem=state; + + return STEP_YIELD_BIT; + } + } + +}; + +VisualScriptNodeInstance* VisualScriptYield::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceYield * instance = memnew(VisualScriptNodeInstanceYield ); + //instance->instance=p_instance; + instance->mode=yield_mode; + instance->wait_time=wait_time; + return instance; +} + +void VisualScriptYield::set_yield_mode(YieldMode p_mode) { + + if (yield_mode==p_mode) + return; + yield_mode=p_mode; + ports_changed_notify(); + _change_notify(); +} + +VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode(){ + + return yield_mode; +} + +void VisualScriptYield::set_wait_time(float p_time) { + + if (wait_time==p_time) + return; + wait_time=p_time; + ports_changed_notify(); + +} + +float VisualScriptYield::get_wait_time(){ + + return wait_time; +} + + +void VisualScriptYield::_validate_property(PropertyInfo& property) const { + + + if (property.name=="wait_time") { + if (yield_mode!=YIELD_WAIT) { + property.usage=0; + } + } +} + +void VisualScriptYield::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_yield_mode","mode"),&VisualScriptYield::set_yield_mode); + ObjectTypeDB::bind_method(_MD("get_yield_mode"),&VisualScriptYield::get_yield_mode); + + ObjectTypeDB::bind_method(_MD("set_wait_time","sec"),&VisualScriptYield::set_wait_time); + ObjectTypeDB::bind_method(_MD("get_wait_time"),&VisualScriptYield::get_wait_time); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Frame,FixedFrame,Time",PROPERTY_USAGE_NOEDITOR),_SCS("set_yield_mode"),_SCS("get_yield_mode")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"wait_time"),_SCS("set_wait_time"),_SCS("get_wait_time")); + + + BIND_CONSTANT( YIELD_FRAME ); + BIND_CONSTANT( YIELD_FIXED_FRAME ); + BIND_CONSTANT( YIELD_WAIT ); + +} + +VisualScriptYield::VisualScriptYield() { + + yield_mode=YIELD_FRAME; + wait_time=1; + +} + + +template<VisualScriptYield::YieldMode MODE> +static Ref<VisualScriptNode> create_yield_node(const String& p_name) { + + Ref<VisualScriptYield> node; + node.instance(); + node->set_yield_mode(MODE); + return node; +} + +/////////////////////////////////////////////////// +////////////////YIELD SIGNAL////////////////////// +////////////////////////////////////////////////// + +int VisualScriptYieldSignal::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptYieldSignal::has_input_sequence_port() const{ + + return true; +} +#ifdef TOOLS_ENABLED + +static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { + + if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) + return NULL; + + Ref<Script> scr = p_current_node->get_script(); + + if (scr.is_valid() && scr==script) + return p_current_node; + + for(int i=0;i<p_current_node->get_child_count();i++) { + Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); + if (n) + return n; + } + + return NULL; +} + +#endif +Node *VisualScriptYieldSignal::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + +StringName VisualScriptYieldSignal::_get_base_type() const { + + if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { + Node *path = _get_base_node(); + if (path) + return path->get_type(); + + } + + return base_type; +} + +int VisualScriptYieldSignal::get_input_value_port_count() const{ + + if (call_mode==CALL_MODE_INSTANCE) + return 1; + else + return 0; + +} +int VisualScriptYieldSignal::get_output_value_port_count() const{ + + + MethodInfo sr; + + if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + return 0; + + return sr.arguments.size(); + +} + +String VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_INSTANCE) + return PropertyInfo(Variant::OBJECT,"instance"); + else + return PropertyInfo(); + +} + +PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const{ + + MethodInfo sr; + + if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + return PropertyInfo(); //no signal + ERR_FAIL_INDEX_V(p_idx,sr.arguments.size(),PropertyInfo()); + return sr.arguments[p_idx]; + +} + + +String VisualScriptYieldSignal::get_caption() const { + + static const char*cname[3]= { + "WaitSignal", + "WaitNodeSignal", + "WaitInstanceSigna;", + }; + + return cname[call_mode]; +} + +String VisualScriptYieldSignal::get_text() const { + + if (call_mode==CALL_MODE_SELF) + return " "+String(signal)+"()"; + else + return " "+_get_base_type()+"."+String(signal)+"()"; + +} + + +void VisualScriptYieldSignal::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptYieldSignal::get_base_type() const{ + + return base_type; +} + +void VisualScriptYieldSignal::set_signal(const StringName& p_type){ + + if (signal==p_type) + return; + + signal=p_type; + + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptYieldSignal::get_signal() const { + + + return signal; +} + +void VisualScriptYieldSignal::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptYieldSignal::get_base_path() const { + + return base_path; +} + + +void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + + _change_notify(); + ports_changed_notify(); + +} + +VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const { + + return call_mode; +} + + +void VisualScriptYieldSignal::_validate_property(PropertyInfo& property) const { + + if (property.name=="signal/base_type") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + + if (property.name=="signal/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="signal/signal") { + property.hint=PROPERTY_HINT_ENUM; + + + List<MethodInfo> methods; + + ObjectTypeDB::get_signal_list(_get_base_type(),&methods); + + List<String> mstring; + for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + mstring.push_back(E->get().name.get_slice(":",0)); + } + + mstring.sort(); + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + property.hint_string=ml; + } + + +} + + +void VisualScriptYieldSignal::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptYieldSignal::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptYieldSignal::get_base_type); + + ObjectTypeDB::bind_method(_MD("set_signal","signal"),&VisualScriptYieldSignal::set_signal); + ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptYieldSignal::get_signal); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptYieldSignal::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptYieldSignal::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptYieldSignal::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptYieldSignal::get_base_path); + + + + String bt; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (i>0) + bt+=","; + + bt+=Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); + + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + BIND_CONSTANT( CALL_MODE_INSTANCE); + +} + +class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance { +public: + + + VisualScriptYieldSignal::CallMode call_mode; + NodePath node_path; + int output_args; + StringName signal; + + VisualScriptYieldSignal *node; + VisualScriptInstance *instance; + + + + virtual int get_working_memory_size() const { return 1; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + if (p_start_mode==START_MODE_RESUME_YIELD) { + return 0; //resuming yield + } else { + //yield + + Object * object; + + switch(call_mode) { + + case VisualScriptYieldSignal::CALL_MODE_SELF: { + + object=instance->get_owner_ptr(); + + } break; + case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + object=another; + + } break; + case VisualScriptYieldSignal::CALL_MODE_INSTANCE: { + + object = *p_inputs[0]; + if (!object) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Supplied instance input is null."; + return 0; + + } + + } break; + + } + + Ref<VisualScriptFunctionState> state; + state.instance(); + + state->connect_to_signal(object,signal,Array()); + + *p_working_mem=state; + + return STEP_YIELD_BIT; + } + + + } + + +}; + +VisualScriptNodeInstance* VisualScriptYieldSignal::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceYieldSignal * instance = memnew(VisualScriptNodeInstanceYieldSignal ); + instance->node=this; + instance->instance=p_instance; + instance->signal=signal; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->output_args = get_output_value_port_count(); + return instance; +} +VisualScriptYieldSignal::VisualScriptYieldSignal() { + + call_mode=CALL_MODE_INSTANCE; + base_type="Object"; + +} + +template<VisualScriptYieldSignal::CallMode cmode> +static Ref<VisualScriptNode> create_yield_signal_node(const String& p_name) { + + Ref<VisualScriptYieldSignal> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + +void register_visual_script_yield_nodes() { + + VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame",create_yield_node<VisualScriptYield::YIELD_FRAME>); + VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_fixed_frame",create_yield_node<VisualScriptYield::YIELD_FIXED_FRAME>); + VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time",create_yield_node<VisualScriptYield::YIELD_WAIT>); + + VisualScriptLanguage::singleton->add_register_func("functions/yield/instance_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/yield/self_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/yield/node_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_NODE_PATH>); + +} diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h new file mode 100644 index 0000000000..a7e200305d --- /dev/null +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -0,0 +1,127 @@ +#ifndef VISUAL_SCRIPT_YIELD_NODES_H +#define VISUAL_SCRIPT_YIELD_NODES_H + +#include "visual_script.h" + +class VisualScriptYield : public VisualScriptNode { + + OBJ_TYPE(VisualScriptYield,VisualScriptNode) +public: + + enum YieldMode { + YIELD_FRAME, + YIELD_FIXED_FRAME, + YIELD_WAIT + + }; +private: + + YieldMode yield_mode; + float wait_time; + + +protected: + + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_yield_mode(YieldMode p_mode); + YieldMode get_yield_mode(); + + void set_wait_time(float p_time); + float get_wait_time(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptYield(); +}; +VARIANT_ENUM_CAST( VisualScriptYield::YieldMode ) + +class VisualScriptYieldSignal : public VisualScriptNode { + + OBJ_TYPE(VisualScriptYieldSignal,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + CALL_MODE_INSTANCE, + + }; +private: + + CallMode call_mode; + StringName base_type; + NodePath base_path; + StringName signal; + + Node *_get_base_node() const; + StringName _get_base_type() const; + + +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_signal(const StringName& p_type); + StringName get_signal() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptYieldSignal(); +}; + +VARIANT_ENUM_CAST(VisualScriptYieldSignal::CallMode ); + +void register_visual_script_yield_nodes(); + +#endif // VISUAL_SCRIPT_YIELD_NODES_H diff --git a/platform/android/java/res/values-zh/strings.xml b/platform/android/java/res/values-zh-rCN/strings.xml index 397e662851..6668c56bd9 100644 --- a/platform/android/java/res/values-zh/strings.xml +++ b/platform/android/java/res/values-zh-rCN/strings.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="godot_project_name_string">godot-project-name-zh</string> -</resources>
\ No newline at end of file +</resources> diff --git a/platform/android/java/res/values-zh-rHK/strings.xml b/platform/android/java/res/values-zh-rHK/strings.xml new file mode 100644 index 0000000000..8a6269da0f --- /dev/null +++ b/platform/android/java/res/values-zh-rHK/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="godot_project_name_string">godot-project-name-zh_HK</string> +</resources> diff --git a/platform/android/java/res/values-zh-rTW/strings.xml b/platform/android/java/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000..b1bb39d5d6 --- /dev/null +++ b/platform/android/java/res/values-zh-rTW/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="godot_project_name_string">godot-project-name-zh_TW</string> +</resources> diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index dc87f767f6..ffae536ef0 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1494,9 +1494,19 @@ Size2 OS_OSX::get_window_size() const { }; +const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; + void OS_OSX::set_window_size(const Size2 p_size) { Size2 size=p_size; + + // NSRect used by setFrame includes the title bar, so add it to our size.y + CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + if (menuBarHeight != 0.f) { + size.y+= menuBarHeight; + } else { + size.y+= menuHeight; + } NSRect frame = [window_object frame]; [window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, size.x, size.y) display:YES]; }; diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 920c6bf1e6..feaf516f42 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -41,6 +41,8 @@ void Container::_child_minsize_changed() { void Container::add_child_notify(Node *p_child) { + Control::add_child_notify(p_child); + Control *control = p_child->cast_to<Control>(); if (!control) return; @@ -50,18 +52,24 @@ void Container::add_child_notify(Node *p_child) { control->connect("visibility_changed",this,"_child_minsize_changed"); queue_sort(); + } void Container::move_child_notify(Node *p_child) { + Control::move_child_notify(p_child); + if (!p_child->cast_to<Control>()) return; queue_sort(); + + } void Container::remove_child_notify(Node *p_child) { + Control::remove_child_notify(p_child); Control *control = p_child->cast_to<Control>(); if (!control) diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index c08e10b9ff..71ec508c81 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -422,6 +422,32 @@ void Control::_resize(const Size2& p_size) { _size_changed(); } +//moved theme configuration here, so controls can set up even if still not inside active scene + +void Control::add_child_notify(Node *p_child) { + + Control *child_c=p_child->cast_to<Control>(); + if (!child_c) + return; + + if (child_c->data.theme.is_null() && data.theme_owner) { + child_c->data.theme_owner=data.theme_owner; + child_c->notification(NOTIFICATION_THEME_CHANGED); + } +} + +void Control::remove_child_notify(Node *p_child) { + + Control *child_c=p_child->cast_to<Control>(); + if (!child_c) + return; + + if (child_c->data.theme_owner && child_c->data.theme.is_null()) { + child_c->data.theme_owner=NULL; + //notification(NOTIFICATION_THEME_CHANGED); + } + +} void Control::_notification(int p_notification) { @@ -512,10 +538,10 @@ void Control::_notification(int p_notification) { } - if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { - data.theme_owner=data.parent->data.theme_owner; - notification(NOTIFICATION_THEME_CHANGED); - } + //if (data.theme.is_null() && data.parent && data.parent->data.theme_owner) { + // data.theme_owner=data.parent->data.theme_owner; + // notification(NOTIFICATION_THEME_CHANGED); + //} } break; case NOTIFICATION_EXIT_CANVAS: { @@ -547,10 +573,10 @@ void Control::_notification(int p_notification) { data.parent=NULL; data.parent_canvas_item=NULL; - if (data.theme_owner && data.theme.is_null()) { - data.theme_owner=NULL; + //if (data.theme_owner && data.theme.is_null()) { + // data.theme_owner=NULL; //notification(NOTIFICATION_THEME_CHANGED); - } + //} } break; case NOTIFICATION_MOVED_IN_PARENT: { diff --git a/scene/gui/control.h b/scene/gui/control.h index 1337cbc4b9..b9ac53067a 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -194,12 +194,16 @@ private: void _font_changed(); + friend class Viewport; void _modal_stack_remove(); void _modal_set_prev_focus_owner(ObjectID p_prev); protected: + virtual void add_child_notify(Node *p_child); + virtual void remove_child_notify(Node *p_child); + //virtual void _window_input_event(InputEvent p_event); bool _set(const StringName& p_name, const Variant& p_value); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 9ad621b7aa..458e51b4fd 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -100,6 +100,15 @@ void GraphEdit::get_connection_list(List<Connection> *r_connections) const { *r_connections=connections; } +void GraphEdit::set_scroll_ofs(const Vector2& p_ofs) { + + setting_scroll_ofs=true; + h_scroll->set_val(p_ofs.x); + v_scroll->set_val(p_ofs.y); + _update_scroll(); + setting_scroll_ofs=false; +} + Vector2 GraphEdit::get_scroll_ofs() const{ return Vector2(h_scroll->get_val(),v_scroll->get_val()); @@ -109,6 +118,14 @@ void GraphEdit::_scroll_moved(double) { _update_scroll_offset(); top_layer->update(); + if (is_using_snap()) { + //must redraw grid + update(); + } + + if (!setting_scroll_ofs) {//in godot, signals on change value are avoided as a convention + emit_signal("scroll_offset_changed",get_scroll_ofs()); + } } void GraphEdit::_update_scroll_offset() { @@ -178,6 +195,7 @@ void GraphEdit::_graph_node_raised(Node* p_gn) { ERR_FAIL_COND(!gn); gn->raise(); top_layer->raise(); + emit_signal("node_selected",p_gn); } @@ -191,6 +209,8 @@ void GraphEdit::_graph_node_moved(Node *p_gn) { void GraphEdit::add_child_notify(Node *p_child) { + Control::add_child_notify(p_child); + top_layer->call_deferred("raise"); //top layer always on top! GraphNode *gn = p_child->cast_to<GraphNode>(); if (gn) { @@ -200,10 +220,14 @@ void GraphEdit::add_child_notify(Node *p_child) { _graph_node_moved(gn); gn->set_stop_mouse(false); } + + } void GraphEdit::remove_child_notify(Node *p_child) { + Control::remove_child_notify(p_child); + top_layer->call_deferred("raise"); //top layer always on top! GraphNode *gn = p_child->cast_to<GraphNode>(); if (gn) { @@ -228,6 +252,11 @@ void GraphEdit::_notification(int p_what) { h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height); h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + zoom_minus->set_icon(get_icon("minus")); + zoom_reset->set_icon(get_icon("reset")); + zoom_plus->set_icon(get_icon("more")); + snap_button->set_icon(get_icon("snap")); // zoom_icon->set_texture( get_icon("Zoom", "EditorIcons")); } @@ -235,6 +264,48 @@ void GraphEdit::_notification(int p_what) { draw_style_box( get_stylebox("bg"),Rect2(Point2(),get_size()) ); VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); + if (is_using_snap()) { + //draw grid + + int snap = get_snap(); + + Vector2 offset = get_scroll_ofs()/zoom; + Size2 size = get_size()/zoom; + + Point2i from = (offset/float(snap)).floor(); + Point2i len = (size/float(snap)).floor()+Vector2(1,1); + + Color grid_minor = get_color("grid_minor"); + Color grid_major = get_color("grid_major"); + + for(int i=from.x;i<from.x+len.x;i++) { + + Color color; + + if (ABS(i)%10==0) + color=grid_major; + else + color=grid_minor; + + float base_ofs = i*snap*zoom - offset.x*zoom; + draw_line(Vector2(base_ofs,0),Vector2(base_ofs,get_size().height),color); + } + + for(int i=from.y;i<from.y+len.y;i++) { + + Color color; + + if (ABS(i)%10==0) + color=grid_major; + else + color=grid_minor; + + float base_ofs = i*snap*zoom - offset.y*zoom; + draw_line(Vector2(0,base_ofs),Vector2(get_size().width,base_ofs),color); + } + + } + } if (p_what==NOTIFICATION_RESIZED) { @@ -295,6 +366,36 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) { Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); if (pos.distance_to(mpos)<grab_r) { + + if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { + //check disconnect + for (List<Connection>::Element*E=connections.front();E;E=E->next()) { + + if (E->get().from==gn->get_name() && E->get().from_port==j) { + + Node*to = get_node(String(E->get().to)); + if (to && to->cast_to<GraphNode>()) { + + connecting_from=E->get().to; + connecting_index=E->get().to_port; + connecting_out=false; + connecting_type=to->cast_to<GraphNode>()->get_connection_input_type(E->get().to_port); + connecting_color=to->cast_to<GraphNode>()->get_connection_input_color(E->get().to_port); + connecting_target=false; + connecting_to=pos; + + emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port); + to = get_node(String(connecting_from)); //maybe it was erased + if (to && to->cast_to<GraphNode>()) { + connecting=true; + } + return; + } + + } + } + } + connecting=true; connecting_from=gn->get_name(); connecting_index=j; @@ -315,7 +416,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) { if (pos.distance_to(mpos)<grab_r) { - if (right_disconnects) { + if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect for (List<Connection>::Element*E=connections.front();E;E=E->next()) { @@ -381,7 +482,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) { Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); int type =gn->get_connection_output_type(j); - if (type==connecting_type && pos.distance_to(mpos)<grab_r) { + if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) { connecting_target=true; connecting_to=pos; @@ -398,7 +499,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) { Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); int type =gn->get_connection_input_type(j); - if (type==connecting_type && pos.distance_to(mpos)<grab_r) { + if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) { connecting_target=true; connecting_to=pos; connecting_target_to=gn->get_name(); @@ -433,7 +534,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) { } -void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) { +void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color,const Color& p_to_color) { static const int steps = 20; @@ -454,7 +555,7 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const if (i>0) { - top_layer->draw_line(prev,p,p_color,2); + top_layer->draw_line(prev,p,p_color.linear_interpolate(p_to_color,d),2); } prev=p; @@ -488,7 +589,7 @@ void GraphEdit::_top_layer_draw() { col.g+=0.4; col.b+=0.4; } - _draw_cos_line(pos,topos,col); + _draw_cos_line(pos,topos,col,col); } List<List<Connection>::Element* > to_erase; @@ -526,7 +627,8 @@ void GraphEdit::_top_layer_draw() { Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos(); Color color = gfrom->get_connection_output_color(E->get().from_port); Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos(); - _draw_cos_line(frompos,topos,color); + Color tocolor = gto->get_connection_input_color(E->get().to_port); + _draw_cos_line(frompos,topos,color,tocolor); } @@ -538,6 +640,18 @@ void GraphEdit::_top_layer_draw() { top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3)); } +void GraphEdit::set_selected(Node* p_child) { + + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + gn->set_selected(gn==p_child); + } +} + void GraphEdit::_input_event(const InputEvent& p_ev) { if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { @@ -553,8 +667,16 @@ void GraphEdit::_input_event(const InputEvent& p_ev) { drag_accum = get_local_mouse_pos() - drag_origin; for(int i=get_child_count()-1;i>=0;i--) { GraphNode *gn=get_child(i)->cast_to<GraphNode>(); - if (gn && gn->is_selected()) - gn->set_offset((gn->get_drag_from()*zoom+drag_accum)/zoom); + if (gn && gn->is_selected()) { + + Vector2 pos = (gn->get_drag_from()*zoom+drag_accum)/zoom; + if (is_using_snap()) { + int snap = get_snap(); + pos = pos.snapped(Vector2(snap,snap)); + } + + gn->set_offset(pos); + } } } @@ -807,6 +929,29 @@ bool GraphEdit::is_right_disconnects_enabled() const{ return right_disconnects; } +void GraphEdit::add_valid_right_disconnect_type(int p_type) { + + valid_right_disconnect_types.insert(p_type); +} + +void GraphEdit::remove_valid_right_disconnect_type(int p_type){ + + valid_right_disconnect_types.erase(p_type); + +} + +void GraphEdit::add_valid_left_disconnect_type(int p_type){ + + valid_left_disconnect_types.insert(p_type); + +} + +void GraphEdit::remove_valid_left_disconnect_type(int p_type){ + + valid_left_disconnect_types.erase(p_type); + +} + Array GraphEdit::_get_connection_list() const { List<Connection> conns; @@ -841,6 +986,67 @@ void GraphEdit::_zoom_plus() { set_zoom(zoom*ZOOM_SCALE); } +void GraphEdit::add_valid_connection_type(int p_type,int p_with_type) { + + ConnType ct; + ct.type_a=p_type; + ct.type_b=p_with_type; + + valid_connection_types.insert(ct); +} + +void GraphEdit::remove_valid_connection_type(int p_type,int p_with_type) { + + ConnType ct; + ct.type_a=p_type; + ct.type_b=p_with_type; + + valid_connection_types.erase(ct); + +} + +bool GraphEdit::is_valid_connection_type(int p_type,int p_with_type) const { + + ConnType ct; + ct.type_a=p_type; + ct.type_b=p_with_type; + + return valid_connection_types.has(ct); + +} + +void GraphEdit::set_use_snap(bool p_enable) { + + snap_button->set_pressed(p_enable); + update(); +} + +bool GraphEdit::is_using_snap() const{ + + return snap_button->is_pressed(); + +} + +int GraphEdit::get_snap() const{ + + return snap_amount->get_val(); +} + +void GraphEdit::set_snap(int p_snap) { + + ERR_FAIL_COND(p_snap<5); + snap_amount->set_val(p_snap); + update(); +} +void GraphEdit::_snap_toggled() { + update(); +} + +void GraphEdit::_snap_value_changed(double) { + + update(); +} + void GraphEdit::_bind_methods() { @@ -849,10 +1055,17 @@ void GraphEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node); ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list); ObjectTypeDB::bind_method(_MD("get_scroll_ofs"),&GraphEdit::get_scroll_ofs); + ObjectTypeDB::bind_method(_MD("set_scroll_ofs","ofs"),&GraphEdit::set_scroll_ofs); ObjectTypeDB::bind_method(_MD("set_zoom","p_zoom"),&GraphEdit::set_zoom); ObjectTypeDB::bind_method(_MD("get_zoom"),&GraphEdit::get_zoom); + ObjectTypeDB::bind_method(_MD("set_snap","pixels"),&GraphEdit::set_snap); + ObjectTypeDB::bind_method(_MD("get_snap"),&GraphEdit::get_snap); + + ObjectTypeDB::bind_method(_MD("set_use_snap","enable"),&GraphEdit::set_use_snap); + ObjectTypeDB::bind_method(_MD("is_using_snap"),&GraphEdit::is_using_snap); + ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects); ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled); @@ -865,16 +1078,22 @@ void GraphEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("_zoom_minus"),&GraphEdit::_zoom_minus); ObjectTypeDB::bind_method(_MD("_zoom_reset"),&GraphEdit::_zoom_reset); ObjectTypeDB::bind_method(_MD("_zoom_plus"),&GraphEdit::_zoom_plus); + ObjectTypeDB::bind_method(_MD("_snap_toggled"),&GraphEdit::_snap_toggled); + ObjectTypeDB::bind_method(_MD("_snap_value_changed"),&GraphEdit::_snap_value_changed); ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event); + ObjectTypeDB::bind_method(_MD("set_selected","node"),&GraphEdit::set_selected); + ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position"))); ADD_SIGNAL(MethodInfo("duplicate_nodes_request")); + ADD_SIGNAL(MethodInfo("node_selected",PropertyInfo(Variant::OBJECT,"node"))); ADD_SIGNAL(MethodInfo("delete_nodes_request")); ADD_SIGNAL(MethodInfo("_begin_node_move")); ADD_SIGNAL(MethodInfo("_end_node_move")); + ADD_SIGNAL(MethodInfo("scroll_offset_changed",PropertyInfo(Variant::VECTOR2,"ofs"))); } @@ -905,6 +1124,13 @@ GraphEdit::GraphEdit() { box_selecting = false; dragging = false; + //set large minmax so it can scroll even if not resized yet + h_scroll->set_min(-10000); + h_scroll->set_max(10000); + + v_scroll->set_min(-10000); + v_scroll->set_max(10000); + h_scroll->connect("value_changed", this,"_scroll_moved"); v_scroll->connect("value_changed", this,"_scroll_moved"); @@ -918,17 +1144,33 @@ GraphEdit::GraphEdit() { zoom_minus = memnew( ToolButton ); zoom_hb->add_child(zoom_minus); zoom_minus->connect("pressed",this,"_zoom_minus"); - zoom_minus->set_icon(get_icon("minus")); + zoom_minus->set_focus_mode(FOCUS_NONE); zoom_reset = memnew( ToolButton ); zoom_hb->add_child(zoom_reset); zoom_reset->connect("pressed",this,"_zoom_reset"); - zoom_reset->set_icon(get_icon("reset")); + zoom_reset->set_focus_mode(FOCUS_NONE); zoom_plus = memnew( ToolButton ); zoom_hb->add_child(zoom_plus); zoom_plus->connect("pressed",this,"_zoom_plus"); - zoom_plus->set_icon(get_icon("more")); - + zoom_plus->set_focus_mode(FOCUS_NONE); + + snap_button = memnew( ToolButton ); + snap_button->set_toggle_mode(true); + snap_button->connect("pressed",this,"_snap_toggled"); + snap_button->set_pressed(true); + snap_button->set_focus_mode(FOCUS_NONE); + zoom_hb->add_child(snap_button); + + snap_amount = memnew( SpinBox ); + snap_amount->set_min(5); + snap_amount->set_max(100); + snap_amount->set_step(1); + snap_amount->set_val(20); + snap_amount->connect("value_changed",this,"_snap_value_changed"); + zoom_hb->add_child(snap_amount); + + setting_scroll_ofs=false; } diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index ed6838ac1d..6d35e1518f 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -33,6 +33,7 @@ #include "scene/gui/scroll_bar.h" #include "scene/gui/slider.h" #include "scene/gui/tool_button.h" +#include "scene/gui/spin_box.h" #include "texture_frame.h" class GraphEdit; @@ -70,6 +71,9 @@ private: ToolButton *zoom_reset; ToolButton *zoom_plus; + ToolButton *snap_button; + SpinBox *snap_amount; + void _zoom_minus(); void _zoom_reset(); void _zoom_plus(); @@ -103,11 +107,12 @@ private: Rect2 box_selecting_rect; List<GraphNode*> previus_selected; + bool setting_scroll_ofs; bool right_disconnects; bool updating; List<Connection> connections; - void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color); + void _draw_cos_line(const Vector2& p_from, const Vector2& p_to, const Color& p_color, const Color &p_to_color); void _graph_node_raised(Node* p_gn); void _graph_node_moved(Node *p_gn); @@ -123,8 +128,34 @@ private: Array _get_connection_list() const; + struct ConnType { + + union { + struct { + uint32_t type_a; + uint32_t type_b; + }; + uint64_t key; + }; + + bool operator<(const ConnType& p_type) const { + return key<p_type.key; + } + + ConnType(uint32_t a=0, uint32_t b=0) { + type_a=a; + type_b=b; + } + }; + + Set<ConnType> valid_connection_types; + Set<int> valid_left_disconnect_types; + Set<int> valid_right_disconnect_types; + friend class GraphEditFilter; bool _filter_input(const Point2& p_point); + void _snap_toggled(); + void _snap_value_changed(double); protected: static void _bind_methods(); @@ -139,6 +170,10 @@ public: void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); void clear_connections(); + void add_valid_connection_type(int p_type,int p_with_type); + void remove_valid_connection_type(int p_type,int p_with_type); + bool is_valid_connection_type(int p_type,int p_with_type) const; + void set_zoom(float p_zoom); float get_zoom() const; @@ -148,8 +183,22 @@ public: void set_right_disconnects(bool p_enable); bool is_right_disconnects_enabled() const; + void add_valid_right_disconnect_type(int p_type); + void remove_valid_right_disconnect_type(int p_type); + + void add_valid_left_disconnect_type(int p_type); + void remove_valid_left_disconnect_type(int p_type); + + void set_scroll_ofs(const Vector2& p_ofs); Vector2 get_scroll_ofs() const; + void set_selected(Node* p_child); + + void set_use_snap(bool p_enable); + bool is_using_snap() const; + + int get_snap() const; + void set_snap(int p_snap); GraphEdit(); }; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 3705541865..66d2725ad2 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -189,6 +189,8 @@ void GraphNode::_notification(int p_what) { if (p_what==NOTIFICATION_DRAW) { Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame"); + sb=sb->duplicate(); + sb->call("set_modulate",modulate); Ref<Texture> port =get_icon("port"); Ref<Texture> close =get_icon("close"); int close_offset = get_constant("close_offset"); @@ -198,8 +200,25 @@ void GraphNode::_notification(int p_what) { Point2i icofs = -port->get_size()*0.5; int edgeofs=get_constant("port_offset"); icofs.y+=sb->get_margin(MARGIN_TOP); + + + draw_style_box(sb,Rect2(Point2(),get_size())); + switch(overlay) { + case OVERLAY_DISABLED: { + + } break; + case OVERLAY_BREAKPOINT: { + + draw_style_box(get_stylebox("breakpoint"),Rect2(Point2(),get_size())); + } break; + case OVERLAY_POSITION: { + draw_style_box(get_stylebox("position"),Rect2(Point2(),get_size())); + + } break; + } + int w = get_size().width-sb->get_minimum_size().x; if (show_close) @@ -223,10 +242,20 @@ void GraphNode::_notification(int p_what) { continue; const Slot &s=slot_info[E->key()]; //left - if (s.enable_left) - port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left); - if (s.enable_right) - port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right); + if (s.enable_left) { + Ref<Texture> p = port; + if (s.custom_slot_left.is_valid()) { + p=s.custom_slot_left; + } + p->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left); + } + if (s.enable_right) { + Ref<Texture> p = port; + if (s.custom_slot_right.is_valid()) { + p=s.custom_slot_right; + } + p->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right); + } } } @@ -239,7 +268,7 @@ void GraphNode::_notification(int p_what) { } -void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) { +void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left,const Ref<Texture>& p_custom_right) { ERR_FAIL_COND(p_idx<0); @@ -255,6 +284,8 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo s.enable_right=p_enable_right; s.type_right=p_type_right; s.color_right=p_color_right; + s.custom_slot_left=p_custom_left; + s.custom_slot_right=p_custom_right; slot_info[p_idx]=s; update(); connpos_dirty=true; @@ -578,6 +609,26 @@ void GraphNode::_input_event(const InputEvent& p_ev) { } +void GraphNode::set_modulate(const Color &p_color) { + + modulate=p_color; + update(); +} + +Color GraphNode::get_modulate() const{ + + return modulate; +} +void GraphNode::set_overlay(Overlay p_overlay) { + + overlay=p_overlay; + update(); +} + +GraphNode::Overlay GraphNode::get_overlay() const{ + + return overlay; +} void GraphNode::_bind_methods() { @@ -585,7 +636,7 @@ void GraphNode::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title); ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event); - ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot); + ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right","custom_left","custom_right"),&GraphNode::set_slot,DEFVAL(Ref<Texture>()),DEFVAL(Ref<Texture>())); ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot); ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots); ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left); @@ -608,10 +659,15 @@ void GraphNode::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_connection_input_type","idx"),&GraphNode::get_connection_input_type); ObjectTypeDB::bind_method(_MD("get_connection_input_color","idx"),&GraphNode::get_connection_input_color); + ObjectTypeDB::bind_method(_MD("set_modulate","color"),&GraphNode::set_modulate); + ObjectTypeDB::bind_method(_MD("get_modulate"),&GraphNode::get_modulate); ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button); ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible); + ObjectTypeDB::bind_method(_MD("set_overlay","overlay"),&GraphNode::set_overlay); + ObjectTypeDB::bind_method(_MD("get_overlay"),&GraphNode::get_overlay); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible")); @@ -619,10 +675,17 @@ void GraphNode::_bind_methods() { ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to"))); ADD_SIGNAL(MethodInfo("raise_request")); ADD_SIGNAL(MethodInfo("close_request")); + + BIND_CONSTANT( OVERLAY_DISABLED ); + BIND_CONSTANT( OVERLAY_BREAKPOINT ); + BIND_CONSTANT( OVERLAY_POSITION ); } GraphNode::GraphNode() { + + overlay=OVERLAY_DISABLED; show_close=false; connpos_dirty=true; set_stop_mouse(false); + modulate=Color(1,1,1,1); } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 5a50d0d68d..e87fb15b93 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -34,8 +34,14 @@ class GraphNode : public Container { OBJ_TYPE(GraphNode,Container); +public: - + enum Overlay { + OVERLAY_DISABLED, + OVERLAY_BREAKPOINT, + OVERLAY_POSITION + }; +private: struct Slot { bool enable_left; @@ -44,6 +50,8 @@ class GraphNode : public Container { bool enable_right; int type_right; Color color_right; + Ref<Texture> custom_slot_left; + Ref<Texture> custom_slot_right; Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); } @@ -75,6 +83,10 @@ class GraphNode : public Container { Vector2 drag_from; bool selected; + + Overlay overlay; + + Color modulate; protected: @@ -91,7 +103,7 @@ public: - void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right); + void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left=Ref<Texture>(),const Ref<Texture>& p_custom_right=Ref<Texture>()); void clear_slot(int p_idx); void clear_all_slots(); bool is_slot_enabled_left(int p_idx) const; @@ -126,10 +138,17 @@ public: Color get_connection_output_color(int p_idx); + void set_modulate(const Color& p_color); + Color get_modulate() const; + + void set_overlay(Overlay p_overlay); + Overlay get_overlay() const; + virtual Size2 get_minimum_size() const; GraphNode(); }; +VARIANT_ENUM_CAST( GraphNode::Overlay ) #endif // GRAPH_NODE_H diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 4c025e92df..ec89b7b690 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -334,7 +334,7 @@ int Label::get_longest_line_width() const { } } else { - int char_width=font->get_char_size(current).width; + int char_width=font->get_char_size(current,text[i+1]).width; line_width+=char_width; } @@ -454,7 +454,7 @@ void Label::regenerate_word_cache() { word_pos=i; } - char_width=font->get_char_size(current).width; + char_width=font->get_char_size(current,text[i+1]).width; current_word_size+=char_width; line_width+=char_width; total_char_cache++; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 0e0339c488..8557500488 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -400,6 +400,7 @@ void TabContainer::_child_renamed_callback() { void TabContainer::add_child_notify(Node *p_child) { + Control::add_child_notify(p_child); Control *c = p_child->cast_to<Control>(); if (!c) @@ -532,6 +533,8 @@ Control* TabContainer::get_current_tab_control() const { void TabContainer::remove_child_notify(Node *p_child) { + Control::remove_child_notify(p_child); + int tc = get_tab_count(); if (current==tc-1) { current--; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c3bdf7c856..f0301fc250 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -438,7 +438,7 @@ public: bool is_highlight_all_occurrences_enabled() const; bool is_selection_active() const; int get_selection_from_line() const; - int get_selection_from_column() const; + int get_selection_from_column() const; int get_selection_to_line() const; int get_selection_to_column() const; String get_selection_text() const; @@ -496,7 +496,7 @@ public: String get_text_for_completion(); - virtual bool is_text_field() const; + virtual bool is_text_field() const; TextEdit(); ~TextEdit(); }; diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index a7ef7ca7c1..77156203b8 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -45,6 +45,30 @@ #include "scene/resources/material.h" #include "scene/resources/mesh.h" + +void SceneTreeTimer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_time_left","time"),&SceneTreeTimer::set_time_left); + ObjectTypeDB::bind_method(_MD("get_time_left"),&SceneTreeTimer::get_time_left); + + ADD_SIGNAL(MethodInfo("timeout")); +} + + +void SceneTreeTimer::set_time_left(float p_time) { + time_left=p_time; +} + +float SceneTreeTimer::get_time_left() const { + return time_left; +} + + +SceneTreeTimer::SceneTreeTimer() { + time_left=0; +} + + void SceneTree::tree_changed() { tree_version++; @@ -547,6 +571,23 @@ bool SceneTree::idle(float p_time){ _flush_delete_queue(); + //go through timers + + for (List<Ref<SceneTreeTimer> >::Element *E=timers.front();E;) { + + List<Ref<SceneTreeTimer> >::Element *N = E->next(); + + float time_left = E->get()->get_time_left(); + time_left-=p_time; + E->get()->set_time_left(time_left); + + if (time_left<0) { + E->get()->emit_signal("timeout"); + timers.erase(E); + } + E=N; + } + return _quit; } @@ -1604,6 +1645,16 @@ void SceneTree::drop_files(const Vector<String>& p_files,int p_from_screen) { MainLoop::drop_files(p_files,p_from_screen); } + +Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec) { + + Ref<SceneTreeTimer> stt; + stt.instance(); + stt->set_time_left(p_delay_sec); + timers.push_back(stt); + return stt; +} + void SceneTree::_bind_methods() { @@ -1634,6 +1685,8 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_paused"),&SceneTree::is_paused); ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneTree::set_input_as_handled); + ObjectTypeDB::bind_method(_MD("create_timer:SceneTreeTimer","time_sec"),&SceneTree::create_timer); + ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneTree::get_node_count); ObjectTypeDB::bind_method(_MD("get_frame"),&SceneTree::get_frame); diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 38d13c0447..6129a12446 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -47,6 +47,22 @@ class Viewport; class Material; class Mesh; + + +class SceneTreeTimer : public Reference { + OBJ_TYPE(SceneTreeTimer,Reference); + + float time_left; +protected: + static void _bind_methods(); +public: + + void set_time_left(float p_time); + float get_time_left() const; + + SceneTreeTimer(); +}; + class SceneTree : public MainLoop { _THREAD_SAFE_CLASS_ @@ -155,6 +171,8 @@ private: void _change_scene(Node* p_to); //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); + List<Ref<SceneTreeTimer> > timers; + static SceneTree *singleton; friend class Node; @@ -339,6 +357,8 @@ public: Error change_scene_to(const Ref<PackedScene>& p_scene); Error reload_current_scene(); + Ref<SceneTreeTimer> create_timer(float p_delay_sec); + //used by Main::start, don't use otherwise void add_current_scene(Node * p_current); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index bc0951e436..be2c12d63a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -632,6 +632,7 @@ void register_scene_types() { ObjectTypeDB::register_type<PackedScene>(); ObjectTypeDB::register_type<SceneTree>(); + ObjectTypeDB::register_virtual_type<SceneTreeTimer>(); //sorry, you can't create it OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 499cf0a169..2033599307 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -626,22 +626,27 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F // GraphNode - Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,3,24,16,5); - Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,3,24,16,5); + Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5); + Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,16,24,16,5); Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4); Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4); + Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png,6,24,6,5,16,24,16,5); + Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png,6,24,6,5,16,24,16,5); + //graphsb->set_expand_margin_size(MARGIN_LEFT,10); //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); t->set_stylebox("frame","GraphNode", graphsb ); t->set_stylebox("selectedframe","GraphNode", graphsbselected ); t->set_stylebox("defaultframe", "GraphNode", graphsbdefault ); t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus ); + t->set_stylebox("breakpoint", "GraphNode", graph_bpoint ); + t->set_stylebox("position", "GraphNode", graph_position ); t->set_constant("separation","GraphNode", 1 *scale); t->set_icon("port","GraphNode", make_icon( graph_port_png ) ); t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) ); t->set_font("title_font","GraphNode", default_font ); t->set_color("title_color","GraphNode", Color(0,0,0,1)); - t->set_constant("title_offset","GraphNode", 18 *scale); + t->set_constant("title_offset","GraphNode", 20 *scale); t->set_constant("close_offset","GraphNode", 18 *scale); t->set_constant("port_offset","GraphNode", 3 *scale); @@ -921,7 +926,10 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F t->set_icon("minus","GraphEdit", make_icon(icon_zoom_less_png) ); t->set_icon("reset","GraphEdit", make_icon(icon_zoom_reset_png) ); t->set_icon("more","GraphEdit", make_icon(icon_zoom_more_png) ); + t->set_icon("snap","GraphEdit", make_icon(icon_snap_png) ); t->set_stylebox("bg","GraphEdit", make_stylebox( tree_bg_png,4,4,4,5) ); + t->set_color("grid_minor","GraphEdit", Color(1,1,1,0.05) ); + t->set_color("grid_major","GraphEdit", Color(1,1,1,0.2) ); diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png Binary files differindex 5eea134b25..ed0b6a6cd2 100644 --- a/scene/resources/default_theme/graph_node.png +++ b/scene/resources/default_theme/graph_node.png diff --git a/scene/resources/default_theme/graph_node_breakpoint.png b/scene/resources/default_theme/graph_node_breakpoint.png Binary files differnew file mode 100644 index 0000000000..0e36f31bd4 --- /dev/null +++ b/scene/resources/default_theme/graph_node_breakpoint.png diff --git a/scene/resources/default_theme/graph_node_position.png b/scene/resources/default_theme/graph_node_position.png Binary files differnew file mode 100644 index 0000000000..7ec15e2ff4 --- /dev/null +++ b/scene/resources/default_theme/graph_node_position.png diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differindex 22fdc7e89f..33c4d06128 100644 --- a/scene/resources/default_theme/graph_node_selected.png +++ b/scene/resources/default_theme/graph_node_selected.png diff --git a/scene/resources/default_theme/icon_snap.png b/scene/resources/default_theme/icon_snap.png Binary files differnew file mode 100644 index 0000000000..b835238d1e --- /dev/null +++ b/scene/resources/default_theme/icon_snap.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index ab758f72b4..2286973bf2 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -5,12 +5,12 @@ static const unsigned char arrow_down_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x4,0x0,0x0,0x0,0xfc,0x7c,0x94,0x6c,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x4a,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0xa0,0x1a,0x60,0x64,0x60,0x60,0x60,0x78,0xf0,0x1f,0x55,0x50,0x81,0x91,0x81,0x81,0x9,0x97,0xe,0xfc,0x12,0x8c,0xf1,0xc,0x5f,0xe1,0x22,0xdf,0x19,0xd3,0x91,0xe4,0xef,0x6b,0xdc,0xbf,0xf4,0xe0,0xff,0x83,0xff,0xf,0xae,0x3f,0xd6,0x45,0xb2,0x9c,0x81,0x81,0x81,0xe1,0x5,0xf7,0xcf,0x29,0xc,0xc,0xec,0x39,0x12,0x5f,0x19,0xa8,0xd,0x0,0x99,0x85,0x11,0xfa,0x28,0xbe,0xff,0xef,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x6d,0x49,0x44,0x41,0x54,0x28,0x91,0x63,0x60,0x18,0x74,0x80,0x11,0xc6,0x78,0xf0,0xe0,0xc1,0x7f,0x7c,0xa,0x15,0x14,0x14,0x18,0x19,0x18,0x18,0x18,0x98,0x48,0xb5,0x81,0x7c,0xd,0x8c,0x8c,0x8c,0xf1,0xc,0xc,0xc,0x5f,0xb1,0xa8,0xf9,0xce,0xc8,0xc8,0x98,0xe,0x57,0x87,0x2c,0x73,0xff,0xfe,0x7d,0xd,0x6,0x6,0x86,0x55,0x8c,0x8c,0x8c,0xba,0x50,0xa1,0x1b,0xcc,0xcc,0xcc,0x61,0xb2,0xb2,0xb2,0x97,0xb1,0x6a,0x60,0x60,0x60,0x60,0x78,0xf1,0xe2,0x5,0xf7,0xcf,0x9f,0x3f,0xa7,0x30,0x30,0x30,0x30,0xb0,0xb3,0xb3,0xe7,0x48,0x48,0x48,0x60,0xb3,0x75,0x30,0x1,0x0,0x28,0x20,0x14,0xc2,0x1b,0xd0,0x7c,0xca,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char arrow_right_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x4,0x0,0x0,0x0,0xfc,0x7c,0x94,0x6c,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x4e,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x20,0x13,0x3c,0xf8,0xff,0xe0,0xff,0x83,0xff,0xf7,0x13,0x10,0x22,0x8c,0x30,0x9,0x6,0x6,0x6,0x6,0x86,0xaf,0x8c,0xe6,0xf2,0x57,0x21,0x22,0x4c,0x28,0x1a,0xb9,0xff,0xaf,0x7a,0xc1,0x8d,0x4d,0x82,0x81,0x41,0xeb,0xe7,0x14,0xec,0x12,0x70,0x80,0x2e,0x71,0x8d,0x3d,0x7,0x9b,0xc4,0x57,0xc6,0x30,0x89,0xaf,0x58,0x24,0xfe,0xe7,0xc0,0xdc,0x44,0xe,0x0,0x0,0xa0,0xe1,0x15,0x49,0x2,0x9f,0xab,0x0,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x28,0x91,0x63,0x60,0xa0,0x35,0x60,0x44,0xe6,0x3c,0x78,0xf0,0xe0,0x3f,0x8c,0xfd,0xff,0xff,0xff,0x44,0x45,0x45,0xc5,0x5,0xe8,0x1a,0x98,0x70,0x9a,0xc4,0xc8,0x38,0xe5,0xe1,0xc3,0x87,0xda,0x44,0x6b,0x60,0x60,0x60,0xe0,0xfe,0xff,0xff,0xff,0xaa,0x17,0x2f,0x5e,0x70,0x13,0xab,0x81,0x81,0x81,0x81,0x41,0xeb,0xe7,0xcf,0x9f,0x53,0x48,0xd1,0x80,0x1,0x8,0x69,0xb8,0xc6,0xce,0xce,0x9e,0x43,0xac,0x86,0xaf,0x8c,0x8c,0x8c,0x61,0x12,0x12,0x12,0x5f,0x89,0xd2,0xf0,0xff,0xff,0xff,0x1c,0x79,0x79,0xf9,0xab,0x84,0x1d,0x49,0x6d,0x0,0x0,0x8f,0x30,0x1e,0x10,0x6e,0x79,0xda,0xf9,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -60,12 +60,12 @@ static const unsigned char checker_bg_png[]={ static const unsigned char close_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x28,0xcf,0xad,0x90,0xd1,0xa,0x80,0x20,0xc,0x45,0xad,0xa7,0x6b,0xee,0x35,0xb1,0x3f,0xf3,0xbb,0x13,0xc,0xea,0x5f,0x5c,0xf,0x42,0x4d,0x1c,0x14,0xd4,0xde,0xc6,0x39,0xd3,0xdd,0x19,0xf3,0x53,0xd9,0x48,0x5e,0xf6,0xe4,0x6d,0x6c,0x30,0xa,0xd2,0xad,0x90,0x47,0x42,0x11,0xa,0xcd,0x76,0x5,0x63,0x9b,0x16,0xd9,0xb9,0x20,0x9f,0xbc,0x14,0x15,0xb,0x65,0x47,0x56,0x71,0x55,0x90,0xc1,0x60,0x1c,0x12,0x8f,0x5a,0x26,0x1e,0xd4,0x79,0xf9,0x45,0x5d,0x57,0x59,0xd2,0x85,0x36,0x51,0x87,0xfb,0xd0,0xef,0xe,0xf5,0x78,0xea,0x4f,0x75,0x2,0x30,0x98,0x34,0x72,0xa,0x11,0xfb,0xc2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9b,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x92,0x31,0xe,0xc2,0x30,0x10,0x4,0x17,0xaa,0x3d,0x67,0xdb,0x58,0xd0,0xd3,0xf0,0xa3,0x7c,0x36,0x3c,0x82,0x48,0x44,0x22,0x6f,0xb1,0x4d,0x85,0x14,0x81,0xf,0x2c,0x28,0xe0,0xda,0xd5,0x8c,0x4e,0x77,0xb,0xfc,0xd5,0x98,0xd9,0x20,0x29,0x7a,0xb9,0xa4,0x68,0x66,0x83,0xb,0x93,0xcc,0x24,0xa7,0x9a,0x44,0x52,0x24,0x39,0x91,0xcc,0x55,0x89,0xa4,0xde,0xcc,0xce,0x24,0xb,0xc9,0x39,0x84,0xb0,0xf7,0xb2,0xae,0xeb,0x76,0xde,0x8a,0x4f,0x92,0x66,0xd8,0x91,0x5c,0x49,0x5e,0x9a,0xe1,0xb5,0x64,0x5,0x16,0x92,0x8b,0x7,0x6f,0x9b,0x8c,0x0,0x4a,0x29,0x9b,0x26,0x81,0xa4,0x3e,0xa5,0x34,0x2,0x38,0x2,0x58,0x0,0xcc,0x0,0xe,0x39,0xe7,0xd3,0xfa,0xb0,0xee,0xea,0x8f,0x7,0x7b,0xf5,0x9d,0xb7,0xb0,0x97,0x55,0x25,0x5f,0x17,0xe9,0x2e,0xf9,0xb8,0xca,0x3f,0x9b,0x1b,0x1a,0xe3,0x40,0x47,0xa0,0xda,0xda,0x61,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char close_hl_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x28,0xcf,0xad,0x90,0xd1,0xa,0x80,0x20,0xc,0x45,0xad,0xa7,0x6b,0xee,0x35,0xb1,0x3f,0xf3,0xbb,0x13,0xc,0xea,0x5f,0x5c,0xf,0x42,0x4d,0x1c,0x14,0xd4,0xde,0xc6,0x39,0xd3,0xdd,0x19,0xf3,0x53,0xd9,0x48,0x5e,0xf6,0xe4,0x6d,0x6c,0x30,0xa,0xd2,0xad,0x90,0x47,0x42,0x11,0xa,0xcd,0x76,0x5,0x63,0x9b,0x16,0xd9,0xb9,0x20,0x9f,0xbc,0x14,0x15,0xb,0x65,0x47,0x56,0x71,0x55,0x90,0xc1,0x60,0x1c,0x12,0x8f,0x5a,0x26,0x1e,0xd4,0x79,0xf9,0x45,0x5d,0x57,0x59,0xd2,0x85,0x36,0x51,0x87,0xfb,0xd0,0xef,0xe,0xf5,0x78,0xea,0x4f,0x75,0x2,0x30,0x98,0x34,0x72,0xa,0x11,0xfb,0xc2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9b,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x92,0x31,0xe,0xc2,0x30,0x10,0x4,0x17,0xaa,0x3d,0x67,0xdb,0x58,0xd0,0xd3,0xf0,0xa3,0x7c,0x36,0x3c,0x82,0x48,0x44,0x22,0x6f,0xb1,0x4d,0x85,0x14,0x81,0xf,0x2c,0x28,0xe0,0xda,0xd5,0x8c,0x4e,0x77,0xb,0xfc,0xd5,0x98,0xd9,0x20,0x29,0x7a,0xb9,0xa4,0x68,0x66,0x83,0xb,0x93,0xcc,0x24,0xa7,0x9a,0x44,0x52,0x24,0x39,0x91,0xcc,0x55,0x89,0xa4,0xde,0xcc,0xce,0x24,0xb,0xc9,0x39,0x84,0xb0,0xf7,0xb2,0xae,0xeb,0x76,0xde,0x8a,0x4f,0x92,0x66,0xd8,0x91,0x5c,0x49,0x5e,0x9a,0xe1,0xb5,0x64,0x5,0x16,0x92,0x8b,0x7,0x6f,0x9b,0x8c,0x0,0x4a,0x29,0x9b,0x26,0x81,0xa4,0x3e,0xa5,0x34,0x2,0x38,0x2,0x58,0x0,0xcc,0x0,0xe,0x39,0xe7,0xd3,0xfa,0xb0,0xee,0xea,0x8f,0x7,0x7b,0xf5,0x9d,0xb7,0xb0,0x97,0x55,0x25,0x5f,0x17,0xe9,0x2e,0xf9,0xb8,0xca,0x3f,0x9b,0x1b,0x1a,0xe3,0x40,0x47,0xa0,0xda,0xda,0x61,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -100,12 +100,17 @@ static const unsigned char full_panel_bg_png[]={ static const unsigned char graph_node_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x3,0x0,0x0,0x0,0x24,0xa3,0x7,0xa4,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x1,0x4d,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xd,0x10,0x17,0x14,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x10,0x13,0x0,0x0,0x0,0x19,0x17,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x16,0x12,0x19,0x0,0x0,0x0,0xe,0xb,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0xb,0x10,0x16,0x12,0x19,0x0,0x0,0x0,0x1d,0x1a,0x1f,0x35,0x2f,0x38,0xba,0xa9,0xc3,0xc3,0xb7,0xcb,0xbd,0xad,0xc5,0xb9,0xa9,0xc3,0xb5,0xa3,0xbf,0xb4,0xa1,0xbe,0xb4,0xa2,0xbd,0xb4,0xa2,0xbe,0xb3,0xa2,0xbe,0xb1,0xa0,0xbc,0xb2,0xa0,0xbc,0xb2,0x9f,0xbc,0xb0,0x9e,0xba,0xb0,0x9d,0xbb,0xb1,0x9e,0xbb,0xb0,0x9e,0xbb,0xb1,0x9e,0xba,0xaf,0x9c,0xb9,0xae,0x9c,0xb9,0xae,0x9c,0xb8,0xaf,0x9d,0xb9,0xad,0x9b,0xb7,0xad,0x9a,0xb7,0xad,0x9a,0xb8,0xac,0x99,0xb6,0xab,0x99,0xb6,0xac,0x98,0xb6,0xab,0x98,0xb6,0xab,0x99,0xb5,0xa9,0x97,0xb4,0xa9,0x97,0xb5,0xaa,0x97,0xb4,0xa8,0x95,0xb3,0xa8,0x95,0xb2,0xa7,0x95,0xb3,0xa7,0x93,0xb1,0xa6,0x93,0xb1,0xa5,0x91,0xaf,0xa5,0x91,0xb0,0xa4,0x91,0xaf,0xa5,0x92,0xb0,0xa4,0x91,0xb0,0xa5,0x92,0xaf,0xa3,0x90,0xae,0xa3,0x90,0xad,0xa3,0x8f,0xae,0xa2,0x90,0xae,0xa1,0x8e,0xac,0xa1,0x8e,0xad,0xa2,0x8e,0xac,0x9f,0x8d,0xab,0xa0,0x8d,0xab,0xa0,0x8c,0xab,0xa0,0x8d,0xaa,0x9f,0x8c,0xaa,0x9f,0x8c,0xab,0x9e,0x8a,0xaa,0x9e,0x8b,0xa9,0x9e,0x8b,0xaa,0x9e,0x8a,0xa9,0x9d,0x8a,0xa9,0x9c,0x88,0xa7,0x9c,0x88,0xa8,0x9c,0x89,0xa7,0x9c,0x89,0xa8,0x9a,0x87,0xa6,0x9b,0x87,0xa6,0x9b,0x86,0xa6,0x9b,0x87,0xa7,0x19,0x15,0x1c,0x4a,0x42,0x4f,0x3b,0x34,0x3f,0x39,0x30,0x3f,0x24,0x1e,0x27,0xff,0xff,0xff,0x8f,0x6b,0x6d,0x0,0x0,0x0,0x0,0x22,0x74,0x52,0x4e,0x53,0x0,0x1,0x3,0x6,0x8,0x9,0x2,0xc,0x1e,0x33,0x41,0x46,0xd,0x31,0x9a,0xe3,0x5,0x24,0xb4,0x39,0xf4,0x44,0xa,0x47,0x45,0x3d,0xf8,0x2a,0xcd,0x11,0x3f,0xd3,0xfd,0x2b,0x85,0xa8,0x7,0x57,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x6e,0x22,0xf,0x51,0x17,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x1,0x53,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd4,0x69,0x57,0x1,0x51,0x18,0xc0,0xf1,0x8b,0x99,0xb1,0x8c,0x65,0x6c,0x63,0x9d,0xc1,0x10,0xd1,0xc4,0x44,0x23,0x6b,0xb2,0x55,0xa8,0x24,0x92,0xb2,0x15,0x45,0x8a,0xef,0xff,0xb6,0x6b,0xba,0x39,0x4e,0xbd,0xe8,0xb,0xf8,0x9f,0xe7,0xdc,0x73,0x9e,0xdf,0xfb,0xe7,0x2,0x0,0x64,0x72,0x5,0x86,0xc3,0x30,0x85,0x5c,0x6,0x60,0x84,0x52,0xa5,0xd6,0x90,0x30,0x8d,0x5a,0xa5,0x24,0xe0,0xae,0xd5,0xe9,0xd,0x9c,0x94,0x41,0xaf,0xd3,0x12,0x80,0x32,0x9a,0xfc,0x81,0x3d,0xa9,0x80,0xdf,0x64,0xa4,0x0,0x66,0xb6,0x4,0x43,0xfb,0x52,0xa1,0xa0,0xc5,0x8c,0x1,0xdc,0xca,0x85,0x23,0x7,0x61,0x9e,0xe7,0x23,0x3c,0xcf,0x59,0x71,0x40,0xdb,0xb8,0xc3,0x68,0x34,0x1a,0x83,0x13,0x8b,0x71,0x36,0x1a,0xe0,0x24,0x27,0x1c,0x9,0x71,0x21,0x9e,0x48,0x8,0xc7,0x8,0xc4,0xe4,0x49,0x4a,0x4c,0x8a,0x29,0x51,0x44,0x90,0xce,0x64,0xd2,0xe9,0x2c,0x9c,0x2c,0x82,0x5c,0x3e,0x97,0x3b,0xcd,0x17,0xf2,0x67,0x5,0x4,0x45,0x58,0xa9,0x5c,0x2a,0x96,0xcb,0x8,0x2a,0xd5,0x6a,0x65,0xdd,0x79,0x5,0xc1,0xc5,0xe5,0xba,0xf5,0x8b,0xa0,0x56,0x6f,0xd4,0xae,0x1a,0x8d,0xfa,0xf5,0xd,0x82,0xe6,0x6d,0xb3,0xd9,0x6a,0xc1,0xb9,0x43,0xd0,0x6e,0x77,0xee,0xdb,0xb0,0x4e,0x1b,0x41,0xf7,0xa1,0xf7,0xf8,0xd4,0xef,0xf6,0x7b,0x7d,0x4,0x83,0xe1,0x68,0x38,0x1c,0xd,0xc6,0xe3,0x67,0x4,0x2f,0x93,0xe9,0x74,0x3a,0x81,0xbd,0x22,0x78,0x9b,0xc1,0xe6,0xf3,0xd9,0xec,0x1d,0xc1,0x56,0x12,0x2c,0x3e,0x36,0x2d,0xbe,0xe1,0x73,0xd3,0xe,0x76,0xf0,0x1f,0xd0,0xb6,0xdf,0x60,0xdf,0x6,0x3b,0xd,0x30,0x87,0x73,0xf9,0xb3,0x2f,0x9d,0xe,0xc,0x50,0x2e,0xf7,0xa,0xc9,0x72,0xe5,0x76,0x51,0x80,0x60,0x58,0x8f,0x77,0x21,0xe5,0xf5,0xb0,0xc,0xbc,0x75,0x39,0xe3,0x63,0x49,0x1b,0x8c,0x64,0x7d,0x8c,0x5c,0xfa,0xd,0x14,0x38,0x2d,0x85,0x2b,0x8,0xf0,0xb7,0x2f,0x56,0x15,0x7,0x92,0x8b,0x88,0xb4,0x10,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x7,0x1d,0x1,0x8,0x10,0x1e,0x6f,0x12,0x2b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char graph_node_breakpoint_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x6,0xf,0x3b,0x1c,0xec,0x64,0x51,0x75,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x8f,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xd7,0xbd,0x9,0xc0,0x20,0x10,0x5,0xe0,0x53,0x2c,0x5d,0x40,0x74,0x4,0xf7,0x9f,0xc4,0x11,0x22,0x2e,0x60,0x6f,0x9a,0x13,0x4e,0x21,0x41,0x50,0x48,0x91,0x77,0x95,0xf8,0xf3,0x79,0x62,0xf5,0x88,0x36,0x4b,0xf5,0x41,0x2d,0xf1,0x22,0x22,0xbf,0x78,0x2e,0x5b,0x97,0x2,0xc9,0xc3,0xc,0x2c,0x95,0xdc,0x6f,0x78,0xce,0x5b,0x97,0xd4,0x42,0x27,0xd9,0xba,0x14,0xac,0x4b,0xa1,0x96,0xd8,0x24,0x20,0x9f,0x41,0x1d,0x7b,0xba,0x59,0xb6,0xaf,0xa7,0x3d,0x7e,0x78,0xdb,0x54,0xbc,0x36,0x74,0xa7,0x77,0x7f,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e,0x4,0xe4,0xb7,0xfc,0xc8,0x6b,0x59,0xce,0x99,0x39,0x95,0x71,0xb4,0x6b,0x4b,0x89,0xf5,0x44,0x72,0x3d,0x93,0x9d,0x3f,0xad,0x1b,0x54,0xed,0x49,0xd3,0x36,0x45,0x4f,0x1f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char graph_node_close_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x4,0x0,0x0,0x0,0xfc,0x7c,0x94,0x6c,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x75,0x90,0x4b,0xe,0x80,0x20,0xc,0x44,0x47,0x57,0x53,0x64,0x2b,0x91,0x9b,0x71,0x6e,0x49,0x30,0xd1,0xbb,0x80,0xb,0xa2,0xb6,0x26,0x74,0x37,0x9f,0x34,0xaf,0x5,0x20,0xc9,0x7,0xa8,0xf1,0x41,0x12,0x0,0x49,0xac,0xcc,0x5f,0xe4,0x3,0x33,0xab,0x24,0xf8,0x55,0x76,0x36,0x1e,0x2e,0x2,0x78,0xd5,0xb2,0x29,0xe1,0xa2,0xb1,0x55,0xef,0x64,0x31,0x76,0x8f,0x58,0xd8,0xd8,0x78,0x3d,0xf6,0x8c,0xdf,0xb4,0xc9,0xf4,0xf5,0xaa,0x8e,0x61,0x48,0xc,0xa1,0x25,0x51,0xd1,0xf0,0xc0,0xd1,0x4b,0x6e,0xc7,0xae,0x34,0x72,0x3,0xf5,0x60,0xdd,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x93,0x49,0x44,0x41,0x54,0x28,0x91,0x95,0x92,0x31,0xe,0xc2,0x30,0x10,0x4,0x17,0xaa,0x3d,0x7b,0xdb,0x58,0xa4,0xa7,0xe1,0x47,0xfe,0x2c,0x3c,0x82,0x48,0x44,0x22,0x6f,0xb1,0x4d,0x15,0xc9,0x20,0x1f,0x52,0xae,0xdd,0xd9,0x2b,0xe6,0xe,0x0,0x60,0x66,0x59,0x52,0x82,0x33,0x92,0x92,0x99,0x65,0xec,0x30,0xc9,0x4a,0x72,0x19,0x95,0x24,0x25,0x92,0xb,0xc9,0x6a,0x66,0x19,0x92,0x26,0x33,0x7b,0x92,0x6c,0x24,0xd7,0x10,0xc2,0xdc,0xc1,0x5f,0x59,0x8c,0xf1,0x32,0xc,0x42,0x8,0xb3,0xb,0x3b,0xdb,0xde,0x24,0x5f,0x2e,0xdc,0x97,0x3a,0xb0,0x91,0xdc,0x7e,0xe1,0xb3,0x67,0x66,0x9f,0xd6,0xda,0x69,0x58,0x90,0x34,0x95,0x52,0xee,0x0,0x6e,0x0,0x36,0x0,0x2b,0x80,0x6b,0xad,0xf5,0xd1,0x8b,0x70,0x6d,0xb8,0xf6,0xfe,0xd9,0x18,0x96,0xe,0x1f,0xe,0x38,0xf6,0x1a,0x1f,0x9f,0xec,0x40,0x47,0x56,0x51,0x84,0x77,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -119,8 +124,13 @@ static const unsigned char graph_node_default_focus_png[]={ }; +static const unsigned char graph_node_position_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x6,0xf,0x3b,0x3b,0x49,0x6e,0xe4,0x1e,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x90,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xd7,0xbd,0x9,0xc0,0x20,0x10,0x5,0xe0,0x53,0x2c,0xdd,0x40,0x47,0x70,0x7,0x67,0x77,0x7,0x47,0x88,0x1b,0xd8,0x9b,0xe6,0x84,0x53,0x48,0x10,0x14,0x52,0xe4,0x5d,0x25,0xfe,0x7c,0x9e,0x58,0x3d,0xa2,0xcd,0x52,0x7d,0x50,0x63,0xb8,0x88,0xc8,0x2d,0x9e,0x2b,0x36,0x65,0x4f,0xf2,0x30,0x3,0x4b,0x25,0xf7,0x1b,0x9e,0x73,0x36,0x65,0xb5,0xd0,0x49,0xb1,0x29,0x7b,0x9b,0xb2,0xaf,0x31,0x34,0x9,0xc8,0x67,0x50,0xc7,0x9e,0x6e,0x96,0xed,0xeb,0x69,0x8f,0x1b,0xde,0x36,0x15,0xaf,0xd,0xdd,0xe9,0xdd,0x5f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x1f,0x1,0xe5,0x2d,0x3f,0xf2,0x5a,0x91,0x73,0x66,0x4e,0x65,0x1c,0xed,0xda,0x52,0x62,0x3d,0x91,0x5c,0xcf,0x64,0xe7,0x4f,0xeb,0x6,0x80,0xff,0x44,0x93,0xd4,0xd9,0xea,0x7e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + static const unsigned char graph_node_selected_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x3,0x0,0x0,0x0,0x24,0xa3,0x7,0xa4,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0xd8,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xd,0x10,0x17,0x14,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x10,0x13,0x0,0x0,0x0,0x19,0x17,0x1b,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x16,0x12,0x19,0x0,0x0,0x0,0xe,0xb,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0xb,0x10,0x16,0x12,0x19,0x0,0x0,0x0,0x1d,0x1a,0x1f,0x35,0x2f,0x38,0x94,0xd6,0x84,0xa4,0xdc,0x95,0x99,0xd8,0x8a,0x8c,0xd3,0x7b,0x8b,0xd2,0x79,0x88,0xd1,0x76,0x87,0xd1,0x74,0x86,0xd0,0x73,0x85,0xd0,0x71,0x83,0xcf,0x70,0x82,0xcf,0x6f,0x81,0xce,0x6d,0x7f,0xce,0x6c,0x7b,0xcc,0x67,0x7d,0xcd,0x68,0x7a,0xcc,0x65,0x79,0xcb,0x64,0x76,0xca,0x61,0x75,0xca,0x60,0x78,0xcb,0x62,0x74,0xc9,0x5e,0x72,0xc9,0x5c,0x70,0xc8,0x59,0x71,0xc8,0x5b,0x6d,0xc7,0x57,0x6f,0xc7,0x58,0x6c,0xc6,0x55,0x68,0xc4,0x51,0x67,0xc4,0x4f,0x69,0xc5,0x52,0x19,0x15,0x1c,0x4a,0x42,0x4f,0x3b,0x34,0x3f,0x39,0x30,0x3f,0x24,0x1e,0x27,0xff,0xff,0xff,0x23,0xbb,0x3,0x70,0x0,0x0,0x0,0x22,0x74,0x52,0x4e,0x53,0x0,0x1,0x3,0x6,0x8,0x9,0x2,0xc,0x1e,0x33,0x41,0x46,0xd,0x31,0x9a,0xe3,0x5,0x24,0xb4,0x39,0xf4,0x44,0xa,0x47,0x45,0x3d,0xf8,0x2a,0xcd,0x11,0x3f,0xd3,0xfd,0x2b,0x85,0xa8,0x7,0x57,0x0,0x0,0x0,0x1,0x62,0x4b,0x47,0x44,0x47,0x60,0xbd,0xc9,0x7b,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x1,0x7,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd4,0xd9,0x5a,0x82,0x40,0x14,0xc0,0xf1,0x23,0x9b,0xb,0x2e,0xb8,0x81,0x1b,0xa8,0x23,0x59,0xb1,0xa4,0x51,0x60,0x81,0x85,0x52,0xf8,0xfe,0x8f,0xd4,0x71,0x3a,0xcd,0xe7,0x57,0x17,0xbd,0x80,0xbf,0x99,0x73,0x71,0xfe,0xf7,0x33,0x0,0x50,0x91,0x64,0x45,0x45,0x8a,0x2c,0x55,0x0,0x69,0xd5,0x5a,0xbd,0xa1,0xa3,0x46,0xbd,0x56,0xd5,0x70,0x6f,0xb6,0xda,0x1d,0xc6,0x75,0xda,0xad,0xa6,0x6,0x46,0xb7,0xb7,0x72,0x6f,0x38,0x77,0xd5,0xeb,0x1a,0xa0,0xf4,0x7,0x6b,0xf7,0x96,0x73,0xd7,0x83,0xbe,0x2,0xea,0x90,0xdd,0x9,0x6c,0xa8,0x82,0x69,0xb1,0x7b,0xe4,0xe1,0xf5,0x3c,0x66,0x99,0xa0,0xea,0xcc,0xf3,0x3d,0x42,0x21,0x8,0x43,0x3f,0x8,0x3,0x3f,0x8,0x28,0x3c,0x8,0x14,0x36,0x68,0x8b,0x67,0xb3,0xa5,0xf0,0x88,0xa2,0x28,0xc2,0xa1,0xf0,0x24,0x50,0x78,0x16,0x28,0xc4,0x71,0x12,0xef,0x92,0x24,0x4e,0x76,0x14,0x5e,0x4,0xa,0xaf,0x2,0x85,0x34,0xcb,0xb2,0x14,0x65,0x29,0x85,0xfd,0xdb,0xd9,0x1e,0x51,0x78,0x17,0x28,0xe4,0x67,0x87,0x43,0x9e,0x1f,0x29,0x5c,0xe0,0xa1,0xf8,0x10,0x8a,0xef,0xf0,0x29,0x5c,0xc3,0x35,0xfc,0x17,0x4c,0xeb,0x77,0x18,0x5d,0x86,0x91,0x9,0xca,0x78,0x52,0xfe,0xec,0xe5,0x64,0xac,0x80,0x31,0x9d,0x9d,0xa8,0x94,0xa7,0xd9,0xd4,0x0,0xcd,0x76,0xe6,0x8b,0x82,0x5b,0xcc,0x1d,0x1b,0xdf,0xba,0x64,0x2f,0x1d,0xdd,0x42,0xba,0xb3,0xb4,0x25,0xfe,0x1b,0xc8,0xaa,0xc9,0xa9,0xb2,0x6,0x7f,0x7d,0x1,0x5d,0xdd,0xb5,0x61,0x26,0xcd,0x71,0x81,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xc9,0xad,0xc8,0x52,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x39,0x3a,0x32,0x36,0x2b,0x30,0x32,0x3a,0x30,0x30,0xb8,0xf0,0x70,0xee,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x6,0xc,0x29,0x12,0x71,0x6e,0xb2,0xf8,0x0,0x0,0x3,0x37,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0x4f,0x88,0xdc,0x74,0x14,0xc7,0xbf,0xef,0x97,0x7f,0x9b,0xcc,0xee,0xec,0x64,0x64,0x76,0x5,0xd1,0xd5,0xc2,0x6e,0x41,0x8f,0xbd,0xef,0x49,0x7a,0x10,0xa,0xeb,0x61,0xa1,0xb5,0x16,0xc4,0xa3,0x87,0xbd,0xb9,0x17,0x8f,0x5e,0xa4,0xc7,0x16,0xbc,0x8,0xa2,0xdb,0x16,0xf,0x7b,0xb0,0x50,0x28,0x54,0x7a,0xea,0xdd,0xa3,0x82,0x16,0x14,0x5,0xc1,0xd9,0xe9,0x4e,0x32,0x3b,0xc9,0x64,0x26,0xbf,0xe4,0xf7,0x3c,0x24,0xd9,0x26,0x99,0x35,0x73,0xf0,0x26,0xf3,0x60,0x66,0x12,0xe6,0xbd,0xcf,0xf7,0xbd,0xef,0xef,0x17,0xc8,0x8f,0x98,0x99,0x0,0x88,0x47,0x8f,0x7e,0xb4,0x92,0xa1,0x67,0xf,0xcf,0x6,0x96,0x62,0x25,0xa4,0x8c,0x9,0xa5,0x30,0xc,0x93,0x5,0x9,0xd5,0x6d,0xf7,0x66,0x7a,0xd7,0x8d,0xae,0x5d,0xbb,0x32,0x3,0xa0,0x88,0x99,0xb5,0x87,0xdf,0x3c,0x5c,0x1b,0x85,0x93,0xd7,0x86,0xbe,0x7f,0x69,0x34,0xf2,0x36,0x83,0x30,0x70,0xe2,0x38,0xd6,0xcb,0x0,0xd3,0x34,0x93,0xd5,0xd6,0xea,0x64,0x7d,0xdd,0xed,0x77,0x3b,0x9d,0xdf,0xd6,0x5b,0xce,0x5f,0x7b,0x1f,0xed,0x8d,0xe9,0xe8,0xe8,0x49,0x2b,0x1e,0xf6,0xdf,0xf2,0x46,0xc3,0xdd,0xf7,0x6f,0xec,0xde,0x31,0x2d,0x5d,0x43,0x43,0xc4,0xb3,0x24,0xfd,0xfe,0xbb,0x67,0x7,0xee,0x7a,0xf7,0x99,0xd9,0xdd,0xfc,0x5d,0x48,0xcf,0x77,0xfa,0x2f,0x4e,0x76,0xf6,0xae,0xef,0xde,0x65,0x66,0x6d,0x7a,0xda,0x46,0x12,0xb8,0x48,0xc3,0x6e,0xe5,0x93,0x4,0x2e,0xa6,0xa7,0x6d,0x30,0xb3,0xb6,0x77,0x7d,0xf7,0x6e,0xff,0xc5,0xc9,0x8e,0xf4,0x7c,0x47,0x8f,0x93,0xc8,0xc,0x83,0xf1,0x86,0xb5,0xa2,0x8b,0x99,0xb7,0x6,0x12,0x84,0x44,0x2a,0x50,0x4d,0x99,0x1,0x90,0x20,0x20,0xea,0xc2,0x72,0xc7,0x22,0xc,0xc6,0x1b,0xb1,0x1b,0x99,0x42,0xb1,0x12,0x93,0x68,0x62,0x3,0x40,0x2a,0x19,0xcc,0x79,0xb1,0xaa,0x56,0x13,0x18,0xcc,0x8c,0x34,0x61,0x0,0xc0,0x24,0x9a,0xd8,0x8a,0x95,0x10,0x52,0x4a,0x4a,0x91,0x12,0x0,0x30,0x65,0xba,0xcc,0xc,0x88,0x5c,0x16,0x0,0x8,0x60,0x5,0x80,0x19,0xe0,0x2c,0x27,0x45,0x4a,0x52,0x4a,0xd2,0xd,0xc3,0x60,0xa4,0x79,0xa2,0x62,0x30,0x8,0x20,0xc6,0xf9,0xc,0x39,0x84,0x99,0x2b,0xbf,0x45,0x4d,0x65,0xa9,0x98,0x19,0x20,0x2,0xc0,0x28,0xf2,0xea,0xc1,0xb5,0x3f,0xf4,0xda,0xbf,0x60,0x95,0x27,0x10,0x97,0xdc,0x2b,0x75,0xd3,0x4,0xe0,0x4c,0xbb,0x7c,0x93,0x15,0xab,0x97,0x90,0x7a,0x67,0x15,0x80,0x52,0xa5,0xd9,0x73,0xf7,0x88,0x73,0x5f,0x98,0x41,0x8b,0x47,0x28,0x4b,0x50,0xa9,0x9f,0xec,0x5b,0x2d,0xea,0x0,0xac,0xc0,0xaa,0x66,0xff,0xbc,0x8b,0xd,0x1e,0xe4,0x73,0xe7,0x4d,0x23,0xdf,0x3e,0xc5,0x30,0xd9,0x55,0x53,0x7,0x19,0x40,0xe5,0x85,0x25,0x35,0x7a,0x39,0xbb,0x6a,0x6,0xa8,0xac,0xbe,0xa2,0x5d,0x56,0xa5,0xc5,0xcb,0x48,0xc5,0x7e,0xa0,0x62,0x33,0x51,0xe1,0x67,0xfe,0x3c,0x34,0x75,0xa0,0xb2,0xc2,0x39,0x25,0x85,0xf3,0x15,0xa9,0x5b,0x3b,0xbf,0x95,0xb9,0xfe,0x28,0x36,0xc7,0xbc,0x89,0x75,0x8d,0x92,0x91,0xb5,0x8b,0x79,0xc0,0x67,0x9f,0x7f,0x8a,0x9f,0x7f,0xfd,0xa9,0x51,0xf1,0xed,0x9d,0x77,0xf0,0xd5,0xb7,0x5f,0x5c,0xc,0xb8,0xb4,0xb5,0xd,0x4d,0x18,0x8d,0x80,0xad,0xd7,0xdf,0xfc,0xf7,0xe,0xc2,0x30,0xc0,0xe8,0xcc,0x6f,0x4,0x84,0x61,0x50,0xb9,0x17,0xf8,0x8f,0xb1,0x4,0x2c,0x1,0x4b,0xc0,0x12,0xb0,0x4,0x2c,0x1,0x4b,0xc0,0xff,0xf,0x20,0xa5,0x24,0x68,0x17,0xbe,0xfe,0x5c,0x1c,0x45,0x8e,0x56,0xea,0x40,0x83,0xc6,0x0,0x60,0xe8,0xfa,0xc2,0xfa,0x22,0xa7,0xa8,0x11,0x96,0x69,0xa5,0x96,0x69,0xc6,0x0,0xe0,0xd8,0xab,0xb,0x1,0x45,0x8e,0x65,0x9a,0xb1,0x65,0x5a,0xa9,0x6e,0xea,0x76,0xbc,0x62,0x3b,0x83,0xd9,0x54,0xf2,0xc1,0xe1,0x7,0x74,0xe7,0x36,0x61,0x12,0x8d,0x21,0x93,0xa4,0x72,0xe8,0x32,0x74,0x1d,0x8e,0xbd,0x86,0x83,0xc3,0x1b,0x98,0x4d,0x25,0xaf,0xd8,0xce,0xc0,0xd4,0xed,0x98,0x8e,0x8e,0x9e,0xb4,0x4e,0xff,0x7c,0xbe,0xed,0x9f,0x79,0xef,0x7e,0xf8,0xf1,0x7b,0xb7,0x2d,0xdb,0x68,0x74,0x62,0x16,0x49,0xbe,0xff,0xf5,0xe3,0xc3,0x4e,0xdb,0x7d,0xfa,0xca,0x1b,0xdb,0xcf,0x89,0x99,0xb5,0x7,0x5f,0x3e,0x68,0xf,0x3c,0x7f,0xcb,0xf3,0xfd,0xcb,0x93,0x28,0xdc,0x90,0x52,0x1a,0x4a,0x55,0xdf,0x56,0x85,0x10,0x30,0xc,0x43,0x3a,0x76,0xeb,0xc4,0xed,0x74,0x7e,0xe9,0xb9,0x9d,0x3f,0x6e,0x7e,0x72,0xf3,0x8c,0x8a,0xd3,0xfb,0xbd,0x7b,0x3f,0xac,0x4,0x7f,0xf7,0x5b,0x52,0xcd,0x4c,0x66,0x75,0xe1,0xf2,0x12,0x9,0x65,0x8,0x2b,0x5e,0x7d,0x75,0x33,0xbc,0x75,0xeb,0xea,0x14,0xc0,0xf9,0xf1,0x4,0xcc,0x4c,0xc7,0xc7,0xc7,0xa2,0xd7,0xeb,0x35,0x8e,0x30,0x18,0xc,0x78,0x7f,0x7f,0x5f,0x11,0x65,0xc7,0xba,0x7f,0x0,0xff,0xc4,0xaa,0x19,0xfd,0xaf,0x1e,0xb7,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -165,32 +175,37 @@ static const unsigned char hsplitter_png[]={ static const unsigned char icon_add_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x0,0x0,0x0,0x0,0x3a,0x98,0xa0,0xbd,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x74,0x52,0x4e,0x53,0x0,0x0,0x76,0x93,0xcd,0x38,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x21,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0xc0,0x1,0x1e,0x3c,0x80,0x32,0x98,0xd0,0x65,0xa8,0x21,0xc0,0xc8,0xf0,0x0,0x85,0xaf,0x80,0xa1,0x82,0x3e,0xee,0xc0,0x0,0x0,0x13,0x86,0x4,0x98,0x60,0x93,0x6c,0x5a,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x36,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0xa0,0x25,0x78,0xf0,0xe0,0xc1,0xff,0x7,0xf,0x1e,0xfc,0xc7,0xa7,0x86,0x89,0x52,0x4b,0x46,0xd,0x60,0x60,0x60,0x64,0x60,0x80,0x84,0x36,0x39,0x9a,0x15,0x14,0x14,0x18,0x29,0x76,0x1,0x5e,0x30,0x9a,0xe,0xe8,0x64,0x0,0xc5,0x0,0x0,0xc7,0x6e,0x12,0x94,0xf9,0x26,0x2e,0xdb,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_close_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x28,0xcf,0xad,0x90,0xd1,0xa,0x80,0x20,0xc,0x45,0xad,0xa7,0x6b,0xee,0x35,0xb1,0x3f,0xf3,0xbb,0x13,0xc,0xea,0x5f,0x5c,0xf,0x42,0x4d,0x1c,0x14,0xd4,0xde,0xc6,0x39,0xd3,0xdd,0x19,0xf3,0x53,0xd9,0x48,0x5e,0xf6,0xe4,0x6d,0x6c,0x30,0xa,0xd2,0xad,0x90,0x47,0x42,0x11,0xa,0xcd,0x76,0x5,0x63,0x9b,0x16,0xd9,0xb9,0x20,0x9f,0xbc,0x14,0x15,0xb,0x65,0x47,0x56,0x71,0x55,0x90,0xc1,0x60,0x1c,0x12,0x8f,0x5a,0x26,0x1e,0xd4,0x79,0xf9,0x45,0x5d,0x57,0x59,0xd2,0x85,0x36,0x51,0x87,0xfb,0xd0,0xef,0xe,0xf5,0x78,0xea,0x4f,0x75,0x2,0x30,0x98,0x34,0x72,0xa,0x11,0xfb,0xc2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9b,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x92,0x31,0xe,0xc2,0x30,0x10,0x4,0x17,0xaa,0x3d,0x67,0xdb,0x58,0xd0,0xd3,0xf0,0xa3,0x7c,0x36,0x3c,0x82,0x48,0x44,0x22,0x6f,0xb1,0x4d,0x85,0x14,0x81,0xf,0x2c,0x28,0xe0,0xda,0xd5,0x8c,0x4e,0x77,0xb,0xfc,0xd5,0x98,0xd9,0x20,0x29,0x7a,0xb9,0xa4,0x68,0x66,0x83,0xb,0x93,0xcc,0x24,0xa7,0x9a,0x44,0x52,0x24,0x39,0x91,0xcc,0x55,0x89,0xa4,0xde,0xcc,0xce,0x24,0xb,0xc9,0x39,0x84,0xb0,0xf7,0xb2,0xae,0xeb,0x76,0xde,0x8a,0x4f,0x92,0x66,0xd8,0x91,0x5c,0x49,0x5e,0x9a,0xe1,0xb5,0x64,0x5,0x16,0x92,0x8b,0x7,0x6f,0x9b,0x8c,0x0,0x4a,0x29,0x9b,0x26,0x81,0xa4,0x3e,0xa5,0x34,0x2,0x38,0x2,0x58,0x0,0xcc,0x0,0xe,0x39,0xe7,0xd3,0xfa,0xb0,0xee,0xea,0x8f,0x7,0x7b,0xf5,0x9d,0xb7,0xb0,0x97,0x55,0x25,0x5f,0x17,0xe9,0x2e,0xf9,0xb8,0xca,0x3f,0x9b,0x1b,0x1a,0xe3,0x40,0x47,0xa0,0xda,0xda,0x61,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_color_pick_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0xe0,0x49,0x44,0x41,0x54,0x28,0xcf,0x95,0x91,0xbf,0x6a,0xc2,0x60,0x14,0xc5,0xcf,0x17,0x82,0xcf,0xd0,0xad,0x75,0x13,0x12,0xa1,0x5b,0xc0,0xdd,0x35,0xe0,0x50,0xfc,0x43,0xfb,0x8,0x6e,0x8e,0x3e,0x44,0x1f,0xa0,0xf,0xd0,0xa9,0x88,0x53,0x85,0x3a,0x38,0x74,0x12,0xc1,0x45,0x1c,0x8c,0xf9,0xce,0x27,0x89,0xa0,0x19,0x3a,0x17,0xe2,0x17,0x87,0xb4,0x60,0x9a,0x48,0xc9,0x99,0xee,0xe5,0x7,0xe7,0x5e,0xce,0x1,0xca,0x4a,0x59,0xab,0xa,0xc0,0x16,0xf7,0x3c,0xb0,0x5,0x88,0x2c,0x96,0x8e,0x78,0x17,0xb3,0xd3,0x9b,0x78,0x11,0x26,0x80,0xe3,0xdd,0x8d,0xf9,0xc7,0xe0,0x1b,0x71,0xe2,0x1a,0xee,0xcf,0x16,0x3,0x46,0x96,0x57,0x97,0x78,0xfe,0x9d,0x93,0x18,0xfd,0xdc,0x7,0xb2,0xc3,0x90,0x3d,0x46,0xd4,0xd4,0xfe,0x53,0x21,0xf6,0x6c,0x40,0x76,0xa9,0xa9,0xd5,0x68,0x55,0x29,0xc4,0xca,0x62,0xe0,0xf,0x19,0xf1,0x4b,0x59,0x57,0xb0,0xec,0x0,0xf2,0x5e,0x3a,0x17,0xd8,0x7f,0x60,0xb0,0xad,0x3,0xb2,0xa6,0x76,0xfe,0x63,0xee,0xf6,0x3f,0x98,0x8d,0xd4,0xdc,0xb3,0x53,0xf3,0xac,0xc,0x40,0x34,0xb1,0x4e,0x36,0x9e,0x6d,0x4e,0x92,0x41,0xf5,0xb5,0x28,0xfd,0x31,0x35,0x3f,0x18,0xca,0x76,0x51,0x37,0x2,0xe0,0x5c,0xec,0xb1,0xc0,0xf4,0xf6,0xb3,0x74,0xb3,0x0,0x70,0x6,0x95,0x2,0x6f,0xae,0x29,0xa4,0x96,0x25,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0xe3,0xb6,0x51,0xb2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0x92,0xeb,0xe9,0xe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x1,0x55,0x49,0x44,0x41,0x54,0x38,0x8d,0xb5,0x92,0xb1,0x4a,0x3,0x41,0x14,0x45,0xef,0xdb,0x6c,0xac,0xf2,0x1,0xda,0xcd,0x40,0x4,0x25,0x11,0x4,0x8b,0x80,0x8d,0x20,0x88,0x5d,0x20,0x88,0x90,0x22,0x9d,0x9d,0xa0,0x85,0x58,0xeb,0x7,0x88,0xe0,0x7,0x58,0x8b,0x36,0x5a,0x88,0xa0,0xa5,0x85,0xa5,0x60,0x61,0xb0,0x70,0xb2,0xef,0x8d,0x44,0x41,0x21,0x1f,0x20,0x6c,0xf2,0x2c,0xcc,0xc2,0x12,0x92,0x8d,0x45,0xbc,0xe5,0xdc,0xb9,0x67,0xee,0xbc,0x19,0xe0,0xbf,0xe5,0xbd,0x2f,0x35,0x9b,0xcd,0x29,0x0,0x10,0x91,0x9a,0x88,0x7c,0x88,0xc8,0xa7,0x88,0xd4,0x0,0x80,0xb2,0xc2,0xcc,0x5c,0x21,0xa2,0x5b,0x22,0xba,0xef,0x76,0xbb,0x97,0x44,0x74,0x4a,0x44,0x61,0xdf,0xfe,0x32,0xc6,0x4c,0x87,0x59,0x0,0x0,0xdf,0x0,0x62,0x55,0xad,0x6,0x41,0x50,0x1d,0xf0,0x62,0x0,0x8,0xb2,0xd2,0xd6,0xda,0x27,0x0,0x27,0x83,0xeb,0xaa,0x1a,0x3,0xd8,0x19,0xb,0x60,0xe6,0x3a,0x80,0x6d,0x0,0xd,0x0,0x9d,0x14,0x60,0xcb,0x18,0x73,0x95,0x9,0x60,0xe6,0x3a,0x11,0x1d,0xc7,0x71,0xbc,0x6e,0x8c,0x39,0x53,0xd5,0xdd,0xc4,0xcb,0xe5,0x72,0x1b,0xc9,0x60,0x87,0x2,0xd2,0xe1,0x62,0xb1,0xf8,0xec,0xbd,0x2f,0x11,0xd1,0x51,0xaf,0xd7,0x3b,0x0,0xd0,0x51,0xd5,0x95,0x42,0xa1,0x30,0x3b,0xf2,0x64,0x11,0x79,0x77,0xce,0x95,0x81,0xdf,0x67,0x14,0x91,0x76,0xff,0x3a,0x60,0xe6,0x45,0x66,0xae,0xc,0xd,0x47,0x51,0xb4,0x29,0x22,0xed,0x56,0xab,0xb5,0xd0,0xdf,0x3c,0xe7,0xbd,0x7f,0x8b,0xa2,0xa8,0x31,0x7a,0x52,0x93,0x8,0x8b,0xc8,0x72,0xba,0xb6,0x73,0xae,0x9c,0xae,0x9d,0xa5,0x0,0x0,0x88,0x68,0xd,0xc0,0x8b,0xaa,0xbe,0x3a,0xe7,0xca,0x61,0x18,0xde,0xa9,0xea,0xbe,0xb5,0xf6,0x7c,0x1c,0x20,0xf9,0x89,0x4b,0x0,0x56,0xf3,0xf9,0xfc,0xd,0x80,0x79,0x55,0xdd,0xb3,0xd6,0x5e,0x8c,0xad,0x9e,0x0,0x54,0x75,0x86,0x88,0xae,0x1,0x3c,0x2,0x38,0x34,0xc6,0x3c,0xfc,0x25,0x3c,0x11,0xfd,0x0,0x28,0x54,0xbb,0xfe,0xad,0x99,0xe5,0xb8,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_folder_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x40,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0xa0,0x14,0x30,0x32,0x30,0x3c,0x38,0xca,0x60,0x85,0x24,0x72,0x44,0xc1,0x16,0x5d,0xc1,0x7f,0x54,0x3d,0xa,0x8c,0xc8,0x3c,0x26,0x4c,0x43,0x1f,0xda,0x10,0x30,0x1,0xd5,0x3a,0x26,0x6,0x7c,0xc0,0x6,0xab,0x15,0xa8,0x60,0xc8,0x28,0x38,0x82,0x4b,0xf2,0xff,0x61,0x42,0xda,0x89,0x1,0x0,0x7c,0x5,0xb,0xf5,0x5d,0xb6,0xe9,0xbb,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0xe3,0xb6,0x51,0xb2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0x92,0xeb,0xe9,0xe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x5f,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x8f,0xc1,0xd,0x80,0x30,0x8,0x45,0x9f,0x9d,0x84,0x39,0x4c,0x3b,0xbd,0x75,0x8f,0x32,0x9,0x5e,0xec,0xa5,0x9,0xa4,0xc6,0x26,0x5e,0x7c,0x17,0xe,0xc0,0xe3,0x3,0x5f,0xb3,0x1,0xb4,0xd6,0x4e,0x60,0x77,0x66,0xaa,0x88,0x14,0x4f,0x90,0xee,0xea,0x2d,0x3,0xe4,0x28,0x41,0x8a,0x9a,0x1d,0x55,0x75,0x25,0xfd,0x5,0x9b,0x11,0xd,0x54,0x11,0x29,0x53,0x9,0x1c,0x32,0x4c,0xbe,0x10,0xf1,0xb,0x16,0xa,0xea,0xd3,0x45,0x33,0x3b,0xde,0x1e,0x5f,0xc3,0x5,0x1f,0xc5,0x12,0x2c,0xc5,0x88,0xe1,0xb4,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_play_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x6b,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0xa0,0x17,0x78,0x70,0xf8,0xc1,0xb5,0x7,0xde,0xf8,0x14,0xfc,0x7f,0xf0,0xff,0xc1,0xff,0x87,0x3b,0x1e,0x6a,0xa1,0xcb,0x30,0x21,0x73,0xfe,0xbb,0xff,0xbf,0xf8,0x60,0xca,0x13,0x61,0x64,0x31,0x46,0x98,0x9,0x48,0x62,0x1f,0x18,0x3b,0x7e,0x4d,0x50,0xfd,0x89,0x5b,0x1,0x3,0x3,0x3,0xc3,0x11,0x5,0x5b,0x2c,0x56,0x60,0x3,0xd8,0x14,0xbc,0x67,0xac,0xf8,0xed,0x2,0xe3,0xb0,0xa0,0x49,0xfe,0x61,0x98,0xc9,0x52,0x2f,0xf3,0x16,0x21,0x80,0xa2,0x80,0x71,0x27,0x43,0x91,0xfc,0x35,0xf2,0x2,0x8a,0x96,0x0,0x0,0xbc,0x2d,0x27,0xc4,0x79,0x12,0x82,0x82,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0xa2,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0xf2,0x80,0x11,0x99,0xf3,0xe0,0xc1,0x83,0xc3,0xc,0xc,0xc,0xc2,0xc,0xc,0xc,0xa5,0xa,0xa,0xa,0x5b,0xc9,0x31,0xe0,0x3f,0x5c,0x82,0x91,0x71,0x27,0x3,0x3,0x43,0x91,0xbc,0xbc,0xfc,0x35,0x7c,0x6,0x30,0xe1,0x92,0xf8,0xff,0xff,0xbf,0xfb,0xff,0xff,0xff,0x2f,0x3e,0x78,0xf0,0x60,0xca,0x93,0x27,0x4f,0x84,0x49,0x76,0x1,0x1a,0xf8,0xc0,0xc8,0xc8,0xd8,0xf1,0xeb,0xd7,0xaf,0x9,0xaa,0xaa,0xaa,0x3f,0x89,0x72,0x1,0x1a,0x10,0xf8,0xff,0xff,0x7f,0x7,0x2b,0x2b,0xeb,0x1e,0x74,0x9,0x62,0xd,0xc0,0x9,0x88,0x35,0xe0,0x3d,0x23,0x23,0x63,0xc5,0xef,0xdf,0xbf,0x5d,0xd0,0x25,0x58,0x8,0x68,0xfc,0xc3,0xc0,0xc0,0x30,0x93,0x85,0x85,0xa5,0x5e,0x46,0x46,0xe6,0x2d,0x36,0x5,0x38,0xd,0x20,0x36,0x1a,0xd1,0xd,0x38,0xc2,0x0,0x4d,0x48,0xf2,0xf2,0xf2,0x44,0x25,0xa4,0x61,0x0,0x0,0x1e,0x57,0x33,0x3c,0xcc,0xe7,0x34,0x69,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_reload_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0xe8,0x49,0x44,0x41,0x54,0x28,0xcf,0xa5,0x91,0x31,0x4e,0x2,0x51,0x10,0x86,0x3f,0x16,0x22,0x5b,0x10,0x88,0x5a,0x1a,0x4a,0x1b,0xd7,0x4,0x4a,0x6e,0x60,0x65,0xa3,0xc1,0xc4,0x8e,0x8e,0x46,0x38,0x90,0x5,0xa5,0x17,0x90,0x46,0xf,0x80,0x56,0x84,0x2,0x48,0xc,0xc9,0xee,0x3c,0x56,0xe,0x60,0xd0,0x64,0x2d,0xde,0x40,0xe3,0xbe,0xdd,0x4d,0xec,0x98,0x6a,0x26,0xf3,0x4d,0xe6,0x9f,0x7f,0xe0,0xd0,0x28,0x65,0xe9,0xaa,0x5a,0xe9,0x97,0xee,0xb9,0x4,0xe6,0xfa,0x64,0x1f,0xcf,0x7f,0xb,0x40,0x7c,0x66,0xc7,0xb4,0x72,0xa3,0xb3,0xf2,0x75,0x73,0x3,0x5e,0x3a,0x6d,0xc7,0xb4,0x88,0xe9,0x26,0x8d,0xa4,0xb1,0xbb,0xe1,0x83,0xb6,0x7d,0x5e,0x55,0x1d,0x1e,0xd,0x45,0xc5,0xc4,0x27,0x69,0x6d,0x8e,0xc5,0x88,0x86,0xf,0xe,0x90,0x77,0x51,0xb9,0xcd,0x8b,0xb,0xbb,0xa2,0x32,0x71,0x2b,0xb8,0x80,0xe4,0x35,0xf,0xd8,0x17,0x20,0x0,0xf,0x64,0x24,0x4a,0xd,0xfc,0x2f,0x19,0x65,0x80,0xf7,0x27,0xdf,0x3,0x7f,0xc0,0x12,0x80,0xa5,0x3f,0xc8,0xdd,0x7f,0x5,0x2c,0x52,0x49,0x81,0x6c,0x65,0x6b,0x82,0xac,0xfd,0x79,0x6a,0xd6,0x5,0x91,0x51,0x2f,0xea,0x39,0xc3,0xea,0xe1,0x9d,0x59,0x8b,0xca,0x74,0x71,0x54,0x70,0xd2,0x5d,0xa4,0xff,0x18,0x55,0x88,0x6f,0xde,0x74,0xf8,0xd3,0x69,0x6e,0xe,0x7e,0x24,0x0,0x7b,0x27,0x64,0x59,0x3b,0x41,0xb6,0x9a,0xe,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x1,0x59,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x92,0x31,0x4b,0x3,0x31,0x18,0x86,0x9f,0x5c,0xe,0xec,0x20,0x76,0x70,0x39,0xd0,0xe3,0xba,0x74,0x51,0x41,0xdd,0xfc,0x7,0xba,0xb8,0x8,0x52,0xec,0x2e,0x4e,0x3a,0x88,0x3f,0xa3,0xa3,0x53,0x7,0x47,0x67,0x41,0x17,0xdd,0x9c,0x5c,0x3b,0xd8,0x82,0x64,0x68,0xca,0xd5,0x55,0x11,0x3c,0x1a,0x87,0x24,0x2e,0xd7,0x72,0x9e,0x9e,0xab,0xbe,0xd3,0xc7,0x1b,0x9e,0x37,0xf9,0xbe,0x7c,0xf0,0xd7,0x12,0x3f,0x99,0x4a,0xa9,0xb9,0x30,0xc,0x8f,0x84,0x10,0x7,0xc0,0x5a,0x6e,0x3f,0x3a,0xe7,0x2e,0xad,0xb5,0xdd,0x66,0xb3,0xf9,0x51,0x19,0x90,0xa6,0xe9,0x92,0xb5,0xf6,0x6,0x58,0xaf,0xb8,0xb4,0x27,0xa5,0xdc,0x8d,0xe3,0xf8,0x19,0x20,0x28,0xdf,0x5c,0x80,0x53,0x60,0xdf,0x18,0x53,0x37,0xc6,0xd4,0xbd,0xf7,0x7b,0xc0,0x13,0xb0,0x61,0xad,0xbd,0x56,0x4a,0xcd,0x1,0x84,0xc5,0x80,0x30,0xc,0x8f,0xa6,0xb0,0x94,0x72,0x33,0x8e,0xe3,0x97,0xc2,0xf1,0xd5,0x68,0x34,0xba,0xf7,0xde,0xf7,0x80,0xd,0x29,0xe5,0x21,0x70,0xfe,0xe5,0x5,0x42,0x88,0x76,0x5e,0x9e,0x96,0x60,0x0,0x92,0x24,0x79,0x75,0xce,0x9d,0x1,0x4,0x41,0xd0,0xfe,0xd6,0x2,0xb0,0x2,0x60,0x8c,0xb9,0xab,0xe8,0x1f,0x6b,0xed,0x6d,0x5e,0xae,0xce,0x2,0xb4,0xd6,0x17,0x5a,0x6b,0x7,0xcc,0x3,0xd4,0x6a,0xb5,0x37,0xad,0xf5,0xc5,0x4f,0x1,0x41,0x10,0x7c,0x19,0x7c,0x90,0x3,0xc7,0xc0,0xa0,0xe0,0xf,0x72,0xef,0x9b,0x84,0x10,0xdb,0x79,0xd9,0x9f,0x5,0x44,0x51,0x94,0x9,0x21,0x5a,0x40,0x6,0x64,0x42,0x88,0x56,0x14,0x45,0x59,0x19,0x1e,0x8f,0xc7,0x8b,0x52,0xca,0xe,0x80,0x73,0xee,0x12,0xa,0xbf,0x90,0x24,0x49,0x7f,0x38,0x1c,0x1e,0x3,0x34,0x1a,0x8d,0x7e,0x11,0x54,0x4a,0x2d,0x48,0x29,0x77,0xac,0xb5,0x1d,0xef,0xfd,0x32,0xd0,0x9b,0x4c,0x26,0x5d,0xa8,0xd8,0xc4,0xb2,0xf2,0xf9,0x4c,0x55,0xbd,0x48,0xbf,0xe8,0x1d,0x78,0x70,0xce,0x9d,0x64,0x59,0xb6,0x35,0x85,0xff,0x87,0x3e,0x1,0x53,0x7,0x87,0x11,0xd3,0x3a,0x9b,0x9e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char icon_snap_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x8,0x4,0x2,0x10,0x2e,0xf0,0x12,0xa6,0x44,0x0,0x0,0x0,0x2d,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0xa0,0x26,0x78,0xf0,0xe0,0xc1,0x7f,0x52,0xd8,0xc,0xc,0xc,0xc,0x4c,0x94,0x5a,0xca,0x88,0xcd,0x54,0x62,0x81,0x82,0x82,0x2,0xe3,0xa8,0x17,0x46,0xbd,0x30,0x4c,0xbc,0x40,0x31,0x0,0x0,0x40,0xb8,0x58,0x7b,0x75,0x2f,0x50,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -200,17 +215,17 @@ static const unsigned char icon_stop_png[]={ static const unsigned char icon_zoom_less_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x0,0x0,0x0,0x0,0x3a,0x98,0xa0,0xbd,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x74,0x52,0x4e,0x53,0x0,0x0,0x76,0x93,0xcd,0x38,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x17,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x18,0x10,0xc0,0xc8,0xf0,0x0,0x85,0xaf,0xc0,0x34,0x30,0xee,0xc0,0x0,0x0,0x97,0xf9,0x1,0x4,0xea,0x8f,0x4a,0x96,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0xe3,0xb6,0x51,0xb2,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x34,0x39,0x2b,0x30,0x32,0x3a,0x30,0x30,0x92,0xeb,0xe9,0xe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x25,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0x5,0xc3,0x0,0x30,0x32,0x30,0x30,0x30,0x3c,0x78,0xf0,0xe0,0x3f,0x39,0x9a,0x15,0x14,0x14,0x18,0x99,0xa8,0xeb,0x9e,0x51,0x30,0x44,0x1,0x0,0xff,0xa9,0x4,0x4,0x4a,0xae,0x20,0xfa,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_zoom_more_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x0,0x0,0x0,0x0,0x3a,0x98,0xa0,0xbd,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x74,0x52,0x4e,0x53,0x0,0x0,0x76,0x93,0xcd,0x38,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x21,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0xc0,0x1,0x1e,0x3c,0x80,0x32,0x98,0xd0,0x65,0xa8,0x21,0xc0,0xc8,0xf0,0x0,0x85,0xaf,0x80,0xa1,0x82,0x3e,0xee,0xc0,0x0,0x0,0x13,0x86,0x4,0x98,0x60,0x93,0x6c,0x5a,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x36,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0xa0,0x25,0x78,0xf0,0xe0,0xc1,0xff,0x7,0xf,0x1e,0xfc,0xc7,0xa7,0x86,0x89,0x52,0x4b,0x46,0xd,0x60,0x60,0x60,0x64,0x60,0x80,0x84,0x36,0x39,0x9a,0x15,0x14,0x14,0x18,0x29,0x76,0x1,0x5e,0x30,0x9a,0xe,0xe8,0x64,0x0,0xc5,0x0,0x0,0xc7,0x6e,0x12,0x94,0xf9,0x26,0x2e,0xdb,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char icon_zoom_reset_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x4e,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0x20,0x6,0x3c,0xc,0x7b,0xf0,0xff,0xc1,0x7f,0xec,0x22,0x8c,0xc,0xc,0xcf,0x44,0x7e,0x5d,0x65,0x10,0x63,0x60,0x50,0x60,0x84,0x49,0x23,0x8b,0x30,0x31,0x30,0xfc,0x9a,0xc6,0x20,0x86,0x6a,0x22,0xa6,0x8,0x3,0xcc,0x40,0x84,0x55,0x30,0x16,0x13,0x21,0xf7,0xb1,0xa0,0x72,0x11,0xee,0x80,0x1,0x82,0x26,0x50,0x5d,0x1,0x7a,0x80,0xd,0xe,0x5f,0x10,0x4,0x0,0xfc,0xc5,0x22,0x8c,0x12,0xab,0xcb,0x61,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x6f,0x49,0x44,0x41,0x54,0x38,0x8d,0xdd,0x91,0xbb,0xd,0x80,0x30,0x10,0x43,0x1f,0x11,0x23,0x20,0xea,0x4c,0xc5,0x62,0x48,0xec,0xc0,0x56,0x97,0x26,0x43,0xa4,0x31,0x15,0x12,0x45,0x72,0x8a,0x14,0xa,0x84,0xab,0xfb,0x58,0x3e,0xeb,0xc,0x83,0x98,0xee,0x22,0xa5,0xb4,0x49,0x3a,0x1,0x62,0x8c,0x53,0x8d,0x5c,0xe3,0x4,0x80,0x9c,0xf3,0x22,0x69,0xf7,0x2e,0xb5,0x38,0x1,0xa0,0x94,0x72,0x0,0xab,0x27,0xd0,0xc3,0xc1,0xcc,0x64,0x66,0x6a,0xf5,0xb5,0x59,0x70,0x15,0x3b,0x30,0x7b,0xcb,0xd6,0x33,0x9f,0x18,0x76,0xf0,0x71,0x81,0x5a,0xa,0xaf,0x3b,0xf8,0x41,0xa,0xc3,0xb8,0x0,0x6c,0x9c,0x3f,0xb8,0x84,0xfc,0x5b,0x85,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -235,7 +250,7 @@ static const unsigned char logo_png[]={ static const unsigned char option_arrow_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x4,0x0,0x0,0x0,0xfc,0x7c,0x94,0x6c,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x5f,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x60,0x20,0xc,0xee,0x27,0xdc,0x4f,0xc0,0x22,0xfc,0x50,0xfb,0xc1,0x97,0x7,0x5f,0x1e,0x6a,0xc3,0xf8,0x4c,0x10,0xea,0x5,0xf7,0xff,0x55,0xc,0xdc,0xc,0xdc,0xff,0x57,0xbd,0xe0,0x46,0x91,0xf8,0x39,0x85,0x41,0x8b,0x81,0x81,0x81,0x81,0x41,0xeb,0xe7,0x14,0x22,0x6c,0xc5,0x7,0x1e,0xce,0x7f,0xf0,0x1f,0x2,0x1f,0xce,0x87,0x88,0x30,0xc2,0x2c,0xff,0x71,0x8a,0x41,0x8b,0x81,0x81,0xe1,0x1a,0x87,0x99,0xc4,0x57,0xbc,0xce,0x25,0xec,0x41,0x74,0x0,0x0,0xec,0x66,0x28,0xba,0x76,0x22,0x7a,0x72,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x98,0x49,0x44,0x41,0x54,0x28,0x91,0xbd,0x91,0xb1,0xd,0xc2,0x30,0x10,0x45,0xdf,0xd1,0xb8,0xf0,0x2,0xee,0xdc,0x87,0x1,0xd8,0x24,0xb5,0xe9,0x19,0x87,0x1e,0xea,0x6c,0xc2,0x0,0xa4,0xb5,0xdc,0x79,0x1,0x17,0xae,0x8e,0x26,0x48,0x76,0x14,0x40,0x48,0x88,0xdf,0xfd,0xf7,0xef,0x4b,0x77,0x3a,0xf8,0x85,0x62,0x8c,0x21,0xc6,0x18,0xb6,0x32,0x59,0x83,0x94,0xd2,0x5e,0x55,0x6f,0x0,0x22,0x72,0xf0,0xde,0xdf,0xdb,0x7c,0xd7,0x9a,0x9c,0xb3,0x55,0xd5,0x9,0xb0,0x80,0x55,0xd5,0x29,0xe7,0x6c,0x5f,0x16,0x6a,0xad,0x67,0x60,0x68,0xd0,0xb0,0xb0,0x3f,0xaa,0x3b,0x3a,0xa5,0x74,0x51,0xd5,0xd0,0xd,0x88,0x5c,0xbd,0xf7,0xc7,0xa7,0xef,0x6e,0x30,0xc6,0x9c,0x80,0xb9,0x41,0xf3,0xc2,0xd8,0x2c,0x38,0xe7,0x8a,0x88,0x8c,0x40,0x1,0x8a,0x88,0x8c,0xce,0xb9,0xf2,0x71,0xcf,0x77,0x8f,0xfb,0x5a,0xf,0x28,0x4a,0x37,0xff,0x58,0x46,0x7b,0x50,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -280,7 +295,7 @@ static const unsigned char popup_bg_disabled_png[]={ static const unsigned char popup_checked_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x4,0x0,0x0,0x0,0x6e,0x6,0x76,0x0,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x8,0xd7,0x63,0x60,0x40,0x3,0x8c,0x8,0xe6,0xd,0x5e,0xf6,0xbd,0x8c,0x3f,0x99,0x60,0xdc,0xff,0x8c,0x1c,0xb,0x18,0x4d,0x19,0xb8,0xe0,0xf2,0xf,0x6a,0x1e,0xfc,0x7f,0xf0,0xee,0xb1,0xa,0xe3,0x83,0xc3,0xc,0x9c,0x7f,0xbc,0x58,0x4c,0x18,0x36,0x33,0x30,0x30,0xf8,0x2a,0x6c,0x63,0xf9,0xcf,0xce,0x68,0xcc,0x72,0x80,0x41,0x92,0x81,0x89,0xa1,0x46,0x61,0x1b,0x3,0x3,0xc3,0x1d,0xb1,0x7,0x97,0x1f,0xfc,0x7f,0xf0,0xff,0xc1,0xda,0xff,0x8c,0x50,0x5b,0xee,0x88,0xb1,0x6c,0x65,0xf8,0xfd,0xc3,0x5d,0xe3,0x33,0x3,0x3,0x3,0x3,0x0,0x6a,0x54,0x21,0x0,0x96,0x26,0x52,0xa9,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0xa3,0x49,0x44,0x41,0x54,0x18,0x95,0x85,0xcd,0xa1,0xa,0xc2,0x50,0x0,0x85,0xe1,0xff,0xdc,0x5d,0xd8,0x14,0x4,0xab,0x69,0x37,0xac,0x98,0xd5,0x27,0xb0,0x89,0x16,0x8b,0xd5,0xf7,0xd0,0xec,0x73,0xf8,0x4,0x16,0x61,0x4d,0x10,0xc,0x16,0xa3,0x61,0x71,0xab,0x16,0xeb,0x84,0x3b,0xae,0x45,0x8b,0xa,0x9e,0x78,0xce,0x7,0x7,0xfe,0x44,0xbf,0xca,0xa2,0x28,0x3a,0x71,0x1c,0x1f,0x24,0x3d,0xcc,0xe7,0x18,0x42,0x50,0x92,0x24,0x5b,0x49,0x23,0xa0,0xfd,0x5,0xaa,0xaa,0x5a,0x1,0x73,0xe0,0x1e,0x45,0xd1,0x42,0x65,0x59,0x9e,0x80,0x96,0xf7,0x7e,0x62,0xad,0x1d,0x2,0xfb,0x97,0x9d,0x39,0xe7,0x72,0x1b,0x42,0x88,0x25,0xd,0xac,0xb5,0x47,0xa0,0x7,0x18,0x60,0xed,0x9c,0xcb,0x1,0x4c,0xd3,0x34,0x53,0xe0,0xa,0xf4,0x81,0x2e,0xb0,0x4b,0xd3,0x74,0xf3,0xbe,0x34,0x59,0x96,0xdd,0xbc,0xf7,0x63,0xe0,0x2,0x9c,0xeb,0xba,0x5e,0x4a,0xa,0x6f,0xf0,0x4,0x57,0x3d,0x2c,0x27,0x2b,0xe9,0x62,0x6b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -390,12 +405,12 @@ static const unsigned char selection_oof_png[]={ static const unsigned char spinbox_updown_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x76,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0x20,0xd,0xdc,0x4f,0x7f,0x98,0x86,0x47,0xfa,0x81,0xe5,0x83,0x1f,0xf,0x7e,0x3d,0xb2,0x45,0x16,0x63,0x44,0xd2,0x2d,0xc1,0x78,0x86,0x41,0x9a,0x81,0x81,0xe1,0x5,0xb3,0x89,0xec,0x53,0x98,0x28,0x13,0x8c,0x71,0x86,0x95,0x61,0x15,0x83,0x34,0x3,0x3,0x3,0x3,0x83,0xc4,0xdf,0x35,0xb7,0xd9,0x31,0x14,0x8,0x4f,0x61,0x44,0x18,0x6d,0xc1,0x36,0x93,0x44,0xc7,0xd3,0x7,0xdc,0x9f,0xf9,0xe0,0x3f,0x2,0x3e,0x9c,0x81,0xe1,0x8b,0xb7,0x39,0xff,0xf,0xc3,0x55,0x1f,0xff,0x95,0x4f,0x74,0x40,0xa1,0x5a,0x63,0x81,0x19,0xd4,0x68,0xe0,0x61,0x1a,0xde,0xc8,0xc2,0x6,0x0,0x74,0x4d,0x32,0x61,0xa3,0xda,0x8e,0xb3,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0xcd,0x49,0x44,0x41,0x54,0x38,0x8d,0xe5,0x53,0x31,0xe,0x82,0x40,0x10,0x9c,0x5d,0x22,0x3e,0x80,0x86,0xc4,0x0,0xe1,0xf,0x16,0x5a,0x58,0xf9,0x5,0xe3,0x13,0xd0,0xc2,0xc4,0xcf,0xd8,0xf0,0x5,0xe3,0x1f,0x2c,0x2c,0x6c,0xf8,0x1,0xc5,0x72,0x85,0x9,0xd,0xf,0x10,0x43,0xce,0x86,0x82,0xe0,0xe9,0x19,0x8d,0x95,0x53,0xce,0xce,0x6e,0x26,0x99,0x59,0xe0,0x97,0x10,0x91,0x95,0x52,0x2a,0x79,0xa5,0xa1,0x67,0x83,0xa2,0x28,0xa6,0x0,0x8e,0x0,0x98,0x99,0xe7,0x61,0x18,0x9e,0xde,0x3e,0x20,0x22,0x3e,0x11,0x65,0x0,0x46,0x2d,0x55,0x3a,0x8e,0x33,0xe,0x82,0xe0,0xd2,0xd7,0x72,0x9f,0xc8,0xb2,0x6c,0x0,0x60,0xdf,0x59,0x6,0x0,0xbf,0x69,0x9a,0x43,0x9e,0xe7,0x43,0xeb,0x1,0xcf,0xf3,0x76,0x44,0x34,0x33,0x18,0x9b,0xb8,0xae,0x9b,0x9a,0x1c,0xff,0x3b,0x1e,0x62,0x14,0x91,0x94,0x88,0x8c,0xe5,0x21,0xa2,0x34,0x8a,0xa2,0x75,0x97,0x7b,0x48,0xa1,0xaa,0xaa,0x8d,0xd6,0xda,0x54,0x9a,0x73,0x5d,0xd7,0x5b,0xab,0x83,0xd6,0xc5,0xe7,0x45,0x2,0x80,0x38,0x8e,0x4b,0xad,0xf5,0x2,0xc0,0x15,0xc0,0x8d,0x99,0x97,0xa6,0x65,0x2b,0x94,0x52,0x89,0xed,0x99,0xbe,0xc6,0x1d,0x31,0x1f,0x40,0xdc,0x74,0x8a,0x5b,0xc1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char submenu_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x4,0x0,0x0,0x0,0x6e,0x6,0x76,0x0,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x4d,0x49,0x44,0x41,0x54,0x8,0xd7,0x55,0xc8,0xa1,0x19,0x40,0x40,0x18,0x0,0xd0,0x77,0x8a,0x60,0x1,0x4d,0xb7,0x80,0x4d,0x64,0x3,0x18,0xc7,0x14,0xf6,0xa1,0xba,0x68,0x81,0xb,0xd2,0x2f,0xf9,0xbe,0xf3,0xe2,0x43,0x8e,0x1c,0x39,0xae,0x5,0x48,0xe4,0x0,0x25,0x4d,0xc3,0x41,0xe3,0xd3,0xc5,0x7e,0x77,0x75,0x30,0x3e,0xdb,0x3f,0xf0,0x8f,0xb3,0x5d,0xeb,0x28,0x69,0xee,0x4b,0x15,0xb1,0xe,0x7,0xbc,0x18,0xe0,0x15,0x49,0xfb,0x84,0x18,0x58,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x64,0x49,0x44,0x41,0x54,0x18,0x95,0x7d,0xca,0x21,0x12,0x80,0x20,0x14,0x45,0xd1,0xf7,0x2d,0x4,0x36,0x40,0x63,0xa8,0xba,0x1f,0xbb,0x9d,0xe5,0xb8,0x0,0xb3,0xfb,0xd1,0xc,0x8d,0xd,0x10,0x48,0xcf,0x22,0x6,0xc7,0xef,0x6d,0x77,0xe6,0x8,0x0,0xa4,0x94,0x88,0x3b,0x92,0x4b,0x8,0x61,0xeb,0x3f,0xe0,0x95,0x88,0xac,0x39,0xe7,0x49,0x5,0x0,0x2c,0xc9,0xbd,0x94,0x62,0x35,0x0,0x0,0x63,0x6b,0x6d,0xfd,0x3,0x4f,0x1a,0x38,0x8d,0x31,0x51,0x3,0x55,0x44,0x66,0xe7,0x5c,0xfd,0x4,0x24,0xa3,0xf7,0xfe,0xe8,0x7f,0x1,0xe,0xc2,0x1e,0x10,0xa,0xf0,0x33,0x4c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -410,7 +425,7 @@ static const unsigned char tab_behind_png[]={ static const unsigned char tab_close_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0xb9,0x49,0x44,0x41,0x54,0x28,0xcf,0xad,0x90,0x5d,0xa,0x82,0x40,0x14,0x85,0xbf,0x31,0xb7,0xa0,0xd4,0x63,0x50,0x94,0x60,0x4b,0x28,0xe9,0x67,0x11,0x2e,0x36,0xa3,0xb6,0x90,0x82,0xc5,0x8,0xce,0x63,0xd0,0x12,0x34,0xa7,0x87,0xc9,0x1c,0x7b,0xa,0xea,0x3c,0xdd,0xcb,0xf9,0xe,0xf7,0x70,0xe1,0x4f,0x2a,0xe3,0xc2,0xb7,0xf7,0xc2,0x2f,0xe3,0x9e,0xad,0x1a,0x95,0x76,0x48,0xe1,0xab,0x54,0x35,0x6,0x71,0x0,0xea,0x44,0x67,0x84,0xee,0x49,0x8d,0x0,0xa4,0x37,0xd8,0x13,0x72,0xe5,0x8,0x20,0x4c,0x46,0x7a,0x6e,0x22,0x16,0x5c,0xd8,0x54,0xb5,0x99,0xf4,0x7a,0x7c,0xb3,0x80,0x16,0x11,0x52,0xd7,0x4,0x9d,0x6d,0x1,0x20,0x3d,0xf7,0x24,0x2,0xa0,0xd0,0xcb,0xd6,0x7e,0x75,0xf8,0x94,0xb0,0x62,0x4e,0xef,0x44,0xa0,0x25,0x39,0x13,0xe,0xa6,0xae,0x5,0xbc,0x4b,0xae,0xaa,0x48,0xa7,0xcc,0x6d,0x4,0x90,0x5e,0x79,0x56,0x5a,0xe5,0xe5,0xd0,0xde,0xc,0xe2,0x0,0xb8,0x5b,0x11,0x92,0xd5,0x91,0xa9,0x36,0xbd,0x3f,0x76,0x64,0xcc,0x74,0xf4,0xfd,0xab,0x7f,0xd2,0x13,0xed,0xc6,0x57,0xcd,0xb6,0x96,0x72,0x87,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0xfa,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x92,0x5f,0x4a,0xc4,0x30,0x10,0x87,0xbf,0xb1,0xb9,0xc2,0x16,0x7c,0x6b,0xc1,0xa2,0x85,0x7a,0x4,0x2d,0xfe,0x39,0xc4,0x9e,0x70,0x4f,0x61,0xc5,0x3d,0x83,0x5,0x95,0x4,0xd2,0x37,0x5,0x8f,0x90,0x94,0xf1,0xc5,0x4a,0x76,0xcd,0x22,0xf8,0xa2,0xf3,0x38,0xc3,0xef,0x9b,0xe4,0x4b,0xe0,0x5f,0x95,0xf7,0x7e,0xed,0x9c,0x2b,0xf,0xcd,0x9d,0x73,0xa5,0xf7,0x7e,0x9d,0xf6,0x8e,0xd2,0xb0,0x88,0x6c,0x8c,0x31,0x43,0xe,0xe2,0x9c,0x2b,0x8d,0x31,0x83,0x88,0x6c,0x52,0xc8,0x17,0x20,0xc6,0x38,0xa8,0xea,0x8,0x74,0xc6,0x98,0xed,0x34,0x4d,0xc7,0xcb,0xcc,0x5a,0xbb,0x2a,0x8a,0xe2,0xe,0xe8,0x80,0x17,0xe0,0x61,0x99,0x49,0xba,0xc5,0x5a,0xbb,0xfa,0xdc,0x72,0xe,0x3c,0x3,0xd7,0x21,0x84,0x98,0xf6,0x54,0xf5,0xaa,0xae,0xeb,0xb7,0x2c,0x60,0x1f,0x22,0x22,0x56,0x55,0x23,0xd0,0xe6,0xc2,0x59,0x40,0x2,0xd9,0x8a,0x48,0xbb,0x28,0x50,0xd5,0x8b,0xfd,0xf0,0x8e,0x83,0x9f,0x4a,0x44,0xb2,0xcb,0xbe,0x1,0x92,0x2b,0xb4,0xaa,0x6a,0x81,0x27,0xe0,0x4,0xb8,0x4f,0xc5,0x66,0x1,0x19,0x89,0x97,0x21,0x84,0x5e,0x55,0x1f,0x81,0xb3,0x1c,0x44,0xe,0x85,0x53,0x61,0xb9,0xd7,0xa9,0xaa,0xea,0x75,0xe7,0x4,0xc6,0x98,0x1b,0x11,0xe9,0x80,0x31,0xc6,0xd8,0xa7,0xc2,0x9a,0xa6,0x79,0x9f,0xe7,0xf9,0x16,0x18,0x81,0x53,0x55,0xed,0xb3,0xa2,0x7e,0xf3,0x95,0xff,0xbe,0x3e,0x0,0xbd,0x2c,0x93,0xec,0xb,0xe5,0x4f,0xb1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -425,12 +440,12 @@ static const unsigned char tab_current_png[]={ static const unsigned char tab_menu_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x4c,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0x18,0x5,0xc,0xc,0xc,0xc,0x8c,0x30,0xc6,0x83,0xff,0xa8,0x12,0xa,0x50,0x19,0x26,0x42,0x26,0x10,0xaf,0x80,0x31,0x9e,0xe1,0x2b,0x5c,0xf4,0x3b,0x63,0x3a,0x16,0xb5,0xf7,0x35,0xee,0x5f,0x7a,0xf0,0xff,0xc1,0xff,0x7,0xd7,0x1f,0xeb,0x62,0x71,0x24,0x3,0x3,0x3,0xc3,0xb,0xee,0x9f,0x53,0x18,0x18,0xd8,0x73,0x24,0xbe,0x32,0x50,0x11,0x0,0x0,0x6,0x9b,0x11,0xfa,0xe0,0x26,0x3d,0x9f,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x6f,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0x5,0xa3,0x80,0x81,0x81,0x11,0x5d,0xe0,0xc1,0x83,0x7,0xff,0xf1,0x69,0x50,0x50,0x50,0x40,0xd1,0xc3,0x44,0xa9,0xb,0xa8,0x6f,0x0,0x23,0x23,0x63,0x3c,0x3,0x3,0xc3,0x57,0x2c,0x6a,0xbf,0x33,0x32,0x32,0xa6,0x63,0xa8,0xc7,0x66,0xea,0xfd,0xfb,0xf7,0x35,0x18,0x18,0x18,0x56,0x31,0x32,0x32,0xea,0x42,0x85,0x6e,0x30,0x33,0x33,0x87,0xc9,0xca,0xca,0x5e,0x26,0xca,0x0,0x6,0x6,0x6,0x86,0x17,0x2f,0x5e,0x70,0xff,0xfc,0xf9,0x73,0xa,0x3,0x3,0x3,0x3,0x3b,0x3b,0x7b,0x8e,0x84,0x84,0x4,0x36,0x57,0xd,0x2,0x0,0x0,0x67,0xf2,0x14,0xc2,0xc2,0xbe,0xf5,0xb5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char tab_menu_hl_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0xb5,0xfa,0x37,0xea,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x5,0x39,0x1a,0x32,0x39,0x0,0x0,0x0,0x4c,0x49,0x44,0x41,0x54,0x28,0xcf,0x63,0x60,0x18,0x5,0xc,0xc,0xc,0xc,0x8c,0x30,0xc6,0x83,0xff,0xa8,0x12,0xa,0x50,0x19,0x26,0x42,0x26,0x10,0xaf,0x80,0x31,0x9e,0xe1,0x2b,0x5c,0xf4,0x3b,0x63,0x3a,0x16,0xb5,0xf7,0x35,0xee,0x5f,0x7a,0xf0,0xff,0xc1,0xff,0x7,0xd7,0x1f,0xeb,0x62,0x71,0x24,0x3,0x3,0x3,0xc3,0xb,0xee,0x9f,0x53,0x18,0x18,0xd8,0x73,0x24,0xbe,0x32,0x50,0x11,0x0,0x0,0x6,0x9b,0x11,0xfa,0xe0,0x26,0x3d,0x9f,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x6f,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0x5,0xa3,0x80,0x81,0x81,0x11,0x5d,0xe0,0xc1,0x83,0x7,0xff,0xf1,0x69,0x50,0x50,0x50,0x40,0xd1,0xc3,0x44,0xa9,0xb,0xa8,0x6f,0x0,0x23,0x23,0x63,0x3c,0x3,0x3,0xc3,0x57,0x2c,0x6a,0xbf,0x33,0x32,0x32,0xa6,0x63,0xa8,0xc7,0x66,0xea,0xfd,0xfb,0xf7,0x35,0x18,0x18,0x18,0x56,0x31,0x32,0x32,0xea,0x42,0x85,0x6e,0x30,0x33,0x33,0x87,0xc9,0xca,0xca,0x5e,0x26,0xca,0x0,0x6,0x6,0x6,0x86,0x17,0x2f,0x5e,0x70,0xff,0xfc,0xf9,0x73,0xa,0x3,0x3,0x3,0x3,0x3b,0x3b,0x7b,0x8e,0x84,0x84,0x4,0x36,0x57,0xd,0x2,0x0,0x0,0x67,0xf2,0x14,0xc2,0xc2,0xbe,0xf5,0xb5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -490,7 +505,7 @@ static const unsigned char unchecked_png[]={ static const unsigned char updown_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x8,0x4,0x0,0x0,0x0,0x81,0x83,0xf6,0xf6,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x20,0x63,0x48,0x52,0x4d,0x0,0x0,0x7a,0x26,0x0,0x0,0x80,0x84,0x0,0x0,0xfa,0x0,0x0,0x0,0x80,0xe8,0x0,0x0,0x75,0x30,0x0,0x0,0xea,0x60,0x0,0x0,0x3a,0x98,0x0,0x0,0x17,0x70,0x9c,0xba,0x51,0x3c,0x0,0x0,0x0,0x2,0x62,0x4b,0x47,0x44,0x0,0xff,0x87,0x8f,0xcc,0xbf,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xe0,0x6,0x16,0x12,0x2b,0x4,0x4e,0x1d,0x2,0xaf,0x0,0x0,0x0,0x86,0x49,0x44,0x41,0x54,0x18,0xd3,0x85,0x8e,0x21,0x12,0xc2,0x30,0x10,0x45,0x5f,0x98,0x9d,0xe9,0x70,0x81,0x3d,0x41,0x1c,0x75,0xe5,0x4,0xc4,0xc1,0x79,0xa9,0xb,0x6,0x49,0x5d,0x8b,0x5b,0x11,0x9d,0xb,0xd4,0xec,0x4c,0x10,0xad,0x43,0xf4,0xb9,0x6f,0xfe,0x7b,0x70,0x44,0x0,0x30,0x95,0x27,0xf8,0x23,0x56,0xb6,0x59,0xe6,0xd2,0x4a,0x2b,0xb3,0x29,0x4,0x53,0x79,0x71,0x61,0x1,0x7a,0xbe,0x7e,0xb,0xe5,0xc3,0x95,0xc5,0x13,0x48,0xa6,0x67,0x3a,0xb5,0x95,0xc9,0x53,0xac,0xb1,0x7a,0x62,0x6a,0xeb,0xa1,0x95,0x50,0xde,0x9c,0xfd,0x1e,0x2b,0x98,0xca,0xc8,0x7a,0x6a,0x1d,0x83,0x64,0x53,0x53,0xc9,0xc,0xad,0xb,0xa6,0x92,0xe9,0x77,0xed,0xe2,0xe9,0x3f,0x6c,0x4f,0x1f,0x61,0x7b,0x3a,0xe6,0x7,0x73,0x18,0x40,0x43,0x76,0xe2,0x28,0x4e,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x63,0x72,0x65,0x61,0x74,0x65,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xba,0x84,0x14,0xff,0x0,0x0,0x0,0x25,0x74,0x45,0x58,0x74,0x64,0x61,0x74,0x65,0x3a,0x6d,0x6f,0x64,0x69,0x66,0x79,0x0,0x32,0x30,0x31,0x36,0x2d,0x30,0x36,0x2d,0x32,0x32,0x54,0x32,0x30,0x3a,0x33,0x35,0x3a,0x35,0x30,0x2b,0x30,0x32,0x3a,0x30,0x30,0xcb,0xd9,0xac,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x2b,0x8a,0x3e,0x7d,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0xa6,0x49,0x44,0x41,0x54,0x28,0x91,0xa5,0x90,0x21,0xe,0xc2,0x50,0x10,0x44,0xdf,0x27,0x9b,0x10,0x2e,0xc0,0x9,0xd6,0x81,0xe3,0x6,0xe0,0xa0,0xd7,0x2d,0xae,0x18,0x24,0x95,0xc5,0x7d,0x51,0xdd,0xb,0x60,0xf6,0x67,0x31,0xfb,0x49,0xc1,0x20,0x3a,0x6a,0x93,0x99,0x9d,0xcc,0xc,0x2c,0x45,0xaa,0x47,0xce,0x79,0x2b,0x22,0x2d,0x80,0x99,0x5d,0x54,0x75,0xfa,0x8,0x82,0xec,0x80,0x7d,0xe8,0x7,0x33,0x3b,0xa9,0xea,0x94,0x82,0xbc,0x1,0x3b,0x60,0x8,0xc1,0x1e,0x78,0x9a,0xd9,0x51,0xc2,0x76,0x57,0xbf,0x0,0xaa,0x9b,0x88,0xb4,0x2b,0x77,0x7f,0x1,0x7d,0xb5,0x54,0xd5,0x29,0x84,0x7d,0x70,0x4b,0x6b,0x8e,0xe3,0x78,0x7,0x36,0x66,0x76,0xae,0xd5,0x22,0xf8,0x15,0x78,0x89,0xbb,0xaf,0x53,0x4a,0x7,0x11,0xe9,0x72,0xce,0x5f,0x21,0xdd,0xfd,0x21,0xa5,0x94,0x66,0x96,0xba,0x9b,0xd5,0x1c,0x4a,0x29,0xcd,0xff,0xa1,0x7e,0xa6,0xbe,0xc6,0xd4,0x9f,0x3c,0xcb,0xf1,0x6,0x8e,0x4e,0x65,0x44,0x6f,0x74,0x5c,0xa1,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 67587a8f8b..679c8a000c 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -30,13 +30,22 @@ #include "dynamic_font.h" #include "os/file_access.h" +bool DynamicFontData::CacheID::operator< (CacheID right) const{ + + if (size<right.size) + return true; + if (mipmaps != right.mipmaps) + return right.mipmaps; + if (filter != right.filter) + return right.filter; + return false; +} - -Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { +Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(CacheID p_id){ - if (size_cache.has(p_size)) { - return Ref<DynamicFontAtSize>( size_cache[p_size] ); + if (size_cache.has(p_id)) { + return Ref<DynamicFontAtSize>( size_cache[p_id] ); } @@ -46,9 +55,8 @@ Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { dfas->font=Ref<DynamicFontData>( this ); - size_cache[p_size]=dfas.ptr(); - - dfas->size=p_size; + size_cache[p_id]=dfas.ptr(); + dfas->id=p_id; dfas->_load(); return dfas; @@ -169,11 +177,16 @@ Error DynamicFontAtSize::_load() { ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); }*/ - error = FT_Set_Pixel_Sizes(face,0,size); + error = FT_Set_Pixel_Sizes(face,0,id.size); ascent=face->size->metrics.ascender>>6; descent=-face->size->metrics.descender>>6; linegap=0; + texture_flags=0; + if (id.mipmaps) + texture_flags|=Texture::FLAG_MIPMAPS; + if (id.filter) + texture_flags|=Texture::FLAG_FILTER; //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); @@ -270,6 +283,15 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next,const Vec return ret; } +void DynamicFontAtSize::set_texture_flags(uint32_t p_flags){ + + texture_flags=p_flags; + for(int i=0;i<textures.size();i++) { + Ref<ImageTexture> &tex = textures[i].texture; + if (!tex.is_null()) + tex->set_flags(p_flags); + } +} float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, CharType p_char,CharType p_next,const Color& p_modulate,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const { @@ -496,7 +518,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) { tex_x = 0; tex_y = 0; - int texsize = MAX(size*8,256); + int texsize = MAX(id.size*8,256); if (mw>texsize) texsize=mw; //special case, adapt to it? if (mh>texsize) @@ -555,7 +577,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) { if (tex.texture.is_null()) { tex.texture.instance(); - tex.texture->create_from_image(img,Texture::FLAG_VIDEO_SURFACE); + tex.texture->create_from_image(img,Texture::FLAG_VIDEO_SURFACE|texture_flags); } else { tex.texture->set_data(img); //update } @@ -595,25 +617,39 @@ DynamicFontAtSize::DynamicFontAtSize() { ascent=1; descent=1; linegap=1; + texture_flags=0; } DynamicFontAtSize::~DynamicFontAtSize(){ if (valid) { FT_Done_FreeType( library ); - font->size_cache.erase(size); + font->size_cache.erase(id); } } ///////////////////////// +void DynamicFont::_reload_cache(){ + + ERR_FAIL_COND(cache_id.size<1); + if (!data.is_valid()) + return; + data_at_size=data->_get_dynamic_font_at_size(cache_id); + for (int i=0;i<fallbacks.size();i++){ + fallback_data_at_size[i]=fallbacks[i]->_get_dynamic_font_at_size(cache_id); + } + + emit_changed(); + _change_notify(); +} void DynamicFont::set_font_data(const Ref<DynamicFontData>& p_data) { data=p_data; if (data.is_valid()) - data_at_size=data->_get_dynamic_font_at_size(size); + data_at_size=data->_get_dynamic_font_at_size(cache_id); else data_at_size=Ref<DynamicFontAtSize>(); @@ -628,23 +664,72 @@ Ref<DynamicFontData> DynamicFont::get_font_data() const{ void DynamicFont::set_size(int p_size){ - if (size==p_size) + if (cache_id.size==p_size) return; - size=p_size; - ERR_FAIL_COND(p_size<1); - if (!data.is_valid()) + cache_id.size=p_size; + _reload_cache(); +} + +int DynamicFont::get_size() const{ + + return cache_id.size; +} + +bool DynamicFont::get_use_mipmaps() const{ + + return cache_id.mipmaps; +} + +void DynamicFont::set_use_mipmaps(bool p_enable){ + + if (cache_id.mipmaps==p_enable) return; - data_at_size=data->_get_dynamic_font_at_size(size); - for(int i=0;i<fallbacks.size();i++) { - fallback_data_at_size[i]=fallbacks[i]->_get_dynamic_font_at_size(size); + cache_id.mipmaps=p_enable; + _reload_cache(); +} + +bool DynamicFont::get_use_filter() const{ + + return cache_id.filter; +} + +void DynamicFont::set_use_filter(bool p_enable){ + + if (cache_id.filter==p_enable) + return; + cache_id.filter=p_enable; + _reload_cache(); +} + +int DynamicFont::get_spacing(int p_type) const{ + + if (p_type == SPACING_TOP){ + return spacing_top; + }else if (p_type == SPACING_BOTTOM){ + return spacing_bottom; + }else if (p_type == SPACING_CHAR){ + return spacing_char; + }else if (p_type == SPACING_SPACE){ + return spacing_space; } - emit_changed(); - _change_notify(); + return 0; } -int DynamicFont::get_size() const{ - return size; +void DynamicFont::set_spacing(int p_type, int p_value){ + + if (p_type == SPACING_TOP){ + spacing_top=p_value; + }else if (p_type == SPACING_BOTTOM){ + spacing_bottom=p_value; + }else if (p_type == SPACING_CHAR){ + spacing_char=p_value; + }else if (p_type == SPACING_SPACE){ + spacing_space=p_value; + } + + emit_changed(); + _change_notify(); } float DynamicFont::get_height() const{ @@ -652,7 +737,7 @@ float DynamicFont::get_height() const{ if (!data_at_size.is_valid()) return 1; - return data_at_size->get_height(); + return data_at_size->get_height()+spacing_top+spacing_bottom; } float DynamicFont::get_ascent() const{ @@ -660,7 +745,7 @@ float DynamicFont::get_ascent() const{ if (!data_at_size.is_valid()) return 1; - return data_at_size->get_ascent(); + return data_at_size->get_ascent()+spacing_top; } float DynamicFont::get_descent() const{ @@ -668,7 +753,7 @@ float DynamicFont::get_descent() const{ if (!data_at_size.is_valid()) return 1; - return data_at_size->get_descent(); + return data_at_size->get_descent()+spacing_bottom; } @@ -677,7 +762,13 @@ Size2 DynamicFont::get_char_size(CharType p_char,CharType p_next) const{ if (!data_at_size.is_valid()) return Size2(1,1); - return data_at_size->get_char_size(p_char,p_next,fallback_data_at_size); + Size2 ret=data_at_size->get_char_size(p_char,p_next,fallback_data_at_size); + if (p_char==' ') + ret.width+=spacing_space+spacing_char; + else if (p_next) + ret.width+=spacing_char; + + return ret; } @@ -691,7 +782,7 @@ float DynamicFont::draw_char(RID p_canvas_item, const Point2& p_pos, CharType p_ if (!data_at_size.is_valid()) return 0; - return data_at_size->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate,fallback_data_at_size); + return data_at_size->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate,fallback_data_at_size)+spacing_char; } void DynamicFont::set_fallback(int p_idx,const Ref<DynamicFontData>& p_data) { @@ -699,7 +790,7 @@ void DynamicFont::set_fallback(int p_idx,const Ref<DynamicFontData>& p_data) { ERR_FAIL_COND(p_data.is_null()); ERR_FAIL_INDEX(p_idx,fallbacks.size()); fallbacks[p_idx]=p_data; - fallback_data_at_size[p_idx]=fallbacks[p_idx]->_get_dynamic_font_at_size(size); + fallback_data_at_size[p_idx]=fallbacks[p_idx]->_get_dynamic_font_at_size(cache_id); } @@ -707,7 +798,7 @@ void DynamicFont::add_fallback(const Ref<DynamicFontData>& p_data) { ERR_FAIL_COND(p_data.is_null()); fallbacks.push_back(p_data); - fallback_data_at_size.push_back(fallbacks[fallbacks.size()-1]->_get_dynamic_font_at_size(size)); //const.. + fallback_data_at_size.push_back(fallbacks[fallbacks.size()-1]->_get_dynamic_font_at_size(cache_id)); //const.. _change_notify(); emit_changed(); @@ -794,6 +885,13 @@ void DynamicFont::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_size","data"),&DynamicFont::set_size); ObjectTypeDB::bind_method(_MD("get_size"),&DynamicFont::get_size); + ObjectTypeDB::bind_method(_MD("set_use_mipmaps","enable"),&DynamicFont::set_use_mipmaps); + ObjectTypeDB::bind_method(_MD("get_use_mipmaps"),&DynamicFont::get_use_mipmaps); + ObjectTypeDB::bind_method(_MD("set_use_filter","enable"),&DynamicFont::set_use_filter); + ObjectTypeDB::bind_method(_MD("get_use_filter"),&DynamicFont::get_use_filter); + ObjectTypeDB::bind_method(_MD("set_spacing","type","value"),&DynamicFont::set_spacing); + ObjectTypeDB::bind_method(_MD("get_spacing","type"),&DynamicFont::get_spacing); + ObjectTypeDB::bind_method(_MD("add_fallback","data:DynamicFontData"),&DynamicFont::add_fallback); ObjectTypeDB::bind_method(_MD("set_fallback","idx","data:DynamicFontData"),&DynamicFont::set_fallback); ObjectTypeDB::bind_method(_MD("get_fallback:DynamicFontData","idx"),&DynamicFont::get_fallback); @@ -802,12 +900,26 @@ void DynamicFont::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"font/size"),_SCS("set_size"),_SCS("get_size")); + ADD_PROPERTYINZ(PropertyInfo(Variant::INT,"extra_spacing/top"),_SCS("set_spacing"),_SCS("get_spacing"),SPACING_TOP); + ADD_PROPERTYINZ(PropertyInfo(Variant::INT,"extra_spacing/bottom"),_SCS("set_spacing"),_SCS("get_spacing"),SPACING_BOTTOM); + ADD_PROPERTYINZ(PropertyInfo(Variant::INT,"extra_spacing/char"),_SCS("set_spacing"),_SCS("get_spacing"),SPACING_CHAR); + ADD_PROPERTYINZ(PropertyInfo(Variant::INT,"extra_spacing/space"),_SCS("set_spacing"),_SCS("get_spacing"),SPACING_SPACE); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"font/use_mipmaps"),_SCS("set_use_mipmaps"),_SCS("get_use_mipmaps")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"font/use_filter"),_SCS("set_use_filter"),_SCS("get_use_filter")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"font/font",PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData"),_SCS("set_font_data"),_SCS("get_font_data")); + + BIND_CONSTANT( SPACING_TOP ); + BIND_CONSTANT( SPACING_BOTTOM ); + BIND_CONSTANT( SPACING_CHAR ); + BIND_CONSTANT( SPACING_SPACE ); } DynamicFont::DynamicFont() { - size=16; + spacing_top=0; + spacing_bottom=0; + spacing_char=0; + spacing_space=0; } DynamicFont::~DynamicFont() { diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index 9ad1b4edbf..4ae58ab0dd 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -45,21 +45,32 @@ class DynamicFontData : public Resource { OBJ_TYPE(DynamicFontData,Resource); +public: + + struct CacheID{ + + int size; + bool mipmaps; + bool filter; + + bool operator< (CacheID right) const; + CacheID() { size=16; mipmaps=false; filter=false; } + }; +private: const uint8_t *font_mem; int font_mem_size; bool force_autohinter; String font_path; - Map<int,DynamicFontAtSize*> size_cache; + Map<CacheID,DynamicFontAtSize*> size_cache; friend class DynamicFontAtSize; friend class DynamicFont; - - Ref<DynamicFontAtSize> _get_dynamic_font_at_size(int p_size); + Ref<DynamicFontAtSize> _get_dynamic_font_at_size(CacheID p_cache); protected: static void _bind_methods(); @@ -90,6 +101,8 @@ class DynamicFontAtSize : public Reference { int linegap; int rect_margin; + uint32_t texture_flags; + bool valid; struct CharTexture { @@ -124,7 +137,7 @@ class DynamicFontAtSize : public Reference { friend class DynamicFontData; Ref<DynamicFontData> font; - int size; + DynamicFontData::CacheID id; @@ -145,7 +158,7 @@ public: float draw_char(RID p_canvas_item, const Point2& p_pos, CharType p_char,CharType p_next,const Color& p_modulate,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const; - + void set_texture_flags(uint32_t p_flags); DynamicFontAtSize(); ~DynamicFontAtSize(); @@ -157,18 +170,35 @@ class DynamicFont : public Font { OBJ_TYPE( DynamicFont, Font ); - Ref<DynamicFontData> data; +public: + + enum SpacingType{ + SPACING_TOP, + SPACING_BOTTOM, + SPACING_CHAR, + SPACING_SPACE + }; + +private: + + Ref<DynamicFontData> data; Ref<DynamicFontAtSize> data_at_size; Vector< Ref<DynamicFontData> > fallbacks; Vector< Ref<DynamicFontAtSize> > fallback_data_at_size; - int size; + DynamicFontData::CacheID cache_id; bool valid; + int spacing_top; + int spacing_bottom; + int spacing_char; + int spacing_space; protected: + void _reload_cache(); + bool _set(const StringName& p_name, const Variant& p_value); bool _get(const StringName& p_name,Variant &r_ret) const; void _get_property_list( List<PropertyInfo> *p_list) const; @@ -183,6 +213,14 @@ public: void set_size(int p_size); int get_size() const; + bool get_use_mipmaps() const; + void set_use_mipmaps(bool p_enable); + + bool get_use_filter() const; + void set_use_filter(bool p_enable); + + int get_spacing(int p_type) const; + void set_spacing(int p_type, int p_value); void add_fallback(const Ref<DynamicFontData>& p_data); void set_fallback(int p_idx,const Ref<DynamicFontData>& p_data); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 8580ffdc5a..59246dfabe 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -141,7 +141,7 @@ void StyleBoxTexture::draw(RID p_canvas_item,const Rect2& p_rect) const { r.pos.y-=expand_margin[MARGIN_TOP]; r.size.x+=expand_margin[MARGIN_LEFT]+expand_margin[MARGIN_RIGHT]; r.size.y+=expand_margin[MARGIN_TOP]+expand_margin[MARGIN_BOTTOM]; - VisualServer::get_singleton()->canvas_item_add_style_box( p_canvas_item,r,region_rect,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center); + VisualServer::get_singleton()->canvas_item_add_style_box( p_canvas_item,r,region_rect,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); } void StyleBoxTexture::set_draw_center(bool p_draw) { @@ -193,6 +193,19 @@ Rect2 StyleBoxTexture::get_region_rect() const { } +void StyleBoxTexture::set_modulate(const Color& p_modulate) { + if (modulate==p_modulate) + return; + modulate=p_modulate; + emit_changed(); +} + +Color StyleBoxTexture::get_modulate() const { + + return modulate; +} + + void StyleBoxTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_texture","texture:Texture"),&StyleBoxTexture::set_texture); @@ -210,6 +223,10 @@ void StyleBoxTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_draw_center","enable"),&StyleBoxTexture::set_draw_center); ObjectTypeDB::bind_method(_MD("get_draw_center"),&StyleBoxTexture::get_draw_center); + ObjectTypeDB::bind_method(_MD("set_modulate","color"),&StyleBoxTexture::set_modulate); + ObjectTypeDB::bind_method(_MD("get_modulate"),&StyleBoxTexture::get_modulate); + + ADD_SIGNAL(MethodInfo("texture_changed")); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_texture"),_SCS("get_texture") ); @@ -222,6 +239,7 @@ void StyleBoxTexture::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::REAL, "expand_margin/right", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_expand_margin_size"),_SCS("get_expand_margin_size"), MARGIN_RIGHT ); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "expand_margin/top", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_expand_margin_size"),_SCS("get_expand_margin_size"), MARGIN_TOP ); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "expand_margin/bottom", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_expand_margin_size"),_SCS("get_expand_margin_size"), MARGIN_BOTTOM ); + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate/color" ), _SCS("set_modulate"),_SCS("get_modulate")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "draw_center" ) , _SCS("set_draw_center"),_SCS("get_draw_center")); } @@ -234,6 +252,7 @@ StyleBoxTexture::StyleBoxTexture() { expand_margin[i]=0; } draw_center=true; + modulate=Color(1,1,1,1); } StyleBoxTexture::~StyleBoxTexture() { diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 98aaee754b..f667318e24 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -84,6 +84,7 @@ class StyleBoxTexture : public StyleBox { Rect2 region_rect; Ref<Texture> texture; bool draw_center; + Color modulate; protected: @@ -109,6 +110,9 @@ public: bool get_draw_center() const; virtual Size2 get_center_size() const; + void set_modulate(const Color& p_modulate); + Color get_modulate() const; + virtual void draw(RID p_canvas_item,const Rect2& p_rect) const; diff --git a/tools/Godot.app/Contents/Info.plist b/tools/Godot.app/Contents/Info.plist index 37c80fc8a3..2a3e727133 100755 --- a/tools/Godot.app/Contents/Info.plist +++ b/tools/Godot.app/Contents/Info.plist @@ -19,11 +19,11 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>2.1-dev</string> + <string>2.2-dev</string> <key>CFBundleSignature</key> <string>godot</string> <key>CFBundleVersion</key> - <string>2.1-dev</string> + <string>2.2-dev</string> <key>NSHumanReadableCopyright</key> <string>© 2007-2016 Juan Linietsky, Ariel Manzur</string> <key>LSMinimumSystemVersion</key> diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp index d2bf070f1b..2779275ea8 100644 --- a/tools/editor/code_editor.cpp +++ b/tools/editor/code_editor.cpp @@ -1054,7 +1054,11 @@ void CodeTextEditor::_code_complete_timer_timeout() { void CodeTextEditor::_complete_request() { List<String> entries; - _code_complete_script(text_editor->get_text_for_completion(),&entries); + String ctext = text_editor->get_text_for_completion(); + _code_complete_script(ctext,&entries); + if (code_complete_func) { + code_complete_func(code_complete_ud,ctext,&entries); + } // print_line("COMPLETE: "+p_request); if (entries.size()==0) return; @@ -1138,13 +1142,16 @@ void CodeTextEditor::_text_changed_idle_timeout() { _validate_script(); + emit_signal("validate_script"); } void CodeTextEditor::_notification(int p_what) { - if (p_what==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) + if (p_what==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { _load_theme_settings(); + emit_signal("load_theme_settings"); + } if (p_what==NOTIFICATION_ENTER_TREE) { _update_font(); } @@ -1160,10 +1167,21 @@ void CodeTextEditor::_bind_methods() { ObjectTypeDB::bind_method("_code_complete_timer_timeout",&CodeTextEditor::_code_complete_timer_timeout); ObjectTypeDB::bind_method("_complete_request",&CodeTextEditor::_complete_request); ObjectTypeDB::bind_method("_font_resize_timeout",&CodeTextEditor::_font_resize_timeout); + + ADD_SIGNAL(MethodInfo("validate_script")); + ADD_SIGNAL(MethodInfo("load_theme_settings")); + } +void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func,void * p_ud) { + code_complete_func=p_code_complete_func; + code_complete_ud=p_ud; +} + + CodeTextEditor::CodeTextEditor() { + code_complete_func=NULL; ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KEY_MASK_CMD|KEY_EQUAL); ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KEY_MASK_CMD|KEY_MINUS); ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KEY_MASK_CMD|KEY_0); diff --git a/tools/editor/code_editor.h b/tools/editor/code_editor.h index 88d882bd33..2affa31482 100644 --- a/tools/editor/code_editor.h +++ b/tools/editor/code_editor.h @@ -189,6 +189,8 @@ public: }; +typedef void (*CodeTextEditorCodeCompleteFunc)(void* p_ud,const String& p_code, List<String>* r_options); + class CodeTextEditor : public VBoxContainer { OBJ_TYPE(CodeTextEditor,VBoxContainer); @@ -219,13 +221,16 @@ class CodeTextEditor : public VBoxContainer { void _zoom_out(); void _reset_zoom(); + + CodeTextEditorCodeCompleteFunc code_complete_func; + void *code_complete_ud; + protected: - void set_error(const String& p_error); virtual void _load_theme_settings() {} - virtual void _validate_script()=0; - virtual void _code_complete_script(const String& p_code, List<String>* r_options) {}; + virtual void _validate_script() {} + virtual void _code_complete_script(const String& p_code, List<String>* r_options) {} void _text_changed_idle_timeout(); void _code_complete_timer_timeout(); @@ -236,10 +241,16 @@ protected: public: + void set_error(const String& p_error); + void update_line_and_column() { _line_col_changed(); } TextEdit *get_text_edit() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } virtual void apply_code() {} + + void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void * p_ud); + + CodeTextEditor(); }; diff --git a/tools/editor/connections_dialog.cpp b/tools/editor/connections_dialog.cpp index bdc420c70f..c4f2435675 100644 --- a/tools/editor/connections_dialog.cpp +++ b/tools/editor/connections_dialog.cpp @@ -674,7 +674,7 @@ void ConnectionsDock::update_tree() { tname=Variant::get_type_name(pi.type); } signaldesc+=tname+" "+(pi.name==""?String("arg "+itos(i)):pi.name); - argnames.push_back(pi.name); + argnames.push_back(pi.name+":"+tname); } signaldesc+=" "; diff --git a/tools/editor/create_dialog.cpp b/tools/editor/create_dialog.cpp index 3ab2e35242..b0cdd79798 100644 --- a/tools/editor/create_dialog.cpp +++ b/tools/editor/create_dialog.cpp @@ -292,9 +292,12 @@ String CreateDialog::get_selected_type() { Object *CreateDialog::instance_selected() { TreeItem *selected = search_options->get_selected(); + if (selected) { String custom = selected->get_metadata(0); + + if (custom!=String()) { if (EditorNode::get_editor_data().get_custom_types().has(custom)) { @@ -323,6 +326,7 @@ Object *CreateDialog::instance_selected() { } } + return NULL; } diff --git a/tools/editor/editor_help.cpp b/tools/editor/editor_help.cpp index 1fc157098c..4ab86ad512 100644 --- a/tools/editor/editor_help.cpp +++ b/tools/editor/editor_help.cpp @@ -943,10 +943,9 @@ Error EditorHelp::_goto_desc(const String& p_class,int p_vscr) { class_desc->add_newline(); } - class_desc->add_newline(); - class_desc->pop(); - + class_desc->pop(); + class_desc->add_newline(); } if (cd.theme_properties.size()) { @@ -987,11 +986,10 @@ Error EditorHelp::_goto_desc(const String& p_class,int p_vscr) { class_desc->add_newline(); } - class_desc->add_newline(); class_desc->pop(); - - + class_desc->add_newline(); } + if (cd.signals.size()) { if (sort_methods) { diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index f27a753464..85c560bf9d 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -86,6 +86,7 @@ #include "plugins/collision_polygon_editor_plugin.h" #include "plugins/collision_polygon_2d_editor_plugin.h" #include "plugins/script_editor_plugin.h" +#include "plugins/script_text_editor.h" #include "plugins/path_2d_editor_plugin.h" #include "plugins/particles_editor_plugin.h" #include "plugins/particles_2d_editor_plugin.h" @@ -5219,6 +5220,17 @@ void EditorNode::reload_scene(const String& p_path) { _scene_tab_changed(current_tab); } +int EditorNode::plugin_init_callback_count=0; + +void EditorNode::add_plugin_init_callback(EditorPluginInitializeCallback p_callback) { + + ERR_FAIL_COND(plugin_init_callback_count==MAX_INIT_CALLBACKS); + + plugin_init_callbacks[plugin_init_callback_count++]=p_callback; +} + +EditorPluginInitializeCallback EditorNode::plugin_init_callbacks[EditorNode::MAX_INIT_CALLBACKS]; + void EditorNode::_bind_methods() { @@ -6447,6 +6459,8 @@ EditorNode::EditorNode() { add_editor_plugin( memnew( SpatialEditorPlugin(this) ) ); add_editor_plugin( memnew( ScriptEditorPlugin(this) ) ); + ScriptTextEditor::register_editor(); //register one for text scripts + if (StreamPeerSSL::is_available()) { add_editor_plugin( memnew( AssetLibraryEditorPlugin(this) ) ); } else { @@ -6496,6 +6510,9 @@ EditorNode::EditorNode() { for(int i=0;i<EditorPlugins::get_plugin_count();i++) add_editor_plugin( EditorPlugins::create(i,this) ); + for(int i=0;i<plugin_init_callback_count;i++) { + plugin_init_callbacks[i](); + } resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin ))); resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin ))); @@ -6505,6 +6522,8 @@ EditorNode::EditorNode() { resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin ))); resource_preview->add_preview_generator( Ref<EditorBitmapPreviewPlugin>( memnew(EditorBitmapPreviewPlugin ))); + + circle_step_msec=OS::get_singleton()->get_ticks_msec(); circle_step_frame=OS::get_singleton()->get_frames_drawn(); circle_step=0; diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index 793c148671..e6119cf577 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -94,6 +94,7 @@ typedef void (*EditorNodeInitCallback)(); +typedef void (*EditorPluginInitializeCallback)(); class EditorPluginList; @@ -575,17 +576,27 @@ private: static void _file_access_close_error_notify(const String& p_str); + + enum { + MAX_INIT_CALLBACKS=128 + }; + + static int plugin_init_callback_count; + static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; protected: void _notification(int p_what); static void _bind_methods(); public: + static void add_plugin_init_callback(EditorPluginInitializeCallback p_callback); + enum EditorTable { EDITOR_2D = 0, EDITOR_3D, EDITOR_SCRIPT }; + void set_visible_editor(EditorTable p_table) { _editor_select(p_table); } static EditorNode* get_singleton() { return singleton; } @@ -740,6 +751,8 @@ public: static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); } + + }; diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 9dcf71e256..582462aa19 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -945,6 +945,8 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { cf->set_value(theme_section, "word_highlighted_color", ((Color)get("text_editor/word_highlighted_color")).to_html()); cf->set_value(theme_section, "search_result_color", ((Color)get("text_editor/search_result_color")).to_html()); cf->set_value(theme_section, "search_result_border_color", ((Color)get("text_editor/search_result_border_color")).to_html()); + + Error err = cf->save(p_file); if (err == OK) { diff --git a/tools/editor/icons/2x/icon_uninstance.png b/tools/editor/icons/2x/icon_uninstance.png Binary files differnew file mode 100644 index 0000000000..bf3dc00368 --- /dev/null +++ b/tools/editor/icons/2x/icon_uninstance.png diff --git a/tools/editor/icons/2x/icon_visual_script.png b/tools/editor/icons/2x/icon_visual_script.png Binary files differnew file mode 100644 index 0000000000..adc6353ed2 --- /dev/null +++ b/tools/editor/icons/2x/icon_visual_script.png diff --git a/tools/editor/icons/icon_mini_aabb.png b/tools/editor/icons/icon_mini_aabb.png Binary files differnew file mode 100644 index 0000000000..a0b11821a9 --- /dev/null +++ b/tools/editor/icons/icon_mini_aabb.png diff --git a/tools/editor/icons/icon_mini_array.png b/tools/editor/icons/icon_mini_array.png Binary files differnew file mode 100644 index 0000000000..2df4a7d516 --- /dev/null +++ b/tools/editor/icons/icon_mini_array.png diff --git a/tools/editor/icons/icon_mini_boolean.png b/tools/editor/icons/icon_mini_boolean.png Binary files differnew file mode 100644 index 0000000000..8753084a5b --- /dev/null +++ b/tools/editor/icons/icon_mini_boolean.png diff --git a/tools/editor/icons/icon_mini_color.png b/tools/editor/icons/icon_mini_color.png Binary files differnew file mode 100644 index 0000000000..ef4e6b5468 --- /dev/null +++ b/tools/editor/icons/icon_mini_color.png diff --git a/tools/editor/icons/icon_mini_color_array.png b/tools/editor/icons/icon_mini_color_array.png Binary files differnew file mode 100644 index 0000000000..fa82c20664 --- /dev/null +++ b/tools/editor/icons/icon_mini_color_array.png diff --git a/tools/editor/icons/icon_mini_dictionary.png b/tools/editor/icons/icon_mini_dictionary.png Binary files differnew file mode 100644 index 0000000000..581a7e4e94 --- /dev/null +++ b/tools/editor/icons/icon_mini_dictionary.png diff --git a/tools/editor/icons/icon_mini_float.png b/tools/editor/icons/icon_mini_float.png Binary files differnew file mode 100644 index 0000000000..240fe7741b --- /dev/null +++ b/tools/editor/icons/icon_mini_float.png diff --git a/tools/editor/icons/icon_mini_float_array.png b/tools/editor/icons/icon_mini_float_array.png Binary files differnew file mode 100644 index 0000000000..205c117522 --- /dev/null +++ b/tools/editor/icons/icon_mini_float_array.png diff --git a/tools/editor/icons/icon_mini_image.png b/tools/editor/icons/icon_mini_image.png Binary files differnew file mode 100644 index 0000000000..8433f57b33 --- /dev/null +++ b/tools/editor/icons/icon_mini_image.png diff --git a/tools/editor/icons/icon_mini_input.png b/tools/editor/icons/icon_mini_input.png Binary files differnew file mode 100644 index 0000000000..5d52ed70f8 --- /dev/null +++ b/tools/editor/icons/icon_mini_input.png diff --git a/tools/editor/icons/icon_mini_int_array.png b/tools/editor/icons/icon_mini_int_array.png Binary files differnew file mode 100644 index 0000000000..3b7bf7dc62 --- /dev/null +++ b/tools/editor/icons/icon_mini_int_array.png diff --git a/tools/editor/icons/icon_mini_integer.png b/tools/editor/icons/icon_mini_integer.png Binary files differnew file mode 100644 index 0000000000..17f3762a46 --- /dev/null +++ b/tools/editor/icons/icon_mini_integer.png diff --git a/tools/editor/icons/icon_mini_matrix3.png b/tools/editor/icons/icon_mini_matrix3.png Binary files differnew file mode 100644 index 0000000000..be97f2014a --- /dev/null +++ b/tools/editor/icons/icon_mini_matrix3.png diff --git a/tools/editor/icons/icon_mini_matrix32.png b/tools/editor/icons/icon_mini_matrix32.png Binary files differnew file mode 100644 index 0000000000..33963066b0 --- /dev/null +++ b/tools/editor/icons/icon_mini_matrix32.png diff --git a/tools/editor/icons/icon_mini_object.png b/tools/editor/icons/icon_mini_object.png Binary files differnew file mode 100644 index 0000000000..ba38ad06b1 --- /dev/null +++ b/tools/editor/icons/icon_mini_object.png diff --git a/tools/editor/icons/icon_mini_path.png b/tools/editor/icons/icon_mini_path.png Binary files differnew file mode 100644 index 0000000000..7645ba6257 --- /dev/null +++ b/tools/editor/icons/icon_mini_path.png diff --git a/tools/editor/icons/icon_mini_plane.png b/tools/editor/icons/icon_mini_plane.png Binary files differnew file mode 100644 index 0000000000..d4f2bda241 --- /dev/null +++ b/tools/editor/icons/icon_mini_plane.png diff --git a/tools/editor/icons/icon_mini_quat.png b/tools/editor/icons/icon_mini_quat.png Binary files differnew file mode 100644 index 0000000000..991b684fcb --- /dev/null +++ b/tools/editor/icons/icon_mini_quat.png diff --git a/tools/editor/icons/icon_mini_raw_array.png b/tools/editor/icons/icon_mini_raw_array.png Binary files differnew file mode 100644 index 0000000000..a655edde01 --- /dev/null +++ b/tools/editor/icons/icon_mini_raw_array.png diff --git a/tools/editor/icons/icon_mini_rect2.png b/tools/editor/icons/icon_mini_rect2.png Binary files differnew file mode 100644 index 0000000000..9d5d48f78c --- /dev/null +++ b/tools/editor/icons/icon_mini_rect2.png diff --git a/tools/editor/icons/icon_mini_rid.png b/tools/editor/icons/icon_mini_rid.png Binary files differnew file mode 100644 index 0000000000..c85e40f315 --- /dev/null +++ b/tools/editor/icons/icon_mini_rid.png diff --git a/tools/editor/icons/icon_mini_string.png b/tools/editor/icons/icon_mini_string.png Binary files differnew file mode 100644 index 0000000000..0e1198eac0 --- /dev/null +++ b/tools/editor/icons/icon_mini_string.png diff --git a/tools/editor/icons/icon_mini_string_array.png b/tools/editor/icons/icon_mini_string_array.png Binary files differnew file mode 100644 index 0000000000..2d8e4ff0aa --- /dev/null +++ b/tools/editor/icons/icon_mini_string_array.png diff --git a/tools/editor/icons/icon_mini_transform.png b/tools/editor/icons/icon_mini_transform.png Binary files differnew file mode 100644 index 0000000000..b90ee1cef8 --- /dev/null +++ b/tools/editor/icons/icon_mini_transform.png diff --git a/tools/editor/icons/icon_mini_variant.png b/tools/editor/icons/icon_mini_variant.png Binary files differnew file mode 100644 index 0000000000..84b1e04264 --- /dev/null +++ b/tools/editor/icons/icon_mini_variant.png diff --git a/tools/editor/icons/icon_mini_vector2.png b/tools/editor/icons/icon_mini_vector2.png Binary files differnew file mode 100644 index 0000000000..56b7726137 --- /dev/null +++ b/tools/editor/icons/icon_mini_vector2.png diff --git a/tools/editor/icons/icon_mini_vector2_array.png b/tools/editor/icons/icon_mini_vector2_array.png Binary files differnew file mode 100644 index 0000000000..a8dd5e89a0 --- /dev/null +++ b/tools/editor/icons/icon_mini_vector2_array.png diff --git a/tools/editor/icons/icon_mini_vector3.png b/tools/editor/icons/icon_mini_vector3.png Binary files differnew file mode 100644 index 0000000000..b8999c9c22 --- /dev/null +++ b/tools/editor/icons/icon_mini_vector3.png diff --git a/tools/editor/icons/icon_mini_vector3_array.png b/tools/editor/icons/icon_mini_vector3_array.png Binary files differnew file mode 100644 index 0000000000..94a6f64043 --- /dev/null +++ b/tools/editor/icons/icon_mini_vector3_array.png diff --git a/tools/editor/icons/icon_override.png b/tools/editor/icons/icon_override.png Binary files differnew file mode 100644 index 0000000000..bbba220bcb --- /dev/null +++ b/tools/editor/icons/icon_override.png diff --git a/tools/editor/icons/icon_uninstance.png b/tools/editor/icons/icon_uninstance.png Binary files differnew file mode 100644 index 0000000000..de8b2f9a40 --- /dev/null +++ b/tools/editor/icons/icon_uninstance.png diff --git a/tools/editor/icons/icon_variant.png b/tools/editor/icons/icon_variant.png Binary files differnew file mode 100644 index 0000000000..1ae2812ff7 --- /dev/null +++ b/tools/editor/icons/icon_variant.png diff --git a/tools/editor/icons/icon_visual_script.png b/tools/editor/icons/icon_visual_script.png Binary files differnew file mode 100644 index 0000000000..f4414088b9 --- /dev/null +++ b/tools/editor/icons/icon_visual_script.png diff --git a/tools/editor/icons/icon_visual_shader_port.png b/tools/editor/icons/icon_visual_shader_port.png Binary files differnew file mode 100644 index 0000000000..9acdc17c3b --- /dev/null +++ b/tools/editor/icons/icon_visual_shader_port.png diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index be4b002d89..74c8ac9766 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -263,369 +263,11 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() { ScriptEditor *ScriptEditor::script_editor=NULL; -Vector<String> ScriptTextEditor::get_functions() { - - - String errortxt; - int line=-1,col; - TextEdit *te=get_text_edit(); - String text = te->get_text(); - List<String> fnc; - - if (script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) { - - //if valid rewrite functions to latest - functions.clear(); - for (List<String>::Element *E=fnc.front();E;E=E->next()) { - - functions.push_back(E->get()); - } - - - } - - return functions; -} - -void ScriptTextEditor::apply_code() { - - if (script.is_null()) - return; -// print_line("applying code"); - script->set_source_code(get_text_edit()->get_text()); - script->update_exports(); -} - -Ref<Script> ScriptTextEditor::get_edited_script() const { - - return script; -} - -void ScriptTextEditor::_load_theme_settings() { - - get_text_edit()->clear_colors(); - - /* keyword color */ - - - get_text_edit()->set_custom_bg_color(EDITOR_DEF("text_editor/background_color",Color(0,0,0,0))); - get_text_edit()->add_color_override("completion_background_color", EDITOR_DEF("text_editor/completion_background_color", Color(0,0,0,0))); - get_text_edit()->add_color_override("completion_selected_color", EDITOR_DEF("text_editor/completion_selected_color", Color::html("434244"))); - get_text_edit()->add_color_override("completion_existing_color", EDITOR_DEF("text_editor/completion_existing_color", Color::html("21dfdfdf"))); - get_text_edit()->add_color_override("completion_scroll_color", EDITOR_DEF("text_editor/completion_scroll_color", Color::html("ffffff"))); - get_text_edit()->add_color_override("completion_font_color", EDITOR_DEF("text_editor/completion_font_color", Color::html("aaaaaa"))); - get_text_edit()->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0))); - get_text_edit()->add_color_override("line_number_color",EDITOR_DEF("text_editor/line_number_color",Color(0,0,0))); - get_text_edit()->add_color_override("caret_color",EDITOR_DEF("text_editor/caret_color",Color(0,0,0))); - get_text_edit()->add_color_override("caret_background_color",EDITOR_DEF("text_editor/caret_background_color",Color(0,0,0))); - get_text_edit()->add_color_override("font_selected_color",EDITOR_DEF("text_editor/text_selected_color",Color(1,1,1))); - get_text_edit()->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1))); - get_text_edit()->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2))); - get_text_edit()->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15))); - get_text_edit()->add_color_override("word_highlighted_color",EDITOR_DEF("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15))); - get_text_edit()->add_color_override("number_color",EDITOR_DEF("text_editor/number_color",Color(0.9,0.6,0.0,2))); - get_text_edit()->add_color_override("function_color",EDITOR_DEF("text_editor/function_color",Color(0.4,0.6,0.8))); - get_text_edit()->add_color_override("member_variable_color",EDITOR_DEF("text_editor/member_variable_color",Color(0.9,0.3,0.3))); - get_text_edit()->add_color_override("mark_color", EDITOR_DEF("text_editor/mark_color", Color(1.0,0.4,0.4,0.4))); - get_text_edit()->add_color_override("breakpoint_color", EDITOR_DEF("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2))); - get_text_edit()->add_color_override("search_result_color",EDITOR_DEF("text_editor/search_result_color",Color(0.05,0.25,0.05,1))); - get_text_edit()->add_color_override("search_result_border_color",EDITOR_DEF("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1))); - get_text_edit()->add_constant_override("line_spacing", EDITOR_DEF("text_editor/line_spacing",4)); - - Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2)); - - List<String> keywords; - script->get_language()->get_reserved_words(&keywords); - for(List<String>::Element *E=keywords.front();E;E=E->next()) { - - get_text_edit()->add_keyword_color(E->get(),keyword_color); - } - - //colorize core types - Color basetype_color= EDITOR_DEF("text_editor/base_type_color",Color(0.3,0.3,0.0)); - - get_text_edit()->add_keyword_color("Vector2",basetype_color); - get_text_edit()->add_keyword_color("Vector3",basetype_color); - get_text_edit()->add_keyword_color("Plane",basetype_color); - get_text_edit()->add_keyword_color("Quat",basetype_color); - get_text_edit()->add_keyword_color("AABB",basetype_color); - get_text_edit()->add_keyword_color("Matrix3",basetype_color); - get_text_edit()->add_keyword_color("Transform",basetype_color); - get_text_edit()->add_keyword_color("Color",basetype_color); - get_text_edit()->add_keyword_color("Image",basetype_color); - get_text_edit()->add_keyword_color("InputEvent",basetype_color); - get_text_edit()->add_keyword_color("Rect2",basetype_color); - get_text_edit()->add_keyword_color("NodePath",basetype_color); - - //colorize engine types - Color type_color= EDITOR_DEF("text_editor/engine_type_color",Color(0.0,0.2,0.4)); - - List<StringName> types; - ObjectTypeDB::get_type_list(&types); - - for(List<StringName>::Element *E=types.front();E;E=E->next()) { - - String n = E->get(); - if (n.begins_with("_")) - n = n.substr(1, n.length()); - - get_text_edit()->add_keyword_color(n,type_color); - } - - //colorize comments - Color comment_color = EDITOR_DEF("text_editor/comment_color",Color::hex(0x797e7eff)); - List<String> comments; - script->get_language()->get_comment_delimiters(&comments); - - for(List<String>::Element *E=comments.front();E;E=E->next()) { - - String comment = E->get(); - String beg = comment.get_slice(" ",0); - String end = comment.get_slice_count(" ")>1?comment.get_slice(" ",1):String(); - - get_text_edit()->add_color_region(beg,end,comment_color,end==""); - } - - //colorize strings - Color string_color = EDITOR_DEF("text_editor/string_color",Color::hex(0x6b6f00ff)); - List<String> strings; - script->get_language()->get_string_delimiters(&strings); - - for (List<String>::Element *E=strings.front();E;E=E->next()) { - - String string = E->get(); - String beg = string.get_slice(" ",0); - String end = string.get_slice_count(" ")>1?string.get_slice(" ",1):String(); - get_text_edit()->add_color_region(beg,end,string_color,end==""); - } - - //colorize symbols - Color symbol_color= EDITOR_DEF("text_editor/symbol_color",Color::hex(0x005291ff)); - get_text_edit()->set_symbol_color(symbol_color); - -} - - -void ScriptTextEditor::reload_text() { - - ERR_FAIL_COND(script.is_null()) ; - - TextEdit *te = get_text_edit(); - int column = te->cursor_get_column(); - int row = te->cursor_get_line(); - int h = te->get_h_scroll(); - int v = te->get_v_scroll(); - - te->set_text(script->get_source_code()); - te->clear_undo_history(); - te->cursor_set_line(row); - te->cursor_set_column(column); - te->set_h_scroll(h); - te->set_v_scroll(v); - - te->tag_saved_version(); - - _line_col_changed(); - -} - -void ScriptTextEditor::_notification(int p_what) { - - if (p_what==NOTIFICATION_READY) { - - //emit_signal("name_changed"); - } -} - - -bool ScriptTextEditor::is_unsaved() { - - return get_text_edit()->get_version()!=get_text_edit()->get_saved_version(); -} - -String ScriptTextEditor::get_name() { - String name; - - if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) { - name=script->get_path().get_file(); - if (get_text_edit()->get_version()!=get_text_edit()->get_saved_version()) { - name+="(*)"; - } - } else if (script->get_name()!="") - name=script->get_name(); - else - name=script->get_type()+"("+itos(script->get_instance_ID())+")"; - - return name; - -} - -Ref<Texture> ScriptTextEditor::get_icon() { - - if (get_parent_control() && get_parent_control()->has_icon(script->get_type(),"EditorIcons")) { - return get_parent_control()->get_icon(script->get_type(),"EditorIcons"); - } - - return Ref<Texture>(); -} - - - -void ScriptTextEditor::set_edited_script(const Ref<Script>& p_script) { - - ERR_FAIL_COND(!script.is_null()); - - script=p_script; - - - _load_theme_settings(); - - get_text_edit()->set_text(script->get_source_code()); - get_text_edit()->clear_undo_history(); - get_text_edit()->tag_saved_version(); - - - emit_signal("name_changed"); - _line_col_changed(); -} - - -void ScriptTextEditor::_validate_script() { - - String errortxt; - int line=-1,col; - TextEdit *te=get_text_edit(); - - String text = te->get_text(); - List<String> fnc; - - if (!script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) { - String error_text="error("+itos(line)+","+itos(col)+"): "+errortxt; - set_error(error_text); - } else { - set_error(""); - line=-1; - if (!script->is_tool()) { - script->set_source_code(text); - script->update_exports(); - //script->reload(); //will update all the variables in property editors - } - - functions.clear(); - for (List<String>::Element *E=fnc.front();E;E=E->next()) { - - functions.push_back(E->get()); - } - - } - - line--; - for(int i=0;i<te->get_line_count();i++) { - te->set_line_as_marked(i,line==i); - } - - emit_signal("name_changed"); -} - - -static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Script>& p_script) { - - if (p_current->get_owner()!=p_base && p_base!=p_current) - return NULL; - Ref<Script> c = p_current->get_script(); - if (c==p_script) - return p_current; - for(int i=0;i<p_current->get_child_count();i++) { - Node *found = _find_node_for_script(p_base,p_current->get_child(i),p_script); - if (found) - return found; - } - - return NULL; -} - -static void _find_changed_scripts_for_external_editor(Node* p_base, Node*p_current, Set<Ref<Script> > &r_scripts) { - - if (p_current->get_owner()!=p_base && p_base!=p_current) - return; - Ref<Script> c = p_current->get_script(); - - if (c.is_valid()) - r_scripts.insert(c); - - for(int i=0;i<p_current->get_child_count();i++) { - _find_changed_scripts_for_external_editor(p_base,p_current->get_child(i),r_scripts); - } - -} - -void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) { - - if (!bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor"))) - return; - - Set<Ref<Script> > scripts; - - Node *base = get_tree()->get_edited_scene_root(); - if (base) { - _find_changed_scripts_for_external_editor(base,base,scripts); - } - - for (Set<Ref<Script> >::Element *E=scripts.front();E;E=E->next()) { - - Ref<Script> script = E->get(); - - if (p_for_script.is_valid() && p_for_script!=script) - continue; - - if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) { - - continue; //internal script, who cares, though weird - } - - uint64_t last_date = script->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(script->get_path()); - - if (last_date!=date) { - - Ref<Script> rel_script = ResourceLoader::load(script->get_path(),script->get_type(),true); - ERR_CONTINUE(!rel_script.is_valid()); - script->set_source_code( rel_script->get_source_code() ); - script->set_last_modified_time( rel_script->get_last_modified_time() ); - script->update_exports(); - } - - } -} - - - -void ScriptTextEditor::_code_complete_script(const String& p_code, List<String>* r_options) { - - Node *base = get_tree()->get_edited_scene_root(); - if (base) { - base = _find_node_for_script(base,base,script); - } - String hint; - Error err = script->get_language()->complete_code(p_code,script->get_path().get_base_dir(),base,r_options,hint); - if (hint!="") { - get_text_edit()->set_code_hint(hint); - } - -} -void ScriptTextEditor::_bind_methods() { - - ADD_SIGNAL(MethodInfo("name_changed")); -} - -ScriptTextEditor::ScriptTextEditor() { -} - /*** SCRIPT EDITOR ******/ -String ScriptEditor::_get_debug_tooltip(const String&p_text,Node *_ste) { +String ScriptEditor::_get_debug_tooltip(const String&p_text,Node *_se) { - ScriptTextEditor *ste=_ste->cast_to<ScriptTextEditor>(); +// ScriptEditorBase *se=_se->cast_to<ScriptEditorBase>(); String val = debugger->get_var_value(p_text); if (val!=String()) { @@ -643,6 +285,17 @@ void ScriptEditor::_breaked(bool p_breaked,bool p_can_debug) { debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), p_breaked ); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), !p_breaked ); + for(int i=0;i<tab_container->get_child_count();i++) { + + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) { + + continue; + } + + se->set_debugger_active(p_breaked); + } + } void ScriptEditor::_show_debugger(bool p_show) { @@ -654,33 +307,6 @@ void ScriptEditor::_script_created(Ref<Script> p_script) { editor->push_item(p_script.operator->()); } -void ScriptEditor::_trim_trailing_whitespace(TextEdit *tx) { - - bool trimed_whitespace = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - if (line.ends_with(" ") || line.ends_with("\t")) { - - if (!trimed_whitespace) { - tx->begin_complex_operation(); - trimed_whitespace = true; - } - - int end = 0; - for (int j = line.length() - 1; j > -1; j--) { - if (line[j] != ' ' && line[j] != '\t') { - end = j+1; - break; - } - } - tx->set_line(i, line.substr(0, end)); - } - } - if (trimed_whitespace) { - tx->end_complex_operation(); - tx->update(); - } -} void ScriptEditor::_goto_script_line2(int p_line) { @@ -688,11 +314,11 @@ void ScriptEditor::_goto_script_line2(int p_line) { if (selected<0 || selected>=tab_container->get_child_count()) return; - ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>(); + ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>(); if (!current) return; - current->get_text_edit()->cursor_set_line(p_line); + current->goto_line(p_line); } @@ -700,7 +326,16 @@ void ScriptEditor::_goto_script_line(REF p_script,int p_line) { editor->push_item(p_script.ptr()); - _goto_script_line2(p_line); + + int selected = tab_container->get_current_tab(); + if (selected<0 || selected>=tab_container->get_child_count()) + return; + + ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>(); + if (!current) + return; + + current->goto_line(p_line,true); } @@ -725,22 +360,20 @@ void ScriptEditor::_go_to_tab(int p_idx) { Node *n = tab_container->get_current_tab_control(); - if (n->cast_to<ScriptTextEditor>()) { + if (n->cast_to<ScriptEditorBase>()) { - history[history_pos].scroll_pos=n->cast_to<ScriptTextEditor>()->get_text_edit()->get_v_scroll(); - history[history_pos].cursor_column=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_column(); - history[history_pos].cursor_row=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_line(); + history[history_pos].state=n->cast_to<ScriptEditorBase>()->get_edit_state(); } if (n->cast_to<EditorHelp>()) { - history[history_pos].scroll_pos=n->cast_to<EditorHelp>()->get_scroll(); + history[history_pos].state=n->cast_to<EditorHelp>()->get_scroll(); } } history.resize(history_pos+1); ScriptHistory sh; sh.control=c; - sh.scroll_pos=0; + sh.state=Variant(); history.push_back(sh); history_pos++; @@ -750,12 +383,12 @@ void ScriptEditor::_go_to_tab(int p_idx) { c = tab_container->get_current_tab_control(); - if (c->cast_to<ScriptTextEditor>()) { + if (c->cast_to<ScriptEditorBase>()) { - script_name_label->set_text(c->cast_to<ScriptTextEditor>()->get_name()); - script_icon->set_texture(c->cast_to<ScriptTextEditor>()->get_icon()); + script_name_label->set_text(c->cast_to<ScriptEditorBase>()->get_name()); + script_icon->set_texture(c->cast_to<ScriptEditorBase>()->get_icon()); if (is_visible()) - c->cast_to<ScriptTextEditor>()->get_text_edit()->grab_focus(); + c->cast_to<ScriptEditorBase>()->ensure_focus(); } if (c->cast_to<EditorHelp>()) { @@ -769,7 +402,8 @@ void ScriptEditor::_go_to_tab(int p_idx) { c->set_meta("__editor_pass",++edit_pass); _update_history_arrows(); - _update_script_colors(); + _update_script_colors(); + _update_selected_editor_menu(); } void ScriptEditor::_close_tab(int p_idx) { @@ -779,9 +413,12 @@ void ScriptEditor::_close_tab(int p_idx) { return; Node *tselected = tab_container->get_child(selected); - ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>(); + ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>(); if (current) { apply_scripts(); + if (current->get_edit_menu()) { + memdelete(current->get_edit_menu()); + } } //remove from history @@ -833,9 +470,9 @@ void ScriptEditor::_close_docs_tab() { int child_count = tab_container->get_child_count(); for (int i = child_count-1; i>=0; i--) { - EditorHelp *ste = tab_container->get_child(i)->cast_to<EditorHelp>(); + EditorHelp *se = tab_container->get_child(i)->cast_to<EditorHelp>(); - if (ste) { + if (se) { _close_tab(i); } @@ -851,21 +488,21 @@ void ScriptEditor::_resave_scripts(const String& p_str) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) continue; //internal script, who cares if (trim_trailing_whitespace_on_save) { - _trim_trailing_whitespace(ste->get_text_edit()); + se->trim_trailing_whitespace(); } editor->save_resource(script); - ste->get_text_edit()->tag_saved_version(); + se->tag_saved_version(); } disk_changed->hide(); @@ -878,14 +515,14 @@ void ScriptEditor::_reload_scripts(){ for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) { continue; } - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) { @@ -907,7 +544,7 @@ void ScriptEditor::_reload_scripts(){ script->set_source_code( rel_script->get_source_code() ); script->set_last_modified_time( rel_script->get_last_modified_time() ); script->reload(); - ste->reload_text(); + se->reload_text(); } @@ -925,14 +562,14 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource>& p_res) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) { continue; } - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) { continue; //internal script, who cares @@ -940,7 +577,7 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource>& p_res) { if (script==p_res) { - ste->get_text_edit()->tag_saved_version(); + se->tag_saved_version(); } } @@ -975,10 +612,10 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (ste) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (se) { - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (p_for_script.is_valid() && p_for_script!=script) continue; @@ -996,7 +633,7 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { TreeItem *ti = disk_changed_list->create_item(r); ti->set_text(0,script->get_path().get_file()); - if (!use_autoreload || ste->is_unsaved()) { + if (!use_autoreload || se->is_unsaved()) { need_ask=true; } need_reload=true; @@ -1019,27 +656,6 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { return need_reload; } -void ScriptEditor::swap_lines(TextEdit *tx, int line1, int line2) -{ - String tmp = tx->get_line(line1); - String tmp2 = tx->get_line(line2); - tx->set_line(line2, tmp); - tx->set_line(line1, tmp2); - - tx->cursor_set_line(line2); -} - -void ScriptEditor::_breakpoint_toggled(const int p_row) { - int selected = tab_container->get_current_tab(); - if (selected<0 || selected>=tab_container->get_child_count()) { - return; - } - - ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>(); - if (current) { - get_debugger()->set_breakpoint(current->get_edited_script()->get_path(),p_row+1,current->get_text_edit()->is_line_set_as_breakpoint(p_row)); - } -} void ScriptEditor::_file_dialog_action(String p_file) { @@ -1081,12 +697,12 @@ void ScriptEditor::_menu_option(int p_option) { #if 0 for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptTextEditor *se = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); + if (!se) continue; - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) continue; //internal script, who cares @@ -1180,7 +796,7 @@ void ScriptEditor::_menu_option(int p_option) { if (selected<0 || selected>=tab_container->get_child_count()) return; - ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>(); + ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>(); if (current) { switch(p_option) { @@ -1193,403 +809,36 @@ void ScriptEditor::_menu_option(int p_option) { if (_test_script_times_on_disk()) return; - if (trim_trailing_whitespace_on_save) { - _trim_trailing_whitespace(current->get_text_edit()); - } + if (trim_trailing_whitespace_on_save) + current->trim_trailing_whitespace(); editor->save_resource( current->get_edited_script() ); } break; case FILE_SAVE_AS: { - if (trim_trailing_whitespace_on_save) { - _trim_trailing_whitespace(current->get_text_edit()); - } + current->trim_trailing_whitespace(); editor->push_item(current->get_edited_script()->cast_to<Object>()); editor->save_resource_as( current->get_edited_script() ); } break; - case EDIT_UNDO: { - current->get_text_edit()->undo(); - current->get_text_edit()->call_deferred("grab_focus"); - } break; - case EDIT_REDO: { - current->get_text_edit()->redo(); - current->get_text_edit()->call_deferred("grab_focus"); - } break; - case EDIT_CUT: { - - current->get_text_edit()->cut(); - current->get_text_edit()->call_deferred("grab_focus"); - } break; - case EDIT_COPY: { - current->get_text_edit()->copy(); - current->get_text_edit()->call_deferred("grab_focus"); - - } break; - case EDIT_PASTE: { - current->get_text_edit()->paste(); - current->get_text_edit()->call_deferred("grab_focus"); - - } break; - case EDIT_SELECT_ALL: { - - current->get_text_edit()->select_all(); - current->get_text_edit()->call_deferred("grab_focus"); - - } break; - case EDIT_MOVE_LINE_UP: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) - { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = from_line; i <= to_line; i++) - { - int line_id = i; - int next_id = i - 1; - - if (line_id == 0 || next_id < 0) - return; - - swap_lines(tx, line_id, next_id); - } - int from_line_up = from_line > 0 ? from_line-1 : from_line; - int to_line_up = to_line > 0 ? to_line-1 : to_line; - tx->select(from_line_up, from_col, to_line_up, to_column); - } - else - { - int line_id = tx->cursor_get_line(); - int next_id = line_id - 1; - - if (line_id == 0 || next_id < 0) - return; - - swap_lines(tx, line_id, next_id); - } - tx->end_complex_operation(); - tx->update(); - - } break; - case EDIT_MOVE_LINE_DOWN: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) - { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = to_line; i >= from_line; i--) - { - int line_id = i; - int next_id = i + 1; - - if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count()) - return; - - swap_lines(tx, line_id, next_id); - } - int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line; - int to_line_down = to_line < tx->get_line_count() ? to_line+1 : to_line; - tx->select(from_line_down, from_col, to_line_down, to_column); - } - else - { - int line_id = tx->cursor_get_line(); - int next_id = line_id + 1; - - if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count()) - return; - - swap_lines(tx, line_id, next_id); - } - tx->end_complex_operation(); - tx->update(); - - } break; - case EDIT_INDENT_LEFT: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) - { - tx->indent_selection_left(); - } - else - { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - // begins with tab - if (line_text.begins_with("\t")) - { - line_text = line_text.substr(1, line_text.length()); - tx->set_line(begin, line_text); - } - // begins with 4 spaces - else if (line_text.begins_with(" ")) - { - line_text = line_text.substr(4, line_text.length()); - tx->set_line(begin, line_text); - } - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); - - } break; - case EDIT_INDENT_RIGHT: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) - { - tx->indent_selection_right(); - } - else - { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - line_text = '\t' + line_text; - tx->set_line(begin, line_text); - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); - - } break; - case EDIT_CLONE_DOWN: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - - int from_line = tx->cursor_get_line(); - int to_line = tx->cursor_get_line(); - int column = tx->cursor_get_column(); - - if (tx->is_selection_active()) { - from_line = tx->get_selection_from_line(); - to_line = tx->get_selection_to_line(); - column = tx->cursor_get_column(); - } - int next_line = to_line + 1; - - tx->begin_complex_operation(); - for (int i = from_line; i <= to_line; i++) { - - if (i >= tx->get_line_count() - 1) { - tx->set_line(i, tx->get_line(i) + "\n"); - } - String line_clone = tx->get_line(i); - tx->insert_at(line_clone, next_line); - next_line++; - } - - tx->cursor_set_column(column); - if (tx->is_selection_active()) { - tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); - } - - tx->end_complex_operation(); - tx->update(); - - } break; - case EDIT_TOGGLE_COMMENT: { - - TextEdit *tx = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - - - tx->begin_complex_operation(); - if (tx->is_selection_active()) - { - int begin = tx->get_selection_from_line(); - int end = tx->get_selection_to_line(); - - // End of selection ends on the first column of the last line, ignore it. - if(tx->get_selection_to_column() == 0) - end -= 1; - - for (int i = begin; i <= end; i++) - { - String line_text = tx->get_line(i); - - if (line_text.begins_with("#")) - line_text = line_text.substr(1, line_text.length()); - else - line_text = "#" + line_text; - tx->set_line(i, line_text); - } - } - else - { - int begin = tx->cursor_get_line(); - String line_text = tx->get_line(begin); - - if (line_text.begins_with("#")) - line_text = line_text.substr(1, line_text.length()); - else - line_text = "#" + line_text; - tx->set_line(begin, line_text); - } - tx->end_complex_operation(); - tx->update(); - //tx->deselect(); - - } break; - case EDIT_COMPLETE: { - - current->get_text_edit()->query_code_comple(); - - } break; - case EDIT_AUTO_INDENT: { - - TextEdit *te = current->get_text_edit(); - String text = te->get_text(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - int begin,end; - if (te->is_selection_active()) { - begin=te->get_selection_from_line(); - end=te->get_selection_to_line(); - } else { - begin=0; - end=te->get_line_count()-1; - } - scr->get_language()->auto_indent_code(text,begin,end); - te->set_text(text); - - - } break; case FILE_TOOL_RELOAD: case FILE_TOOL_RELOAD_SOFT: { - TextEdit *te = current->get_text_edit(); - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) - return; - scr->set_source_code(te->get_text()); - bool soft = p_option==FILE_TOOL_RELOAD_SOFT || scr->get_instance_base_type()=="EditorPlugin"; //always soft-reload editor plugins - - scr->get_language()->reload_tool_script(scr,soft); - } break; - case EDIT_TRIM_TRAILING_WHITESAPCE: { - _trim_trailing_whitespace(current->get_text_edit()); - } break; - case SEARCH_FIND: { - - current->get_find_replace_bar()->popup_search(); - } break; - case SEARCH_FIND_NEXT: { - - current->get_find_replace_bar()->search_next(); - } break; - case SEARCH_FIND_PREV: { - - current->get_find_replace_bar()->search_prev(); - } break; - case SEARCH_REPLACE: { - - current->get_find_replace_bar()->popup_replace(); - } break; - case SEARCH_LOCATE_FUNCTION: { + current->reload(p_option==FILE_TOOL_RELOAD_SOFT); - if (!current) - return; - quick_open->popup(current->get_functions()); } break; - case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(current->get_text_edit()); - } break; - case DEBUG_TOGGLE_BREAKPOINT: { - int line=current->get_text_edit()->cursor_get_line(); - bool dobreak = !current->get_text_edit()->is_line_set_as_breakpoint(line); - current->get_text_edit()->set_line_as_breakpoint(line,dobreak); - get_debugger()->set_breakpoint(current->get_edited_script()->get_path(),line+1,dobreak); - } break; - case DEBUG_REMOVE_ALL_BREAKPOINTS: { - List<int> bpoints; - current->get_text_edit()->get_breakpoints(&bpoints); - - for(List<int>::Element *E=bpoints.front();E;E=E->next()) { - int line = E->get(); - bool dobreak = !current->get_text_edit()->is_line_set_as_breakpoint(line); - current->get_text_edit()->set_line_as_breakpoint(line,dobreak); - get_debugger()->set_breakpoint(current->get_edited_script()->get_path(),line+1,dobreak); - } - } - case DEBUG_GOTO_NEXT_BREAKPOINT: { - List<int> bpoints; - current->get_text_edit()->get_breakpoints(&bpoints); - if (bpoints.size() <= 0) { - return; - } - - int line=current->get_text_edit()->cursor_get_line(); - // wrap around - if (line >= bpoints[bpoints.size() - 1]) { - current->get_text_edit()->cursor_set_line(bpoints[0]); + case FILE_CLOSE: { + if (current->is_unsaved()) { + erase_tab_confirm->set_text("Close and save changes?\n\""+current->get_name()+"\""); + erase_tab_confirm->popup_centered_minsize(); } else { - for(List<int>::Element *E=bpoints.front();E;E=E->next()) { - int bline = E->get(); - if (bline > line) { - current->get_text_edit()->cursor_set_line(bline); - return; - } - } + _close_current_tab(); } - } break; - case DEBUG_GOTO_PREV_BREAKPOINT: { - List<int> bpoints; - current->get_text_edit()->get_breakpoints(&bpoints); - if (bpoints.size() <= 0) { - return; - } - - int line=current->get_text_edit()->cursor_get_line(); - // wrap around - if (line <= bpoints[0]) { - current->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]); - } else { - for(List<int>::Element *E=bpoints.back();E;E=E->prev()) { - int bline = E->get(); - if (bline < line) { - current->get_text_edit()->cursor_set_line(bline); - return; - } - } - } - + case CLOSE_DOCS: { + _close_docs_tab(); } break; case DEBUG_NEXT: { @@ -1614,24 +863,6 @@ void ScriptEditor::_menu_option(int p_option) { debugger->debug_continue(); } break; - case HELP_CONTEXTUAL: { - String text = current->get_text_edit()->get_selection_text(); - if (text == "") - text = current->get_text_edit()->get_word_under_cursor(); - if (text != "") - help_search_dialog->popup(text); - } break; - case FILE_CLOSE: { - if (current->get_text_edit()->get_version()!=current->get_text_edit()->get_saved_version()) { - erase_tab_confirm->set_text("Close and save changes?\n\""+current->get_name()+"\""); - erase_tab_confirm->popup_centered_minsize(); - } else { - _close_current_tab(); - } - } break; - case CLOSE_DOCS: { - _close_docs_tab(); - } break; case WINDOW_MOVE_LEFT: { if (tab_container->get_current_tab()>0) { @@ -1670,10 +901,10 @@ void ScriptEditor::_menu_option(int p_option) { switch(p_option) { - case SEARCH_FIND: { + case HELP_SEARCH_FIND: { help->popup_search(); } break; - case SEARCH_FIND_NEXT: { + case HELP_SEARCH_FIND_NEXT: { help->search_again(); } break; case FILE_CLOSE: { @@ -1763,11 +994,11 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String& p_scene) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); - if (ste) { + if (se) { - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (!script.is_valid()) continue; @@ -1816,12 +1047,12 @@ Dictionary ScriptEditor::get_state() const { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptTextEditor *se = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); + if (!se) continue; - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script->get_path()!="" && script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) { paths.push_back(script->get_path()); @@ -1893,10 +1124,10 @@ void ScriptEditor::clear() { List<ScriptTextEditor*> stes; for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptTextEditor *se = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); + if (!se) continue; - stes.push_back(ste); + stes.push_back(se); } @@ -1922,16 +1153,16 @@ void ScriptEditor::clear() { void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { + for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; List<int> bpoints; - ste->get_text_edit()->get_breakpoints(&bpoints); - - Ref<Script> script = ste->get_edited_script(); + se->get_breakpoints(&bpoints); + Ref<Script> script = se->get_edited_script(); String base = script->get_path(); ERR_CONTINUE( base.begins_with("local://") || base=="" ); @@ -1957,10 +1188,10 @@ void ScriptEditor::ensure_focus_current() { Control *c = tab_container->get_child(cidx)->cast_to<Control>(); if (!c) return; - ScriptTextEditor *ste = c->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = c->cast_to<ScriptEditorBase>(); + if (!se) return; - ste->get_text_edit()->grab_focus(); + se->ensure_focus(); } void ScriptEditor::_script_selected(int p_idx) { @@ -1979,17 +1210,17 @@ void ScriptEditor::ensure_select_current() { Node *current = tab_container->get_child(tab_container->get_current_tab()); - ScriptTextEditor *ste = current->cast_to<ScriptTextEditor>(); - if (ste) { + ScriptEditorBase *se = current->cast_to<ScriptEditorBase>(); + if (se) { - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (!grab_focus_block && is_visible()) - ste->get_text_edit()->grab_focus(); + se->ensure_focus(); + - edit_menu->show(); - search_menu->show(); - script_search_menu->hide(); + //edit_menu->show(); + //search_menu->show(); } @@ -1997,14 +1228,14 @@ void ScriptEditor::ensure_select_current() { EditorHelp *eh = current->cast_to<EditorHelp>(); if (eh) { - edit_menu->hide(); - search_menu->hide(); - script_search_menu->show(); + //edit_menu->hide(); + //search_menu->hide(); + //script_search_menu->show(); } } - + _update_selected_editor_menu(); @@ -2099,19 +1330,19 @@ void ScriptEditor::_update_script_names() { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (ste) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (se) { - String name = ste->get_name(); - Ref<Texture> icon = ste->get_icon(); - String tooltip = ste->get_edited_script()->get_path(); + String name = se->get_name(); + Ref<Texture> icon = se->get_icon(); + String tooltip = se->get_edited_script()->get_path(); _ScriptEditorItemData sd; sd.icon=icon; sd.name=name; sd.tooltip=tooltip; sd.index=i; - sd.used=used.has(ste->get_edited_script()); + sd.used=used.has(se->get_edited_script()); sd.category=0; sedata.push_back(sd); @@ -2202,11 +1433,11 @@ void ScriptEditor::edit(const Ref<Script>& p_script) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; - if (ste->get_edited_script()==p_script) { + if (se->get_edited_script()==p_script) { if (open_dominant || !EditorNode::get_singleton()->is_changing_scene()) { if (tab_container->get_current_tab()!=i) { @@ -2214,7 +1445,7 @@ void ScriptEditor::edit(const Ref<Script>& p_script) { script_list->select( script_list->find_metadata(i) ); } if (is_visible()) - ste->get_text_edit()->grab_focus(); + se->ensure_focus(); } return; } @@ -2222,33 +1453,35 @@ void ScriptEditor::edit(const Ref<Script>& p_script) { // doesn't have it, make a new one - ScriptTextEditor *ste = memnew( ScriptTextEditor ); - ste->set_edited_script(p_script); - ste->get_text_edit()->set_tooltip_request_func(this,"_get_debug_tooltip",ste); - ste->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); - ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); - ste->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); - ste->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); - ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); - ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); - ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); - ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); - ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); - ste->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter")); - ste->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); - ste->get_text_edit()->set_callhint_settings( - EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"), - EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset")); - ste->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); - tab_container->add_child(ste); + ScriptEditorBase *se; + + for(int i=script_editor_func_count-1;i>=0;i--) { + se = script_editor_funcs[i](p_script); + if (se) + break; + } + ERR_FAIL_COND(!se); + tab_container->add_child(se); + se->set_edited_script(p_script); + se->set_tooltip_request_func("_get_debug_tooltip",this); + if (se->get_edit_menu()) { + se->get_edit_menu()->hide(); + menu_hb->add_child(se->get_edit_menu()); + menu_hb->move_child(se->get_edit_menu(),1); + } + + _go_to_tab(tab_container->get_tab_count()-1); + _update_script_names(); _save_layout(); - ste->connect("name_changed",this,"_update_script_names"); + se->connect("name_changed",this,"_update_script_names"); + se->connect("request_help_search",this,"_help_search"); + //test for modification, maybe the script was not edited but was loaded @@ -2262,20 +1495,21 @@ void ScriptEditor::save_all_scripts() { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; + if (!se->is_unsaved()) + continue; + if (trim_trailing_whitespace_on_save) { - _trim_trailing_whitespace(ste->get_text_edit()); + se->trim_trailing_whitespace(); } - if (ste->get_text_edit()->get_version()==ste->get_text_edit()->get_saved_version()) - continue; - Ref<Script> script = ste->get_edited_script(); + Ref<Script> script = se->get_edited_script(); if (script.is_valid()) - ste->apply_code(); + se->apply_code(); if (script->get_path()!="" && script->get_path().find("local://")==-1 &&script->get_path().find("::")==-1) { //external script, save it @@ -2287,16 +1521,18 @@ void ScriptEditor::save_all_scripts() { } + _update_script_names(); + } void ScriptEditor::apply_scripts() const { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; - ste->apply_code(); + se->apply_code(); } } @@ -2323,6 +1559,17 @@ void ScriptEditor::_editor_stop() { debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), true ); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true ); debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true ); + + for(int i=0;i<tab_container->get_child_count();i++) { + + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) { + + continue; + } + + se->set_debugger_active(false); + } } @@ -2337,28 +1584,15 @@ void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; - if (ste->get_edited_script()!=script) + if (se->get_edited_script()!=script) continue; - String code = ste->get_text_edit()->get_text(); - int pos = script->get_language()->find_function(p_function,code); - if (pos==-1) { - //does not exist - ste->get_text_edit()->deselect(); - pos=ste->get_text_edit()->get_line_count()+2; - String func = script->get_language()->make_function("",p_function,p_args); - //code=code+func; - ste->get_text_edit()->cursor_set_line(pos+1); - ste->get_text_edit()->cursor_set_column(1000000); //none shall be that big - ste->get_text_edit()->insert_text_at_cursor("\n\n"+func); - } + se->add_callback(p_function,p_args); _go_to_tab(i); - ste->get_text_edit()->cursor_set_line(pos); - ste->get_text_edit()->cursor_set_column(1); script_list->select( script_list->find_metadata(i) ); @@ -2397,21 +1631,11 @@ void ScriptEditor::_editor_settings_changed() { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (!ste) + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (!se) continue; - ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); - ste->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); - ste->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); - ste->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); - ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); - ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); - ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); - ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); - ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); - ste->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter")); - ste->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); + se->update_settings(); } ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/auto_reload_and_parse_scripts_on_save",true)); @@ -2507,10 +1731,10 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { for(int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); - if (ste) { + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (se) { - String path = ste->get_edited_script()->get_path(); + String path = se->get_edited_script()->get_path(); if (!path.is_resource_file()) continue; @@ -2589,19 +1813,47 @@ void ScriptEditor::_help_class_goto(const String& p_desc) { _save_layout(); } +void ScriptEditor::_update_selected_editor_menu() { + + for(int i=0;i<tab_container->get_child_count();i++) { + + bool current = tab_container->get_current_tab() == i; + + ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); + if (se && se->get_edit_menu()) { + + if (current) + se->get_edit_menu()->show(); + else + se->get_edit_menu()->hide(); + } + + EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>(); + + if (eh) { + + if (current) + script_search_menu->show(); + else + script_search_menu->hide(); + } + + + } + +} + void ScriptEditor::_update_history_pos(int p_new_pos) { Node *n = tab_container->get_current_tab_control(); - if (n->cast_to<ScriptTextEditor>()) { + if (n->cast_to<ScriptEditorBase>()) { - history[history_pos].scroll_pos=n->cast_to<ScriptTextEditor>()->get_text_edit()->get_v_scroll(); - history[history_pos].cursor_column=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_column(); - history[history_pos].cursor_row=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_line(); + history[history_pos].state=n->cast_to<ScriptEditorBase>()->get_edit_state(); } if (n->cast_to<EditorHelp>()) { - history[history_pos].scroll_pos=n->cast_to<EditorHelp>()->get_scroll(); + history[history_pos].state=n->cast_to<EditorHelp>()->get_scroll(); } history_pos=p_new_pos; @@ -2609,23 +1861,22 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { n = history[history_pos].control; - if (n->cast_to<ScriptTextEditor>()) { + if (n->cast_to<ScriptEditorBase>()) { - n->cast_to<ScriptTextEditor>()->get_text_edit()->set_v_scroll(history[history_pos].scroll_pos); - n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_set_column( history[history_pos].cursor_column ); - n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_set_line( history[history_pos].cursor_row ); - n->cast_to<ScriptTextEditor>()->get_text_edit()->grab_focus(); + n->cast_to<ScriptEditorBase>()->set_edit_state(history[history_pos].state); + n->cast_to<ScriptEditorBase>()->ensure_focus(); } if (n->cast_to<EditorHelp>()) { - n->cast_to<EditorHelp>()->set_scroll(history[history_pos].scroll_pos); + n->cast_to<EditorHelp>()->set_scroll(history[history_pos].state); n->cast_to<EditorHelp>()->set_focused(); } n->set_meta("__editor_pass",++edit_pass); _update_script_names(); _update_history_arrows(); + _update_selected_editor_menu(); } @@ -2657,52 +1908,38 @@ void ScriptEditor::set_scene_root_script( Ref<Script> p_script ) { bool ScriptEditor::script_go_to_method(Ref<Script> p_script, const String& p_method) { - Vector<String> functions; - bool found=false; for (int i=0;i<tab_container->get_child_count();i++) { - ScriptTextEditor *current = tab_container->get_child(i)->cast_to<ScriptTextEditor>(); + ScriptEditorBase *current = tab_container->get_child(i)->cast_to<ScriptEditorBase>(); if (current && current->get_edited_script()==p_script) { - functions=current->get_functions(); - found=true; + if (current->goto_method(p_method)) { + edit(p_script); + return true; + } break; } } + return false; +} - if (!found) { - String errortxt; - int line=-1,col; - String text=p_script->get_source_code(); - List<String> fnc; - - if (p_script->get_language()->validate(text,line,col,errortxt,p_script->get_path(),&fnc)) { - - for (List<String>::Element *E=fnc.front();E;E=E->next()) - functions.push_back(E->get()); - } - } - - String method_search = p_method + ":"; +void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) { - for (int i=0;i<functions.size();i++) { - String function=functions[i]; + auto_reload_running_scripts=p_enabled; +} - if (function.begins_with(method_search)) { +void ScriptEditor::_help_search(String p_text) { + help_search_dialog->popup(p_text); +} - edit(p_script); - int line=function.get_slice(":",1).to_int(); - _goto_script_line2(line-1); - return true; - } - } - return false; -} +int ScriptEditor::script_editor_func_count=0; +CreateScriptEditorFunc ScriptEditor::script_editor_funcs[ScriptEditor::SCRIPT_EDITOR_FUNC_MAX]; -void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) { +void ScriptEditor::register_create_script_editor_function(CreateScriptEditorFunc p_func) { - auto_reload_running_scripts=p_enabled; + ERR_FAIL_COND(script_editor_func_count==SCRIPT_EDITOR_FUNC_MAX); + script_editor_funcs[script_editor_func_count++]=p_func; } void ScriptEditor::_bind_methods() { @@ -2721,7 +1958,9 @@ void ScriptEditor::_bind_methods() { ObjectTypeDB::bind_method("_res_saved_callback",&ScriptEditor::_res_saved_callback); ObjectTypeDB::bind_method("_goto_script_line",&ScriptEditor::_goto_script_line); ObjectTypeDB::bind_method("_goto_script_line2",&ScriptEditor::_goto_script_line2); - ObjectTypeDB::bind_method("_breakpoint_toggled", &ScriptEditor::_breakpoint_toggled); + ObjectTypeDB::bind_method("_help_search",&ScriptEditor::_help_search); + + ObjectTypeDB::bind_method("_breaked",&ScriptEditor::_breaked); ObjectTypeDB::bind_method("_show_debugger",&ScriptEditor::_show_debugger); ObjectTypeDB::bind_method("_get_debug_tooltip",&ScriptEditor::_get_debug_tooltip); @@ -2787,6 +2026,9 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As..")), FILE_SAVE_AS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_MASK_ALT|KEY_S), FILE_SAVE_ALL); file_menu->get_popup()->add_separator(); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_R), FILE_TOOL_RELOAD_SOFT); + file_menu->get_popup()->add_separator(); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_CTRL|KEY_MASK_ALT|KEY_LEFT), WINDOW_PREV); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KEY_MASK_CTRL|KEY_MASK_ALT|KEY_RIGHT), WINDOW_NEXT); file_menu->get_popup()->add_separator(); @@ -2799,54 +2041,13 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE); file_menu->get_popup()->connect("item_pressed", this,"_menu_option"); - edit_menu = memnew( MenuButton ); - menu_hb->add_child(edit_menu); - edit_menu->set_text(TTR("Edit")); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/undo", TTR("Undo"), KEY_MASK_CMD|KEY_Z), EDIT_UNDO); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/redo", TTR("Redo"), KEY_MASK_CMD|KEY_Y), EDIT_REDO); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/cut", TTR("Cut"), KEY_MASK_CMD|KEY_X), EDIT_CUT); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy", TTR("Copy"), KEY_MASK_CMD|KEY_C), EDIT_COPY); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/paste", TTR("Paste"), KEY_MASK_CMD|KEY_V), EDIT_PASTE); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/select_all", TTR("Select All"), KEY_MASK_CMD|KEY_A), EDIT_SELECT_ALL); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/move_up", TTR("Move Up"), KEY_MASK_ALT|KEY_UP), EDIT_MOVE_LINE_UP); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/move_down", TTR("Move Down"), KEY_MASK_ALT|KEY_DOWN), EDIT_MOVE_LINE_DOWN); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/indent_left", TTR("Indent Left"), KEY_MASK_ALT|KEY_LEFT), EDIT_INDENT_LEFT); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/indent_right", TTR("Indent Right"), KEY_MASK_ALT|KEY_RIGHT), EDIT_INDENT_RIGHT); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD|KEY_K), EDIT_TOGGLE_COMMENT); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD|KEY_B), EDIT_CLONE_DOWN); - edit_menu->get_popup()->add_separator(); -#ifdef OSX_ENABLED - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL|KEY_SPACE), EDIT_COMPLETE); -#else - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD|KEY_SPACE), EDIT_COMPLETE); -#endif - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CTRL|KEY_MASK_ALT|KEY_T), EDIT_TRIM_TRAILING_WHITESAPCE); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD|KEY_I), EDIT_AUTO_INDENT); - edit_menu->get_popup()->connect("item_pressed", this,"_menu_option"); - edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_R), FILE_TOOL_RELOAD_SOFT); - - - search_menu = memnew( MenuButton ); - menu_hb->add_child(search_menu); - search_menu->set_text(TTR("Search")); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F), SEARCH_FIND); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), SEARCH_FIND_NEXT); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT|KEY_F3), SEARCH_FIND_PREV); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace", TTR("Replace.."), KEY_MASK_CMD|KEY_R), SEARCH_REPLACE); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/goto_function", TTR("Goto Function.."), KEY_MASK_SHIFT|KEY_MASK_CMD|KEY_F), SEARCH_LOCATE_FUNCTION); - search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/goto_line", TTR("Goto Line.."), KEY_MASK_CMD|KEY_L), SEARCH_GOTO_LINE); - search_menu->get_popup()->connect("item_pressed", this,"_menu_option"); + script_search_menu = memnew( MenuButton ); menu_hb->add_child(script_search_menu); script_search_menu->set_text(TTR("Search")); - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F), SEARCH_FIND); - script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), SEARCH_FIND_NEXT); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F), HELP_SEARCH_FIND); + script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); script_search_menu->get_popup()->connect("item_pressed", this,"_menu_option"); script_search_menu->hide(); @@ -2854,10 +2055,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { debug_menu = memnew( MenuButton ); menu_hb->add_child(debug_menu); debug_menu->set_text(TTR("Debug")); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9), DEBUG_TOGGLE_BREAKPOINT); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CTRL|KEY_MASK_SHIFT|KEY_F9), DEBUG_REMOVE_ALL_BREAKPOINTS); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/goto_next_breakpoint", TTR("Goto Next Breakpoint"), KEY_MASK_CTRL|KEY_PERIOD), DEBUG_GOTO_NEXT_BREAKPOINT); - debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/goto_previous_breakpoint", TTR("Goto Previous Breakpoint"), KEY_MASK_CTRL|KEY_COMMA), DEBUG_GOTO_PREV_BREAKPOINT); debug_menu->get_popup()->add_separator(); debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10), DEBUG_NEXT); debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11), DEBUG_STEP); @@ -2888,11 +2085,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { #endif - help_menu = memnew( MenuButton ); - menu_hb->add_child(help_menu); - help_menu->set_text(TTR("Help")); - help_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/Contextual", TTR("Contextual Help"), KEY_MASK_SHIFT|KEY_F1), HELP_CONTEXTUAL); - help_menu->get_popup()->connect("item_pressed", this,"_menu_option"); menu_hb->add_spacer(); @@ -2957,8 +2149,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { add_child(file_dialog); file_dialog->connect("file_selected", this,"_file_dialog_action"); - goto_line_dialog = memnew(GotoLineDialog); - add_child(goto_line_dialog); debugger = memnew( ScriptEditorDebugger(editor) ); debugger->connect("goto_script_line",this,"_goto_script_line"); @@ -2991,11 +2181,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_editor=this; - quick_open = memnew( ScriptEditorQuickOpen ); - add_child(quick_open); - - quick_open->connect("goto_line",this,"_goto_script_line2"); - Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"),debugger); debugger->set_tool_button(db); diff --git a/tools/editor/plugins/script_editor_plugin.h b/tools/editor/plugins/script_editor_plugin.h index 2f079b9fc7..5cb70e13d7 100644 --- a/tools/editor/plugins/script_editor_plugin.h +++ b/tools/editor/plugins/script_editor_plugin.h @@ -73,40 +73,44 @@ public: class ScriptEditorDebugger; -class ScriptTextEditor : public CodeTextEditor { - OBJ_TYPE( ScriptTextEditor, CodeTextEditor ); - Ref<Script> script; +class ScriptEditorBase : public Control { + OBJ_TYPE( ScriptEditorBase, Control ); - Vector<String> functions; - - -protected: - - - - virtual void _validate_script(); - virtual void _code_complete_script(const String& p_code, List<String>* r_options); - virtual void _load_theme_settings(); - void _notification(int p_what); - static void _bind_methods(); +public: + virtual void apply_code()=0; + virtual Ref<Script> get_edited_script() const=0; + virtual Vector<String> get_functions()=0; + virtual void set_edited_script(const Ref<Script>& p_script)=0; + virtual void reload_text()=0; + virtual String get_name()=0; + virtual Ref<Texture> get_icon()=0; + virtual bool is_unsaved()=0; + virtual Variant get_edit_state()=0; + virtual void set_edit_state(const Variant& p_state)=0; + virtual void goto_line(int p_line,bool p_with_error=false)=0; + virtual void trim_trailing_whitespace()=0; + virtual void ensure_focus()=0; + virtual void tag_saved_version()=0; + virtual void reload(bool p_soft)=0; + virtual void get_breakpoints(List<int> *p_breakpoints)=0; + virtual bool goto_method(const String& p_method)=0; + virtual void add_callback(const String& p_function,StringArray p_args)=0; + virtual void update_settings()=0; + virtual void set_debugger_active(bool p_active)=0; + + virtual void set_tooltip_request_func(String p_method,Object* p_obj)=0; + virtual Control *get_edit_menu()=0; + + ScriptEditorBase() {} +}; -public: - virtual void apply_code(); - Ref<Script> get_edited_script() const; - Vector<String> get_functions() ; - void set_edited_script(const Ref<Script>& p_script); - void reload_text(); - String get_name() ; - Ref<Texture> get_icon() ; - bool is_unsaved(); - ScriptTextEditor(); +typedef ScriptEditorBase* (*CreateScriptEditorFunc)(const Ref<Script>& p_script); -}; class EditorScriptCodeCompletionCache; @@ -128,43 +132,19 @@ class ScriptEditor : public VBoxContainer { FILE_SAVE_THEME_AS, FILE_CLOSE, CLOSE_DOCS, - EDIT_UNDO, - EDIT_REDO, - EDIT_CUT, - EDIT_COPY, - EDIT_PASTE, - EDIT_SELECT_ALL, - EDIT_COMPLETE, - EDIT_AUTO_INDENT, - EDIT_TRIM_TRAILING_WHITESAPCE, - EDIT_TOGGLE_COMMENT, - EDIT_MOVE_LINE_UP, - EDIT_MOVE_LINE_DOWN, - EDIT_INDENT_RIGHT, - EDIT_INDENT_LEFT, - EDIT_CLONE_DOWN, FILE_TOOL_RELOAD, FILE_TOOL_RELOAD_SOFT, - SEARCH_FIND, - SEARCH_FIND_NEXT, - SEARCH_FIND_PREV, - SEARCH_REPLACE, - SEARCH_LOCATE_FUNCTION, - SEARCH_GOTO_LINE, - SEARCH_HELP, - SEARCH_CLASSES, - SEARCH_WEBSITE, - DEBUG_TOGGLE_BREAKPOINT, - DEBUG_REMOVE_ALL_BREAKPOINTS, - DEBUG_GOTO_NEXT_BREAKPOINT, - DEBUG_GOTO_PREV_BREAKPOINT, DEBUG_NEXT, DEBUG_STEP, DEBUG_BREAK, DEBUG_CONTINUE, DEBUG_SHOW, DEBUG_SHOW_KEEP_OPEN, - HELP_CONTEXTUAL, + SEARCH_HELP, + SEARCH_CLASSES, + SEARCH_WEBSITE, + HELP_SEARCH_FIND, + HELP_SEARCH_FIND_NEXT, WINDOW_MOVE_LEFT, WINDOW_MOVE_RIGHT, WINDOW_NEXT, @@ -175,10 +155,8 @@ class ScriptEditor : public VBoxContainer { HBoxContainer *menu_hb; MenuButton *file_menu; MenuButton *edit_menu; - MenuButton *search_menu; MenuButton *script_search_menu; MenuButton *debug_menu; - MenuButton *help_menu; Timer *autosave_timer; uint64_t idle; @@ -191,7 +169,6 @@ class ScriptEditor : public VBoxContainer { HSplitContainer *script_split; TabContainer *tab_container; EditorFileDialog *file_dialog; - GotoLineDialog *goto_line_dialog; ConfirmationDialog *erase_tab_confirm; ScriptCreateDialog *script_create_dialog; ScriptEditorDebugger* debugger; @@ -205,13 +182,17 @@ class ScriptEditor : public VBoxContainer { ToolButton *script_back; ToolButton *script_forward; + enum { + SCRIPT_EDITOR_FUNC_MAX=32 + }; + + static int script_editor_func_count; + static CreateScriptEditorFunc script_editor_funcs[SCRIPT_EDITOR_FUNC_MAX]; struct ScriptHistory { Control *control; - int scroll_pos; - int cursor_column; - int cursor_row; + Variant state; }; Vector<ScriptHistory> history; @@ -246,7 +227,7 @@ class ScriptEditor : public VBoxContainer { bool auto_reload_running_scripts; void _live_auto_reload_running_scripts(); - ScriptEditorQuickOpen *quick_open; + void _update_selected_editor_menu(); EditorScriptCodeCompletionCache *completion_cache; @@ -286,6 +267,7 @@ class ScriptEditor : public VBoxContainer { void _unhandled_input(const InputEvent& p_event); + void _help_search(String p_text); void _history_forward(); void _history_back(); @@ -323,8 +305,7 @@ public: void get_breakpoints(List<String> *p_breakpoints); - void swap_lines(TextEdit *tx, int line1, int line2); - void _breakpoint_toggled(const int p_row); + //void swap_lines(TextEdit *tx, int line1, int line2); void save_all_scripts(); @@ -342,6 +323,7 @@ public: ScriptEditorDebugger *get_debugger() { return debugger; } void set_live_auto_reload_running_scripts(bool p_enabled); + static void register_create_script_editor_function(CreateScriptEditorFunc p_func); ScriptEditor(EditorNode *p_editor); ~ScriptEditor(); }; diff --git a/tools/editor/plugins/script_text_editor.cpp b/tools/editor/plugins/script_text_editor.cpp new file mode 100644 index 0000000000..57cf8cbea3 --- /dev/null +++ b/tools/editor/plugins/script_text_editor.cpp @@ -0,0 +1,1091 @@ +/*************************************************************************/ +/* script_text_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "script_text_editor.h" +#include "tools/editor/editor_settings.h" +#include "os/keyboard.h" +#include "tools/editor/script_editor_debugger.h" + +Vector<String> ScriptTextEditor::get_functions() { + + + String errortxt; + int line=-1,col; + TextEdit *te=code_editor->get_text_edit(); + String text = te->get_text(); + List<String> fnc; + + if (script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) { + + //if valid rewrite functions to latest + functions.clear(); + for (List<String>::Element *E=fnc.front();E;E=E->next()) { + + functions.push_back(E->get()); + } + + + } + + return functions; +} + +void ScriptTextEditor::apply_code() { + + if (script.is_null()) + return; +// print_line("applying code"); + script->set_source_code(code_editor->get_text_edit()->get_text()); + script->update_exports(); +} + +Ref<Script> ScriptTextEditor::get_edited_script() const { + + return script; +} + +bool ScriptTextEditor::goto_method(const String& p_method) { + + + Vector<String> functions = get_functions(); + + String method_search = p_method + ":"; + + for (int i=0;i<functions.size();i++) { + String function=functions[i]; + + if (function.begins_with(method_search)) { + + int line=function.get_slice(":",1).to_int(); + goto_line(line-1); + return true; + } + } + + return false; +} + +void ScriptTextEditor::_load_theme_settings() { + + TextEdit *text_edit = code_editor->get_text_edit(); + + text_edit->clear_colors(); + + /* keyword color */ + + + text_edit->set_custom_bg_color(EDITOR_DEF("text_editor/background_color",Color(0,0,0,0))); + text_edit->add_color_override("completion_background_color", EDITOR_DEF("text_editor/completion_background_color", Color(0,0,0,0))); + text_edit->add_color_override("completion_selected_color", EDITOR_DEF("text_editor/completion_selected_color", Color::html("434244"))); + text_edit->add_color_override("completion_existing_color", EDITOR_DEF("text_editor/completion_existing_color", Color::html("21dfdfdf"))); + text_edit->add_color_override("completion_scroll_color", EDITOR_DEF("text_editor/completion_scroll_color", Color::html("ffffff"))); + text_edit->add_color_override("completion_font_color", EDITOR_DEF("text_editor/completion_font_color", Color::html("aaaaaa"))); + text_edit->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0))); + text_edit->add_color_override("line_number_color",EDITOR_DEF("text_editor/line_number_color",Color(0,0,0))); + text_edit->add_color_override("caret_color",EDITOR_DEF("text_editor/caret_color",Color(0,0,0))); + text_edit->add_color_override("caret_background_color",EDITOR_DEF("text_editor/caret_background_color",Color(0,0,0))); + text_edit->add_color_override("font_selected_color",EDITOR_DEF("text_editor/text_selected_color",Color(1,1,1))); + text_edit->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1))); + text_edit->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2))); + text_edit->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15))); + text_edit->add_color_override("word_highlighted_color",EDITOR_DEF("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15))); + text_edit->add_color_override("number_color",EDITOR_DEF("text_editor/number_color",Color(0.9,0.6,0.0,2))); + text_edit->add_color_override("function_color",EDITOR_DEF("text_editor/function_color",Color(0.4,0.6,0.8))); + text_edit->add_color_override("member_variable_color",EDITOR_DEF("text_editor/member_variable_color",Color(0.9,0.3,0.3))); + text_edit->add_color_override("mark_color", EDITOR_DEF("text_editor/mark_color", Color(1.0,0.4,0.4,0.4))); + text_edit->add_color_override("breakpoint_color", EDITOR_DEF("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2))); + text_edit->add_color_override("search_result_color",EDITOR_DEF("text_editor/search_result_color",Color(0.05,0.25,0.05,1))); + text_edit->add_color_override("search_result_border_color",EDITOR_DEF("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1))); + text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/line_spacing",4)); + + Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2)); + + List<String> keywords; + script->get_language()->get_reserved_words(&keywords); + for(List<String>::Element *E=keywords.front();E;E=E->next()) { + + text_edit->add_keyword_color(E->get(),keyword_color); + } + + //colorize core types + Color basetype_color= EDITOR_DEF("text_editor/base_type_color",Color(0.3,0.3,0.0)); + + text_edit->add_keyword_color("Vector2",basetype_color); + text_edit->add_keyword_color("Vector3",basetype_color); + text_edit->add_keyword_color("Plane",basetype_color); + text_edit->add_keyword_color("Quat",basetype_color); + text_edit->add_keyword_color("AABB",basetype_color); + text_edit->add_keyword_color("Matrix3",basetype_color); + text_edit->add_keyword_color("Transform",basetype_color); + text_edit->add_keyword_color("Color",basetype_color); + text_edit->add_keyword_color("Image",basetype_color); + text_edit->add_keyword_color("InputEvent",basetype_color); + text_edit->add_keyword_color("Rect2",basetype_color); + text_edit->add_keyword_color("NodePath",basetype_color); + + //colorize engine types + Color type_color= EDITOR_DEF("text_editor/engine_type_color",Color(0.0,0.2,0.4)); + + List<StringName> types; + ObjectTypeDB::get_type_list(&types); + + for(List<StringName>::Element *E=types.front();E;E=E->next()) { + + String n = E->get(); + if (n.begins_with("_")) + n = n.substr(1, n.length()); + + text_edit->add_keyword_color(n,type_color); + } + + //colorize comments + Color comment_color = EDITOR_DEF("text_editor/comment_color",Color::hex(0x797e7eff)); + List<String> comments; + script->get_language()->get_comment_delimiters(&comments); + + for(List<String>::Element *E=comments.front();E;E=E->next()) { + + String comment = E->get(); + String beg = comment.get_slice(" ",0); + String end = comment.get_slice_count(" ")>1?comment.get_slice(" ",1):String(); + + text_edit->add_color_region(beg,end,comment_color,end==""); + } + + //colorize strings + Color string_color = EDITOR_DEF("text_editor/string_color",Color::hex(0x6b6f00ff)); + List<String> strings; + script->get_language()->get_string_delimiters(&strings); + + for (List<String>::Element *E=strings.front();E;E=E->next()) { + + String string = E->get(); + String beg = string.get_slice(" ",0); + String end = string.get_slice_count(" ")>1?string.get_slice(" ",1):String(); + text_edit->add_color_region(beg,end,string_color,end==""); + } + + //colorize symbols + Color symbol_color= EDITOR_DEF("text_editor/symbol_color",Color::hex(0x005291ff)); + text_edit->set_symbol_color(symbol_color); + +} + + +void ScriptTextEditor::reload_text() { + + ERR_FAIL_COND(script.is_null()) ; + + TextEdit *te = code_editor->get_text_edit(); + int column = te->cursor_get_column(); + int row = te->cursor_get_line(); + int h = te->get_h_scroll(); + int v = te->get_v_scroll(); + + te->set_text(script->get_source_code()); + te->clear_undo_history(); + te->cursor_set_line(row); + te->cursor_set_column(column); + te->set_h_scroll(h); + te->set_v_scroll(v); + + te->tag_saved_version(); + + code_editor->update_line_and_column(); + +} + +void ScriptTextEditor::_notification(int p_what) { + + if (p_what==NOTIFICATION_READY) { + + //emit_signal("name_changed"); + } +} + +void ScriptTextEditor::add_callback(const String& p_function,StringArray p_args) { + + String code = code_editor->get_text_edit()->get_text(); + int pos = script->get_language()->find_function(p_function,code); + if (pos==-1) { + //does not exist + code_editor->get_text_edit()->deselect(); + pos=code_editor->get_text_edit()->get_line_count()+2; + String func = script->get_language()->make_function("",p_function,p_args); + //code=code+func; + code_editor->get_text_edit()->cursor_set_line(pos+1); + code_editor->get_text_edit()->cursor_set_column(1000000); //none shall be that big + code_editor->get_text_edit()->insert_text_at_cursor("\n\n"+func); + } + code_editor->get_text_edit()->cursor_set_line(pos); + code_editor->get_text_edit()->cursor_set_column(1); +} + +void ScriptTextEditor::update_settings() { + + code_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); + code_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); + code_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); + code_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); + code_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); + code_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); + code_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + code_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + code_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); + code_editor->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter")); + code_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); +} + +bool ScriptTextEditor::is_unsaved() { + + return code_editor->get_text_edit()->get_version()!=code_editor->get_text_edit()->get_saved_version(); +} + +Variant ScriptTextEditor::get_edit_state() { + + Dictionary state; + + state["scroll_pos"]=code_editor->get_text_edit()->get_v_scroll(); + state["column"]=code_editor->get_text_edit()->cursor_get_column(); + state["row"]=code_editor->get_text_edit()->cursor_get_line(); + + return state; +} + +void ScriptTextEditor::trim_trailing_whitespace() { + + TextEdit *tx = code_editor->get_text_edit(); + + bool trimed_whitespace = false; + for (int i = 0; i < tx->get_line_count(); i++) { + String line = tx->get_line(i); + if (line.ends_with(" ") || line.ends_with("\t")) { + + if (!trimed_whitespace) { + tx->begin_complex_operation(); + trimed_whitespace = true; + } + + int end = 0; + for (int j = line.length() - 1; j > -1; j--) { + if (line[j] != ' ' && line[j] != '\t') { + end = j+1; + break; + } + } + tx->set_line(i, line.substr(0, end)); + } + } + if (trimed_whitespace) { + tx->end_complex_operation(); + tx->update(); + } +} + +void ScriptTextEditor::tag_saved_version() { + + code_editor->get_text_edit()->tag_saved_version(); +} + +void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { + code_editor->get_text_edit()->cursor_set_line(p_line); +} + +void ScriptTextEditor::ensure_focus() { + + code_editor->get_text_edit()->grab_focus(); +} + +void ScriptTextEditor::set_edit_state(const Variant& p_state) { + + Dictionary state=p_state; + code_editor->get_text_edit()->set_v_scroll(state["scroll_pos"]); + code_editor->get_text_edit()->cursor_set_column( state["column"]); + code_editor->get_text_edit()->cursor_set_line( state["row"] ); + code_editor->get_text_edit()->grab_focus(); + + //int scroll_pos; + //int cursor_column; + //int cursor_row; +} + +String ScriptTextEditor::get_name() { + String name; + + if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) { + name=script->get_path().get_file(); + if (is_unsaved()) { + name+="(*)"; + } + } else if (script->get_name()!="") + name=script->get_name(); + else + name=script->get_type()+"("+itos(script->get_instance_ID())+")"; + + return name; + +} + +Ref<Texture> ScriptTextEditor::get_icon() { + + if (get_parent_control() && get_parent_control()->has_icon(script->get_type(),"EditorIcons")) { + return get_parent_control()->get_icon(script->get_type(),"EditorIcons"); + } + + return Ref<Texture>(); +} + + + +void ScriptTextEditor::set_edited_script(const Ref<Script>& p_script) { + + ERR_FAIL_COND(!script.is_null()); + + script=p_script; + + + _load_theme_settings(); + + code_editor->get_text_edit()->set_text(script->get_source_code()); + code_editor->get_text_edit()->clear_undo_history(); + code_editor->get_text_edit()->tag_saved_version(); + + emit_signal("name_changed"); + code_editor->update_line_and_column(); +} + + +void ScriptTextEditor::_validate_script() { + + String errortxt; + int line=-1,col; + TextEdit *te=code_editor->get_text_edit(); + + String text = te->get_text(); + List<String> fnc; + + if (!script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) { + String error_text="error("+itos(line)+","+itos(col)+"): "+errortxt; + code_editor->set_error(error_text); + } else { + code_editor->set_error(""); + line=-1; + if (!script->is_tool()) { + script->set_source_code(text); + script->update_exports(); + //script->reload(); //will update all the variables in property editors + } + + functions.clear(); + for (List<String>::Element *E=fnc.front();E;E=E->next()) { + + functions.push_back(E->get()); + } + + } + + line--; + for(int i=0;i<te->get_line_count();i++) { + te->set_line_as_marked(i,line==i); + } + + emit_signal("name_changed"); +} + + +static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Script>& p_script) { + + if (p_current->get_owner()!=p_base && p_base!=p_current) + return NULL; + Ref<Script> c = p_current->get_script(); + if (c==p_script) + return p_current; + for(int i=0;i<p_current->get_child_count();i++) { + Node *found = _find_node_for_script(p_base,p_current->get_child(i),p_script); + if (found) + return found; + } + + return NULL; +} + +static void _find_changed_scripts_for_external_editor(Node* p_base, Node*p_current, Set<Ref<Script> > &r_scripts) { + + if (p_current->get_owner()!=p_base && p_base!=p_current) + return; + Ref<Script> c = p_current->get_script(); + + if (c.is_valid()) + r_scripts.insert(c); + + for(int i=0;i<p_current->get_child_count();i++) { + _find_changed_scripts_for_external_editor(p_base,p_current->get_child(i),r_scripts); + } + +} + +void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) { + + if (!bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor"))) + return; + + Set<Ref<Script> > scripts; + + Node *base = get_tree()->get_edited_scene_root(); + if (base) { + _find_changed_scripts_for_external_editor(base,base,scripts); + } + + for (Set<Ref<Script> >::Element *E=scripts.front();E;E=E->next()) { + + Ref<Script> script = E->get(); + + if (p_for_script.is_valid() && p_for_script!=script) + continue; + + if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) { + + continue; //internal script, who cares, though weird + } + + uint64_t last_date = script->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(script->get_path()); + + if (last_date!=date) { + + Ref<Script> rel_script = ResourceLoader::load(script->get_path(),script->get_type(),true); + ERR_CONTINUE(!rel_script.is_valid()); + script->set_source_code( rel_script->get_source_code() ); + script->set_last_modified_time( rel_script->get_last_modified_time() ); + script->update_exports(); + } + + } +} + + +void ScriptTextEditor::_code_complete_scripts(void* p_ud,const String& p_code, List<String>* r_options) { + + ScriptTextEditor *ste = (ScriptTextEditor *)p_ud; + ste->_code_complete_script(p_code,r_options); +} + +void ScriptTextEditor::_code_complete_script(const String& p_code, List<String>* r_options) { + + Node *base = get_tree()->get_edited_scene_root(); + if (base) { + base = _find_node_for_script(base,base,script); + } + String hint; + Error err = script->get_language()->complete_code(p_code,script->get_path().get_base_dir(),base,r_options,hint); + if (hint!="") { + code_editor->get_text_edit()->set_code_hint(hint); + } + +} + +void ScriptTextEditor::_breakpoint_toggled(int p_row) { + + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(),p_row+1,code_editor->get_text_edit()->is_line_set_as_breakpoint(p_row)); + +} + +static void swap_lines(TextEdit *tx, int line1, int line2) +{ + String tmp = tx->get_line(line1); + String tmp2 = tx->get_line(line2); + tx->set_line(line2, tmp); + tx->set_line(line1, tmp2); + + tx->cursor_set_line(line2); +} + + +void ScriptTextEditor::_edit_option(int p_op) { + + switch(p_op) { + case EDIT_UNDO: { + code_editor->get_text_edit()->undo(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + } break; + case EDIT_REDO: { + code_editor->get_text_edit()->redo(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + } break; + case EDIT_CUT: { + + code_editor->get_text_edit()->cut(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + } break; + case EDIT_COPY: { + code_editor->get_text_edit()->copy(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + + } break; + case EDIT_PASTE: { + code_editor->get_text_edit()->paste(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + + } break; + case EDIT_SELECT_ALL: { + + code_editor->get_text_edit()->select_all(); + code_editor->get_text_edit()->call_deferred("grab_focus"); + + } break; + case EDIT_MOVE_LINE_UP: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = script; + if (scr.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) + { + int from_line = tx->get_selection_from_line(); + int from_col = tx->get_selection_from_column(); + int to_line = tx->get_selection_to_line(); + int to_column = tx->get_selection_to_column(); + + for (int i = from_line; i <= to_line; i++) + { + int line_id = i; + int next_id = i - 1; + + if (line_id == 0 || next_id < 0) + return; + + swap_lines(tx, line_id, next_id); + } + int from_line_up = from_line > 0 ? from_line-1 : from_line; + int to_line_up = to_line > 0 ? to_line-1 : to_line; + tx->select(from_line_up, from_col, to_line_up, to_column); + } + else + { + int line_id = tx->cursor_get_line(); + int next_id = line_id - 1; + + if (line_id == 0 || next_id < 0) + return; + + swap_lines(tx, line_id, next_id); + } + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_MOVE_LINE_DOWN: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) + { + int from_line = tx->get_selection_from_line(); + int from_col = tx->get_selection_from_column(); + int to_line = tx->get_selection_to_line(); + int to_column = tx->get_selection_to_column(); + + for (int i = to_line; i >= from_line; i--) + { + int line_id = i; + int next_id = i + 1; + + if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count()) + return; + + swap_lines(tx, line_id, next_id); + } + int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line; + int to_line_down = to_line < tx->get_line_count() ? to_line+1 : to_line; + tx->select(from_line_down, from_col, to_line_down, to_column); + } + else + { + int line_id = tx->cursor_get_line(); + int next_id = line_id + 1; + + if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count()) + return; + + swap_lines(tx, line_id, next_id); + } + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_INDENT_LEFT: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) + { + tx->indent_selection_left(); + } + else + { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + // begins with tab + if (line_text.begins_with("\t")) + { + line_text = line_text.substr(1, line_text.length()); + tx->set_line(begin, line_text); + } + // begins with 4 spaces + else if (line_text.begins_with(" ")) + { + line_text = line_text.substr(4, line_text.length()); + tx->set_line(begin, line_text); + } + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_INDENT_RIGHT: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + + tx->begin_complex_operation(); + if (tx->is_selection_active()) + { + tx->indent_selection_right(); + } + else + { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + line_text = '\t' + line_text; + tx->set_line(begin, line_text); + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_CLONE_DOWN: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + + int from_line = tx->cursor_get_line(); + int to_line = tx->cursor_get_line(); + int column = tx->cursor_get_column(); + + if (tx->is_selection_active()) { + from_line = tx->get_selection_from_line(); + to_line = tx->get_selection_to_line(); + column = tx->cursor_get_column(); + } + int next_line = to_line + 1; + + tx->begin_complex_operation(); + for (int i = from_line; i <= to_line; i++) { + + if (i >= tx->get_line_count() - 1) { + tx->set_line(i, tx->get_line(i) + "\n"); + } + String line_clone = tx->get_line(i); + tx->insert_at(line_clone, next_line); + next_line++; + } + + tx->cursor_set_column(column); + if (tx->is_selection_active()) { + tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); + } + + tx->end_complex_operation(); + tx->update(); + + } break; + case EDIT_TOGGLE_COMMENT: { + + TextEdit *tx = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + + + tx->begin_complex_operation(); + if (tx->is_selection_active()) + { + int begin = tx->get_selection_from_line(); + int end = tx->get_selection_to_line(); + + // End of selection ends on the first column of the last line, ignore it. + if(tx->get_selection_to_column() == 0) + end -= 1; + + for (int i = begin; i <= end; i++) + { + String line_text = tx->get_line(i); + + if (line_text.begins_with("#")) + line_text = line_text.substr(1, line_text.length()); + else + line_text = "#" + line_text; + tx->set_line(i, line_text); + } + } + else + { + int begin = tx->cursor_get_line(); + String line_text = tx->get_line(begin); + + if (line_text.begins_with("#")) + line_text = line_text.substr(1, line_text.length()); + else + line_text = "#" + line_text; + tx->set_line(begin, line_text); + } + tx->end_complex_operation(); + tx->update(); + //tx->deselect(); + + } break; + case EDIT_COMPLETE: { + + code_editor->get_text_edit()->query_code_comple(); + + } break; + case EDIT_AUTO_INDENT: { + + TextEdit *te = code_editor->get_text_edit(); + String text = te->get_text(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + int begin,end; + if (te->is_selection_active()) { + begin=te->get_selection_from_line(); + end=te->get_selection_to_line(); + } else { + begin=0; + end=te->get_line_count()-1; + } + scr->get_language()->auto_indent_code(text,begin,end); + te->set_text(text); + + + } break; + case EDIT_TRIM_TRAILING_WHITESAPCE: { + trim_trailing_whitespace(); + } break; + + + case SEARCH_FIND: { + + code_editor->get_find_replace_bar()->popup_search(); + } break; + case SEARCH_FIND_NEXT: { + + code_editor->get_find_replace_bar()->search_next(); + } break; + case SEARCH_FIND_PREV: { + + code_editor->get_find_replace_bar()->search_prev(); + } break; + case SEARCH_REPLACE: { + + code_editor->get_find_replace_bar()->popup_replace(); + } break; + case SEARCH_LOCATE_FUNCTION: { + + quick_open->popup(get_functions()); + } break; + case SEARCH_GOTO_LINE: { + + goto_line_dialog->popup_find_line(code_editor->get_text_edit()); + } break; + case DEBUG_TOGGLE_BREAKPOINT: { + int line=code_editor->get_text_edit()->cursor_get_line(); + bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); + code_editor->get_text_edit()->set_line_as_breakpoint(line,dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(),line+1,dobreak); + } break; + case DEBUG_REMOVE_ALL_BREAKPOINTS: { + List<int> bpoints; + code_editor->get_text_edit()->get_breakpoints(&bpoints); + + for(List<int>::Element *E=bpoints.front();E;E=E->next()) { + int line = E->get(); + bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); + code_editor->get_text_edit()->set_line_as_breakpoint(line,dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(),line+1,dobreak); + } + } + case DEBUG_GOTO_NEXT_BREAKPOINT: { + List<int> bpoints; + code_editor->get_text_edit()->get_breakpoints(&bpoints); + if (bpoints.size() <= 0) { + return; + } + + int line=code_editor->get_text_edit()->cursor_get_line(); + // wrap around + if (line >= bpoints[bpoints.size() - 1]) { + code_editor->get_text_edit()->cursor_set_line(bpoints[0]); + } else { + for(List<int>::Element *E=bpoints.front();E;E=E->next()) { + int bline = E->get(); + if (bline > line) { + code_editor->get_text_edit()->cursor_set_line(bline); + return; + } + } + } + + } break; + case DEBUG_GOTO_PREV_BREAKPOINT: { + List<int> bpoints; + code_editor->get_text_edit()->get_breakpoints(&bpoints); + if (bpoints.size() <= 0) { + return; + } + + int line=code_editor->get_text_edit()->cursor_get_line(); + // wrap around + if (line <= bpoints[0]) { + code_editor->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]); + } else { + for(List<int>::Element *E=bpoints.back();E;E=E->prev()) { + int bline = E->get(); + if (bline < line) { + code_editor->get_text_edit()->cursor_set_line(bline); + return; + } + } + } + + } break; + + case HELP_CONTEXTUAL: { + String text = code_editor->get_text_edit()->get_selection_text(); + if (text == "") + text = code_editor->get_text_edit()->get_word_under_cursor(); + if (text != "") { + emit_signal("request_help_search",text); + } + } break; + } +} + +void ScriptTextEditor::_bind_methods() { + + ObjectTypeDB::bind_method("_validate_script",&ScriptTextEditor::_validate_script); + ObjectTypeDB::bind_method("_load_theme_settings",&ScriptTextEditor::_load_theme_settings); + ObjectTypeDB::bind_method("_breakpoint_toggled",&ScriptTextEditor::_breakpoint_toggled); + ObjectTypeDB::bind_method("_edit_option",&ScriptTextEditor::_edit_option); + ObjectTypeDB::bind_method("_goto_line",&ScriptTextEditor::_goto_line); + + ADD_SIGNAL(MethodInfo("name_changed")); + ADD_SIGNAL(MethodInfo("request_help_search",PropertyInfo(Variant::STRING,"topic"))); +} + +Control *ScriptTextEditor::get_edit_menu() { + + return edit_hb; +} + +void ScriptTextEditor::reload(bool p_soft) { + + TextEdit *te = code_editor->get_text_edit(); + Ref<Script> scr = get_edited_script(); + if (scr.is_null()) + return; + scr->set_source_code(te->get_text()); + bool soft = p_soft || scr->get_instance_base_type()=="EditorPlugin"; //always soft-reload editor plugins + + scr->get_language()->reload_tool_script(scr,soft); +} + +void ScriptTextEditor::get_breakpoints(List<int> *p_breakpoints) { + + code_editor->get_text_edit()->get_breakpoints(p_breakpoints); + +} + +void ScriptTextEditor::set_tooltip_request_func(String p_method,Object* p_obj) { + + code_editor->get_text_edit()->set_tooltip_request_func(p_obj,p_method,this); +} + +void ScriptTextEditor::set_debugger_active(bool p_active) { + + +} + +ScriptTextEditor::ScriptTextEditor() { + + code_editor = memnew( CodeTextEditor ); + add_child(code_editor); + code_editor->set_area_as_parent_rect(); + code_editor->connect("validate_script",this,"_validate_script"); + code_editor->connect("load_theme_settings",this,"_load_theme_settings"); + code_editor->set_code_complete_func(_code_complete_scripts,this); + code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); + + code_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); + code_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); + code_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size")); + code_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs")); + code_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); + code_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); + code_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + code_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + code_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); + code_editor->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter")); + code_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret")); + code_editor->get_text_edit()->set_callhint_settings( + EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"), + EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset")); + + edit_hb = memnew (HBoxContainer); + + edit_menu = memnew( MenuButton ); + edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_separator(); +#ifdef OSX_ENABLED + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); +#else + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); +#endif + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT); + edit_menu->get_popup()->connect("item_pressed", this,"_edit_option"); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_breakpoint"), DEBUG_TOGGLE_BREAKPOINT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT); + + search_menu = memnew( MenuButton ); + edit_hb->add_child(search_menu); + search_menu->set_text(TTR("Search")); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); + + search_menu->get_popup()->connect("item_pressed", this,"_edit_option"); + + edit_hb->add_child(edit_menu); + + quick_open = memnew( ScriptEditorQuickOpen ); + add_child(quick_open); + quick_open->connect("goto_line",this,"_goto_line"); + + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); +} + +static ScriptEditorBase * create_editor(const Ref<Script>& p_script) { + + if (p_script->has_source_code()) { + return memnew( ScriptTextEditor ); + } + + return NULL; +} + +void ScriptTextEditor::register_editor() { + + ED_SHORTCUT("script_text_editor/undo", TTR("Undo"), KEY_MASK_CMD|KEY_Z); + ED_SHORTCUT("script_text_editor/redo", TTR("Redo"), KEY_MASK_CMD|KEY_Y); + ED_SHORTCUT("script_text_editor/cut", TTR("Cut"), KEY_MASK_CMD|KEY_X); + ED_SHORTCUT("script_text_editor/copy", TTR("Copy"), KEY_MASK_CMD|KEY_C); + ED_SHORTCUT("script_text_editor/paste", TTR("Paste"), KEY_MASK_CMD|KEY_V); + ED_SHORTCUT("script_text_editor/select_all", TTR("Select All"), KEY_MASK_CMD|KEY_A); + ED_SHORTCUT("script_text_editor/move_up", TTR("Move Up"), KEY_MASK_ALT|KEY_UP); + ED_SHORTCUT("script_text_editor/move_down", TTR("Move Down"), KEY_MASK_ALT|KEY_DOWN); + ED_SHORTCUT("script_text_editor/indent_left", TTR("Indent Left"), KEY_MASK_ALT|KEY_LEFT); + ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), KEY_MASK_ALT|KEY_RIGHT); + ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD|KEY_K); + ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD|KEY_B); +#ifdef OSX_ENABLED + ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL|KEY_SPACE); +#else + ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD|KEY_SPACE); +#endif + ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CTRL|KEY_MASK_ALT|KEY_T); + ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD|KEY_I); + + ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9); + ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CTRL|KEY_MASK_SHIFT|KEY_F9); + ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Goto Next Breakpoint"), KEY_MASK_CTRL|KEY_PERIOD); + ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Goto Previous Breakpoint"), KEY_MASK_CTRL|KEY_COMMA); + + ED_SHORTCUT("script_text_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F); + ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3); + ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT|KEY_F3); + ED_SHORTCUT("script_text_editor/replace", TTR("Replace.."), KEY_MASK_CMD|KEY_R); + + ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function.."), KEY_MASK_SHIFT|KEY_MASK_CMD|KEY_F); + ED_SHORTCUT("script_text_editor/goto_line", TTR("Goto Line.."), KEY_MASK_CMD|KEY_L); + + ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_SHIFT|KEY_F1); + + ScriptEditor::register_create_script_editor_function(create_editor); +} diff --git a/tools/editor/plugins/script_text_editor.h b/tools/editor/plugins/script_text_editor.h new file mode 100644 index 0000000000..247fd97e81 --- /dev/null +++ b/tools/editor/plugins/script_text_editor.h @@ -0,0 +1,142 @@ +/*************************************************************************/ +/* script_text_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#ifndef SCRIPT_TEXT_EDITOR_H +#define SCRIPT_TEXT_EDITOR_H + +#include "script_editor_plugin.h" + + +class ScriptTextEditor : public ScriptEditorBase { + + OBJ_TYPE( ScriptTextEditor, ScriptEditorBase ); + + CodeTextEditor *code_editor; + + Ref<Script> script; + + + Vector<String> functions; + + HBoxContainer *edit_hb; + + MenuButton *edit_menu; + MenuButton *search_menu; + + GotoLineDialog *goto_line_dialog; + ScriptEditorQuickOpen *quick_open; + + enum { + EDIT_UNDO, + EDIT_REDO, + EDIT_CUT, + EDIT_COPY, + EDIT_PASTE, + EDIT_SELECT_ALL, + EDIT_COMPLETE, + EDIT_AUTO_INDENT, + EDIT_TRIM_TRAILING_WHITESAPCE, + EDIT_TOGGLE_COMMENT, + EDIT_MOVE_LINE_UP, + EDIT_MOVE_LINE_DOWN, + EDIT_INDENT_RIGHT, + EDIT_INDENT_LEFT, + EDIT_CLONE_DOWN, + SEARCH_FIND, + SEARCH_FIND_NEXT, + SEARCH_FIND_PREV, + SEARCH_REPLACE, + SEARCH_LOCATE_FUNCTION, + SEARCH_GOTO_LINE, + DEBUG_TOGGLE_BREAKPOINT, + DEBUG_REMOVE_ALL_BREAKPOINTS, + DEBUG_GOTO_NEXT_BREAKPOINT, + DEBUG_GOTO_PREV_BREAKPOINT, + HELP_CONTEXTUAL, + }; + + +protected: + + + static void _code_complete_scripts(void* p_ud,const String& p_code, List<String>* r_options); + void _breakpoint_toggled(int p_row); + + //no longer virtual + void _validate_script(); + void _code_complete_script(const String& p_code, List<String>* r_options); + void _load_theme_settings(); + + void _notification(int p_what); + static void _bind_methods(); + + void _edit_option(int p_op); + + void _goto_line(int p_line) { goto_line(p_line); } +public: + + virtual void apply_code(); + virtual Ref<Script> get_edited_script() const; + virtual Vector<String> get_functions() ; + virtual void set_edited_script(const Ref<Script>& p_script); + virtual void reload_text(); + virtual String get_name() ; + virtual Ref<Texture> get_icon() ; + virtual bool is_unsaved(); + + virtual Variant get_edit_state(); + virtual void set_edit_state(const Variant& p_state); + virtual void ensure_focus(); + virtual void trim_trailing_whitespace(); + virtual void tag_saved_version(); + + virtual void goto_line(int p_line,bool p_with_error=false); + + virtual void reload(bool p_soft); + virtual void get_breakpoints(List<int> *p_breakpoints); + + virtual void add_callback(const String& p_function,StringArray p_args); + virtual void update_settings(); + virtual bool goto_method(const String& p_method); + + virtual void set_tooltip_request_func(String p_method,Object* p_obj); + + virtual void set_debugger_active(bool p_active); + + Control *get_edit_menu(); + + static void register_editor(); + + ScriptTextEditor(); + +}; + + + + +#endif // SCRIPT_TEXT_EDITOR_H diff --git a/tools/editor/plugins/texture_region_editor_plugin.cpp b/tools/editor/plugins/texture_region_editor_plugin.cpp index db888208fb..3d220b8474 100644 --- a/tools/editor/plugins/texture_region_editor_plugin.cpp +++ b/tools/editor/plugins/texture_region_editor_plugin.cpp @@ -503,8 +503,8 @@ void TextureRegionEditor::_scroll_changed(float) void TextureRegionEditor::_set_snap_mode(int p_mode) { - snap_mode_button->get_popup()->set_item_checked(snap_mode,false); snap_mode = p_mode; + snap_mode_button->get_popup()->set_item_checked(snap_mode,false); snap_mode_button->set_text(snap_mode_button->get_popup()->get_item_text(p_mode)); snap_mode_button->get_popup()->set_item_checked(snap_mode,true); diff --git a/tools/editor/project_manager.cpp b/tools/editor/project_manager.cpp index 28d9738fee..dc1d6ec0f9 100644 --- a/tools/editor/project_manager.cpp +++ b/tools/editor/project_manager.cpp @@ -364,12 +364,6 @@ public: mode=p_mode; } - void import_from_file(const String& p_file) { - mode=MODE_IMPORT; - _file_selected(p_file); - ok_pressed(); - } - void show_dialog() { @@ -518,23 +512,23 @@ void ProjectManager::_panel_draw(Node *p_hb) { void ProjectManager::_update_project_buttons() { - String single_selected = ""; - if (selected_list.size() == 1) { - single_selected = selected_list.front()->key(); - } - - single_selected_main = ""; for(int i=0;i<scroll_childs->get_child_count();i++) { + CanvasItem *item = scroll_childs->get_child(i)->cast_to<CanvasItem>(); item->update(); + } - if (single_selected!="" && single_selected == item->get_meta("name")) - single_selected_main = item->get_meta("main_scene"); + bool has_runnable_scene = false; + for (Map<String,String>::Element *E=selected_list.front(); E; E=E->next()) { + const String &selected_main = E->get(); + if (selected_main == "") continue; + has_runnable_scene = true; + break; } erase_btn->set_disabled(selected_list.size()<1); open_btn->set_disabled(selected_list.size()<1); - run_btn->set_disabled(selected_list.size()<1 || (selected_list.size()==1 && single_selected_main=="")); + run_btn->set_disabled(!has_runnable_scene); } void ProjectManager::_panel_input(const InputEvent& p_ev,Node *p_hb) { @@ -605,6 +599,10 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { switch (k.scancode) { + case KEY_RETURN: { + + _open_project(); + } break; case KEY_HOME: { for (int i=0; i<scroll_childs->get_child_count(); i++) { @@ -614,6 +612,7 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { selected_list.clear(); selected_list.insert(hb->get_meta("name"), hb->get_meta("main_scene")); scroll->set_v_scroll(0); + _update_project_buttons(); break; } } @@ -628,6 +627,7 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { selected_list.clear(); selected_list.insert(hb->get_meta("name"), hb->get_meta("main_scene")); scroll->set_v_scroll(scroll_childs->get_size().y); + _update_project_buttons(); break; } } @@ -658,6 +658,8 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { if (offset_diff > 0) scroll->set_v_scroll(scroll->get_v_scroll() - offset_diff); + _update_project_buttons(); + break; } else if (current==selected_list.back()->key()) { @@ -694,6 +696,8 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { if (offset_diff > 0) scroll->set_v_scroll(scroll->get_v_scroll() + offset_diff); + _update_project_buttons(); + break; } else if (current==selected_list.back()->key()) { @@ -714,12 +718,6 @@ void ProjectManager::_unhandled_input(const InputEvent& p_ev) { if (scancode_handled) { accept_event(); - - for(int i=0;i<scroll_childs->get_child_count();i++) { - CanvasItem *item = scroll_childs->get_child(i)->cast_to<CanvasItem>(); - if (item) - item->update(); - } } } } @@ -897,14 +895,14 @@ void ProjectManager::_load_recent_projects() { scroll_childs->add_child(hb); } - + for (Map<String,String>::Element *E = selected_list_copy.front();E;E = E->next()) { String key = E->key(); selected_list.erase(key); } - + scroll->set_v_scroll(0); - + _update_project_buttons(); EditorSettings::get_singleton()->save(); @@ -943,7 +941,7 @@ void ProjectManager::_open_project() { } if (selected_list.size()>1) { - multi_open_ask->set_text(TTR("Are you sure to open more than one projects?")); + multi_open_ask->set_text(TTR("Are you sure to open more than one project?")); multi_open_ask->popup_centered_minsize(); } else { _open_project_confirm(); @@ -983,7 +981,7 @@ void ProjectManager::_run_project() { } if (selected_list.size()>1) { - multi_run_ask->set_text(TTR("Are you sure to run more than one projects?")); + multi_run_ask->set_text(TTR("Are you sure to run more than one project?")); multi_run_ask->popup_centered_minsize(); } else { _run_project_confirm(); @@ -1072,7 +1070,6 @@ void ProjectManager::_erase_project_confirm() { EditorSettings::get_singleton()->save(); selected_list.clear(); last_clicked = ""; - single_selected_main=""; _load_recent_projects(); } @@ -1104,13 +1101,53 @@ void ProjectManager::_install_project(const String& p_zip_path,const String& p_t } void ProjectManager::_files_dropped(StringArray p_files, int p_screen) { + Set<String> folders_set; + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < p_files.size(); i++) { - if (p_files[i].ends_with("engine.cfg")) { - npdialog->import_from_file(p_files[i]); + String file = p_files[i]; + folders_set.insert(da->dir_exists(file) ? file : file.get_base_dir()); + } + memdelete(da); + if (folders_set.size()>0) { + StringArray folders; + for (Set<String>::Element *E=folders_set.front();E;E=E->next()) { + folders.append(E->get()); + } + + bool confirm = true; + if (folders.size()==1) { + DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (dir->change_dir(folders[0])==OK) { + dir->list_dir_begin(); + String file = dir->get_next(); + while(confirm && file!=String()) { + if (!da->current_is_dir() && file.ends_with("engine.cfg")) { + confirm = false; + } + file = dir->get_next(); + } + dir->list_dir_end(); + } + memdelete(dir); + } + if (confirm) { + multi_scan_ask->get_ok()->disconnect("pressed", this, "_scan_multiple_folders"); + multi_scan_ask->get_ok()->connect("pressed", this, "_scan_multiple_folders", varray(folders)); + multi_scan_ask->set_text(vformat(TTR("You are about the scan %s folders for existing Godot projects. Do you confirm?"), folders.size())); + multi_scan_ask->popup_centered_minsize(); + } else { + _scan_multiple_folders(folders); } } } +void ProjectManager::_scan_multiple_folders(StringArray p_files) +{ + for (int i = 0; i < p_files.size(); i++) { + _scan_begin(p_files.get(i)); + } +} + void ProjectManager::_bind_methods() { ObjectTypeDB::bind_method("_open_project",&ProjectManager::_open_project); @@ -1131,6 +1168,7 @@ void ProjectManager::_bind_methods() { ObjectTypeDB::bind_method("_favorite_pressed",&ProjectManager::_favorite_pressed); ObjectTypeDB::bind_method("_install_project",&ProjectManager::_install_project); ObjectTypeDB::bind_method("_files_dropped",&ProjectManager::_files_dropped); + ObjectTypeDB::bind_method(_MD("_scan_multiple_folders", "files"),&ProjectManager::_scan_multiple_folders); } @@ -1265,6 +1303,7 @@ ProjectManager::ProjectManager() { scan_dir = memnew( FileDialog ); scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM); scan_dir->set_mode(FileDialog::MODE_OPEN_DIR); + scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden scan_dir->set_current_dir( EditorSettings::get_singleton()->get("global/default_project_path") ); gui_base->add_child(scan_dir); scan_dir->connect("dir_selected",this,"_scan_begin"); @@ -1329,6 +1368,11 @@ ProjectManager::ProjectManager() { gui_base->add_child(multi_run_ask); + multi_scan_ask = memnew( ConfirmationDialog ); + multi_scan_ask->get_ok()->set_text(TTR("Scan")); + + gui_base->add_child(multi_scan_ask); + OS::get_singleton()->set_low_processor_usage_mode(true); npdialog = memnew( NewProjectDialog ); diff --git a/tools/editor/project_manager.h b/tools/editor/project_manager.h index 50bd7d94c8..46f7aea3a5 100644 --- a/tools/editor/project_manager.h +++ b/tools/editor/project_manager.h @@ -55,12 +55,12 @@ class ProjectManager : public Control { ConfirmationDialog *erase_ask; ConfirmationDialog *multi_open_ask; ConfirmationDialog *multi_run_ask; + ConfirmationDialog *multi_scan_ask; NewProjectDialog *npdialog; ScrollContainer *scroll; VBoxContainer *scroll_childs; Map<String, String> selected_list; // name -> main_scene String last_clicked; - String single_selected_main; bool importing; HBoxContainer *projects_hb; @@ -69,8 +69,6 @@ class ProjectManager : public Control { Control *gui_base; - void _item_doubleclicked(); - void _scan_projects(); @@ -96,6 +94,7 @@ class ProjectManager : public Control { void _unhandled_input(const InputEvent& p_ev); void _favorite_pressed(Node *p_hb); void _files_dropped(StringArray p_files, int p_screen); + void _scan_multiple_folders(StringArray p_files); protected: diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 26a49e92f0..0518018e5a 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -45,6 +45,7 @@ #include "scene/resources/packed_scene.h" #include "scene/main/viewport.h" #include "editor_file_system.h" +#include "create_dialog.h" void CustomPropertyEditor::_notification(int p_what) { @@ -210,6 +211,10 @@ void CustomPropertyEditor::_menu_option(int p_which) { ERR_BREAK( !obj ); Resource *res=obj->cast_to<Resource>(); ERR_BREAK( !res ); + if (owner && hint==PROPERTY_HINT_RESOURCE_TYPE && hint_text=="Script") { + //make visual script the right type + res->call("set_instance_base_type",owner->get_type()); + } v=Ref<Resource>(res).get_ref_ptr(); emit_signal("variant_changed"); @@ -431,6 +436,23 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty action_buttons[0]->set_text(TTR("Close")); action_buttons[0]->show(); + } else if (hint==PROPERTY_HINT_TYPE_STRING) { + + if (!create_dialog) { + create_dialog = memnew( CreateDialog ); + create_dialog->connect("create",this,"_create_dialog_callback"); + add_child(create_dialog); + } + + if (hint_text!=String()) { + create_dialog->set_base_type(hint_text); + } else { + create_dialog->set_base_type("Object"); + } + + create_dialog->popup(false); + hide(); + } else { List<String> names; names.push_back("string:"); @@ -940,11 +962,23 @@ void CustomPropertyEditor::_color_changed(const Color& p_color) { void CustomPropertyEditor::_node_path_selected(NodePath p_path) { - if (owner) { + + if (hint==PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && hint_text!=String()) { + + Node* node=get_node(hint_text); + if (node) { + + Node *tonode=node->get_node(p_path); + if (tonode) { + p_path=node->get_path_to(tonode); + } + } + + } else if (owner) { Node *node=NULL; - if (owner->is_type("Node")) + if (owner->is_type("Node")) node = owner->cast_to<Node>(); else if (owner->is_type("ArrayPropertyEdit")) node = owner->cast_to<ArrayPropertyEdit>()->get_node(); @@ -1319,17 +1353,34 @@ void CustomPropertyEditor::_text_edit_changed() { } +void CustomPropertyEditor::_create_dialog_callback() { + + + v=create_dialog->get_selected_type(); + emit_signal("variant_changed"); +} + void CustomPropertyEditor::_modified(String p_string) { if (updating) return; updating=true; switch(type) { + case Variant::INT: { + + if (evaluator) + v=evaluator->eval(value_editor[0]->get_text()); + else + v=value_editor[0]->get_text().to_int(); + emit_signal("variant_changed"); + + + } break; case Variant::REAL: { if (hint!=PROPERTY_HINT_EXP_EASING) { if (evaluator) - evaluator->eval(value_editor[0]->get_text()); + v=evaluator->eval(value_editor[0]->get_text()); else v=value_editor[0]->get_text().to_double(); emit_signal("variant_changed"); @@ -1533,7 +1584,8 @@ void CustomPropertyEditor::_modified(String p_string) { } break; case Variant::NODE_PATH: { - + v=NodePath(value_editor[0]->get_text()); + emit_signal("variant_changed"); } break; case Variant::INPUT_EVENT: { @@ -1700,6 +1752,7 @@ void CustomPropertyEditor::_bind_methods() { ObjectTypeDB::bind_method("_drag_easing",&CustomPropertyEditor::_drag_easing); ObjectTypeDB::bind_method( "_text_edit_changed",&CustomPropertyEditor::_text_edit_changed); ObjectTypeDB::bind_method( "_menu_option",&CustomPropertyEditor::_menu_option); + ObjectTypeDB::bind_method( "_create_dialog_callback",&CustomPropertyEditor::_create_dialog_callback); @@ -1822,6 +1875,8 @@ CustomPropertyEditor::CustomPropertyEditor() { add_child(slider); slider->set_area_as_parent_rect(5); slider->connect("value_changed",this,"_range_modified"); + + create_dialog = NULL; } bool PropertyEditor::_might_be_in_instance() { @@ -2089,6 +2144,12 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p } break; case Variant::STRING: + + if (p_hint==PROPERTY_HINT_TYPE_STRING) { + + p_item->set_text(1,obj->get(p_name)); + } + if (p_hint==PROPERTY_HINT_ENUM) { Vector<String> strings = p_hint_text.split(","); @@ -2355,15 +2416,27 @@ Variant PropertyEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) if (!item) return Variant(); - int col = tree->get_column_at_pos(p_point); - if (col!=1) - return Variant(); - - Dictionary d = item->get_metadata(0); if (!d.has("name")) return Variant(); + int col = tree->get_column_at_pos(p_point); + if (col==0) { + + Dictionary dp; + dp["type"]="obj_property"; + dp["object"]=obj; + dp["property"]=d["name"]; + dp["value"]=obj->get(d["name"]); + + Label *label =memnew( Label ); + label->set_text(d["name"]); + set_drag_preview(label); + return dp; + } + + + Variant val = obj->get(d["name"]); if (val.get_type()==Variant::OBJECT) { @@ -3099,6 +3172,15 @@ void PropertyEditor::update_tree() { } break; + case PROPERTY_HINT_TYPE_STRING: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM); + item->set_editable(1,!read_only); + if (show_type_icons) + item->set_icon( 0, get_icon("String","EditorIcons") ); + item->set_text(1,obj->get(p.name)); + + } break; default: { item->set_cell_mode( 1, TreeItem::CELL_MODE_STRING ); @@ -4349,7 +4431,7 @@ SectionedPropertyEditor::~SectionedPropertyEditor() { double PropertyValueEvaluator::eval(const String& p_text) { - if (!obj) + if (!obj || !script_language) return _default_eval(p_text); Ref<Script> script= Ref<Script>(script_language ->create_script()); @@ -4361,6 +4443,8 @@ double PropertyValueEvaluator::eval(const String& p_text) { } ScriptInstance *script_instance = script->instance_create(this); + if (!script_instance) + return _default_eval(p_text); Variant::CallError call_err; script_instance->call("set_this",obj); @@ -4388,7 +4472,13 @@ String PropertyValueEvaluator::_build_script(const String& p_text) { } PropertyValueEvaluator::PropertyValueEvaluator() { - script_language = ScriptServer::get_language(0); // todo: get script language from editor setting + script_language=NULL; + + for(int i=0;i<ScriptServer::get_language_count();i++) { + if (ScriptServer::get_language(i)->get_name()=="GDScript") { + script_language=ScriptServer::get_language(i); + } + } } PropertyValueEvaluator::~PropertyValueEvaluator() { diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index a909b5ccd3..d911aae883 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -48,7 +48,7 @@ */ class PropertyValueEvaluator; - +class CreateDialog; class CustomPropertyEditor : public Popup { OBJ_TYPE( CustomPropertyEditor, Popup ); @@ -102,6 +102,7 @@ class CustomPropertyEditor : public Popup { Control *easing_draw; + CreateDialog *create_dialog; Object* owner; @@ -118,6 +119,7 @@ class CustomPropertyEditor : public Popup { void _focus_exit(); void _action_pressed(int p_which); void _type_create_selected(int p_idx); + void _create_dialog_callback(); void _color_changed(const Color& p_color); diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 35ddb49465..94587456f1 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -42,17 +42,31 @@ #include "scene/main/viewport.h" +void SceneTreeDock::_nodes_drag_begin() { + + + if (restore_script_editor_on_drag) { + EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT); + restore_script_editor_on_drag=false; + } + +} + +void SceneTreeDock::_input(InputEvent p_event) { + + if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { + restore_script_editor_on_drag=false; //lost chance + } +} void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { if (get_viewport()->get_modal_stack_top()) return; //ignore because of modal window - uint32_t sc = p_event.key.get_scancode_with_modifiers(); if (!p_event.key.pressed || p_event.key.echo) return; - if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } @@ -83,9 +97,11 @@ void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) { _tool_selected(TOOL_NEW_SCENE_FROM); } - switch(sc) { - case KEY_MASK_SHIFT|KEY_DELETE: { _tool_selected(TOOL_ERASE, true); } break; - case KEY_DELETE: { _tool_selected(TOOL_ERASE); } break; + else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) { + _tool_selected(TOOL_ERASE, true); + } + else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) { + _tool_selected(TOOL_ERASE); } } @@ -667,6 +683,8 @@ void SceneTreeDock::_notification(int p_what) { } button_add->set_icon(get_icon("Add","EditorIcons")); button_instance->set_icon(get_icon("Instance","EditorIcons")); + button_create_script->set_icon(get_icon("Script","EditorIcons")); + filter_icon->set_texture(get_icon("Zoom","EditorIcons")); @@ -698,7 +716,13 @@ void SceneTreeDock::_node_selected() { return; } + if (ScriptEditor::get_singleton()->is_visible()) { + restore_script_editor_on_drag=true; + } + editor->push_item(node); + + } void SceneTreeDock::_node_renamed() { @@ -1280,11 +1304,18 @@ void SceneTreeDock::_delete_confirm() { void SceneTreeDock::_selection_changed() { - if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size()>1) { + int selection_size = EditorNode::get_singleton()->get_editor_selection()->get_selection().size(); + if (selection_size>1) { //automatically turn on multi-edit _tool_selected(TOOL_MULTI_EDIT); } + if (selection_size==1 && EditorNode::get_singleton()->get_editor_selection()->get_selection().front()->key()->get_script().is_null()) { + button_create_script->show(); + } else { + button_create_script->hide(); + } + //tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); } @@ -1769,7 +1800,7 @@ void SceneTreeDock::_tree_rmb(const Vector2& p_menu_pos) { } menu->add_separator(); - menu->add_icon_item(get_icon("Remove","EditorIcons"),TTR("Delete Node(s)"), TOOL_ERASE, KEY_DELETE); + menu->add_icon_shortcut(get_icon("Remove","EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE); menu->set_size(Size2(1,1)); menu->set_pos(p_menu_pos); @@ -1807,6 +1838,8 @@ void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_load_request"),&SceneTreeDock::_load_request); ObjectTypeDB::bind_method(_MD("_script_open_request"),&SceneTreeDock::_script_open_request); ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&SceneTreeDock::_unhandled_key_input); + ObjectTypeDB::bind_method(_MD("_input"),&SceneTreeDock::_input); + ObjectTypeDB::bind_method(_MD("_nodes_drag_begin"),&SceneTreeDock::_nodes_drag_begin); ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm); ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed); ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene); @@ -1846,6 +1879,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec ED_SHORTCUT("scene_tree/reparent", TTR("Reparent")); ED_SHORTCUT("scene_tree/merge_from_scene", TTR("Merge From Scene")); ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene")); + ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KEY_MASK_SHIFT|KEY_DELETE); + ED_SHORTCUT("scene_tree/delete", TTR("Delete"), KEY_DELETE); tb = memnew( ToolButton ); tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_NEW, false)); @@ -1873,6 +1908,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec filter->connect("text_changed",this,"_filter_changed"); + tb = memnew( ToolButton ); + tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_SCRIPT, false)); + tb->set_tooltip(TTR("Create a new script for the selected node.")); + tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_script")); + filter_hbc->add_child(tb); + button_create_script=tb; scene_tree = memnew( SceneTreeEditor(false,true,true )); @@ -1887,6 +1928,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec scene_tree->connect("open_script",this,"_script_open_request"); scene_tree->connect("nodes_rearranged",this,"_nodes_dragged"); scene_tree->connect("files_dropped",this,"_files_dropped"); + scene_tree->connect("nodes_dragged",this,"_nodes_drag_begin"); scene_tree->set_undo_redo(&editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); @@ -1939,7 +1981,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec add_child(menu); menu->connect("item_pressed",this,"_tool_selected"); first_enter=true; - + restore_script_editor_on_drag=false; vbc->add_constant_override("separation",4); + set_process_input(true); } diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index 04ed16967f..af612cbc77 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -71,12 +71,14 @@ class SceneTreeDock : public VBoxContainer { }; + bool restore_script_editor_on_drag; int current_option; CreateDialog *create_dialog; ToolButton *button_add; ToolButton *button_instance; + ToolButton *button_create_script; SceneTreeEditor *scene_tree; @@ -128,6 +130,8 @@ class SceneTreeDock : public VBoxContainer { void _node_prerenamed(Node* p_node, const String& p_new_name); + void _nodes_drag_begin(); + void _input(InputEvent p_event); void _unhandled_key_input(InputEvent p_event); void _import_subscene(); diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index 73358e805d..e5a97fa26e 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/tools/editor/scene_tree_editor.cpp @@ -966,7 +966,7 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) drag_data["nodes"]=objs; tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN|Tree::DROP_MODE_ON_ITEM); - + emit_signal("nodes_dragged"); return drag_data; } @@ -1110,6 +1110,7 @@ void SceneTreeEditor::_bind_methods() { ADD_SIGNAL( MethodInfo("node_renamed") ); ADD_SIGNAL( MethodInfo("node_prerename") ); ADD_SIGNAL( MethodInfo("node_changed") ); + ADD_SIGNAL( MethodInfo("nodes_dragged") ); 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")) ) ; diff --git a/tools/editor/script_create_dialog.cpp b/tools/editor/script_create_dialog.cpp index e93a40efbc..749198314a 100644 --- a/tools/editor/script_create_dialog.cpp +++ b/tools/editor/script_create_dialog.cpp @@ -117,20 +117,20 @@ void ScriptCreateDialog::ok_pressed() { - String text = ScriptServer::get_language( language_menu->get_selected() )->get_template(cname,parent_name->get_text()); - Script *script = ScriptServer::get_language( language_menu->get_selected() )->create_script(); - script->set_source_code(text); - if (cname!="") - script->set_name(cname); + Ref<Script> scr = ScriptServer::get_language( language_menu->get_selected() )->get_template(cname,parent_name->get_text()); + //scr->set_source_code(text); + + + if (cname!="") + scr->set_name(cname); - Ref<Script> scr(script); if (!internal->is_pressed()) { String lpath = Globals::get_singleton()->localize_path(file_path->get_text()); - script->set_path(lpath); + scr->set_path(lpath); if (!path_valid) { alert->set_text(TTR("Invalid path!")); @@ -145,7 +145,7 @@ void ScriptCreateDialog::ok_pressed() { alert->popup_centered_minsize(); return; } - scr->set_path(lpath); + //scr->set_path(lpath); //EditorFileSystem::get_singleton()->update_file(lpath,scr->get_type()); diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp index b6390e5aae..da42f54095 100644 --- a/tools/editor/script_editor_debugger.cpp +++ b/tools/editor/script_editor_debugger.cpp @@ -220,6 +220,7 @@ void ScriptEditorDebugger::debug_continue() { msg.push_back("continue"); ppeer->put_var(msg); + } void ScriptEditorDebugger::_scene_tree_folded(Object* obj) { @@ -360,7 +361,7 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat forward->set_disabled(true); dobreak->set_disabled(false); docontinue->set_disabled(true); - emit_signal("breaked",false,false); + emit_signal("breaked",false,false,Variant()); //tabs->set_current_tab(0); profiler->set_enabled(true); profiler->disable_seeking(); diff --git a/version.py b/version.py index 19ff05f715..bf1d33c1cf 100644 --- a/version.py +++ b/version.py @@ -1,5 +1,5 @@ short_name="godot" name="Godot Engine" major=2 -minor=1 -status="rc1" +minor=2 +status="alpha" |