diff --git a/SConstruct b/SConstruct index c27d2d869d8..7b1a10a03b9 100644 --- a/SConstruct +++ b/SConstruct @@ -134,8 +134,8 @@ Help(opts.GenerateHelpText(env_base)) # generate help # add default include paths env_base.Append(CPPPATH=['#core','#core/math','#tools','#drivers','#']) - -# configure ENV for platform + +# configure ENV for platform env_base.platform_exporters=platform_exporters """ diff --git a/bin/tests/test_math.cpp b/bin/tests/test_math.cpp index 2db945d5fde..ea324a73815 100644 --- a/bin/tests/test_math.cpp +++ b/bin/tests/test_math.cpp @@ -80,6 +80,7 @@ MainLoop* test() { { + // print_line("NUM: "+itos(237641278346127)); print_line("NUM: "+itos(-128)); return NULL; diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 16ee3973824..2d503bae50c 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -186,10 +186,12 @@ Error Dictionary::parse_json(const String& p_json) { String errstr; int errline=0; + if (p_json != ""){ Error err = JSON::parse(p_json,*this,errstr,errline); if (err!=OK) { ERR_EXPLAIN("Error parsing JSON: "+errstr+" at line: "+itos(errline)); ERR_FAIL_COND_V(err!=OK,err); + } } return OK; diff --git a/core/io/json.cpp b/core/io/json.cpp index a83d7e4d6e0..88a23eb4cd8 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -250,7 +250,7 @@ Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_toke if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) { //a number const CharType *rptr; - double number = String::to_double(&p_str[idx],-1,&rptr); + double number = String::to_double(&p_str[idx],&rptr); idx+=(rptr - &p_str[idx]); r_token.type=TK_NUMBER; r_token.value=number; diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp index 0e75e22767a..f83c1740844 100644 --- a/core/io/stream_peer_tcp.cpp +++ b/core/io/stream_peer_tcp.cpp @@ -32,7 +32,7 @@ StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL; void StreamPeerTCP::_bind_methods() { - ObjectTypeDB::bind_method(_MD("connect","host","ip"),&StreamPeerTCP::connect); + ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::connect); ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected); ObjectTypeDB::bind_method(_MD("get_status"),&StreamPeerTCP::get_status); ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host); diff --git a/core/method_bind.h b/core/method_bind.h index 3f08c70af8b..6ea9340ad54 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -178,6 +178,7 @@ public: #ifdef DEBUG_METHODS_ENABLED _FORCE_INLINE_ void set_return_type(const StringName& p_type) { ret_type=p_type; } + _FORCE_INLINE_ StringName get_return_type() const { return ret_type; } _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const { diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp index efd92542ce8..f7917b74184 100644 --- a/core/object_type_db.cpp +++ b/core/object_type_db.cpp @@ -191,6 +191,7 @@ MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,co HashMap ObjectTypeDB::types; HashMap ObjectTypeDB::resource_base_extensions; +HashMap ObjectTypeDB::compat_types; ObjectTypeDB::TypeInfo::TypeInfo() { @@ -263,12 +264,22 @@ bool ObjectTypeDB::type_exists(const String &p_type) { return types.has(p_type); } +void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringName& p_fallback) { + + compat_types[p_type]=p_fallback; +} + Object *ObjectTypeDB::instance(const String &p_type) { TypeInfo *ti; { OBJTYPE_LOCK; ti=types.getptr(p_type); + if (!ti || ti->disabled || !ti->creation_func) { + if (compat_types.has(p_type)) { + ti=types.getptr(compat_types[p_type]); + } + } ERR_FAIL_COND_V(!ti,NULL); ERR_FAIL_COND_V(ti->disabled,NULL); ERR_FAIL_COND_V(!ti->creation_func,NULL); @@ -914,6 +925,7 @@ void ObjectTypeDB::cleanup() { } types.clear(); resource_base_extensions.clear(); + compat_types.clear(); } // diff --git a/core/object_type_db.h b/core/object_type_db.h index f2ff194e28b..617a0a7c20c 100644 --- a/core/object_type_db.h +++ b/core/object_type_db.h @@ -151,6 +151,7 @@ class ObjectTypeDB { static Mutex *lock; static HashMap types; static HashMap resource_base_extensions; + static HashMap compat_types; #ifdef DEBUG_METHODS_ENABLED static MethodBind* bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount); @@ -482,6 +483,7 @@ public: static void get_resource_base_extensions(List *p_extensions); static void get_extensions_for_type(const StringName& p_type,List *p_extensions); + static void add_compatibility_type(const StringName& p_type,const StringName& p_fallback); static void init(); static void cleanup(); }; diff --git a/core/os/input.cpp b/core/os/input.cpp index 4151c1b5a8c..a827e75896c 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -29,6 +29,7 @@ #include "input.h" #include "input_map.h" #include "os/os.h" +#include "globals.h" Input *Input::singleton=NULL; Input *Input::get_singleton() { @@ -69,6 +70,30 @@ void Input::_bind_methods() { ADD_SIGNAL( MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")) ); } +void Input::get_argument_options(const StringName& p_function,int p_idx,List*r_options) const { +#ifdef TOOLS_ENABLED + + String pf=p_function; + if (p_idx==0 && (pf=="is_action_pressed" || pf=="action_press" || pf=="action_release")) { + + List pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + + for(List::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()); + r_options->push_back("\""+name+"\""); + + } + } +#endif + +} + Input::Input() { singleton=this; diff --git a/core/os/input.h b/core/os/input.h index 1cb0f35d963..387a43a35a4 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -76,6 +76,8 @@ public: virtual void action_press(const StringName& p_action)=0; virtual void action_release(const StringName& p_action)=0; + void get_argument_options(const StringName& p_function,int p_idx,List*r_options) const; + Input(); }; diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index a4201c34eaa..c9979d19214 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -353,3 +353,8 @@ int find_keycode(const String& p_code) { return 0; } + +int latin_keyboard_keycode_convert(int p_keycode){ + + return p_keycode; +} diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 18b56b58303..b4ec5da26fb 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -328,5 +328,6 @@ 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 latin_keyboard_keycode_convert(int p_keycode); #endif diff --git a/core/os/os.cpp b/core/os/os.cpp index 081f7c1c5ea..5e0e5eed77c 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -485,6 +485,11 @@ void OS::set_time_scale(float p_scale) { _time_scale=p_scale; } +OS::LatinKeyboardVariant OS::get_latin_keyboard_variant() const { + + return LATIN_KEYBOARD_QWERTY; +} + float OS::get_time_scale() const { return _time_scale; diff --git a/core/os/os.h b/core/os/os.h index 805d6ac57da..d4deff2f5e7 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -34,6 +34,7 @@ #include "vector.h" #include "os/main_loop.h" #include + /** @author Juan Linietsky */ @@ -348,6 +349,18 @@ public: virtual Error dialog_input_text(String p_title, String p_description, String p_partial, Object* p_obj, String p_callback); + enum LatinKeyboardVariant { + LATIN_KEYBOARD_QWERTY, + LATIN_KEYBOARD_QWERTZ, + LATIN_KEYBOARD_AZERTY, + LATIN_KEYBOARD_QZERTY, + LATIN_KEYBOARD_DVORAK, + LATIN_KEYBOARD_NEO, + }; + + + virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + void set_time_scale(float p_scale); float get_time_scale() const; diff --git a/core/translation.cpp b/core/translation.cpp index 81f2c360756..6ad34651b2d 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -550,7 +550,7 @@ StringName TranslationServer::translate(const StringName& p_message) const { continue; // locale not match //near match - bool match = (l!=lptr); + bool match = (l!=locale); if (near_match && !match) continue; //only near-match once @@ -570,6 +570,42 @@ StringName TranslationServer::translate(const StringName& p_message) const { } + if (!res) { + //try again with fallback + if (fallback.length()>=2) { + + const CharType *fptr=&fallback[0]; + bool near_match=false; + for (const Set< Ref >::Element *E=translations.front();E;E=E->next()) { + + const Ref& t = E->get(); + String l = t->get_locale(); + if (fptr[0]!=l[0] || fptr[1]!=l[1]) + continue; // locale not match + + //near match + bool match = (l!=fallback); + + if (near_match && !match) + continue; //only near-match once + + StringName r=t->get_message(p_message); + + if (!r) + continue; + + res=r; + + if (match) + break; + else + near_match=true; + + } + } + } + + if (!res) return p_message; @@ -604,9 +640,27 @@ bool TranslationServer::_load_translations(const String& p_from) { void TranslationServer::setup() { + String test = GLOBAL_DEF("locale/test",""); + test=test.strip_edges(); + if (test!="") + set_locale( test ); + else + set_locale( OS::get_singleton()->get_locale() ); + fallback = GLOBAL_DEF("locale/fallback","en"); +#ifdef TOOLS_ENABLED - set_locale( GLOBAL_DEF("locale/default",OS::get_singleton()->get_locale()) ); - fallback = GLOBAL_DEF("locale/fallback",""); + { + String options=""; + int idx=0; + while(locale_list[idx]) { + if (idx>0) + options+=", "; + options+=locale_list[idx]; + idx++; + } + Globals::get_singleton()->set_custom_property_info("locale/fallback",PropertyInfo(Variant::STRING,"locale/fallback",PROPERTY_HINT_ENUM,options)); + } +#endif //load translations } @@ -629,6 +683,7 @@ void TranslationServer::load_translations() { String locale = get_locale(); bool found = _load_translations("locale/translations"); //all + if (_load_translations("locale/translations_"+locale.substr(0,2))) found=true; if ( locale.substr(0,2) != locale ) { @@ -637,17 +692,6 @@ void TranslationServer::load_translations() { } - if (!found && fallback!="") { //none found anywhere, use fallback - - _load_translations("locale/translations_"+fallback.substr(0,2)); - if ( fallback.substr(0,2) != fallback ) { - _load_translations("locale/translations_"+fallback); - } - - this->locale=fallback; - - } - } TranslationServer::TranslationServer() { diff --git a/core/ustring.cpp b/core/ustring.cpp index d75c21d16e3..581cc29440b 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -626,7 +626,7 @@ Vector String::split_floats(const String &p_splitter,bool p_allow_empty) if (end<0) end=len; if (p_allow_empty || (end>from)) - ret.push_back(String::to_double(&c_str()[from],end-from)); + ret.push_back(String::to_double(&c_str()[from])); if (end==len) break; @@ -654,8 +654,9 @@ Vector String::split_floats_mk(const Vector &p_splitters,bool p_a spl_len=p_splitters[idx].length(); } - if (p_allow_empty || (end>from)) - ret.push_back(String::to_double(&c_str()[from],end-from)); + if (p_allow_empty || (end>from)) { + ret.push_back(String::to_double(&c_str()[from])); + } if (end==len) break; @@ -1959,8 +1960,10 @@ float String::to_float() const { return to_double(); } -double String::to_double(const CharType* p_str, int p_len, const CharType **r_end) { +double String::to_double(const CharType* p_str, const CharType **r_end) { + return built_in_strtod(p_str,(CharType**)r_end); +#if 0 #if 0 //ndef NO_USE_STDLIB return wcstod(p_str,p_len<0?NULL:p_str+p_len); @@ -2053,6 +2056,7 @@ double String::to_double(const CharType* p_str, int p_len, const CharType **r_en return sign*(integer+decimal)*Math::pow(10,exp_sign*exp); #endif +#endif } int64_t String::to_int(const CharType* p_str,int p_len) { @@ -3437,7 +3441,7 @@ String String::percent_encode() const { uint8_t c = cs[i]; if ( (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='-' || c=='_' || c=='~' || c=='.') { - char p[2]={c,0}; + char p[2]={(char)c,0}; encoded+=p; } else { char p[4]={'%',0,0,0}; diff --git a/core/ustring.h b/core/ustring.h index 8fe3a95463d..e1d67617423 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -142,7 +142,7 @@ public: int64_t to_int64() const; static int to_int(const char* p_str); static double to_double(const char* p_str); - static double to_double(const CharType* p_str, int p_len=-1, const CharType **r_end=NULL); + static double to_double(const CharType* p_str, const CharType **r_end=NULL); static int64_t to_int(const CharType* p_str,int p_len=-1); String capitalize() const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 9c489c5ef2e..ec43b1275cb 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -922,21 +922,31 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) case REAL: { return; } break; case STRING: { - if (p_value.type!=Variant::STRING) - return; - if (p_index.get_type()==Variant::INT || p_index.get_type()==Variant::REAL) { - //string index - int idx=p_index; - String *str=reinterpret_cast(_data._mem); - if (idx >=0 && idxlength()) { - String chr = p_value; - *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length()); - valid=true; - return; - } + if (p_index.type!=Variant::INT && p_index.type!=Variant::REAL) + return; + + int idx=p_index; + String *str=reinterpret_cast(_data._mem); + if (idx <0 || idx>=str->length()) + return; + + String chr; + if (p_value.type==Variant::INT || p_value.type==Variant::REAL) { + + chr = String::chr(p_value); + } else if (p_value.type==Variant::STRING) { + + chr = p_value; + } else { + return; } + *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length()); + valid=true; + return; + + } break; case VECTOR2: { @@ -951,7 +961,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) Vector2 *v=reinterpret_cast(_data._mem); valid=true; - v[idx]=p_value; + (*v)[idx]=p_value; return; } } else if (p_index.get_type()==Variant::STRING) { @@ -1045,7 +1055,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid) Vector3 *v=reinterpret_cast(_data._mem); valid=true; - v[idx]=p_value; + (*v)[idx]=p_value; return; } } else if (p_index.get_type()==Variant::STRING) { diff --git a/demos/2d/platformer/player.gd b/demos/2d/platformer/player.gd index 481f340ab8c..b08105212ce 100644 --- a/demos/2d/platformer/player.gd +++ b/demos/2d/platformer/player.gd @@ -53,12 +53,15 @@ var enemy func _integrate_forces(s): + + var lv = s.get_linear_velocity() var step = s.get_step() var new_anim=anim var new_siding_left=siding_left + # Get the controls var move_left = Input.is_action_pressed("move_left") var move_right = Input.is_action_pressed("move_right") diff --git a/demos/2d/platformer/player.xml b/demos/2d/platformer/player.xml index c129d01f0df..196881dee43 100644 --- a/demos/2d/platformer/player.xml +++ b/demos/2d/platformer/player.xml @@ -1,13 +1,13 @@ - + - - + + @@ -50,7 +50,52 @@ - "run" + "jumping" + 0.5 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1, 1, 1 + "values" + + 23 + 24 + 23 + + "times" + 0, 0.25, 0.5 + + + + + "idle_weapon" + 0.5 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1 + "values" + + 25 + + "times" + 0 + + + + 1.25 True 0.25 @@ -75,55 +120,6 @@ 0, 0.25, 0.5, 0.75, 1, 1.25 - - - "run_gun_fire" - 1.25 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1, 1, 1, 1, 1, 1 - "values" - - 10 - 11 - 12 - 13 - 14 - 5 - - "times" - 0, 0.25, 0.5, 0.75, 1, 1.25 - - - - - "jumping_weapon" - 0.5 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 26 - - "times" - 0 - - "crouch" @@ -148,7 +144,55 @@ - "jumping" + "falling" + 0.01 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1 + "values" + + 21 + + "times" + 0 + + + + + 1.25 + True + 0.25 + "value" + "sprite:frame" + 1 + + "cont" + False + "transitions" + 1, 1, 1, 1, 1, 1 + "values" + + 10 + 11 + 12 + 13 + 14 + 5 + + "times" + 0, 0.25, 0.5, 0.75, 1, 1.25 + + + + + "falling_weapon" 0.5 True 0.25 @@ -159,20 +203,17 @@ "cont" False "transitions" - 1, 1, 1 + 1 "values" - - 23 - 24 - 23 + + 26 "times" - 0, 0.25, 0.5 + 0 - - "run_weapon" + 1.25 True 0.25 @@ -198,30 +239,7 @@ - - "idle_weapon" - 0.5 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 25 - - "times" - 0 - - - - - "falling_weapon" + 0.5 True 0.25 @@ -241,28 +259,6 @@ 0 - - - "falling" - 0.01 - True - 0.25 - "value" - "sprite:frame" - 1 - - "cont" - False - "transitions" - 1 - "values" - - 21 - - "times" - 0 - - @@ -294,9 +290,10 @@ "names" - + "player" "RigidBody2D" + "_import_path" "visibility/visible" "visibility/opacity" "visibility/self_opacity" @@ -311,6 +308,7 @@ "shapes/1/shape" "shapes/1/transform" "shapes/1/trigger" + "layers" "mode" "mass" "friction" @@ -319,7 +317,7 @@ "continuous_cd" "contacts_reported" "contact_monitor" - "active" + "sleeping" "can_sleep" "velocity/linear" "velocity/angular" @@ -354,6 +352,8 @@ "config/flip_h" "config/flip_v" "config/texture" + "config/h_frames" + "config/v_frames" "params/direction" "params/spread" "params/linear_velocity" @@ -364,9 +364,12 @@ "params/radial_accel" "params/tangential_accel" "params/damping" + "params/initial_angle" "params/initial_size" "params/final_size" "params/hue_variation" + "params/anim_speed_scale" + "params/anim_initial_pos" "randomness/direction" "randomness/spread" "randomness/linear_velocity" @@ -377,9 +380,12 @@ "randomness/radial_accel" "randomness/tangential_accel" "randomness/damping" + "randomness/initial_angle" "randomness/initial_size" "randomness/final_size" "randomness/hue_variation" + "randomness/anim_speed_scale" + "randomness/anim_initial_pos" "color_phases/count" "phase_0/pos" "phase_0/color" @@ -396,15 +402,15 @@ "playback/default_blend_time" "root/root" "anims/idle" - "anims/run" - "anims/standing_weapon_ready" - "anims/jumping_weapon" - "anims/crouch" "anims/jumping" - "anims/run_weapon" "anims/idle_weapon" - "anims/falling_weapon" + "anims/run" + "anims/crouch" "anims/falling" + "anims/standing_weapon_ready" + "anims/falling_weapon" + "anims/run_weapon" + "anims/jumping_weapon" "playback/active" "playback/speed" "blend_times" @@ -473,7 +479,8 @@ "node_count" 14 "variants" - + + "" True 1 False @@ -485,6 +492,7 @@ 1, -0, 0, 1.76469, 0.291992, -12.1587 1, -0, 0, 1, 0, 0 + 1 3 0 3 @@ -507,11 +515,17 @@ False "zoom" 2.272073 + "use_snap" + False "ofs" -181.946, -86.2812 + "snap" + 10 "3D" + "deflight_rot_y" + 0.628319 "zfar" 500 "fov" @@ -525,10 +539,12 @@ 0 "y_rot" 0 - "use_orthogonal" - False + "listener" + True "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -539,10 +555,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -553,10 +571,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -567,10 +587,12 @@ 0 "y_rot" 0 - "use_orthogonal" + "listener" False "use_environment" False + "use_orthogonal" + False "pos" 0, 0, 0 @@ -579,12 +601,18 @@ 1 "default_light" True + "ambient_light_color" + 0.15, 0.15, 0.15, 1 "show_grid" True "show_origin" True "znear" 0.1 + "default_srgb" + False + "deflight_rot_x" + 0.942478 "__editor_run_settings__" @@ -595,14 +623,13 @@ 0 "__editor_plugin_screen__" - "3D" + "Script" 16 1, 1, 1, 1 0, 0, 0, 0 0.363636 - 1 20.7312, 3.21187 83.450417 4 @@ -654,7 +681,7 @@ "shoot" "nodes" - -1, -1, 1, 0, -1, 28, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 2, 13, 9, 14, 10, 15, 2, 16, 6, 17, 11, 18, 4, 19, 4, 20, 0, 21, 12, 22, 13, 23, 2, 24, 0, 25, 0, 26, 3, 27, 4, 28, 14, 29, 15, 0, 0, 0, 31, 30, -1, 18, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 32, 16, 33, 0, 34, 3, 35, 2, 36, 2, 37, 6, 38, 17, 39, 12, 40, 18, 41, 2, 42, 19, 0, 1, 0, 44, 43, -1, 57, 2, 0, 3, 1, 4, 20, 5, 2, 45, 21, 6, 22, 7, 23, 8, 5, 46, 24, 47, 25, 48, 1, 49, 4, 50, 25, 51, 2, 52, 3, 53, 3, 54, 2, 55, 26, 56, 2, 57, 2, 58, 27, 59, 4, 60, 28, 61, 29, 62, 1, 63, 4, 64, 4, 65, 30, 66, 4, 67, 4, 68, 4, 69, 31, 70, 31, 71, 4, 72, 4, 73, 4, 74, 4, 75, 31, 76, 4, 77, 4, 78, 4, 79, 4, 80, 4, 81, 4, 82, 4, 83, 4, 84, 4, 85, 6, 86, 4, 87, 18, 88, 1, 89, 32, 90, 1, 91, 33, 92, 1, 93, 34, 94, 35, 0, 0, 0, 96, 95, -1, 17, 97, 21, 98, 4, 99, 36, 100, 37, 101, 38, 102, 39, 103, 40, 104, 41, 105, 42, 106, 43, 107, 44, 108, 45, 109, 46, 110, 0, 111, 31, 112, 47, 113, 48, 0, 0, 0, 115, 114, -1, 22, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 33, 0, 116, 2, 117, 0, 118, 4, 119, 5, 120, 12, 121, 12, 122, 49, 123, 49, 124, 0, 125, 0, 126, 50, 127, 50, 128, 50, 129, 50, 0, 0, 0, 131, 130, -1, 7, 2, 0, 3, 1, 4, 1, 5, 2, 6, 51, 7, 4, 8, 5, 0, 0, 0, 132, 132, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 52, 7, 4, 8, 53, 133, 7, 134, 2, 0, 0, 0, 136, 135, -1, 14, 137, 13, 138, 54, 139, 4, 140, 1, 141, 4, 142, 4, 143, 4, 144, 55, 145, 55, 146, 55, 147, 55, 148, 6, 149, 4, 150, 4, 0, 0, 0, 151, 151, -1, 9, 2, 0, 3, 1, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 152, 12, 153, 56, 0, 0, 0, 155, 154, -1, 4, 156, 12, 34, 3, 157, 4, 158, 5, 0, 9, 0, 160, 159, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 57, 7, 4, 8, 58, 161, 59, 162, 60, 163, 60, 164, 0, 165, 61, 166, 21, 0, 9, 0, 160, 167, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 62, 7, 4, 8, 58, 161, 63, 162, 60, 163, 60, 164, 0, 165, 64, 166, 21, 0, 9, 0, 160, 168, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 65, 7, 4, 8, 58, 161, 66, 162, 60, 163, 60, 164, 2, 165, 67, 166, 21, 0, 9, 0, 160, 169, -1, 13, 2, 0, 3, 1, 4, 1, 5, 2, 6, 68, 7, 4, 8, 58, 161, 69, 162, 60, 163, 60, 164, 2, 165, 70, 166, 21, 0 + -1, -1, 1, 0, -1, 30, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 9, 13, 3, 14, 10, 15, 11, 16, 3, 17, 12, 18, 7, 19, 13, 20, 5, 21, 5, 22, 1, 23, 14, 24, 15, 25, 3, 26, 3, 27, 1, 28, 4, 29, 5, 30, 16, 31, 17, 0, 0, 0, 33, 32, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 34, 18, 35, 1, 36, 4, 37, 3, 38, 3, 39, 7, 40, 19, 41, 14, 42, 20, 43, 3, 44, 21, 0, 1, 0, 46, 45, -1, 66, 2, 0, 3, 1, 4, 2, 5, 22, 6, 3, 47, 12, 7, 23, 8, 24, 9, 6, 48, 25, 49, 26, 50, 2, 51, 5, 52, 26, 53, 3, 54, 4, 55, 4, 56, 3, 57, 27, 58, 3, 59, 3, 60, 28, 61, 12, 62, 12, 63, 5, 64, 29, 65, 30, 66, 2, 67, 5, 68, 5, 69, 31, 70, 5, 71, 5, 72, 5, 73, 5, 74, 32, 75, 32, 76, 5, 77, 2, 78, 5, 79, 5, 80, 5, 81, 5, 82, 32, 83, 5, 84, 5, 85, 5, 86, 5, 87, 5, 88, 5, 89, 5, 90, 5, 91, 5, 92, 5, 93, 5, 94, 5, 95, 7, 96, 5, 97, 20, 98, 2, 99, 33, 100, 2, 101, 34, 102, 2, 103, 35, 104, 36, 0, 0, 0, 106, 105, -1, 18, 2, 0, 107, 12, 108, 5, 109, 37, 110, 38, 111, 39, 112, 40, 113, 41, 114, 42, 115, 43, 116, 44, 117, 45, 118, 46, 119, 47, 120, 1, 121, 32, 122, 48, 123, 49, 0, 0, 0, 125, 124, -1, 23, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 35, 1, 126, 3, 127, 1, 128, 5, 129, 6, 130, 14, 131, 14, 132, 50, 133, 50, 134, 1, 135, 1, 136, 51, 137, 51, 138, 51, 139, 51, 0, 0, 0, 141, 140, -1, 8, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 52, 8, 5, 9, 6, 0, 0, 0, 142, 142, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 53, 8, 5, 9, 54, 143, 8, 144, 3, 0, 0, 0, 146, 145, -1, 15, 2, 0, 147, 15, 148, 55, 149, 5, 150, 2, 151, 5, 152, 5, 153, 5, 154, 56, 155, 56, 156, 56, 157, 56, 158, 7, 159, 5, 160, 5, 0, 0, 0, 161, 161, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 162, 14, 163, 57, 0, 0, 0, 165, 164, -1, 5, 2, 0, 166, 14, 36, 4, 167, 5, 168, 6, 0, 9, 0, 170, 169, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 58, 8, 5, 9, 59, 171, 60, 172, 61, 173, 61, 174, 1, 175, 62, 176, 12, 0, 9, 0, 170, 177, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 63, 8, 5, 9, 59, 171, 64, 172, 61, 173, 61, 174, 1, 175, 65, 176, 12, 0, 9, 0, 170, 178, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 66, 8, 5, 9, 59, 171, 67, 172, 61, 173, 61, 174, 3, 175, 68, 176, 12, 0, 9, 0, 170, 179, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 69, 8, 5, 9, 59, 171, 70, 172, 61, 173, 61, 174, 3, 175, 71, 176, 12, 0 "conns" diff --git a/drivers/builtin_openssl2/openssl/md5.h b/drivers/builtin_openssl2/openssl/md5.h index 8f392f0ec64..765be94335a 100644 --- a/drivers/builtin_openssl2/openssl/md5.h +++ b/drivers/builtin_openssl2/openssl/md5.h @@ -105,9 +105,9 @@ typedef struct MD5state_st unsigned int num; } MD5_CTX; -#ifdef OPENSSL_FIPS +//#ifdef OPENSSL_FIPS int private_MD5_Init(MD5_CTX *c); -#endif +//#endif //#define MD5_Init _SSL_MD5_Init #define MD5_Final _SSL_MD5_Final diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 9d47084c1c7..fdf73a6c216 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -139,11 +139,13 @@ static _FORCE_INLINE_ uint16_t make_half_float(float f) { else if (exp <= 0x38000000) { - // store a denorm half-float value or zero + /*// store a denorm half-float value or zero exp = (0x38000000 - exp) >> 23; mantissa >>= (14 + exp); hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa); + */ + hf=0; //denormals do not work for 3D, convert to zero } else { @@ -969,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu - if (img.detect_alpha()==Image::ALPHA_BLEND) { + if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) { texture->has_alpha=true; } @@ -4224,7 +4226,6 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) { } w=DVector::Write(); - r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels); //r_capture->flip_y(); @@ -8188,8 +8189,18 @@ void RasterizerGLES2::canvas_draw_polygon(int p_vertex_count, const int* p_indic } if (p_indices) { - +#ifdef GLEW_ENABLED glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices ); +#else + static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!! + ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices); + static uint16_t _draw_poly_indices[_max_draw_poly_indices]; + for (int i=0; iseek_end(0); - streamlen=f->get_pos(); - f->seek(0); + //printf("file size is %i\n", f->get_len()); + //f->seek_end(0); + streamlen=f->get_len(); + //f->seek(0); if (streamlen<=0) { memdelete(f); f=NULL; diff --git a/drivers/theoraplayer/SCsub b/drivers/theoraplayer/SCsub index cd8cabcc948..419f2b65ae6 100644 --- a/drivers/theoraplayer/SCsub +++ b/drivers/theoraplayer/SCsub @@ -61,13 +61,17 @@ src/YUV/C/yuv420_rgb_c.c src/TheoraVideoFrame.cpp """) +env_theora = env.Clone() + if env["platform"] == "iphone": sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm") env.Append(LINKFLAGS=['-framework', 'CoreVideo', '-framework', 'CoreMedia', '-framework', 'AVFoundation']) + if env["target"] == "release": + env_theora.Append(CPPFLAGS=["-D_IOS", "-D__ARM_NEON__", "-fstrict-aliasing", "-fmessage-length=210", "-fdiagnostics-show-note-include-stack", "-fmacro-backtrace-limit=0", "-fcolor-diagnostics", "-Wno-trigraphs", "-fpascal-strings", "-fvisibility=hidden", "-fvisibility-inlines-hidden"]) -env_theora = env.Clone() - -env_theora.Append(CPPFLAGS=["-D_YUV_C", "-D_LIB", "-D__THEORA"]) +env_theora.Append(CPPFLAGS=["-D_LIB", "-D__THEORA"]) # removed -D_YUV_C +env_theora.Append(CPPFLAGS=["-D_YUV_LIBYUV", "-DLIBYUV_NEON"]) +#env_theora.Append(CPPFLAGS=["-D_YUV_C"]) if env["platform"] == "iphone": env_theora.Append(CPPFLAGS=["-D__AVFOUNDATION"]) diff --git a/drivers/theoraplayer/src/TheoraVideoClip.cpp b/drivers/theoraplayer/src/TheoraVideoClip.cpp index ed9f2c22dac..16897ee80eb 100644 --- a/drivers/theoraplayer/src/TheoraVideoClip.cpp +++ b/drivers/theoraplayer/src/TheoraVideoClip.cpp @@ -249,6 +249,7 @@ int TheoraVideoClip::discardOutdatedFrames(float absTime) if (nPop > 0) { +#define _DEBUG #ifdef _DEBUG std::string log = getName() + ": dropped frame "; diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp index 62dee1336a7..9f4a44ae9d9 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.cpp +++ b/drivers/theoraplayer/video_stream_theoraplayer.cpp @@ -215,7 +215,7 @@ public: channels = p_channels; freq = p_freq; total_wrote = 0; - rb_power = 12; + rb_power = 22; rb.resize(rb_power); }; @@ -258,10 +258,12 @@ public: void update(float time_increase) { + float prev_time = mTime; //mTime = (float)(stream->get_total_wrote()) / freq; //mTime = MAX(0,mTime-AudioServer::get_singleton()->get_output_delay()); //mTime = (float)sample_count / channels / freq; mTime += time_increase; + if (mTime - prev_time > .02) printf("time increase %f secs\n", mTime - prev_time); //float duration=mClip->getDuration(); //if (mTime > duration) mTime=duration; //printf("time at timer is %f, %f, samples %i\n", mTime, time_increase, sample_count); @@ -386,7 +388,7 @@ void VideoStreamTheoraplayer::pop_frame(Ref p_tex) { { DVector::Write wr = data.write(); uint8_t* ptr = wr.ptr(); - copymem(ptr, f->getBuffer(), imgsize); + memcpy(ptr, f->getBuffer(), imgsize); } /* for (int i=0; inext == ringptr) && (ringptr->prev == ringptr); bool is_list = ( ringlist == ringptr ); - RingPtr *new_ringptr=(RingPtr*)::realloc(ringptr, p_bytes+sizeof(RingPtr)); ERR_FAIL_COND_V( new_ringptr == 0, NULL ); /// reallocation failed @@ -213,7 +211,7 @@ void MemoryPoolStaticMalloc::free(void *p_ptr) { ERR_FAIL_COND( !MemoryPoolStatic::get_singleton()); - #if DFAULT_ALIGNMENT == 1 + #if DEFAULT_ALIGNMENT == 1 _free(p_ptr); #else diff --git a/drivers/webp/dsp/dsp.h b/drivers/webp/dsp/dsp.h index 9ff53174d49..afe30413c64 100644 --- a/drivers/webp/dsp/dsp.h +++ b/drivers/webp/dsp/dsp.h @@ -33,7 +33,7 @@ extern "C" { #define WEBP_ANDROID_NEON // Android targets that might support NEON #endif -#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED) +#if ( (defined(__ARM_NEON__) && !defined(__aarch64__)) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED) #define WEBP_USE_NEON #endif diff --git a/drivers/webp/utils/bit_reader.h b/drivers/webp/utils/bit_reader.h index d80b4971490..43cd948fd4f 100644 --- a/drivers/webp/utils/bit_reader.h +++ b/drivers/webp/utils/bit_reader.h @@ -1,3 +1,4 @@ +// // Copyright 2010 Google Inc. All Rights Reserved. // // This code is licensed under the same terms as WebM: diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index d4fe8b626be..6289e6961c8 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -45,8 +45,13 @@ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) return; error=p_error; - err_line=p_node->line; - err_column=p_node->column; + if (p_node) { + err_line=p_node->line; + err_column=p_node->column; + } else { + err_line=0; + err_column=0; + } } bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) { @@ -1522,7 +1527,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars GDScript::MemberInfo minfo; minfo.index = p_script->member_indices.size(); minfo.setter = p_class->variables[i].setter; - minfo.getter = p_class->variables[i].getter; + minfo.getter = p_class->variables[i].getter; p_script->member_indices[name]=minfo; p_script->members.insert(name); @@ -1586,6 +1591,48 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars return err; } +#ifdef DEBUG_ENABLED + //validate setters/getters if debug is enabled + for(int i=0;ivariables.size();i++) { + + if (p_class->variables[i].setter) { + const Map::Element *E=p_script->get_member_functions().find(p_class->variables[i].setter); + if (!E) { + _set_error("Setter function '"+String(p_class->variables[i].setter)+"' not found in class.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + if (E->get().is_static()) { + + _set_error("Setter function '"+String(p_class->variables[i].setter)+"' is static.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + } + if (p_class->variables[i].getter) { + const Map::Element *E=p_script->get_member_functions().find(p_class->variables[i].getter); + if (!E) { + _set_error("Getter function '"+String(p_class->variables[i].getter)+"' not found in class.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + if (E->get().is_static()) { + + _set_error("Getter function '"+String(p_class->variables[i].getter)+"' is static.",NULL); + err_line=p_class->variables[i].line; + err_column=0; + return ERR_PARSE_ERROR; + } + + } + } +#endif return OK; } diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index eb1d0a4db32..12dc1bb1391 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" - +#include "globals.h" void GDScriptLanguage::get_comment_delimiters(List *p_delimiters) const { @@ -1276,7 +1276,23 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set& result, String& arghint) { - if (id.type==Variant::OBJECT && id.obj_type!=StringName()) { + if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) { + + List pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + + for(List::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()); + result.insert("\""+name+"\""); + } + + + } else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) { MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method); @@ -1299,7 +1315,7 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St const GDParser::OperatorNode *op=static_cast(p_node); if (op->arguments.size()>) - }*/ + }*/ } else { Object *obj=id.value; @@ -1826,6 +1842,37 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base _find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint); } break; + case GDParser::COMPLETION_VIRTUAL_FUNC: { + + GDCompletionIdentifier cid = _get_native_class(context); + + if (cid.obj_type!=StringName()) { + List vm; + ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm); + for(List::Element *E=vm.front();E;E=E->next()) { + + MethodInfo &mi=E->get(); + String m = mi.name; + if (m.find(":")!=-1) + m=m.substr(0,m.find(":")); + m+="("; + + if (mi.arguments.size()) { + for(int i=0;i0) + m+=", "; + String n =mi.arguments[i].name; + if (n.find(":")!=-1) + n=n.substr(0,n.find(":")); + m+=n; + } + } + m+="):"; + + options.insert(m); + } + } + } break; } diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 0d11734bbd2..fcfbbb04da3 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -1166,6 +1166,8 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="WeakRef"; + return mi; } break; @@ -1173,6 +1175,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("funcref",PropertyInfo(Variant::OBJECT,"instance"),PropertyInfo(Variant::STRING,"funcname")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="FuncRef"; return mi; } break; @@ -1231,6 +1234,7 @@ MethodInfo GDFunctions::get_info(Function p_func) { MethodInfo mi("load",PropertyInfo(Variant::STRING,"path")); mi.return_val.type=Variant::OBJECT; + mi.return_val.name="Resource"; return mi; } break; case INST2DICT: { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index f79f3ee44a5..aa2878f9e14 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -2027,14 +2027,20 @@ void GDParser::_parse_class(ClassNode *p_class) { } - if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) { + tokenizer->advance(); + StringName name; + + if (_get_completable_identifier(COMPLETION_VIRTUAL_FUNC,name)) { + + } + + + if (name==StringName()) { _set_error("Expected identifier after 'func' (syntax: 'func ([arguments]):' )."); return; } - StringName name = tokenizer->get_token_identifier(1); - for(int i=0;ifunctions.size();i++) { if (p_class->functions[i]->name==name) { _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+")."); @@ -2045,7 +2051,7 @@ void GDParser::_parse_class(ClassNode *p_class) { _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+")."); } } - tokenizer->advance(2); + if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index 26955d2b7a2..44e7b55323a 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -363,6 +363,7 @@ public: COMPLETION_METHOD, COMPLETION_CALL_ARGUMENTS, COMPLETION_INDEX, + COMPLETION_VIRTUAL_FUNC }; diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 140718a91a4..e621a5e061b 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -1192,8 +1192,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { undo_redo=p_editor->get_undo_redo(); int mw = EDITOR_DEF("grid_map/palette_min_width",230); - EmptyControl *ec = memnew( EmptyControl); - ec->set_minsize(Size2(mw,0)); + Control *ec = memnew( Control); + ec->set_custom_minimum_size(Size2(mw,0)); add_child(ec); diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp index 3c3c8aa98fd..887687a37bf 100644 --- a/modules/gridmap/register_types.cpp +++ b/modules/gridmap/register_types.cpp @@ -27,16 +27,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_types.h" +#ifndef _3D_DISABLED #include "object_type_db.h" #include "grid_map.h" #include "grid_map_editor_plugin.h" +#endif void register_gridmap_types() { +#ifndef _3D_DISABLED ObjectTypeDB::register_type(); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type(); #endif +#endif } diff --git a/platform/android/detect.py b/platform/android/detect.py index 417f3e68ab1..695caf1e5d4 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -124,11 +124,11 @@ def configure(env): # env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ') if env['x86']=='yes': - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') + env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') elif env["armv6"]!="no": - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') + env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') else: - env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') + env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED') env.Append(LDPATH=[ld_path]) env.Append(LIBS=['OpenSLES']) diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java index f6cd57f4f3c..1a7659a473a 100644 --- a/platform/android/java/src/com/android/godot/Godot.java +++ b/platform/android/java/src/com/android/godot/Godot.java @@ -358,7 +358,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC GodotLib.initialize(this,io.needsReloadHooks(),command_line); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); + mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); result_callback = null; diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 93345be7302..f8d86a3c7a6 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -54,20 +54,35 @@ def configure(env): env['AR'] = 'ar' import string - #env['CCFLAGS'] = string.split('-arch armv7 -Wall -fno-strict-aliasing -fno-common -D__IPHONE_OS_VERSION_MIN_REQUIRED=20000 -isysroot $IPHONESDK -fvisibility=hidden -mmacosx-version-min=10.5 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\" -DNO_THUMB') - env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK') + if (env["bits"]=="64"): + #env['CCFLAGS'] = string.split('-arch arm64 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -miphoneos-version-min=5.1.1 -Wmost -Wno-four-char-constants -Wno-unknown-pragmas -Wno-invalid-offsetof -ffast-math -m64 -DDEBUG -D_DEBUG -MMD -MT dependencies -isysroot $IPHONESDK') + env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=5.1.1 -isysroot $IPHONESDK') + env.Append(CPPFLAGS=['-DNEED_LONG_INT']) + env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON']) + else: + env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK') - -#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ fno-objc-arc -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -v -Os -ffast-math -DSTOREKIT_ENABLED -DIPHONE_ENABLED -DUNIX_ENABLED -DGLES2_ENABLED -DNO_THREADS -DMODULE_GRIDMAP_ENABLED -DMUSEPACK_ENABLED -DOLD_SCENE_FORMAT_ENABLED -DSQUIRREL_ENABLED -DVORBIS_ENABLED -DTHEORA_ENABLED -DPNG_ENABLED -DDDS_ENABLED -DPVR_ENABLED -DJPG_ENABLED -DSPEEX_ENABLED -DTOOLS_ENABLED -DGDSCRIPT_ENABLED -DMINIZIP_ENABLED -DXML_ENABLED -Icore -Icore/math -Itools -Idrivers -I. -Iplatform/iphone -Iplatform/iphone/include -Iplatform/iphone/scoreloop/SDKs -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework/Headers -Iscript/squirrel/src -Iscript/vorbis script/gdscript/gd_script.cpp -#/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -x objective-c -arch armv7 -fmessage-length=0 -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-generated-files.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-own-target-headers.hmap -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-all-target-headers.hmap -iquote /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/test2-project-headers.hmap -I/Users/red/test2/build/Release-iphoneos/include -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources/armv7 -I/Users/red/test2/build/test2.build/Release-iphoneos/test2.build/DerivedSources -F/Users/red/test2/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 -include /var/folders/LX/LXYXHTeSHSqbkhuPJRIsuE+++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/test2-Prefix-dvdhnltoisfpmyalexovdrmfyeky/test2-Prefix.pch -MMD -MT dependencies -MF /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.d -c /Users/red/test2/test2/main.m -o /Users/red/test2/build/test2.build/Release-iphoneos/test2.build/Objects-normal/armv7/main.o - - - - - - env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3', + if (env["bits"]=="64"): + env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1', + '-isysroot', '$IPHONESDK', + #'-stdlib=libc++', + '-framework', 'Foundation', + '-framework', 'UIKit', + '-framework', 'CoreGraphics', + '-framework', 'OpenGLES', + '-framework', 'QuartzCore', + '-framework', 'CoreAudio', + '-framework', 'AudioToolbox', + '-framework', 'SystemConfiguration', + '-framework', 'Security', + #'-framework', 'AdSupport', + '-framework', 'MediaPlayer', + '-framework', 'AVFoundation', + '-framework', 'CoreMedia', + ]) + else: + env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3', '-isysroot', '$IPHONESDK', - #'-mmacosx-version-min=10.5', '-framework', 'Foundation', '-framework', 'UIKit', '-framework', 'CoreGraphics', @@ -128,4 +143,4 @@ def configure(env): env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } ) -# /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c-header -arch armv7s -fmessage-length=0 -std=gnu99 -fobjc-arc -Wno-trigraphs -fpascal-strings -Os -Wno-missing-field-initializers -Wno-missing-prototypes -Wreturn-type -Wno-implicit-atomic-properties -Wno-receiver-is-weak -Wduplicate-method-match -Wformat -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-shorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector -Wno-deprecated-implementations -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk -Wprotocol -Wdeprecated-declarations -g -fvisibility=hidden -Wno-sign-conversion "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-generated-files.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-own-target-headers.hmap -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-all-target-headers.hmap -iquote /Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/test-project-headers.hmap -I/Users/lucasgondolo/test/build/Release-iphoneos/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources/armv7s -I/Users/lucasgondolo/test/build/test.build/Release-iphoneos/test.build/DerivedSources -F/Users/lucasgondolo/test/build/Release-iphoneos -DNS_BLOCK_ASSERTIONS=1 --serialize-diagnostics /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.dia -c /Users/lucasgondolo/test/test/test-Prefix.pch -o /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.pth -MMD -MT dependencies -MF /var/folders/9r/_65jj9457bgb4n4nxcsm0xl80000gn/C/com.apple.Xcode.501/SharedPrecompiledHeaders/test-Prefix-esrzoamhgruxcxbhemvvlrjmmvoh/test-Prefix.pch.d + diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index df50d30f408..7e961176d9d 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -30,3 +30,4 @@ #define GLES2_INCLUDE_H #define GLES1_INCLUDE_H +#define PLATFORM_REFCOUNT diff --git a/platform/iphone/platform_refcount.h b/platform/iphone/platform_refcount.h new file mode 100644 index 00000000000..45391e651ae --- /dev/null +++ b/platform/iphone/platform_refcount.h @@ -0,0 +1,18 @@ +#include "safe_refcount.h" + +#ifdef IPHONE_ENABLED + +#define REFCOUNT_T int +#define REFCOUNT_GET_T int const volatile& + +#include + +inline int atomic_conditional_increment(volatile int* v) { + return (*v==0)? 0 : OSAtomicIncrement32(v); +} + +inline int atomic_decrement(volatile int* v) { + return OSAtomicDecrement32(v); +} + +#endif diff --git a/platform/windows/detect.py b/platform/windows/detect.py index be92ee8f6da..245d6f1bd3d 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -135,6 +135,27 @@ def configure(env): env.Append(LIBPATH=[DIRECTX_PATH+"/Lib/x86"]) env['ENV'] = os.environ; else: + + # Workaround for MinGW. See: + # http://www.scons.org/wiki/LongCmdLinesOnWin32 + if (os.name=="nt"): + import subprocess + def mySpawn(sh, escape, cmd, args, env): + newargs = ' '.join(args[1:]) + cmdline = cmd + " " + newargs + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env) + data, err = proc.communicate() + rv = proc.wait() + if rv: + print "=====" + print err + print "=====" + return rv + env['SPAWN'] = mySpawn + #build using mingw if (os.name=="nt"): env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes diff --git a/platform/winrt/include/angle_windowsstore.h b/platform/winrt/include/angle_windowsstore.h new file mode 100644 index 00000000000..fe587bf2690 --- /dev/null +++ b/platform/winrt/include/angle_windowsstore.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// angle_windowsstore.h: + +#ifndef ANGLE_WINDOWSSTORE_H_ +#define ANGLE_WINDOWSSTORE_H_ + +// The following properties can be set on the CoreApplication to support additional +// ANGLE configuration options. +// +// The Visual Studio sample templates provided with this version of ANGLE have examples +// of how to set these property values. + +// +// Property: EGLNativeWindowTypeProperty +// Type: IInspectable +// Description: Set this property to specify the window type to use for creating a surface. +// If this property is missing, surface creation will fail. +// +const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; + +// +// Property: EGLRenderSurfaceSizeProperty +// Type: Size +// Description: Set this property to specify a preferred size in pixels of the render surface. +// The render surface size width and height must be greater than 0. +// If this property is set, then the render surface size is fixed. +// If this property is missing, a default behavior will be provided. +// The default behavior uses the window size if a CoreWindow is specified or +// the size of the SwapChainPanel control if one is specified. +// +const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty"; + +#endif // ANGLE_WINDOWSSTORE_H_ diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp index 99dfa67c27b..a231acd13d5 100644 --- a/scene/2d/sample_player_2d.cpp +++ b/scene/2d/sample_player_2d.cpp @@ -102,6 +102,7 @@ void SamplePlayer2D::_notification(int p_what) { void SamplePlayer2D::set_sample_library(const Ref& p_library) { library=p_library; + _change_notify(); } Ref SamplePlayer2D::get_sample_library() const { diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 1db98862615..27420f80021 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -86,6 +86,10 @@ bool Camera::_set(const StringName& p_name, const Variant& p_value) { set_keep_aspect_mode(KeepAspect(int(p_value))); else if (p_name=="vaspect") set_keep_aspect_mode(p_value?KEEP_WIDTH:KEEP_HEIGHT); + else if (p_name=="h_offset") + h_offset=p_value; + else if (p_name=="v_offset") + v_offset=p_value; else if (p_name=="current") { if (p_value.operator bool()) { make_current(); @@ -128,6 +132,10 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const { } } else if (p_name=="visible_layers") { r_ret=get_visible_layers(); + } else if (p_name=="h_offset") { + r_ret=get_h_offset(); + } else if (p_name=="v_offset") { + r_ret=get_v_offset(); } else if (p_name=="environment") { r_ret=get_environment(); } else @@ -170,12 +178,16 @@ void Camera::_get_property_list( List *p_list) const { p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) ); p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) ); p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "h_offset" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "v_offset" ) ); } void Camera::_update_camera() { Transform tr = get_camera_transform(); + tr.origin+=tr.basis.get_axis(1)*v_offset; + tr.origin+=tr.basis.get_axis(0)*h_offset; VisualServer::get_singleton()->camera_set_transform( camera, tr ); // here goes listener stuff @@ -757,6 +769,27 @@ void Camera::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, cons } +void Camera::set_v_offset(float p_offset) { + + v_offset=p_offset; + _update_camera();; +} + +float Camera::get_v_offset() const { + + return v_offset; +} + +void Camera::set_h_offset(float p_offset) { + h_offset=p_offset; + _update_camera(); +} + +float Camera::get_h_offset() const { + + return h_offset; +} + Camera::Camera() { @@ -772,6 +805,8 @@ Camera::Camera() { set_perspective(60.0,0.1,100.0); keep_aspect=KEEP_HEIGHT; layers=0xfffff; + v_offset=0; + h_offset=0; VisualServer::get_singleton()->camera_set_visible_layers(camera,layers); //active=false; } diff --git a/scene/3d/camera.h b/scene/3d/camera.h index bac8173bb7c..950688dfda3 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -61,6 +61,8 @@ private: float fov; float size; float near,far; + float v_offset; + float h_offset; KeepAspect keep_aspect; RID camera; @@ -140,6 +142,12 @@ public: void look_at(const Vector3& p_target, const Vector3& p_up_normal); void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal); + void set_v_offset(float p_offset); + float get_v_offset() const; + + void set_h_offset(float p_offset); + float get_h_offset() const; + Camera(); ~Camera(); diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 82158405ea7..9c388a28834 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -47,6 +47,11 @@ void CollisionObject::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { + if (area) + PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform()); + else + PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + RID space = get_world()->get_space(); if (area) { PhysicsServer::get_singleton()->area_set_space(rid,space); diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp index a4206894ff3..651d20ae71a 100644 --- a/scene/3d/immediate_geometry.cpp +++ b/scene/3d/immediate_geometry.cpp @@ -127,7 +127,7 @@ void ImmediateGeometry::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color); ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv); ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2); - ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex); + ObjectTypeDB::bind_method(_MD("add_vertex","pos"),&ImmediateGeometry::add_vertex); ObjectTypeDB::bind_method(_MD("add_sphere","lats","lons","radius"),&ImmediateGeometry::add_sphere); ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end); ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 5c047b3fef1..f2806f2af29 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -852,6 +852,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { //motion recover for(int i=0;icollide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) { collided=true; @@ -870,9 +872,6 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { for(int j=0;j<8;j++) { for(int i=0;i "+b); diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 6bc0c677c0d..639a86e7593 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -95,18 +95,6 @@ void RayCast::_notification(int p_what) { if (enabled && !get_tree()->is_editor_hint()) { set_fixed_process(true); - Node *p = get_parent(); - while( p && p->cast_to() ) { - - CollisionObject *co = p->cast_to(); - if (co) { - - exception=co->get_rid(); - exceptions.insert(exception); - } - - p=p->get_parent(); - } } else set_fixed_process(false); @@ -119,7 +107,6 @@ void RayCast::_notification(int p_what) { set_fixed_process(false); } - exceptions.erase(exception); } break; case NOTIFICATION_FIXED_PROCESS: { @@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) { + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) { collided=true; against=rr.collider_id; @@ -160,6 +147,41 @@ void RayCast::_notification(int p_what) { } } +void RayCast::add_exception_rid(const RID& p_rid) { + + exclude.insert(p_rid); +} + +void RayCast::add_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to(); + if (!co) + return; + add_exception_rid(co->get_rid()); +} + +void RayCast::remove_exception_rid(const RID& p_rid) { + + exclude.erase(p_rid); +} + +void RayCast::remove_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to(); + if (!co) + return; + remove_exception_rid(co->get_rid()); +} + + +void RayCast::clear_exceptions(){ + + exclude.clear(); +} + + void RayCast::_bind_methods() { @@ -176,6 +198,14 @@ void RayCast::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point); ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal); + ObjectTypeDB::bind_method(_MD("add_exception_rid","rid"),&RayCast::add_exception_rid); + ObjectTypeDB::bind_method(_MD("add_exception","node"),&RayCast::add_exception); + + ObjectTypeDB::bind_method(_MD("remove_exception_rid","rid"),&RayCast::remove_exception_rid); + ObjectTypeDB::bind_method(_MD("remove_exception","node"),&RayCast::remove_exception); + + ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 96606b1628a..0239c61b678 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -45,8 +45,7 @@ class RayCast : public Spatial { Vector3 cast_to; - RID exception; - Set exceptions; + Set exclude; protected: @@ -66,6 +65,12 @@ public: Vector3 get_collision_point() const; Vector3 get_collision_normal() const; + void add_exception_rid(const RID& p_rid); + void add_exception(const Object* p_object); + void remove_exception_rid(const RID& p_rid); + void remove_exception(const Object* p_object); + void clear_exceptions(); + RayCast(); }; diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp index b4a5d3bc1bb..6dc71e06ad4 100644 --- a/scene/3d/spatial_sample_player.cpp +++ b/scene/3d/spatial_sample_player.cpp @@ -103,6 +103,7 @@ void SpatialSamplePlayer::_notification(int p_what) { void SpatialSamplePlayer::set_sample_library(const Ref& p_library) { library=p_library; + _change_notify(); } Ref SpatialSamplePlayer::get_sample_library() const { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 77f2cf5cc1f..35f6523c6af 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -497,7 +497,7 @@ void Sprite3D::set_frame(int p_frame) { frame=p_frame; _queue_update(); - ADD_SIGNAL(MethodInfo("frame_changed")); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index ec72123c983..5172907d185 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -83,7 +83,8 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value) ERR_FAIL_COND_V(nt==NODE_MAX,false); - add_node(nt,id); + if (nt!=NODE_OUTPUT) + add_node(nt,id); node_set_pos(id,pos); diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp index 90994f01b4b..bf1c5e97a35 100644 --- a/scene/audio/sample_player.cpp +++ b/scene/audio/sample_player.cpp @@ -498,6 +498,7 @@ bool SamplePlayer::is_active() const { void SamplePlayer::set_sample_library(const Ref& p_library) { library=p_library; + _change_notify(); } Ref SamplePlayer::get_sample_library() const { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 5a0706f01ef..ce268843b1a 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1126,6 +1126,7 @@ void Control::_window_input_event(InputEvent p_event) { over = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform); } + if (window->drag_data.get_type()==Variant::NIL && over && !window->modal_stack.empty()) { Control *top = window->modal_stack.back()->get(); @@ -2267,6 +2268,7 @@ void Control::_window_sort_subwindows() { return; window->modal_stack.sort_custom(); + window->subwindows.sort_custom(); window->subwindow_order_dirty=false; } @@ -2682,8 +2684,8 @@ bool Control::is_stopping_mouse() const { Control *Control::get_focus_owner() const { ERR_FAIL_COND_V(!is_inside_tree(),NULL); - ERR_FAIL_COND_V(!window,NULL); - return window->key_focus; + ERR_FAIL_COND_V(!data.window,NULL); + return data.window->window->key_focus; } void Control::_bind_methods() { diff --git a/scene/gui/empty_control.cpp b/scene/gui/empty_control.cpp deleted file mode 100644 index 1e377b2b731..00000000000 --- a/scene/gui/empty_control.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* empty_control.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "empty_control.h" - -Size2 EmptyControl::get_minimum_size() const { - - return minsize; -} - -void EmptyControl::set_minsize(const Size2& p_size) { - - minsize=p_size; - minimum_size_changed(); -} - -Size2 EmptyControl::get_minsize() const { - - return minsize; -} - - -void EmptyControl::_bind_methods() { - - - ObjectTypeDB::bind_method(_MD("set_minsize","minsize"),&EmptyControl::set_minsize); - ObjectTypeDB::bind_method(_MD("get_minsize"),&EmptyControl::get_minsize); - - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"minsize"), _SCS("set_minsize"),_SCS("get_minsize") ); -} - -EmptyControl::EmptyControl() -{ -} diff --git a/scene/gui/empty_control.h b/scene/gui/empty_control.h deleted file mode 100644 index 993af45ac48..00000000000 --- a/scene/gui/empty_control.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* empty_control.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef EMPTY_CONTROL_H -#define EMPTY_CONTROL_H - -#include "scene/gui/control.h" - -class EmptyControl : public Control { - - OBJ_TYPE(EmptyControl,Control); - Size2 minsize; -protected: - static void _bind_methods(); -public: - virtual Size2 get_minimum_size() const; - void set_minsize(const Size2& p_size); - Size2 get_minsize() const; - - EmptyControl(); -}; - -#endif // EMPTY_CONTROL_H diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp new file mode 100644 index 00000000000..957e63e3ce1 --- /dev/null +++ b/scene/gui/graph_edit.cpp @@ -0,0 +1,517 @@ +#include "graph_edit.h" + +bool GraphEditFilter::has_point(const Point2& p_point) const { + + return ge->_filter_input(p_point); +} + + +GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) { + + ge=p_edit; +} + + +Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + if (is_node_connected(p_from,p_from_port,p_to,p_to_port)) + return OK; + Connection c; + c.from=p_from; + c.from_port=p_from_port; + c.to=p_to; + c.to_port=p_to_port; + connections.push_back(c); + top_layer->update(); + + return OK; +} + +bool GraphEdit::is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + for(List::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) + return true; + } + + return false; + +} + +void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port){ + + + for(List::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) { + + connections.erase(E); + top_layer->update(); + return; + } + } +} + +void GraphEdit::get_connection_list(List *r_connections) { + + *r_connections=connections; +} + + +void GraphEdit::_scroll_moved(double) { + + + _update_scroll_offset(); + top_layer->update(); +} + +void GraphEdit::_update_scroll_offset() { + + for(int i=0;icast_to(); + if (!gn) + continue; + + Point2 pos=gn->get_offset(); + pos-=Point2(h_scroll->get_val(),v_scroll->get_val()); + gn->set_pos(pos); + } + +} + +void GraphEdit::_update_scroll() { + + if (updating) + return; + + updating=true; + Rect2 screen; + screen.size=get_size(); + for(int i=0;icast_to(); + if (!gn) + continue; + + Rect2 r; + r.pos=gn->get_offset(); + r.size=gn->get_size(); + screen = screen.merge(r); + } + + h_scroll->set_min(screen.pos.x); + h_scroll->set_max(screen.pos.x+screen.size.x); + h_scroll->set_page(get_size().x); + if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page()) + h_scroll->hide(); + else + h_scroll->show(); + + v_scroll->set_min(screen.pos.y); + v_scroll->set_max(screen.pos.y+screen.size.y); + v_scroll->set_page(get_size().y); + + if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page()) + v_scroll->hide(); + else + v_scroll->show(); + + _update_scroll_offset(); + updating=false; +} + + +void GraphEdit::_graph_node_raised(Node* p_gn) { + + GraphNode *gn=p_gn->cast_to(); + ERR_FAIL_COND(!gn); + gn->raise(); + top_layer->raise(); + +} + + +void GraphEdit::_graph_node_moved(Node *p_gn) { + + GraphNode *gn=p_gn->cast_to(); + ERR_FAIL_COND(!gn); + + //gn->set_pos(gn->get_offset()+scroll_offset); + + top_layer->update(); +} + +void GraphEdit::add_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to(); + if (gn) { + gn->connect("offset_changed",this,"_graph_node_moved",varray(gn)); + gn->connect("raise_request",this,"_graph_node_raised",varray(gn)); + _graph_node_moved(gn); + gn->set_stop_mouse(false); + } +} + +void GraphEdit::remove_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to(); + if (gn) { + gn->disconnect("offset_changed",this,"_graph_node_moved"); + gn->disconnect("raise_request",this,"_graph_node_raised"); + } +} + +void GraphEdit::_notification(int p_what) { + + if (p_what==NOTIFICATION_READY) { + Size2 size = top_layer->get_size(); + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + + v_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,vmin.width); + v_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + v_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,0); + v_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + h_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,0); + h_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height); + h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + } + if (p_what==NOTIFICATION_DRAW) { + VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); + + } + + if (p_what==NOTIFICATION_RESIZED) { + _update_scroll(); + top_layer->update(); + } +} + +bool GraphEdit::_filter_input(const Point2& p_point) { + + Ref port =get_icon("port","GraphNode"); + + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + for(int j=0;jget_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point)get_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point) port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + for(int j=0;jget_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(mpos)get_name(); + connecting_index=j; + connecting_out=true; + connecting_type=gn->get_connection_output_type(j); + connecting_color=gn->get_connection_output_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + + for(int j=0;jget_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + + if (pos.distance_to(mpos)get_name(); + connecting_index=j; + connecting_out=false; + connecting_type=gn->get_connection_input_type(j); + connecting_color=gn->get_connection_input_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + } + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && connecting) { + + connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y); + connecting_target=false; + top_layer->update(); + + Ref port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to(); + if (!gn) + continue; + + if (!connecting_out) { + for(int j=0;jget_connection_output_count();j++) { + + 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)get_name(); + connecting_target_index=j; + return; + } + + + } + } else { + + for(int j=0;jget_connection_input_count();j++) { + + 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)get_name(); + connecting_target_index=j; + return; + } + } + } + } + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && !p_ev.mouse_button.pressed) { + + if (connecting && connecting_target) { + + String from = connecting_from; + int from_slot = connecting_index; + String to =connecting_target_to; + int to_slot = connecting_target_index; + + if (!connecting_out) { + SWAP(from,to); + SWAP(from_slot,to_slot); + } + emit_signal("connection_request",from,from_slot,to,to_slot); + + } + connecting=false; + top_layer->update(); + + } + + + +} + +void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) { + + static const int steps = 20; + + Rect2 r; + r.pos=p_from; + r.expand_to(p_to); + Vector2 sign=Vector2((p_from.x < p_to.x) ? 1 : -1,(p_from.y < p_to.y) ? 1 : -1); + bool flip = sign.x * sign.y < 0; + + Vector2 prev; + for(int i=0;i<=steps;i++) { + + float d = i/float(steps); + float c=-Math::cos(d*Math_PI) * 0.5+0.5; + if (flip) + c=1.0-c; + Vector2 p = r.pos+Vector2(d*r.size.width,c*r.size.height); + + if (i>0) { + + top_layer->draw_line(prev,p,p_color,2); + } + + prev=p; + } +} + +void GraphEdit::_top_layer_draw() { + + _update_scroll(); + + if (connecting) { + + Node *fromn = get_node(connecting_from); + ERR_FAIL_COND(!fromn); + GraphNode *from = fromn->cast_to(); + ERR_FAIL_COND(!from); + Vector2 pos; + if (connecting_out) + pos=from->get_connection_output_pos(connecting_index); + else + pos=from->get_connection_input_pos(connecting_index); + pos+=from->get_pos(); + + Vector2 topos; + topos=connecting_to; + + Color col=connecting_color; + + if (connecting_target) { + col.r+=0.4; + col.g+=0.4; + col.b+=0.4; + } + _draw_cos_line(pos,topos,col); + } + + List::Element* > to_erase; + for(List::Element *E=connections.front();E;E=E->next()) { + + NodePath fromnp(E->get().from); + + Node * from = get_node(fromnp); + if (!from) { + to_erase.push_back(E); + continue; + } + + GraphNode *gfrom = from->cast_to(); + + if (!gfrom) { + to_erase.push_back(E); + continue; + } + + NodePath tonp(E->get().to); + Node * to = get_node(tonp); + if (!to) { + to_erase.push_back(E); + continue; + } + + GraphNode *gto = to->cast_to(); + + if (!gto) { + to_erase.push_back(E); + continue; + } + + 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); + + } + + while(to_erase.size()) { + connections.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + //draw connections +} + +void GraphEdit::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) { + h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x ); + v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y ); + } +} + +void GraphEdit::clear_connections() { + + connections.clear(); + update(); +} + + +void GraphEdit::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node); + ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected); + ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node); + ObjectTypeDB::bind_method(_MD("_graph_node_moved"),&GraphEdit::_graph_node_moved); + ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised); + + ObjectTypeDB::bind_method(_MD("_top_layer_input"),&GraphEdit::_top_layer_input); + ObjectTypeDB::bind_method(_MD("_top_layer_draw"),&GraphEdit::_top_layer_draw); + ObjectTypeDB::bind_method(_MD("_scroll_moved"),&GraphEdit::_scroll_moved); + + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event); + + ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); + +} + +GraphEdit::GraphEdit() { + top_layer=NULL; + top_layer=memnew(GraphEditFilter(this)); + add_child(top_layer); + top_layer->set_stop_mouse(false); + top_layer->set_area_as_parent_rect(); + top_layer->connect("draw",this,"_top_layer_draw"); + top_layer->set_stop_mouse(false); + top_layer->connect("input_event",this,"_top_layer_input"); + + h_scroll = memnew(HScrollBar); + h_scroll->set_name("_h_scroll"); + top_layer->add_child(h_scroll); + + v_scroll = memnew(VScrollBar); + v_scroll->set_name("_v_scroll"); + top_layer->add_child(v_scroll); + updating=false; + connecting=false; + + h_scroll->connect("value_changed", this,"_scroll_moved"); + v_scroll->connect("value_changed", this,"_scroll_moved"); +} diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h new file mode 100644 index 00000000000..f8a2f3fee73 --- /dev/null +++ b/scene/gui/graph_edit.h @@ -0,0 +1,93 @@ +#ifndef GRAPH_EDIT_H +#define GRAPH_EDIT_H + +#include "scene/gui/graph_node.h" +#include "scene/gui/scroll_bar.h" + +class GraphEdit; + +class GraphEditFilter : public Control { + + OBJ_TYPE(GraphEditFilter,Control); + +friend class GraphEdit; + GraphEdit *ge; + virtual bool has_point(const Point2& p_point) const; + +public: + + + GraphEditFilter(GraphEdit *p_edit); +}; + +class GraphEdit : public Control { + + OBJ_TYPE(GraphEdit,Control); +public: + + struct Connection { + StringName from; + StringName to; + int from_port; + int to_port; + + }; +private: + + HScrollBar* h_scroll; + VScrollBar* v_scroll; + + + bool connecting; + String connecting_from; + bool connecting_out; + int connecting_index; + int connecting_type; + Color connecting_color; + bool connecting_target; + Vector2 connecting_to; + String connecting_target_to; + int connecting_target_index; + + + + bool updating; + List connections; + + void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color); + + void _graph_node_raised(Node* p_gn); + void _graph_node_moved(Node *p_gn); + + void _update_scroll(); + void _scroll_moved(double); + void _input_event(const InputEvent& p_ev); + + GraphEditFilter *top_layer; + void _top_layer_input(const InputEvent& p_ev); + void _top_layer_draw(); + void _update_scroll_offset(); + +friend class GraphEditFilter; + bool _filter_input(const Point2& p_point); +protected: + + static void _bind_methods(); + virtual void add_child_notify(Node *p_child); + virtual void remove_child_notify(Node *p_child); + void _notification(int p_what); + +public: + + Error connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + bool is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void clear_connections(); + + void get_connection_list(List *r_connections); + + + GraphEdit(); +}; + +#endif // GRAPHEdit_H diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 6e3afeefd01..50ee9abcf82 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -76,7 +76,7 @@ void GraphNode::_get_property_list( List *p_list) const{ int idx=0; for(int i=0;icast_to(); - if (!c || c->is_set_as_toplevel() || !c->get_owner()) + if (!c || c->is_set_as_toplevel() ) continue; String base="slot/"+itos(idx)+"/"; @@ -122,6 +122,7 @@ void GraphNode::_resort() { } + int vofs=0; int w = get_size().x - sb->get_minimum_size().x; @@ -131,7 +132,7 @@ void GraphNode::_resort() { Control *c=get_child(i)->cast_to(); if (!c) continue; - if (c->is_set_as_toplevel() || !c->get_owner()) + if (c->is_set_as_toplevel()) continue; Size2i size=c->get_combined_minimum_size(); @@ -150,6 +151,8 @@ void GraphNode::_resort() { _change_notify(); update(); + connpos_dirty=true; + } @@ -160,14 +163,34 @@ void GraphNode::_notification(int p_what) { Ref sb=get_stylebox("frame"); Ref port =get_icon("port"); + Ref close =get_icon("close"); + int close_offset = get_constant("close_offset"); + Ref title_font = get_font("title_font"); + int title_offset = get_constant("title_offset"); + Color title_color = get_color("title_color"); Point2i icofs = -port->get_size()*0.5; - int edgeofs=3; + int edgeofs=get_constant("port_offset"); icofs.y+=sb->get_margin(MARGIN_TOP); draw_style_box(sb,Rect2(Point2(),get_size())); + int w = get_size().width-sb->get_minimum_size().x; + + if (show_close) + w-=close->get_width(); + + draw_string(title_font,Point2(sb->get_margin(MARGIN_LEFT),-title_font->get_height()+title_font->get_ascent()+title_offset),title,title_color,w); + if (show_close) { + Vector2 cpos = Point2(w+sb->get_margin(MARGIN_LEFT),-close->get_height()+close_offset); + draw_texture(close,cpos); + close_rect.pos=cpos; + close_rect.size=close->get_size(); + } else { + close_rect=Rect2(); + } + for (Map::Element *E=slot_info.front();E;E=E->next()) { - if (E->key()>cache_y.size()) + if (E->key() < 0 || E->key()>=cache_y.size()) continue; if (!slot_info.has(E->key())) continue; @@ -180,6 +203,7 @@ void GraphNode::_notification(int p_what) { } } + if (p_what==NOTIFICATION_SORT_CHILDREN) { _resort(); @@ -187,16 +211,6 @@ void GraphNode::_notification(int p_what) { } -void GraphNode::set_title(const String& p_title) { - - title=p_title; - update(); -} - -String GraphNode::get_title() const { - - return title; -} 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) { @@ -216,17 +230,23 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo s.color_right=p_color_right; slot_info[p_idx]=s; update(); + connpos_dirty=true; + } void GraphNode::clear_slot(int p_idx){ slot_info.erase(p_idx); update(); + connpos_dirty=true; + } void GraphNode::clear_all_slots(){ slot_info.clear(); update(); + connpos_dirty=true; + } bool GraphNode::is_slot_enabled_left(int p_idx) const{ @@ -280,18 +300,26 @@ Color GraphNode::get_slot_color_right(int p_idx) const{ Size2 GraphNode::get_minimum_size() const { + Ref title_font = get_font("title_font"); + int sep=get_constant("separation"); Ref sb=get_stylebox("frame"); bool first=true; Size2 minsize; + minsize.x=title_font->get_string_size(title).x; + if (show_close) { + Ref close =get_icon("close"); + minsize.x+=sep+close->get_width(); + } + for(int i=0;icast_to(); if (!c) continue; - if (c->is_set_as_toplevel() || !c->get_owner()) + if (c->is_set_as_toplevel()) continue; Size2i size=c->get_combined_minimum_size(); @@ -308,13 +336,225 @@ Size2 GraphNode::get_minimum_size() const { return minsize+sb->get_minimum_size(); } +void GraphNode::set_title(const String& p_title) { + + title=p_title; + minimum_size_changed(); + update(); + +} + +String GraphNode::get_title() const{ + + return title; +} + +void GraphNode::set_offset(const Vector2& p_offset) { + + offset=p_offset; + emit_signal("offset_changed"); + update(); +} + +Vector2 GraphNode::get_offset() const { + + return offset; +} + + + +void GraphNode::set_show_close_button(bool p_enable){ + + show_close=p_enable; + update(); +} +bool GraphNode::is_close_button_visible() const{ + + return show_close; +} + +void GraphNode::_connpos_update() { + + + int edgeofs=get_constant("port_offset"); + int sep=get_constant("separation"); + + Ref sb=get_stylebox("frame"); + Ref port =get_icon("port"); + conn_input_cache.clear(); + conn_output_cache.clear(); + int vofs=0; + + int idx=0; + + for(int i=0;icast_to(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + Size2i size=c->get_combined_minimum_size(); + + int y = sb->get_margin(MARGIN_TOP)+vofs; + int h = size.y; + + + if (slot_info.has(idx)) { + + if (slot_info[idx].enable_left) { + ConnCache cc; + cc.pos=Point2i(edgeofs,y+h/2); + cc.type=slot_info[idx].type_left; + cc.color=slot_info[idx].color_left; + conn_input_cache.push_back(cc); + } + if (slot_info[idx].enable_right) { + ConnCache cc; + cc.pos=Point2i(get_size().width-edgeofs,y+h/2); + cc.type=slot_info[idx].type_right; + cc.color=slot_info[idx].color_right; + conn_output_cache.push_back(cc); + } + } + + if (vofs>0) + vofs+=sep; + vofs+=size.y; + idx++; + + } + + + connpos_dirty=false; +} + +int GraphNode::get_connection_input_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_input_cache.size(); + +} +int GraphNode::get_connection_output_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_output_cache.size(); + +} + + +Vector2 GraphNode::get_connection_input_pos(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Vector2()); + return conn_input_cache[p_idx].pos; +} + +int GraphNode::get_connection_input_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),0); + return conn_input_cache[p_idx].type; +} + +Color GraphNode::get_connection_input_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Color()); + return conn_input_cache[p_idx].color; +} + +Vector2 GraphNode::get_connection_output_pos(int p_idx){ + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Vector2()); + return conn_output_cache[p_idx].pos; + +} + +int GraphNode::get_connection_output_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),0); + return conn_output_cache[p_idx].type; +} + +Color GraphNode::get_connection_output_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Color()); + return conn_output_cache[p_idx].color; +} + +void GraphNode::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y); + if (close_rect.size!=Size2() && close_rect.has_point(mpos)) { + emit_signal("close_request"); + return; + } + + drag_from=get_offset(); + drag_accum=Vector2(); + dragging=true; + emit_signal("raise_request"); + + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + dragging=false; + emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) { + + drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y); + set_offset(drag_from+drag_accum); + } + +} + void GraphNode::_bind_methods() { + ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title); + ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title); + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event); + 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); + + 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")); + + ADD_SIGNAL(MethodInfo("offset_changed")); + ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to"))); + ADD_SIGNAL(MethodInfo("raise_request")); + ADD_SIGNAL(MethodInfo("close_request")); } GraphNode::GraphNode() { - + dragging=false; + show_close=false; + connpos_dirty=true; } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 3b89da9f0f2..0d5cbf8dd33 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -8,7 +8,7 @@ class GraphNode : public Container { OBJ_TYPE(GraphNode,Container); - String title; + struct Slot { bool enable_left; int type_left; @@ -21,13 +21,36 @@ class GraphNode : public Container { 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); }; }; + String title; + bool show_close; + Vector2 offset; + + Rect2 close_rect; + Vector cache_y; + struct ConnCache { + Vector2 pos; + int type; + Color color; + }; + + Vector conn_input_cache; + Vector conn_output_cache; + Map slot_info; + bool connpos_dirty; + + void _connpos_update(); void _resort(); + + Vector2 drag_from; + Vector2 drag_accum; + bool dragging; protected: + void _input_event(const InputEvent& p_ev); void _notification(int p_what); static void _bind_methods(); @@ -39,8 +62,6 @@ public: - void set_title(const String& p_title); - String get_title() const; 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 clear_slot(int p_idx); @@ -52,6 +73,25 @@ public: int get_slot_type_right(int p_idx) const; Color get_slot_color_right(int p_idx) const; + void set_title(const String& p_title); + String get_title() const; + + void set_offset(const Vector2& p_offset); + Vector2 get_offset() const; + + void set_show_close_button(bool p_enable); + bool is_close_button_visible() const; + + int get_connection_input_count() ; + int get_connection_output_count() ; + Vector2 get_connection_input_pos(int p_idx); + int get_connection_input_type(int p_idx); + Color get_connection_input_color(int p_idx); + Vector2 get_connection_output_pos(int p_idx); + int get_connection_output_type(int p_idx); + Color get_connection_output_color(int p_idx); + + virtual Size2 get_minimum_size() const; GraphNode(); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 7353744d077..d10ca20fc3f 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -84,6 +84,7 @@ void MenuButton::pressed() { popup->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size())); popup->popup(); popup->call_deferred("grab_click_focus"); + popup->set_invalidate_click_until_motion(); } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 65ad02723cc..bccd05d4fe5 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -51,11 +51,18 @@ void Popup::_fix_size() { Control *window = get_window(); ERR_FAIL_COND(!window); - + +#if 0 Point2 pos = get_pos(); Size2 size = get_size(); Point2 window_size = window==this ? get_parent_area_size() :window->get_size(); +#else + Point2 pos = get_global_pos(); + Size2 size = get_size(); + Point2 window_size = get_viewport_rect().size; + +#endif if (pos.x+size.width > window_size.width) pos.x=window_size.width-size.width; if (pos.x<0) @@ -65,8 +72,14 @@ void Popup::_fix_size() { pos.y=window_size.height-size.height; if (pos.y<0) pos.y=0; +#if 0 if (pos!=get_pos()) set_pos(pos); +#else + if (pos!=get_pos()) + set_global_pos(pos); + +#endif } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 0ba3bdb7c65..1fd1d8adc8c 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -30,6 +30,7 @@ #include "print_string.h" #include "os/keyboard.h" #include "translation.h" +#include "os/input.h" String PopupMenu::_get_accel_text(uint32_t p_accel) const { @@ -318,6 +319,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) { int over=_get_mouse_over(Point2(b.x,b.y)); + if (invalidated_click) { + invalidated_click=false; + break; + } if (over<0 || items[over].separator || items[over].disabled) break; //non-activable @@ -336,6 +341,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) { case InputEvent::MOUSE_MOTION: { + if (invalidated_click) { + moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y); + if (moved.length()>4) + invalidated_click=false; + + } + const InputEventMouseMotion &m=p_event.mouse_motion; for(List::Element *E=autohide_areas.front();E;E=E->next()) { @@ -893,12 +905,17 @@ void PopupMenu::_bind_methods() { } + +void PopupMenu::set_invalidate_click_until_motion() { + moved=Vector2(); + invalidated_click=true; +} + PopupMenu::PopupMenu() { idcount=0; mouse_over=-1; - set_focus_mode(FOCUS_ALL); set_as_toplevel(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index b150be10086..c2e988de954 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -70,6 +70,8 @@ class PopupMenu : public Popup { void _activate_submenu(int over); void _submenu_timeout(); + bool invalidated_click; + Vector2 moved; Array _get_items() const; void _set_items(const Array& p_items); @@ -134,6 +136,8 @@ public: void add_autohide_area(const Rect2& p_area); void clear_autohide_areas(); + void set_invalidate_click_until_motion(); + PopupMenu(); ~PopupMenu(); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 2d6f3cd27ac..12a8a83f262 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -602,6 +602,39 @@ void TabContainer::get_translatable_strings(List *p_strings) const { } +Size2 TabContainer::get_minimum_size() const { + + Size2 ms; + + for(int i=0;icast_to(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + if (!c->has_meta("_tab_name")) + continue; + + if (!c->is_visible()) + continue; + + Size2 cms = c->get_minimum_size(); + ms.x=MAX(ms.x,cms.x); + ms.y=MAX(ms.y,cms.y); + } + + Ref tab_bg = get_stylebox("tab_bg"); + Ref tab_fg = get_stylebox("tab_fg"); + Ref font = get_font("font"); + + ms.y+=MAX(tab_bg->get_minimum_size().y,tab_fg->get_minimum_size().y); + ms.y+=font->get_height(); + + return ms; +} + void TabContainer::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index d5b6a2b503c..df7b03e040a 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -85,6 +85,8 @@ public: void set_current_tab(int p_current); int get_current_tab() const; + virtual Size2 get_minimum_size() const; + virtual void get_translatable_strings(List *p_strings) const; TabContainer(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3f2f95bbd97..50a440e91cf 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -26,7 +26,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ - /*****f********************************************/ +/*****f********************************************/ /* text_edit.cpp */ /*************************************************/ /* This file is part of: */ @@ -47,343 +47,343 @@ #define TAB_PIXELS static bool _is_text_char(CharType c) { - - return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; + + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; } static bool _is_symbol(CharType c) { - - return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); + + return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); } static bool _is_pair_right_symbol(CharType c) { - return - c == '"' || - c == '\'' || - c == ')' || - c == ']' || - c == '}'; + return + c == '"' || + c == '\'' || + c == ')' || + c == ']' || + c == '}'; } static bool _is_pair_left_symbol(CharType c) { - return - c == '"' || - c == '\'' || - c == '(' || - c == '[' || - c == '{'; + return + c == '"' || + c == '\'' || + c == '(' || + c == '[' || + c == '{'; } static bool _is_pair_symbol(CharType c) { - return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); + return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); } static CharType _get_right_pair_symbol(CharType c) { - if(c == '"') - return '"'; - if(c == '\'') - return '\''; - if(c == '(') - return ')'; - if(c == '[') - return ']'; - if(c == '{') - return '}'; - return 0; + if(c == '"') + return '"'; + if(c == '\'') + return '\''; + if(c == '(') + return ')'; + if(c == '[') + return ']'; + if(c == '{') + return '}'; + return 0; } void TextEdit::Text::set_font(const Ref& p_font) { - - font=p_font; + + font=p_font; } void TextEdit::Text::set_tab_size(int p_tab_size) { - - tab_size=p_tab_size; + + tab_size=p_tab_size; } void TextEdit::Text::_update_line_cache(int p_line) const { - - int w =0; - int tab_w=font->get_char_size(' ').width; - - int len = text[p_line].data.length(); - const CharType *str = text[p_line].data.c_str(); - - //update width - - for(int i=0;iget_char_size(str[i],str[i+1]).width; - } - } - - - text[p_line].width_cache=w; - - //update regions - - text[p_line].region_info.clear(); - - for(int i=0;isize();j++) { - - const ColorRegion& cr=color_regions->operator [](j); - - /* BEGIN */ - - int lr=cr.begin_key.length(); - if (lr==0 || lr>left) - continue; - - const CharType* kc = cr.begin_key.c_str(); - - bool match=true; - - for(int k=0;kleft) - continue; - - kc = cr.end_key.c_str(); - - match=true; - - for(int k=0;kget_char_size(' ').width; + + int len = text[p_line].data.length(); + const CharType *str = text[p_line].data.c_str(); + + //update width + + for(int i=0;iget_char_size(str[i],str[i+1]).width; + } + } + + + text[p_line].width_cache=w; + + //update regions + + text[p_line].region_info.clear(); + + for(int i=0;isize();j++) { + + const ColorRegion& cr=color_regions->operator [](j); + + /* BEGIN */ + + int lr=cr.begin_key.length(); + if (lr==0 || lr>left) + continue; + + const CharType* kc = cr.begin_key.c_str(); + + bool match=true; + + for(int k=0;kleft) + continue; + + kc = cr.end_key.c_str(); + + match=true; + + for(int k=0;k& TextEdit::Text::get_color_region_info(int p_line) { - - Map *cri=NULL; - ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash - - if (text[p_line].width_cache==-1) { - _update_line_cache(p_line); - } - - return text[p_line].region_info; + + Map *cri=NULL; + ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash + + if (text[p_line].width_cache==-1) { + _update_line_cache(p_line); + } + + return text[p_line].region_info; } int TextEdit::Text::get_line_width(int p_line) const { - - ERR_FAIL_INDEX_V(p_line,text.size(),-1); - - if (text[p_line].width_cache==-1) { - _update_line_cache(p_line); - } - - return text[p_line].width_cache; + + ERR_FAIL_INDEX_V(p_line,text.size(),-1); + + if (text[p_line].width_cache==-1) { + _update_line_cache(p_line); + } + + return text[p_line].width_cache; } void TextEdit::Text::clear_caches() { - - for(int i=0;iget_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); - - - - v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) ); - v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM)) ); - - h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); - h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); - - - int hscroll_rows = ((hmin.height-1)/get_row_height())+1; - int visible_rows = get_visible_rows(); - int total_rows = text.size() * cache.line_spacing; - - int vscroll_pixels = v_scroll->get_combined_minimum_size().width; - int visible_width = size.width - cache.style_normal->get_minimum_size().width; - int total_width = text.get_max_width(); - - bool use_hscroll=true; - bool use_vscroll=true; - - if (total_rows <= visible_rows && total_width <= visible_width) { - //thanks yessopie for this clever bit of logic - use_hscroll=false; - use_vscroll=false; - - } else { - - if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) { - //thanks yessopie for this clever bit of logic - use_hscroll=false; - } - - if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) { - //thanks yessopie for this clever bit of logic - use_vscroll=false; - } - } - - updating_scrolls=true; - - if (use_vscroll) { - - v_scroll->show(); - v_scroll->set_max(total_rows); - v_scroll->set_page(visible_rows); - - v_scroll->set_val(cursor.line_ofs); - - } else { - cursor.line_ofs = 0; - v_scroll->hide(); - } - - if (use_hscroll) { - - h_scroll->show(); - h_scroll->set_max(total_width); - h_scroll->set_page(visible_width); - h_scroll->set_val(cursor.x_ofs); - } else { - - h_scroll->hide(); - } - - - - updating_scrolls=false; + + + Size2 size = get_size(); + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + + + + v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) ); + v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM)) ); + + h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); + h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); + + + int hscroll_rows = ((hmin.height-1)/get_row_height())+1; + int visible_rows = get_visible_rows(); + int total_rows = text.size() * cache.line_spacing; + + int vscroll_pixels = v_scroll->get_combined_minimum_size().width; + int visible_width = size.width - cache.style_normal->get_minimum_size().width; + int total_width = text.get_max_width(); + + bool use_hscroll=true; + bool use_vscroll=true; + + if (total_rows <= visible_rows && total_width <= visible_width) { + //thanks yessopie for this clever bit of logic + use_hscroll=false; + use_vscroll=false; + + } else { + + if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) { + //thanks yessopie for this clever bit of logic + use_hscroll=false; + } + + if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) { + //thanks yessopie for this clever bit of logic + use_vscroll=false; + } + } + + updating_scrolls=true; + + if (use_vscroll) { + + v_scroll->show(); + v_scroll->set_max(total_rows); + v_scroll->set_page(visible_rows); + + v_scroll->set_val(cursor.line_ofs); + + } else { + cursor.line_ofs = 0; + v_scroll->hide(); + } + + if (use_hscroll) { + + h_scroll->show(); + h_scroll->set_max(total_width); + h_scroll->set_page(visible_width); + h_scroll->set_val(cursor.x_ofs); + } else { + + h_scroll->hide(); + } + + + + updating_scrolls=false; } void TextEdit::_notification(int p_what) { - + switch(p_what) { case NOTIFICATION_ENTER_TREE: { - + _update_caches(); if (cursor_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); if (text_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); - + } break; case NOTIFICATION_RESIZED: { - + cache.size=get_size(); adjust_viewport_to_cursor(); - - + + } break; case NOTIFICATION_THEME_CHANGED: { - + _update_caches(); }; case NOTIFICATION_DRAW: { - + int line_number_char_count=0; - + { int lc=text.size()+1; cache.line_number_w=0; @@ -391,20 +391,20 @@ void TextEdit::_notification(int p_what) { cache.line_number_w+=1; lc/=10; }; - + if (line_numbers) { - + line_number_char_count=cache.line_number_w; cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width; } else { cache.line_number_w=0; } - - + + } _update_scrollbars(); - - + + RID ci = get_canvas_item(); int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w; int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT); @@ -412,56 +412,56 @@ void TextEdit::_notification(int p_what) { cache.style_normal->draw(ci,Rect2(Point2(),cache.size)); if (has_focus()) cache.style_focus->draw(ci,Rect2(Point2(),cache.size)); - - + + int ascent=cache.font->get_ascent(); - + int visible_rows = get_visible_rows(); - + int tab_w = cache.font->get_char_size(' ').width*tab_size; - + Color color = cache.font_color; int in_region=-1; - + if (syntax_coloring) { - + if (custom_bg_color.a>0.01) { - + Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0; VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color); } //compute actual region to start (may be inside say, a comment). //slow in very large documments :( but ok for source! - + for(int i=0;i& cri_map=text.get_color_region_info(i); - + if (in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + for( const Map::Element* E= cri_map.front();E;E=E->next() ) { - + const Text::ColorRegionInfo &cri=E->get(); - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + in_region=-1; } } } } } - + int brace_open_match_line=-1; int brace_open_match_column=-1; bool brace_open_matching=false; @@ -470,15 +470,15 @@ void TextEdit::_notification(int p_what) { int brace_close_match_column=-1; bool brace_close_matching=false; bool brace_close_mismatch=false; - - + + if (brace_matching_enabled) { - + if (cursor.column0) { CharType c = text[cursor.line][cursor.column-1]; CharType closec=0; - - - + + + if (c==']') { closec='['; } else if (c=='}') { @@ -535,65 +535,65 @@ void TextEdit::_notification(int p_what) { } else if (c==')') { closec='('; } - + if (closec!=0) { - + int stack=1; - - + + for(int i=cursor.line;i>=0;i--) { - + int from = i==cursor.line?cursor.column-2:text[i].length()-1; for(int j=from;j>=0;j--) { - + CharType cc = text[i][j]; if (cc==c) stack++; else if (cc==closec) stack--; - + if (stack==0) { brace_close_match_line=i; brace_close_match_column=j; brace_close_matching=true; - + break; } } if (brace_close_match_line!=-1) break; } - + if (!brace_close_matching) brace_close_mismatch=true; - - + + } - - + + } } - - + + int deregion=0; //force it to clear inrgion Point2 cursor_pos; - + for (int i=0;i=(int)text.size()) continue; - + const String &str=text[line]; - + int char_margin=xmargin_beg-cursor.x_ofs; int char_ofs=0; int ofs_y=i*get_row_height()+cache.line_spacing/2; bool prev_is_char=false; bool in_keyword=false; Color keyword_color; - + if (cache.line_number_w) { Color fcol = cache.font_color; fcol.a*=0.4; @@ -601,191 +601,191 @@ void TextEdit::_notification(int p_what) { while (fc.length() < line_number_char_count) { fc="0"+fc; } - + cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol); } - + const Map& cri_map=text.get_color_region_info(line); - - + + if (text.is_marked(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color); } - + if (text.is_breakpoint(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color); } - - + + if (line==cursor.line) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color); - + } for (int j=0;j0) { deregion--; if (deregion==0) in_region=-1; } if (syntax_coloring && deregion==0) { - - + + color = cache.font_color; //reset //find keyword bool is_char = _is_text_char(str[j]); bool is_symbol=_is_symbol(str[j]); - + if (j==0 && in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + if (is_symbol && cri_map.has(j)) { - - + + const Text::ColorRegionInfo &cri=cri_map[j]; - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length(); } } } - + if (!is_char) in_keyword=false; - + if (in_region==-1 && !in_keyword && is_char && !prev_is_char) { - + int to=j; while(_is_text_char(str[to]) && to=0) color=color_regions[in_region].color; else if (in_keyword) color=keyword_color; else if (is_symbol) color=symbol_color; - + prev_is_char=is_char; - + } int char_w; - + //handle tabulator - - + + if (str[j]=='\t') { int left = char_ofs%tab_w; if (left==0) char_w=tab_w; else char_w=tab_w-char_ofs%tab_w; // is right... - + } else { char_w=cache.font->get_char_size(str[j],str[j+1]).width; } - + if ( (char_ofs+char_margin)=xmargin_end) { if (syntax_coloring) continue; else break; } - + bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (linecanvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } - - + + if (brace_matching_enabled) { if ( (brace_open_match_line==line && brace_open_match_column==j) || - (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) { - + (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) { + if (brace_open_mismatch) color=cache.brace_mismatch_color; cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); - + } - + if ( - (brace_close_match_line==line && brace_close_match_column==j) || - (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) { - - + (brace_close_match_line==line && brace_close_match_column==j) || + (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) { + + if (brace_close_mismatch) color=cache.brace_mismatch_color; cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); - + } } - - + + if (str[j]>=32) cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color); - + else if (draw_tabs && str[j]=='\t') { int yofs= (get_row_height() - cache.tab_icon->get_height())/2; cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color); } - - + + if (cursor.column==j && cursor.line==line) { - + cursor_pos = Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - - + + } char_ofs+=char_w; - + } - + if (cursor.column==str.length() && cursor.line==line) { - + cursor_pos=Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - + } } - - + + if (completion_active) { // code completion box Ref csb = get_stylebox("completion"); @@ -796,15 +796,15 @@ void TextEdit::_notification(int p_what) { existing.a=0.2; int scrollw = get_constant("completion_scroll_width"); Color scrollc = get_color("completion_scroll_color"); - - - + + + int lines = MIN(completion_options.size(),maxlines); int w=0; int h=lines*get_row_height(); int nofs = cache.font->get_string_size(completion_base).width; - - + + if (completion_options.size() < 50) { for(int i=0;iget_string_size(completion_options[i]).x,cmax_width); @@ -814,39 +814,39 @@ void TextEdit::_notification(int p_what) { } else { w=cmax_width; } - + int th = h + csb->get_minimum_size().y; if (cursor_pos.y+get_row_height()+th > get_size().height) { completion_rect.pos.y=cursor_pos.y-th; } else { completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y; - + } - + if (cursor_pos.x-nofs+w+scrollw > get_size().width) { completion_rect.pos.x=get_size().width-w-scrollw; } else { completion_rect.pos.x=cursor_pos.x-nofs; } - - completion_rect.size.width=w; + + completion_rect.size.width=w+2; completion_rect.size.height=h; if (completion_options.size()<=maxlines) scrollw=0; - + draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0))); - - + + int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines); draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height()))); - + draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing); - - - - + + + + for(int i=0;i= completion_options.size()); Color text_color = cache.font_color; @@ -857,31 +857,31 @@ void TextEdit::_notification(int p_what) { } draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],text_color,completion_rect.size.width); } - + if (scrollw) { //draw a small scroll rectangle to show a position in the options float r = maxlines / (float)completion_options.size(); float o = line_from / (float)completion_options.size(); draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc); } - + completion_line_ofs=line_from; - + } - + if (completion_hint!="") { - + Ref sb = get_stylebox("panel","TooltipPanel"); Ref font = cache.font; Color font_color = get_color("font_color","TooltipLabel"); - - + + int max_w=0; int sc = completion_hint.get_slice_count("\n"); int offset=0; int spacing=0; for(int i=0;iget_string_size(l).x; max_w = MAX(len,max_w); @@ -890,35 +890,35 @@ void TextEdit::_notification(int p_what) { } else { spacing+=cache.line_spacing; } - - + + } - - - + + + Size2 size = Size2(max_w,sc*font->get_height()+spacing); Size2 minsize = size+sb->get_minimum_size(); - - + + if (completion_hint_offset==-0xFFFF) { completion_hint_offset=cursor_pos.x-offset; } - - + + Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y); draw_style_box(sb,Rect2(hint_ofs,minsize)); - + spacing=0; for(int i=0;iget_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x; end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x; } - + draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color); if (end>0) { Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1); @@ -927,1477 +927,1527 @@ void TextEdit::_notification(int p_what) { spacing+=cache.line_spacing; } } - - + + } break; case NOTIFICATION_FOCUS_ENTER: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect()); - + } break; case NOTIFICATION_FOCUS_EXIT: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->hide_virtual_keyboard(); - + } break; - + } } void TextEdit::_consume_pair_symbol(CharType ch) { - - int cursor_position_to_move = cursor_get_column() + 1; - - CharType ch_single[2] = {ch, 0}; - CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; - CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; - - if(is_selection_active()) { - - int new_column,new_line; - - _begin_compex_operation(); - _insert_text(get_selection_from_line(), get_selection_from_column(), - ch_single, - &new_line, &new_column); - - int to_col_offset = 0; - if(get_selection_from_line() == get_selection_to_line()) - to_col_offset = 1; - - _insert_text(get_selection_to_line(), - get_selection_to_column() + to_col_offset, - ch_single_pair, - &new_line,&new_column); - _end_compex_operation(); - - cursor_set_line(get_selection_to_line()); - cursor_set_column(get_selection_to_column() + to_col_offset); - - deselect(); - update(); - return; - } - - if( (ch == '\'' || ch == '"') && - cursor_get_column() > 0 && - _is_text_char(text[cursor.line][cursor_get_column() - 1]) - ) { - insert_text_at_cursor(ch_single); - cursor_set_column(cursor_position_to_move); - return; - } - - if(cursor_get_column() < text[cursor.line].length()) { - if(_is_text_char(text[cursor.line][cursor_get_column()])) { - insert_text_at_cursor(ch_single); - cursor_set_column(cursor_position_to_move); - return; - } - if( _is_pair_right_symbol(ch) && - text[cursor.line][cursor_get_column()] == ch - ) { - cursor_set_column(cursor_position_to_move); - return; - } - } - - - insert_text_at_cursor(ch_pair); - cursor_set_column(cursor_position_to_move); - return; - + + int cursor_position_to_move = cursor_get_column() + 1; + + CharType ch_single[2] = {ch, 0}; + CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; + CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; + + if(is_selection_active()) { + + int new_column,new_line; + + _begin_compex_operation(); + _insert_text(get_selection_from_line(), get_selection_from_column(), + ch_single, + &new_line, &new_column); + + int to_col_offset = 0; + if(get_selection_from_line() == get_selection_to_line()) + to_col_offset = 1; + + _insert_text(get_selection_to_line(), + get_selection_to_column() + to_col_offset, + ch_single_pair, + &new_line,&new_column); + _end_compex_operation(); + + cursor_set_line(get_selection_to_line()); + cursor_set_column(get_selection_to_column() + to_col_offset); + + deselect(); + update(); + return; + } + + if( (ch == '\'' || ch == '"') && + cursor_get_column() > 0 && + _is_text_char(text[cursor.line][cursor_get_column() - 1]) + ) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + + if(cursor_get_column() < text[cursor.line].length()) { + if(_is_text_char(text[cursor.line][cursor_get_column()])) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + if( _is_pair_right_symbol(ch) && + text[cursor.line][cursor_get_column()] == ch + ) { + cursor_set_column(cursor_position_to_move); + return; + } + } + + + insert_text_at_cursor(ch_pair); + cursor_set_column(cursor_position_to_move); + return; + } void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column) { - - bool remove_right_symbol = false; - - if(cursor.column < text[cursor.line].length() && cursor.column > 0) { - - CharType left_char = text[cursor.line][cursor.column - 1]; - CharType right_char = text[cursor.line][cursor.column]; - - if(right_char == _get_right_pair_symbol(left_char)) { - remove_right_symbol = true; - } - - } - if(remove_right_symbol) { - _remove_text(prev_line,prev_column,cursor.line,cursor.column + 1); - } else { - _remove_text(prev_line,prev_column,cursor.line,cursor.column); - } - + + bool remove_right_symbol = false; + + if(cursor.column < text[cursor.line].length() && cursor.column > 0) { + + CharType left_char = text[cursor.line][cursor.column - 1]; + CharType right_char = text[cursor.line][cursor.column]; + + if(right_char == _get_right_pair_symbol(left_char)) { + remove_right_symbol = true; + } + + } + if(remove_right_symbol) { + _remove_text(prev_line,prev_column,cursor.line,cursor.column + 1); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + } void TextEdit::backspace_at_cursor() { + if (readonly) + return; - if (cursor.column==0 && cursor.line==0) - return; - - int prev_line = cursor.column?cursor.line:cursor.line-1; - int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); - if(auto_brace_completion_enabled && - cursor.column > 0 && - _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { - _consume_backspace_for_pair_symbol(prev_line, prev_column); - } else { - _remove_text(prev_line,prev_column,cursor.line,cursor.column); - } - - cursor_set_line(prev_line); - cursor_set_column(prev_column); - + if (cursor.column==0 && cursor.line==0) + return; + + int prev_line = cursor.column?cursor.line:cursor.line-1; + int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); + if(auto_brace_completion_enabled && + cursor.column > 0 && + _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { + _consume_backspace_for_pair_symbol(prev_line, prev_column); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + + cursor_set_line(prev_line); + cursor_set_column(prev_column); + } bool TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const { - - int row=p_mouse.y; - row-=cache.style_normal->get_margin(MARGIN_TOP); - row/=get_row_height(); - - if (row<0 || row>=get_visible_rows()) - return false; - - row+=cursor.line_ofs; - int col=0; - - if (row>=text.size()) { - - row=text.size()-1; - col=text[row].size(); - } else { - - col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); - col+=cursor.x_ofs; - col=get_char_pos_for( col, get_line(row) ); - } - - r_row=row; - r_col=col; - return true; + + int row=p_mouse.y; + row-=cache.style_normal->get_margin(MARGIN_TOP); + row/=get_row_height(); + + if (row<0 || row>=get_visible_rows()) + return false; + + row+=cursor.line_ofs; + int col=0; + + if (row>=text.size()) { + + row=text.size()-1; + col=text[row].size(); + } else { + + col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); + col+=cursor.x_ofs; + col=get_char_pos_for( col, get_line(row) ); + } + + r_row=row; + r_col=col; + return true; } void TextEdit::_input_event(const InputEvent& p_input_event) { - - switch(p_input_event.type) { - - case InputEvent::MOUSE_BUTTON: { - - const InputEventMouseButton &mb=p_input_event.mouse_button; - - if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) { - - if (!mb.pressed) - return; - - if (mb.button_index==BUTTON_WHEEL_UP) { - if (completion_index>0) { - completion_index--; - completion_current=completion_options[completion_index]; - update(); - } - - } - if (mb.button_index==BUTTON_WHEEL_DOWN) { - - if (completion_indexset_val( v_scroll->get_val() -3 ); - } - if (mb.button_index==BUTTON_WHEEL_DOWN) { - v_scroll->set_val( v_scroll->get_val() +3 ); - } - if (mb.button_index==BUTTON_LEFT) { - - int row,col; - if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col)) - return; - - int prev_col=cursor.column; - int prev_line=cursor.line; - - - - cursor_set_line( row ); - cursor_set_column( col ); - - if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { - - selection.active=true; - selection.selecting_mode=Selection::MODE_POINTER; - selection.from_column=prev_col; - selection.from_line=prev_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - if (selection.from_column>selection.to_column) { - SWAP(selection.from_column,selection.to_column); - SWAP(selection.from_line,selection.to_line); - } - selection.selecting_line=prev_line; - selection.selecting_column=prev_col; - update(); - - } else { - - //if sel active and dblick last time < something - - //else - selection.active=false; - selection.selecting_mode=Selection::MODE_POINTER; - selection.selecting_line=row; - selection.selecting_column=col; - } - - - if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) { - //tripleclick select line - select(cursor.line,0,cursor.line,text[cursor.line].length()); - last_dblclk=0; - - } else if (mb.doubleclick && text[cursor.line].length()) { - - //doubleclick select world - String s = text[cursor.line]; - int beg=CLAMP(cursor.column,0,s.length()); - int end=beg; - - if (s[beg]>32 || beg==s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { - beg--; - } - while(end32 && (symbol==_is_symbol(s[end+1]))) { - end++; - } - - if (endget_ticks_msec(); - - } - - update(); - } - } else { - - selection.selecting_mode=Selection::MODE_NONE; - // notify to show soft keyboard - notification(NOTIFICATION_FOCUS_ENTER); - } - - } break; - case InputEvent::MOUSE_MOTION: { - - const InputEventMouseMotion &mm=p_input_event.mouse_motion; - - if (mm.button_mask&BUTTON_MASK_LEFT) { - - int row,col; - if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col)) - return; - - if (selection.selecting_mode==Selection::MODE_POINTER) { - - select(selection.selecting_line,selection.selecting_column,row,col); - - cursor_set_line( row ); - cursor_set_column( col ); - update(); - - } - - } - - } break; - - case InputEvent::KEY: { - - InputEventKey k=p_input_event.key; - - if (!k.pressed) - return; - - if (completion_active) { - - bool valid=true; - if (k.mod.command || k.mod.alt || k.mod.meta) - valid=false; - - if (valid) { - - if (k.scancode==KEY_UP) { - - if (completion_index>0) { - completion_index--; - completion_current=completion_options[completion_index]; - update(); - } - accept_event(); - return; - } - - - if (k.scancode==KEY_DOWN) { - - if (completion_index=completion_options.size()) - completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_HOME) { - - completion_index=0; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_END) { - - completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - - if (k.scancode==KEY_DOWN) { - - if (completion_index32) { - - if (cursor.column0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { - txt.remove(i); - //i--; - } - } - } else { - - for(int i=0;i0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { - txt=txt.insert(i,"\t"); - //i--; - } - } - } - - if (txt!=prev_txt) { - - int sel_line=selection.from_line; - int sel_column=selection.from_column; - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - _begin_compex_operation(); - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - _insert_text_at_cursor(txt); - _end_compex_operation(); - selection.active=true; - selection.from_column=sel_column; - selection.from_line=sel_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - update(); - } - - dobreak=true; - accept_event(); - - } break; - case KEY_X: - case KEY_C: - //special keys often used with control, wait... - clear=(!k.mod.command || k.mod.shift || k.mod.alt ); - break; - case KEY_DELETE: - case KEY_BACKSPACE: - accept_event(); - clear=true; dobreak=true; - break; - case KEY_LEFT: - case KEY_RIGHT: - case KEY_UP: - case KEY_DOWN: - case KEY_PAGEUP: - case KEY_PAGEDOWN: - case KEY_HOME: - case KEY_END: - // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) - if (k.mod.command || k.mod.shift || k.mod.alt || k.mod.command) - break; - unselect=true; - break; - - default: - if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) - clear=true; - if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) - clear=false; - } - - if (unselect) { - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - } - if (clear) { - - selection.active=false; - update(); - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - update(); - } - if (dobreak) - break; - } - - selection.selecting_test=false; - - bool scancode_handled=true; - - // special scancode test... - - switch (k.scancode) { - - case KEY_ENTER: - case KEY_RETURN: { - - String ins="\n"; - - //keep indentation - for(int i=0;i0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') { - //simple unindent - - backspace_at_cursor(); - } - } else { - //simple indent - _insert_text_at_cursor("\t"); - } - } - - } break; - case KEY_BACKSPACE: { - if (readonly) - break; - backspace_at_cursor(); - - } break; - case KEY_LEFT: { - - if (k.mod.shift) - _pre_shift_selection(); - -#ifdef APPLE_STYLE_KEYS - if (k.mod.command) { - cursor_set_column(0); - } else if (k.mod.alt) { - -#else - if (k.mod.alt) { - scancode_handled=false; - break; - } else if (k.mod.command) { -#endif - bool prev_char=false; - int cc=cursor.column; - while (cc>0) { - - bool ischar=_is_text_char(text[cursor.line][cc-1]); - - if (prev_char && !ischar) - break; - - prev_char=ischar; - cc--; - - } - - cursor_set_column(cc); - - } else if (cursor.column==0) { - - if (cursor.line>0) { - cursor_set_line(cursor.line-1); - cursor_set_column(text[cursor.line].length()); - } - } else { - cursor_set_column(cursor_get_column()-1); - } - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_RIGHT: { - - if (k.mod.shift) - _pre_shift_selection(); - -#ifdef APPLE_STYLE_KEYS - if (k.mod.command) { - cursor_set_column(text[cursor.line].length()); - } else if (k.mod.alt) { -#else - if (k.mod.alt) { - scancode_handled=false; - break; - } else if (k.mod.command) { -#endif - bool prev_char=false; - int cc=cursor.column; - while (ccset_clipboard(clipboard); - cursor_set_line(cursor.line); - cursor_set_column(0); - _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); - - backspace_at_cursor(); - update(); - cursor_set_line(cursor.line+1); - cut_copy_line = true; - - } - else - { - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - cut_copy_line = false; - } - - } break; - case KEY_C: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - if (!selection.active){ - String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = true; - } - else{ - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = false; - } - } break; - case KEY_Z: { - - if (!k.mod.command) { - scancode_handled=false; - break; - } - - if (k.mod.shift) - redo(); - else - undo(); - } break; - case KEY_V: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - String clipboard = OS::get_singleton()->get_clipboard(); - - if (selection.active) { - selection.active=false; - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - } - else if (cut_copy_line) - { - cursor_set_column(0); - String ins="\n"; - clipboard += ins; - } - - _insert_text_at_cursor(clipboard); - - update(); - } break; - case KEY_SPACE: { - if (completion_enabled && k.mod.command) { - - query_code_comple(); - scancode_handled=true; - } else { - scancode_handled=false; - } - - } break; - - case KEY_U:{ - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - else { - if (selection.active) { - int ini = selection.from_line; - int end = selection.to_line; - for (int i=ini; i<= end; i++) - { - if (text[i][0] == '#') - _remove_text(i,0,i,1); - } - } - else{ - if (text[cursor.line][0] == '#') - _remove_text(cursor.line,0,cursor.line,1); - } - update(); - } - break;} - - default: { - - scancode_handled=false; + + switch(p_input_event.type) { + + case InputEvent::MOUSE_BUTTON: { + + const InputEventMouseButton &mb=p_input_event.mouse_button; + + if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) { + + if (!mb.pressed) + return; + + if (mb.button_index==BUTTON_WHEEL_UP) { + if (completion_index>0) { + completion_index--; + completion_current=completion_options[completion_index]; + update(); + } + + } + if (mb.button_index==BUTTON_WHEEL_DOWN) { + + if (completion_indexset_val( v_scroll->get_val() -3 ); + } + if (mb.button_index==BUTTON_WHEEL_DOWN) { + v_scroll->set_val( v_scroll->get_val() +3 ); + } + if (mb.button_index==BUTTON_LEFT) { + + int row,col; + if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col)) + return; + + int prev_col=cursor.column; + int prev_line=cursor.line; + + + + cursor_set_line( row ); + cursor_set_column( col ); + + if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { + + if (!selection.active) { + selection.active=true; + selection.selecting_mode=Selection::MODE_POINTER; + selection.from_column=prev_col; + selection.from_line=prev_line; + selection.to_column=cursor.column; + selection.to_line=cursor.line; + + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + selection.shiftclick_left=false; + } else { + selection.shiftclick_left=true; + } + selection.selecting_line=prev_line; + selection.selecting_column=prev_col; + update(); + } else { + + if (cursor.lineselection.to_line || (cursor.line==selection.to_line && cursor.column>=selection.to_column)) { + selection.to_column=cursor.column; + selection.to_line=cursor.line; + + } else if (!selection.shiftclick_left) { + + selection.from_column=cursor.column; + selection.from_line=cursor.line; + } else { + + selection.to_column=cursor.column; + selection.to_line=cursor.line; + } + + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + } + update(); + } + + + + + + + + } else { + + //if sel active and dblick last time < something + + //else + selection.active=false; + selection.selecting_mode=Selection::MODE_POINTER; + selection.selecting_line=row; + selection.selecting_column=col; + } + + + if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) { + //tripleclick select line + select(cursor.line,0,cursor.line,text[cursor.line].length()); + last_dblclk=0; + + } else if (mb.doubleclick && text[cursor.line].length()) { + + //doubleclick select world + String s = text[cursor.line]; + int beg=CLAMP(cursor.column,0,s.length()); + int end=beg; + + if (s[beg]>32 || beg==s.length()) { + + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { + beg--; + } + while(end32 && (symbol==_is_symbol(s[end+1]))) { + end++; + } + + if (endget_ticks_msec(); + + } + + update(); + } + } else { + + selection.selecting_mode=Selection::MODE_NONE; + // notify to show soft keyboard + notification(NOTIFICATION_FOCUS_ENTER); + } + } break; + case InputEvent::MOUSE_MOTION: { + + const InputEventMouseMotion &mm=p_input_event.mouse_motion; + + if (mm.button_mask&BUTTON_MASK_LEFT) { + + int row,col; + if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col)) + return; + + if (selection.selecting_mode==Selection::MODE_POINTER) { + + select(selection.selecting_line,selection.selecting_column,row,col); + + cursor_set_line( row ); + cursor_set_column( col ); + update(); + + } + + } + + } break; + + case InputEvent::KEY: { + + InputEventKey k=p_input_event.key; + + if (!k.pressed) + return; + + if (completion_active) { + if (readonly) + break; - } + bool valid=true; + if (k.mod.command || k.mod.alt || k.mod.meta) + valid=false; + + if (valid) { + + if (k.scancode==KEY_UP) { + + if (completion_index>0) { + completion_index--; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + + + if (k.scancode==KEY_DOWN) { + + if (completion_index=completion_options.size()) + completion_index=completion_options.size()-1; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + if (k.scancode==KEY_HOME) { + + completion_index=0; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + if (k.scancode==KEY_END) { + + completion_index=completion_options.size()-1; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + + if (k.scancode==KEY_DOWN) { + + if (completion_index32) { + + if (cursor.column=32) { + bool clear=false; + bool unselect=false; + bool dobreak=false; + + switch(k.scancode) { + + case KEY_TAB: { + + String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + String prev_txt=txt; + + if (k.mod.shift) { + + for(int i=0;i0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { + txt.remove(i); + //i--; + } + } + } else { + + for(int i=0;i0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { + txt=txt.insert(i,"\t"); + //i--; + } + } + } + + if (txt!=prev_txt) { + + int sel_line=selection.from_line; + int sel_column=selection.from_column; + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + _begin_compex_operation(); + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + _insert_text_at_cursor(txt); + _end_compex_operation(); + selection.active=true; + selection.from_column=sel_column; + selection.from_line=sel_line; + selection.to_column=cursor.column; + selection.to_line=cursor.line; + update(); + } + + dobreak=true; + accept_event(); + + } break; + case KEY_X: + case KEY_C: + //special keys often used with control, wait... + clear=(!k.mod.command || k.mod.shift || k.mod.alt ); + break; + case KEY_DELETE: + case KEY_BACKSPACE: + accept_event(); + clear=true; dobreak=true; + break; + case KEY_LEFT: + case KEY_RIGHT: + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + case KEY_HOME: + case KEY_END: + // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) + if (k.mod.command || k.mod.shift || k.mod.alt || k.mod.command) + break; + unselect=true; + break; + + default: + if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) + clear=true; + if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) + clear=false; + } + + if (unselect) { + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + } + if (clear) { + + selection.active=false; + update(); + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + update(); + } + if (dobreak) + break; + } + + selection.selecting_test=false; + + bool scancode_handled=true; + + // special scancode test... + + switch (k.scancode) { + + case KEY_ENTER: + case KEY_RETURN: { - if (readonly) - break; + if (readonly) + break; - accept_event(); - } else { - - break; - } - } + String ins="\n"; + + //keep indentation + for(int i=0;i0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') { + //simple unindent + + backspace_at_cursor(); + } + } else { + //simple indent + _insert_text_at_cursor("\t"); + } + } + + } break; + case KEY_BACKSPACE: { + if (readonly) + break; + backspace_at_cursor(); + + } break; + case KEY_LEFT: { + + if (k.mod.shift) + _pre_shift_selection(); + +#ifdef APPLE_STYLE_KEYS + if (k.mod.command) { + cursor_set_column(0); + } else if (k.mod.alt) { + +#else + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { +#endif + bool prev_char=false; + int cc=cursor.column; + while (cc>0) { + + bool ischar=_is_text_char(text[cursor.line][cc-1]); + + if (prev_char && !ischar) + break; + + prev_char=ischar; + cc--; + + } + + cursor_set_column(cc); + + } else if (cursor.column==0) { + + if (cursor.line>0) { + cursor_set_line(cursor.line-1); + cursor_set_column(text[cursor.line].length()); + } + } else { + cursor_set_column(cursor_get_column()-1); + } + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_RIGHT: { + + if (k.mod.shift) + _pre_shift_selection(); + +#ifdef APPLE_STYLE_KEYS + if (k.mod.command) { + cursor_set_column(text[cursor.line].length()); + } else if (k.mod.alt) { +#else + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { +#endif + bool prev_char=false; + int cc=cursor.column; + while (ccset_clipboard(clipboard); + cursor_set_line(cursor.line); + cursor_set_column(0); + _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); + + backspace_at_cursor(); + update(); + cursor_set_line(cursor.line+1); + cut_copy_line = true; + + } + else + { + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + cut_copy_line = false; + } + + } break; + case KEY_C: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + if (!selection.active){ + String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = true; + } + else{ + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = false; + } + } break; + case KEY_Z: { + + if (!k.mod.command) { + scancode_handled=false; + break; + } + + if (k.mod.shift) + redo(); + else + undo(); + } break; + case KEY_V: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + String clipboard = OS::get_singleton()->get_clipboard(); + + if (selection.active) { + selection.active=false; + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + } + else if (cut_copy_line) + { + cursor_set_column(0); + String ins="\n"; + clipboard += ins; + } + + _insert_text_at_cursor(clipboard); + + update(); + } break; + case KEY_SPACE: { +#ifdef OSX_ENABLED + if (completion_enabled && k.mod.meta) { //cmd-space is spotlight shortcut in OSX +#else + if (completion_enabled && k.mod.command) { +#endif + + query_code_comple(); + scancode_handled=true; + } else { + scancode_handled=false; + } + + } break; + + case KEY_U:{ + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + else { + if (selection.active) { + int ini = selection.from_line; + int end = selection.to_line; + for (int i=ini; i<= end; i++) + { + if (text[i][0] == '#') + _remove_text(i,0,i,1); + } + } + else{ + if (text[cursor.line][0] == '#') + _remove_text(cursor.line,0,cursor.line,1); + } + update(); + } + break;} + + default: { + + scancode_handled=false; + } break; + + } + + if (scancode_handled) + accept_event(); + /* + if (!scancode_handled && !k.mod.command && !k.mod.alt) { + + if (k.unicode>=32) { + + if (readonly) + break; + + accept_event(); + } else { + + break; + } + } */ - if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds - - if (k.unicode>=32) { - - if (readonly) - break; - - const CharType chr[2] = {k.unicode, 0}; - - if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { - _consume_pair_symbol(chr[0]); - } else { - _insert_text_at_cursor(chr); - } - - accept_event(); - } else { - - break; - } - } - - - if (!selection.selecting_test) { - - selection.selecting_mode=Selection::MODE_NONE; - } - - return; - } break; - - } - + if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds + + if (k.unicode>=32) { + + if (readonly) + break; + + const CharType chr[2] = {k.unicode, 0}; + + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } + + accept_event(); + } else { + + break; + } + } + + + if (!selection.selecting_test) { + + selection.selecting_mode=Selection::MODE_NONE; + } + + return; + } break; + + } + } void TextEdit::_pre_shift_selection() { - - - if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) { - - selection.selecting_line=cursor.line; - selection.selecting_column=cursor.column; - selection.active=true; - selection.selecting_mode=Selection::MODE_SHIFT; - } + + + if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) { + + selection.selecting_line=cursor.line; + selection.selecting_column=cursor.column; + selection.active=true; + selection.selecting_mode=Selection::MODE_SHIFT; + } } void TextEdit::_post_shift_selection() { - - - if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) { - - select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column); - update(); - } - - - selection.selecting_test=true; + + + if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) { + + select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column); + update(); + } + + + selection.selecting_test=true; } /**** TEXT EDIT CORE API ****/ void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) { - - //save for undo... - ERR_FAIL_INDEX(p_line,text.size()); - ERR_FAIL_COND(p_char<0); - - /* STEP 1 add spaces if the char is greater than the end of the line */ - while(p_char>text[p_line].length()) { - - text.set(p_line,text[p_line]+String::chr(' ')); - } - - /* STEP 2 separate dest string in pre and post text */ - - String preinsert_text = text[p_line].substr(0,p_char); - String postinsert_text = text[p_line].substr(p_char,text[p_line].size()); - - /* STEP 3 remove \r from source text and separate in substrings */ - - //buh bye \r and split - Vector substrings = p_text.replace("\r","").split("\n"); - - - for(int i=0;ipush_call(this,"_text_changed_emit"); - text_changed_dirty=true; - } - + + //save for undo... + ERR_FAIL_INDEX(p_line,text.size()); + ERR_FAIL_COND(p_char<0); + + /* STEP 1 add spaces if the char is greater than the end of the line */ + while(p_char>text[p_line].length()) { + + text.set(p_line,text[p_line]+String::chr(' ')); + } + + /* STEP 2 separate dest string in pre and post text */ + + String preinsert_text = text[p_line].substr(0,p_char); + String postinsert_text = text[p_line].substr(p_char,text[p_line].size()); + + /* STEP 3 remove \r from source text and separate in substrings */ + + //buh bye \r and split + Vector substrings = p_text.replace("\r","").split("\n"); + + + for(int i=0;ipush_call(this,"_text_changed_emit"); + text_changed_dirty=true; + } + } String TextEdit::_base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const { - - ERR_FAIL_INDEX_V(p_from_line,text.size(),String()); - ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String()); - ERR_FAIL_INDEX_V(p_to_line,text.size(),String()); - ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String()); - ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to - ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column to - - String ret; - - for(int i=p_from_line;i<=p_to_line;i++) { - - int begin = (i==p_from_line)?p_from_column:0; - int end = (i==p_to_line)?p_to_column:text[i].length(); - - if (i>p_from_line) - ret+="\n"; - ret+=text[i].substr(begin,end-begin); - } - - return ret; + + ERR_FAIL_INDEX_V(p_from_line,text.size(),String()); + ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String()); + ERR_FAIL_INDEX_V(p_to_line,text.size(),String()); + ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String()); + ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to + ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column to + + String ret; + + for(int i=p_from_line;i<=p_to_line;i++) { + + int begin = (i==p_from_line)?p_from_column:0; + int end = (i==p_to_line)?p_to_column:text[i].length(); + + if (i>p_from_line) + ret+="\n"; + ret+=text[i].substr(begin,end-begin); + } + + return ret; } void TextEdit::_base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - - ERR_FAIL_INDEX(p_from_line,text.size()); - ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1); - ERR_FAIL_INDEX(p_to_line,text.size()); - ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1); - ERR_FAIL_COND(p_to_line < p_from_line ); // from > to - ERR_FAIL_COND(p_to_line == p_from_line && p_to_column to - - - String pre_text = text[p_from_line].substr(0,p_from_column); - String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length()); - - for(int i=p_from_line;ipush_call(this,"_text_changed_emit"); - text_changed_dirty=true; - } + + ERR_FAIL_INDEX(p_from_line,text.size()); + ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1); + ERR_FAIL_INDEX(p_to_line,text.size()); + ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1); + ERR_FAIL_COND(p_to_line < p_from_line ); // from > to + ERR_FAIL_COND(p_to_line == p_from_line && p_to_column to + + + String pre_text = text[p_from_line].substr(0,p_from_column); + String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length()); + + for(int i=p_from_line;ipush_call(this,"_text_changed_emit"); + text_changed_dirty=true; + } } void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_end_line,int *r_end_column) { - - if (!setting_text) - idle_detect->start(); - - if (undo_enabled) { - _clear_redo(); - } - - int retline,retchar; - _base_insert_text(p_line,p_char,p_text,retline,retchar); - if (r_end_line) - *r_end_line=retline; - if (r_end_column) - *r_end_column=retchar; - - if (!undo_enabled) - return; - - /* UNDO!! */ - TextOperation op; - op.type=TextOperation::TYPE_INSERT; - op.from_line=p_line; - op.from_column=p_char; - op.to_line=retline; - op.to_column=retchar; - op.text=p_text; - op.version=++version; - op.chain_forward=false; - op.chain_backward=false; - - //see if it shold just be set as current op - if (current_op.type!=op.type) { - _push_current_op(); - current_op=op; - - return; //set as current op, return - } - //see if it can be merged - if (current_op.to_line!=p_line || current_op.to_column!=p_char) { - _push_current_op(); - current_op=op; - return; //set as current op, return - } - //merge current op - - current_op.text+=p_text; - current_op.to_column=retchar; - current_op.to_line=retline; - current_op.version=op.version; - + + if (!setting_text) + idle_detect->start(); + + if (undo_enabled) { + _clear_redo(); + } + + int retline,retchar; + _base_insert_text(p_line,p_char,p_text,retline,retchar); + if (r_end_line) + *r_end_line=retline; + if (r_end_column) + *r_end_column=retchar; + + if (!undo_enabled) + return; + + /* UNDO!! */ + TextOperation op; + op.type=TextOperation::TYPE_INSERT; + op.from_line=p_line; + op.from_column=p_char; + op.to_line=retline; + op.to_column=retchar; + op.text=p_text; + op.version=++version; + op.chain_forward=false; + op.chain_backward=false; + + //see if it shold just be set as current op + if (current_op.type!=op.type) { + _push_current_op(); + current_op=op; + + return; //set as current op, return + } + //see if it can be merged + if (current_op.to_line!=p_line || current_op.to_column!=p_char) { + _push_current_op(); + current_op=op; + return; //set as current op, return + } + //merge current op + + current_op.text+=p_text; + current_op.to_column=retchar; + current_op.to_line=retline; + current_op.version=op.version; + } void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - - if (!setting_text) - idle_detect->start(); - - String text; - if (undo_enabled) { - _clear_redo(); - text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column); - } - - _base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column); - - if (!undo_enabled) - return; - - /* UNDO!! */ - TextOperation op; - op.type=TextOperation::TYPE_REMOVE; - op.from_line=p_from_line; - op.from_column=p_from_column; - op.to_line=p_to_line; - op.to_column=p_to_column; - op.text=text; - op.version=++version; - op.chain_forward=false; - op.chain_backward=false; - - //see if it shold just be set as current op - if (current_op.type!=op.type) { - _push_current_op(); - current_op=op; - return; //set as current op, return - } - //see if it can be merged - if (current_op.from_line==p_to_line && current_op.from_column==p_to_column) { - //basckace or similar - current_op.text=text+current_op.text; - current_op.from_line=p_from_line; - current_op.from_column=p_from_column; - return; //update current op - } - if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) { - - //current_op.text=text+current_op.text; - //current_op.from_line=p_from_line; - //current_op.from_column=p_from_column; - //return; //update current op - } - - _push_current_op(); - current_op=op; - + + if (!setting_text) + idle_detect->start(); + + String text; + if (undo_enabled) { + _clear_redo(); + text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column); + } + + _base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column); + + if (!undo_enabled) + return; + + /* UNDO!! */ + TextOperation op; + op.type=TextOperation::TYPE_REMOVE; + op.from_line=p_from_line; + op.from_column=p_from_column; + op.to_line=p_to_line; + op.to_column=p_to_column; + op.text=text; + op.version=++version; + op.chain_forward=false; + op.chain_backward=false; + + //see if it shold just be set as current op + if (current_op.type!=op.type) { + _push_current_op(); + current_op=op; + return; //set as current op, return + } + //see if it can be merged + if (current_op.from_line==p_to_line && current_op.from_column==p_to_column) { + //basckace or similar + current_op.text=text+current_op.text; + current_op.from_line=p_from_line; + current_op.from_column=p_from_column; + return; //update current op + } + if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) { + + //current_op.text=text+current_op.text; + //current_op.from_line=p_from_line; + //current_op.from_column=p_from_column; + //return; //update current op + } + + _push_current_op(); + current_op=op; + } void TextEdit::_insert_text_at_cursor(const String& p_text) { - - int new_column,new_line; - _insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column); - cursor_set_line(new_line); - cursor_set_column(new_column); - - update(); + + int new_column,new_line; + _insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column); + cursor_set_line(new_line); + cursor_set_column(new_column); + + update(); } int TextEdit::get_char_count() { - - int totalsize=0; - - for (int i=0;i0) - totalsize++; // incliude \n - totalsize+=text[i].length(); - } - - return totalsize; // omit last \n + + int totalsize=0; + + for (int i=0;i0) + totalsize++; // incliude \n + totalsize+=text[i].length(); + } + + return totalsize; // omit last \n } Size2 TextEdit::get_minimum_size() { - - return cache.style_normal->get_minimum_size(); + + return cache.style_normal->get_minimum_size(); } int TextEdit::get_visible_rows() const { - - int total=cache.size.height; - total-=cache.style_normal->get_minimum_size().height; - total/=get_row_height(); - return total; + + int total=cache.size.height; + total-=cache.style_normal->get_minimum_size().height; + total/=get_row_height(); + return total; } void TextEdit::adjust_viewport_to_cursor() { - - if (cursor.line_ofs>cursor.line) - cursor.line_ofs=cursor.line; - - int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w; - if (v_scroll->is_visible()) - visible_width-=v_scroll->get_combined_minimum_size().width; - visible_width-=20; // give it a little more space - - - //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); - - int visible_rows = get_visible_rows(); - if (h_scroll->is_visible()) - visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height()); - - if (cursor.line>=(cursor.line_ofs+visible_rows)) - cursor.line_ofs=cursor.line-visible_rows+1; - if (cursor.line(cursor.x_ofs+visible_width)) - cursor.x_ofs=cursor_x-visible_width+1; - - if (cursor_x < cursor.x_ofs) - cursor.x_ofs=cursor_x; - - update(); -/* + + if (cursor.line_ofs>cursor.line) + cursor.line_ofs=cursor.line; + + int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w; + if (v_scroll->is_visible()) + visible_width-=v_scroll->get_combined_minimum_size().width; + visible_width-=20; // give it a little more space + + + //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); + + int visible_rows = get_visible_rows(); + if (h_scroll->is_visible()) + visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height()); + + if (cursor.line>=(cursor.line_ofs+visible_rows)) + cursor.line_ofs=cursor.line-visible_rows+1; + if (cursor.line(cursor.x_ofs+visible_width)) + cursor.x_ofs=cursor_x-visible_width+1; + + if (cursor_x < cursor.x_ofs) + cursor.x_ofs=cursor_x; + + update(); + /* get_range()->set_max(text.size()); - + get_range()->set_page(get_visible_rows()); - + get_range()->set((int)cursor.line_ofs); */ - - + + } void TextEdit::cursor_set_column(int p_col) { - - if (p_col<0) - p_col=0; - - cursor.column=p_col; - if (cursor.column > get_line( cursor.line ).length()) - cursor.column=get_line( cursor.line ).length(); - - cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line)); - - adjust_viewport_to_cursor(); - - if (!cursor_changed_dirty) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); - cursor_changed_dirty=true; - } - + + if (p_col<0) + p_col=0; + + cursor.column=p_col; + if (cursor.column > get_line( cursor.line ).length()) + cursor.column=get_line( cursor.line ).length(); + + cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line)); + + adjust_viewport_to_cursor(); + + if (!cursor_changed_dirty) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); + cursor_changed_dirty=true; + } + } void TextEdit::cursor_set_line(int p_row) { - - if (setting_row) - return; - - setting_row=true; - if (p_row<0) - p_row=0; - - - if (p_row>=(int)text.size()) - p_row=(int)text.size()-1; - - cursor.line=p_row; - cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) ); - - - adjust_viewport_to_cursor(); - - setting_row=false; - - - if (!cursor_changed_dirty) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); - cursor_changed_dirty=true; - } - + + if (setting_row) + return; + + setting_row=true; + if (p_row<0) + p_row=0; + + + if (p_row>=(int)text.size()) + p_row=(int)text.size()-1; + + cursor.line=p_row; + cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) ); + + + adjust_viewport_to_cursor(); + + setting_row=false; + + + if (!cursor_changed_dirty) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); + cursor_changed_dirty=true; + } + } int TextEdit::cursor_get_column() const { - - return cursor.column; + + return cursor.column; } int TextEdit::cursor_get_line() const { - - return cursor.line; + + return cursor.line; } void TextEdit::_scroll_moved(double p_to_val) { - - if (updating_scrolls) - return; - - if (h_scroll->is_visible()) - cursor.x_ofs=h_scroll->get_val(); - if (v_scroll->is_visible()) - cursor.line_ofs=v_scroll->get_val(); - update(); + + if (updating_scrolls) + return; + + if (h_scroll->is_visible()) + cursor.x_ofs=h_scroll->get_val(); + if (v_scroll->is_visible()) + cursor.line_ofs=v_scroll->get_val(); + update(); } @@ -2405,798 +2455,798 @@ void TextEdit::_scroll_moved(double p_to_val) { int TextEdit::get_row_height() const { - - return cache.font->get_height()+cache.line_spacing; + + return cache.font->get_height()+cache.line_spacing; } int TextEdit::get_char_pos_for(int p_px,String p_str) const { - - int px=0; - int c=0; - - int tab_w = cache.font->get_char_size(' ').width*tab_size; - - while (cget_char_size(p_str[c],p_str[c+1]).width; - } - - if (p_px<(px+w/2)) - break; - px+=w; - c++; - } - - return c; + + int px=0; + int c=0; + + int tab_w = cache.font->get_char_size(' ').width*tab_size; + + while (cget_char_size(p_str[c],p_str[c+1]).width; + } + + if (p_px<(px+w/2)) + break; + px+=w; + c++; + } + + return c; } int TextEdit::get_column_x_offset(int p_char,String p_str) { - - int px=0; - - int tab_w = cache.font->get_char_size(' ').width*tab_size; - - for (int i=0;i=p_str.length()) - break; - - if (p_str[i]=='\t') { - - int left = px%tab_w; - if (left==0) - px+=tab_w; - else - px+=tab_w-px%tab_w; // is right... - - } else { - px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width; - } - } - - return px; - + + int px=0; + + int tab_w = cache.font->get_char_size(' ').width*tab_size; + + for (int i=0;i=p_str.length()) + break; + + if (p_str[i]=='\t') { + + int left = px%tab_w; + if (left==0) + px+=tab_w; + else + px+=tab_w-px%tab_w; // is right... + + } else { + px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width; + } + } + + return px; + } void TextEdit::insert_text_at_cursor(const String& p_text) { - - if (selection.active) { - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - - } - - _insert_text_at_cursor(p_text); - update(); - + + if (selection.active) { + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + + } + + _insert_text_at_cursor(p_text); + update(); + } Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { - if(completion_active && completion_rect.has_point(p_pos)) { - return CURSOR_ARROW; - } - return CURSOR_IBEAM; + if(completion_active && completion_rect.has_point(p_pos)) { + return CURSOR_ARROW; + } + return CURSOR_IBEAM; } void TextEdit::set_text(String p_text){ - - setting_text=true; - _clear(); - _insert_text_at_cursor(p_text); - - cursor.column=0; - cursor.line=0; - cursor.x_ofs=0; - cursor.line_ofs=0; - cursor.last_fit_x=0; - cursor_set_line(0); - cursor_set_column(0); - update(); - setting_text=false; - - //get_range()->set(0); + + setting_text=true; + _clear(); + _insert_text_at_cursor(p_text); + + cursor.column=0; + cursor.line=0; + cursor.x_ofs=0; + cursor.line_ofs=0; + cursor.last_fit_x=0; + cursor_set_line(0); + cursor_set_column(0); + update(); + setting_text=false; + + //get_range()->set(0); }; String TextEdit::get_text() { - String longthing; - int len = text.size(); - for (int i=0;i=text.size()) - return ""; - - return text[line]; - + + if (line<0 || line>=text.size()) + return ""; + + return text[line]; + }; void TextEdit::_clear() { - - clear_undo_history(); - text.clear(); - cursor.column=0; - cursor.line=0; - cursor.x_ofs=0; - cursor.line_ofs=0; - cursor.last_fit_x=0; + + clear_undo_history(); + text.clear(); + cursor.column=0; + cursor.line=0; + cursor.x_ofs=0; + cursor.line_ofs=0; + cursor.last_fit_x=0; } void TextEdit::clear() { - - setting_text=true; - _clear(); - setting_text=false; - + + setting_text=true; + _clear(); + setting_text=false; + }; void TextEdit::set_readonly(bool p_readonly) { - - - readonly=p_readonly; + + + readonly=p_readonly; } void TextEdit::set_wrap(bool p_wrap) { - - wrap=p_wrap; + + wrap=p_wrap; } void TextEdit::set_max_chars(int p_max_chars) { - - max_chars=p_max_chars; + + max_chars=p_max_chars; } void TextEdit::_update_caches() { - - cache.style_normal=get_stylebox("normal"); - cache.style_focus=get_stylebox("focus"); - cache.font=get_font("font"); - cache.font_color=get_color("font_color"); - cache.font_selected_color=get_color("font_selected_color"); - cache.keyword_color=get_color("keyword_color"); - cache.selection_color=get_color("selection_color"); - cache.mark_color=get_color("mark_color"); - cache.current_line_color=get_color("current_line_color"); - cache.breakpoint_color=get_color("breakpoint_color"); - cache.brace_mismatch_color=get_color("brace_mismatch_color"); - cache.line_spacing=get_constant("line_spacing"); - cache.row_height = cache.font->get_height() + cache.line_spacing; - cache.tab_icon=get_icon("tab"); - text.set_font(cache.font); - + + cache.style_normal=get_stylebox("normal"); + cache.style_focus=get_stylebox("focus"); + cache.font=get_font("font"); + cache.font_color=get_color("font_color"); + cache.font_selected_color=get_color("font_selected_color"); + cache.keyword_color=get_color("keyword_color"); + cache.selection_color=get_color("selection_color"); + cache.mark_color=get_color("mark_color"); + cache.current_line_color=get_color("current_line_color"); + cache.breakpoint_color=get_color("breakpoint_color"); + cache.brace_mismatch_color=get_color("brace_mismatch_color"); + cache.line_spacing=get_constant("line_spacing"); + cache.row_height = cache.font->get_height() + cache.line_spacing; + cache.tab_icon=get_icon("tab"); + text.set_font(cache.font); + } void TextEdit::clear_colors() { - - keywords.clear(); - color_regions.clear();; - text.clear_caches(); - custom_bg_color=Color(0,0,0,0); + + keywords.clear(); + color_regions.clear();; + text.clear_caches(); + custom_bg_color=Color(0,0,0,0); } void TextEdit::set_custom_bg_color(const Color& p_color) { - - custom_bg_color=p_color; - update(); + + custom_bg_color=p_color; + update(); } void TextEdit::add_keyword_color(const String& p_keyword,const Color& p_color) { - - keywords[p_keyword]=p_color; - update(); - + + keywords[p_keyword]=p_color; + update(); + } void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_key,const Color &p_color,bool p_line_only) { - - color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only)); - text.clear_caches(); - update(); - + + color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only)); + text.clear_caches(); + update(); + } void TextEdit::set_symbol_color(const Color& p_color) { - - symbol_color=p_color; - update(); + + symbol_color=p_color; + update(); } void TextEdit::set_syntax_coloring(bool p_enabled) { - - syntax_coloring=p_enabled; - update(); + + syntax_coloring=p_enabled; + update(); } bool TextEdit::is_syntax_coloring_enabled() const { - - return syntax_coloring; + + return syntax_coloring; } void TextEdit::cut() { - - if (!selection.active) - return; - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - + + if (!selection.active) + return; + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + } void TextEdit::copy() { - - if (!selection.active) - return; - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - + + if (!selection.active) + return; + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + } void TextEdit::paste() { - - if (selection.active) { - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - - } - - String clipboard = OS::get_singleton()->get_clipboard(); - _insert_text_at_cursor(clipboard); - update(); - + + if (selection.active) { + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + + } + + String clipboard = OS::get_singleton()->get_clipboard(); + _insert_text_at_cursor(clipboard); + update(); + } void TextEdit::select_all() { - - if (text.size()==1 && text[0].length()==0) - return; - selection.active=true; - selection.from_line=0; - selection.from_column=0; - selection.to_line=text.size()-1; - selection.to_column=text[selection.to_line].size(); - selection.selecting_mode=Selection::MODE_NONE; - update(); - + + if (text.size()==1 && text[0].length()==0) + return; + selection.active=true; + selection.from_line=0; + selection.from_column=0; + selection.to_line=text.size()-1; + selection.to_column=text[selection.to_line].size(); + selection.selecting_mode=Selection::MODE_NONE; + update(); + } void TextEdit::deselect() { - - selection.active=false; - update(); + + selection.active=false; + update(); } void TextEdit::select(int p_from_line,int p_from_column,int p_to_line,int p_to_column) { - - if (p_from_line>=text.size()) - p_from_line=text.size()-1; - if (p_from_column>=text[p_from_line].length()) - p_from_column=text[p_from_line].length(); - - if (p_to_line>=text.size()) - p_to_line=text.size()-1; - if (p_to_column>=text[p_to_line].length()) - p_to_column=text[p_to_line].length(); - - selection.from_line=p_from_line; - selection.from_column=p_from_column; - selection.to_line=p_to_line; - selection.to_column=p_to_column; - - selection.active=true; - - if (selection.from_line==selection.to_line) { - - if (selection.from_column==selection.to_column) { - - selection.active=false; - - } else if (selection.from_column>selection.to_column) { - - SWAP( selection.from_column, selection.to_column ); - } - } else if (selection.from_line>selection.to_line) { - - SWAP( selection.from_line, selection.to_line ); - SWAP( selection.from_column, selection.to_column ); - } - - - update(); + + if (p_from_line>=text.size()) + p_from_line=text.size()-1; + if (p_from_column>=text[p_from_line].length()) + p_from_column=text[p_from_line].length(); + + if (p_to_line>=text.size()) + p_to_line=text.size()-1; + if (p_to_column>=text[p_to_line].length()) + p_to_column=text[p_to_line].length(); + + selection.from_line=p_from_line; + selection.from_column=p_from_column; + selection.to_line=p_to_line; + selection.to_column=p_to_column; + + selection.active=true; + + if (selection.from_line==selection.to_line) { + + if (selection.from_column==selection.to_column) { + + selection.active=false; + + } else if (selection.from_column>selection.to_column) { + + SWAP( selection.from_column, selection.to_column ); + } + } else if (selection.from_line>selection.to_line) { + + SWAP( selection.from_line, selection.to_line ); + SWAP( selection.from_column, selection.to_column ); + } + + + update(); } bool TextEdit::is_selection_active() const { - - return selection.active; + + return selection.active; } int TextEdit::get_selection_from_line() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.from_line; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.from_line; + } int TextEdit::get_selection_from_column() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.from_column; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.from_column; + } int TextEdit::get_selection_to_line() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.to_line; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.to_line; + } int TextEdit::get_selection_to_column() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.to_column; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.to_column; + } String TextEdit::get_selection_text() const { - - if (!selection.active) - return ""; - - return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - + + if (!selection.active) + return ""; + + return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + } String TextEdit::get_word_under_cursor() const { - - int prev_cc = cursor.column; - while(prev_cc >0) { - bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); - if (!is_char) - break; - --prev_cc; - } - - int next_cc = cursor.column; - while(next_cc0) { + bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); + if (!is_char) + break; + --prev_cc; + } + + int next_cc = cursor.column; + while(next_cc TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const { - - int col,line; - if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) { - DVector result; - result.resize(2); - result.set(0,line); - result.set(1,col); - return result; - - } else { - - return DVector(); - } + + int col,line; + if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) { + DVector result; + result.resize(2); + result.set(0,line); + result.set(1,col); + return result; + + } else { + + return DVector(); + } } bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_line, int p_from_column,int &r_line,int &r_column) const { - - if (p_key.length()==0) - return false; - ERR_FAIL_INDEX_V(p_from_line,text.size(),false); - ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false); - - //search through the whole documment, but start by current line - - int line=-1; - int pos=-1; - - line=p_from_line; - - for(int i=0;i0 && _is_text_char(text_line[pos-1])) - pos=-1; - else if (_is_text_char(text_line[pos+p_key.length()])) - pos=-1; - } - - if (pos!=-1) - break; - - if (p_search_flags&SEARCH_BACKWARDS) - line--; - else - line++; - - } - - if (pos==-1) { - r_line=-1; - r_column=-1; - return false; - } - - r_line=line; - r_column=pos; - - - return true; + + if (p_key.length()==0) + return false; + ERR_FAIL_INDEX_V(p_from_line,text.size(),false); + ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false); + + //search through the whole documment, but start by current line + + int line=-1; + int pos=-1; + + line=p_from_line; + + for(int i=0;i0 && _is_text_char(text_line[pos-1])) + pos=-1; + else if (_is_text_char(text_line[pos+p_key.length()])) + pos=-1; + } + + if (pos!=-1) + break; + + if (p_search_flags&SEARCH_BACKWARDS) + line--; + else + line++; + + } + + if (pos==-1) { + r_line=-1; + r_column=-1; + return false; + } + + r_line=line; + r_column=pos; + + + return true; } void TextEdit::_cursor_changed_emit() { - - emit_signal("cursor_changed"); - cursor_changed_dirty=false; + + emit_signal("cursor_changed"); + cursor_changed_dirty=false; } void TextEdit::_text_changed_emit() { - - emit_signal("text_changed"); - text_changed_dirty=false; + + emit_signal("text_changed"); + text_changed_dirty=false; } void TextEdit::set_line_as_marked(int p_line,bool p_marked) { - - ERR_FAIL_INDEX(p_line,text.size()); - text.set_marked(p_line,p_marked); - update(); + + ERR_FAIL_INDEX(p_line,text.size()); + text.set_marked(p_line,p_marked); + update(); } bool TextEdit::is_line_set_as_breakpoint(int p_line) const { - - ERR_FAIL_INDEX_V(p_line,text.size(),false); - return text.is_breakpoint(p_line); - + + ERR_FAIL_INDEX_V(p_line,text.size(),false); + return text.is_breakpoint(p_line); + } void TextEdit::set_line_as_breakpoint(int p_line,bool p_breakpoint) { - - - ERR_FAIL_INDEX(p_line,text.size()); - text.set_breakpoint(p_line,p_breakpoint); - update(); + + + ERR_FAIL_INDEX(p_line,text.size()); + text.set_breakpoint(p_line,p_breakpoint); + update(); } void TextEdit::get_breakpoints(List *p_breakpoints) const { - - for(int i=0;ipush_back(i); - } + + for(int i=0;ipush_back(i); + } } int TextEdit::get_line_count() const { - - return text.size(); + + return text.size(); } void TextEdit::_do_text_op(const TextOperation& p_op, bool p_reverse) { - - ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE); - - bool insert = p_op.type==TextOperation::TYPE_INSERT; - if (p_reverse) - insert=!insert; - - if (insert) { - - int check_line; - int check_column; - _base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column); - ERR_FAIL_COND( check_line != p_op.to_line ); // BUG - ERR_FAIL_COND( check_column != p_op.to_column ); // BUG - } else { - - _base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column); - } - + + ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE); + + bool insert = p_op.type==TextOperation::TYPE_INSERT; + if (p_reverse) + insert=!insert; + + if (insert) { + + int check_line; + int check_column; + _base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column); + ERR_FAIL_COND( check_line != p_op.to_line ); // BUG + ERR_FAIL_COND( check_column != p_op.to_column ); // BUG + } else { + + _base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column); + } + } void TextEdit::_clear_redo() { - - if (undo_stack_pos==NULL) - return; //nothing to clear - - _push_current_op(); - - while (undo_stack_pos) { - List::Element *elem = undo_stack_pos; - undo_stack_pos=undo_stack_pos->next(); - undo_stack.erase(elem); - } + + if (undo_stack_pos==NULL) + return; //nothing to clear + + _push_current_op(); + + while (undo_stack_pos) { + List::Element *elem = undo_stack_pos; + undo_stack_pos=undo_stack_pos->next(); + undo_stack.erase(elem); + } } void TextEdit::undo() { - - _push_current_op(); - - if (undo_stack_pos==NULL) { - - if (!undo_stack.size()) - return; //nothing to undo - - undo_stack_pos=undo_stack.back(); - - } else if (undo_stack_pos==undo_stack.front()) - return; // at the bottom of the undo stack - else - undo_stack_pos=undo_stack_pos->prev(); - - _do_text_op( undo_stack_pos->get(),true); - if(undo_stack_pos->get().chain_backward) { - do { - undo_stack_pos = undo_stack_pos->prev(); - _do_text_op(undo_stack_pos->get(), true); - } while(!undo_stack_pos->get().chain_forward); - } - - cursor_set_line(undo_stack_pos->get().from_line); - cursor_set_column(undo_stack_pos->get().from_column); - update(); + + _push_current_op(); + + if (undo_stack_pos==NULL) { + + if (!undo_stack.size()) + return; //nothing to undo + + undo_stack_pos=undo_stack.back(); + + } else if (undo_stack_pos==undo_stack.front()) + return; // at the bottom of the undo stack + else + undo_stack_pos=undo_stack_pos->prev(); + + _do_text_op( undo_stack_pos->get(),true); + if(undo_stack_pos->get().chain_backward) { + do { + undo_stack_pos = undo_stack_pos->prev(); + _do_text_op(undo_stack_pos->get(), true); + } while(!undo_stack_pos->get().chain_forward); + } + + cursor_set_line(undo_stack_pos->get().from_line); + cursor_set_column(undo_stack_pos->get().from_column); + update(); } void TextEdit::redo() { - - _push_current_op(); - - if (undo_stack_pos==NULL) - return; //nothing to do. - - _do_text_op(undo_stack_pos->get(), false); - if(undo_stack_pos->get().chain_forward) { - do { - undo_stack_pos=undo_stack_pos->next(); - _do_text_op(undo_stack_pos->get(), false); - } while(!undo_stack_pos->get().chain_backward); - } - cursor_set_line(undo_stack_pos->get().from_line); - cursor_set_column(undo_stack_pos->get().from_column); - undo_stack_pos=undo_stack_pos->next(); - update(); + + _push_current_op(); + + if (undo_stack_pos==NULL) + return; //nothing to do. + + _do_text_op(undo_stack_pos->get(), false); + if(undo_stack_pos->get().chain_forward) { + do { + undo_stack_pos=undo_stack_pos->next(); + _do_text_op(undo_stack_pos->get(), false); + } while(!undo_stack_pos->get().chain_backward); + } + cursor_set_line(undo_stack_pos->get().from_line); + cursor_set_column(undo_stack_pos->get().from_column); + undo_stack_pos=undo_stack_pos->next(); + update(); } void TextEdit::clear_undo_history() { - - saved_version=0; - current_op.type=TextOperation::TYPE_NONE; - undo_stack_pos=NULL; - undo_stack.clear(); - + + saved_version=0; + current_op.type=TextOperation::TYPE_NONE; + undo_stack_pos=NULL; + undo_stack.clear(); + } void TextEdit::_begin_compex_operation() { - _push_current_op(); - next_operation_is_complex=true; + _push_current_op(); + next_operation_is_complex=true; } void TextEdit::_end_compex_operation() { - - _push_current_op(); - ERR_FAIL_COND(undo_stack.size() == 0); - - if(undo_stack.back()->get().chain_forward) { - undo_stack.back()->get().chain_forward=false; - return; - } - - undo_stack.back()->get().chain_backward=true; + + _push_current_op(); + ERR_FAIL_COND(undo_stack.size() == 0); + + if(undo_stack.back()->get().chain_forward) { + undo_stack.back()->get().chain_forward=false; + return; + } + + undo_stack.back()->get().chain_backward=true; } void TextEdit::_push_current_op() { - - if (current_op.type==TextOperation::TYPE_NONE) - return; // do nothing - - if(next_operation_is_complex) { - current_op.chain_forward=true; - next_operation_is_complex=false; - } - - undo_stack.push_back(current_op); - current_op.type=TextOperation::TYPE_NONE; - current_op.text=""; - current_op.chain_forward=false; - + + if (current_op.type==TextOperation::TYPE_NONE) + return; // do nothing + + if(next_operation_is_complex) { + current_op.chain_forward=true; + next_operation_is_complex=false; + } + + undo_stack.push_back(current_op); + current_op.type=TextOperation::TYPE_NONE; + current_op.text=""; + current_op.chain_forward=false; + } void TextEdit::set_draw_tabs(bool p_draw) { - - draw_tabs=p_draw; + + draw_tabs=p_draw; } bool TextEdit::is_drawing_tabs() const{ - - return draw_tabs; + + return draw_tabs; } uint32_t TextEdit::get_version() const { - return current_op.version; + return current_op.version; } uint32_t TextEdit::get_saved_version() const { - - return saved_version; + + return saved_version; } void TextEdit::tag_saved_version() { - - saved_version=get_version(); + + saved_version=get_version(); } int TextEdit::get_v_scroll() const { - - return v_scroll->get_val(); + + return v_scroll->get_val(); } void TextEdit::set_v_scroll(int p_scroll) { - - v_scroll->set_val(p_scroll); - cursor.line_ofs=p_scroll; + + v_scroll->set_val(p_scroll); + cursor.line_ofs=p_scroll; } int TextEdit::get_h_scroll() const { - - return h_scroll->get_val(); + + return h_scroll->get_val(); } void TextEdit::set_h_scroll(int p_scroll) { - - h_scroll->set_val(p_scroll); + + h_scroll->set_val(p_scroll); } void TextEdit::set_completion(bool p_enabled,const Vector& p_prefixes) { - - completion_prefixes.clear(); - completion_enabled=p_enabled; - for(int i=0;i=l.length() || l[c]!=remaining[i]) { - same=false; - break; - } - } - - if (same) - cursor_set_column(cursor.column+remaining.length()); - else { - insert_text_at_cursor(remaining); - if (remaining.ends_with("(") && auto_brace_completion_enabled) { - insert_text_at_cursor(")"); - cursor.column--; + + String remaining=completion_current.substr(completion_base.length(),completion_current.length()-completion_base.length()); + String l = text[cursor.line]; + bool same=true; + //if what is going to be inserted is the same as what it is, don't change it + for(int i=0;i=l.length() || l[c]!=remaining[i]) { + same=false; + break; + } } - } - - _cancel_completion(); + + if (same) + cursor_set_column(cursor.column+remaining.length()); + else { + insert_text_at_cursor(remaining); + if (remaining.ends_with("(") && auto_brace_completion_enabled) { + insert_text_at_cursor(")"); + cursor.column--; + } + } + + _cancel_completion(); } @@ -3206,185 +3256,207 @@ void TextEdit::_cancel_code_hint() { } void TextEdit::_cancel_completion() { - - if (!completion_active) - return; - - completion_active=false; - update(); - + + if (!completion_active) + return; + + completion_active=false; + update(); + } static bool _is_completable(CharType c) { - + return !_is_symbol(c) || c=='"' || c=='\''; } void TextEdit::_update_completion_candidates() { + + String l = text[cursor.line]; + int cofs = CLAMP(cursor.column,0,l.length()); + + + String s; - String l = text[cursor.line]; - int cofs = CLAMP(cursor.column,0,l.length()); + //look for keywords first + + bool pre_keyword=false; + + if (cofs>0 && l[cofs-1]==' ') { + int kofs=cofs-1; + String kw; + while (kofs>=0 && l[kofs]==' ') + kofs--; + + while(kofs>=0 && l[kofs]>32 && _is_completable(l[kofs])) { + kw=String::chr(l[kofs])+kw; + kofs--; + } + + pre_keyword=keywords.has(kw); + print_line("KW "+kw+"? "+itos(pre_keyword)); + + } else { - String s; + while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) { + s=String::chr(l[cofs-1])+s; + if (l[cofs-1]=='\'' || l[cofs-1]=='"') + break; - while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) { - s=String::chr(l[cofs-1])+s; - if (l[cofs-1]=='\'' || l[cofs-1]=='"') - break; - - cofs--; - } - - - update(); - - if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { - //none to complete, cancel - _cancel_completion(); - return; - } - - completion_options.clear(); - completion_index=0; - completion_base=s; - int ci_match=0; - for(int i=0;i=completion_strings[i].length()) - break; - if (completion_current[j]!=completion_strings[i][j]) - break; - m++; - } - if (m>ci_match) { - ci_match=m; - completion_index=completion_options.size()-1; - } - - } - } - - - - if (completion_options.size()==0) { - //no options to complete, cancel - _cancel_completion(); - return; - - } - - completion_current=completion_options[completion_index]; + cofs--; + } + } + + update(); + + if (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { + //none to complete, cancel + _cancel_completion(); + return; + } + + completion_options.clear(); + completion_index=0; + completion_base=s; + int ci_match=0; + for(int i=0;i=completion_strings[i].length()) + break; + if (completion_current[j]!=completion_strings[i][j]) + break; + m++; + } + if (m>ci_match) { + ci_match=m; + completion_index=completion_options.size()-1; + } + + } + } + + + + if (completion_options.size()==0) { + //no options to complete, cancel + _cancel_completion(); + return; + + } + + completion_current=completion_options[completion_index]; + #if 0 // even there's only one option, user still get the chance to choose using it or not - if (completion_options.size()==1) { - //one option to complete, just complete it automagically - _confirm_completion(); -// insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); - _cancel_completion(); - return; - - } + if (completion_options.size()==1) { + //one option to complete, just complete it automagically + _confirm_completion(); + // insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); + _cancel_completion(); + return; + + } #endif - if (completion_options.size()==1 && s==completion_options[0]) - _cancel_completion(); - - completion_enabled=true; + if (completion_options.size()==1 && s==completion_options[0]) + _cancel_completion(); + + completion_enabled=true; } void TextEdit::query_code_comple() { - + String l = text[cursor.line]; int ofs = CLAMP(cursor.column,0,l.length()); - + if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1])))) emit_signal("request_completion"); - + } void TextEdit::set_code_hint(const String& p_hint) { - + completion_hint=p_hint; completion_hint_offset=-0xFFFF; update(); } void TextEdit::code_complete(const Vector &p_strings) { - - - completion_strings=p_strings; - completion_active=true; - completion_current=""; - completion_index=0; - _update_completion_candidates(); -// + + + completion_strings=p_strings; + completion_active=true; + completion_current=""; + completion_index=0; + _update_completion_candidates(); + // } String TextEdit::get_tooltip(const Point2& p_pos) const { - - if (!tooltip_obj) - return Control::get_tooltip(p_pos); - int row,col; - if (!_get_mouse_pos(p_pos, row,col)) { - return Control::get_tooltip(p_pos); - } - - String s = text[row]; - if (s.length()==0) - return Control::get_tooltip(p_pos); - int beg=CLAMP(col,0,s.length()); - int end=beg; - - - if (s[beg]>32 || beg==s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { - beg--; - } - while(end32 && (symbol==_is_symbol(s[end+1]))) { - end++; - } - - if (endcall(tooltip_func,s.substr(beg,end-beg),tooltip_ud); - - return tt; - - } - - return Control::get_tooltip(p_pos); - + + if (!tooltip_obj) + return Control::get_tooltip(p_pos); + int row,col; + if (!_get_mouse_pos(p_pos, row,col)) { + return Control::get_tooltip(p_pos); + } + + String s = text[row]; + if (s.length()==0) + return Control::get_tooltip(p_pos); + int beg=CLAMP(col,0,s.length()); + int end=beg; + + + if (s[beg]>32 || beg==s.length()) { + + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { + beg--; + } + while(end32 && (symbol==_is_symbol(s[end+1]))) { + end++; + } + + if (endcall(tooltip_func,s.substr(beg,end-beg),tooltip_ud); + + return tt; + + } + + return Control::get_tooltip(p_pos); + } void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName& p_function,const Variant& p_udata) { - - tooltip_obj=p_obj; - tooltip_func=p_function; - tooltip_ud=p_udata; + + tooltip_obj=p_obj; + tooltip_func=p_function; + tooltip_ud=p_udata; } void TextEdit::set_line(int line, String new_text) { - if (line < 0 || line > text.size()) - return; - _remove_text(line, 0, line, text[line].length()); - _insert_text(line, 0, new_text); + if (line < 0 || line > text.size()) + return; + _remove_text(line, 0, line, text[line].length()); + _insert_text(line, 0, new_text); } void TextEdit::insert_at(const String &p_text, int at) @@ -3395,167 +3467,167 @@ void TextEdit::insert_at(const String &p_text, int at) } void TextEdit::set_show_line_numbers(bool p_show) { - - line_numbers=p_show; - update(); + + line_numbers=p_show; + update(); } void TextEdit::_bind_methods() { - - - ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event); - ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved); - ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit); - ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); - ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); - - BIND_CONSTANT( SEARCH_MATCH_CASE ); - BIND_CONSTANT( SEARCH_WHOLE_WORDS ); - BIND_CONSTANT( SEARCH_BACKWARDS ); - -/* + + + ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event); + ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved); + ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit); + ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); + ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); + + BIND_CONSTANT( SEARCH_MATCH_CASE ); + BIND_CONSTANT( SEARCH_WHOLE_WORDS ); + BIND_CONSTANT( SEARCH_BACKWARDS ); + + /* ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char); ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line); */ - - ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text); - ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor); - - ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count); - ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text); - ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line); - - ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column); - ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line); - - ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); - ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); - - - ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly); - ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); - ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars); - - ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut); - ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy); - ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste); - ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all); - ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select); - - ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active); - ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line); - ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column); - ObjectTypeDB::bind_method(_MD("get_selection_to_line"),&TextEdit::get_selection_to_line); - ObjectTypeDB::bind_method(_MD("get_selection_to_column"),&TextEdit::get_selection_to_column); - ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); - ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); - ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); - - ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); - ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo); - ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); - - ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring); - ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); - - - ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color); - ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false)); - ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); - ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); - ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); - - - ADD_SIGNAL(MethodInfo("cursor_changed")); - ADD_SIGNAL(MethodInfo("text_changed")); - ADD_SIGNAL(MethodInfo("request_completion")); - + + ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text); + ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor); + + ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count); + ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text); + ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line); + + ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column); + ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line); + + ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); + ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); + + + ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly); + ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); + ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars); + + ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut); + ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy); + ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste); + ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all); + ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select); + + ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active); + ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line); + ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column); + ObjectTypeDB::bind_method(_MD("get_selection_to_line"),&TextEdit::get_selection_to_line); + ObjectTypeDB::bind_method(_MD("get_selection_to_column"),&TextEdit::get_selection_to_column); + ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); + ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); + ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); + + ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); + ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo); + ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); + + ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring); + ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); + + + ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color); + ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); + ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); + ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); + + + ADD_SIGNAL(MethodInfo("cursor_changed")); + ADD_SIGNAL(MethodInfo("text_changed")); + ADD_SIGNAL(MethodInfo("request_completion")); + } TextEdit::TextEdit() { - - readonly=false; - setting_row=false; - draw_tabs=false; - max_chars=0; - clear(); - wrap=false; - set_focus_mode(FOCUS_ALL); - _update_caches(); - cache.size=Size2(1,1); - tab_size=4; - text.set_tab_size(tab_size); - text.clear(); -// text.insert(1,"Mongolia.."); -// text.insert(2,"PAIS GENEROSO!!"); - text.set_color_regions(&color_regions); - - h_scroll = memnew( HScrollBar ); - v_scroll = memnew( VScrollBar ); - - add_child(h_scroll); - add_child(v_scroll); - - updating_scrolls=false; - selection.active=false; - - h_scroll->connect("value_changed", this,"_scroll_moved"); - v_scroll->connect("value_changed", this,"_scroll_moved"); - - cursor_changed_dirty=false; - text_changed_dirty=false; - - selection.selecting_mode=Selection::MODE_NONE; - selection.selecting_line=0; - selection.selecting_column=0; - selection.selecting_test=false; - selection.active=false; - syntax_coloring=false; - - custom_bg_color=Color(0,0,0,0); - idle_detect = memnew( Timer ); - add_child(idle_detect); - idle_detect->set_one_shot(true); - idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3)); - idle_detect->connect("timeout", this,"_push_current_op"); - + + readonly=false; + setting_row=false; + draw_tabs=false; + max_chars=0; + clear(); + wrap=false; + set_focus_mode(FOCUS_ALL); + _update_caches(); + cache.size=Size2(1,1); + tab_size=4; + text.set_tab_size(tab_size); + text.clear(); + // text.insert(1,"Mongolia.."); + // text.insert(2,"PAIS GENEROSO!!"); + text.set_color_regions(&color_regions); + + h_scroll = memnew( HScrollBar ); + v_scroll = memnew( VScrollBar ); + + add_child(h_scroll); + add_child(v_scroll); + + updating_scrolls=false; + selection.active=false; + + h_scroll->connect("value_changed", this,"_scroll_moved"); + v_scroll->connect("value_changed", this,"_scroll_moved"); + + cursor_changed_dirty=false; + text_changed_dirty=false; + + selection.selecting_mode=Selection::MODE_NONE; + selection.selecting_line=0; + selection.selecting_column=0; + selection.selecting_test=false; + selection.active=false; + syntax_coloring=false; + + custom_bg_color=Color(0,0,0,0); + idle_detect = memnew( Timer ); + add_child(idle_detect); + idle_detect->set_one_shot(true); + idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3)); + idle_detect->connect("timeout", this,"_push_current_op"); + #if 0 - syntax_coloring=true; - keywords["void"]=Color(0.3,0.0,0.1); - keywords["int"]=Color(0.3,0.0,0.1); - keywords["function"]=Color(0.3,0.0,0.1); - keywords["class"]=Color(0.3,0.0,0.1); - keywords["extends"]=Color(0.3,0.0,0.1); - keywords["constructor"]=Color(0.3,0.0,0.1); - symbol_color=Color(0.1,0.0,0.3,1.0); - - color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4))); - color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4))); - color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7))); - color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8))); - color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2))); - + syntax_coloring=true; + keywords["void"]=Color(0.3,0.0,0.1); + keywords["int"]=Color(0.3,0.0,0.1); + keywords["function"]=Color(0.3,0.0,0.1); + keywords["class"]=Color(0.3,0.0,0.1); + keywords["extends"]=Color(0.3,0.0,0.1); + keywords["constructor"]=Color(0.3,0.0,0.1); + symbol_color=Color(0.1,0.0,0.3,1.0); + + color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4))); + color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4))); + color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7))); + color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8))); + color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2))); + #endif - - current_op.type=TextOperation::TYPE_NONE; - undo_enabled=true; - undo_stack_pos=NULL; - setting_text=false; - last_dblclk=0; - current_op.version=0; - version=0; - saved_version=0; - - completion_enabled=false; - completion_active=false; - completion_line_ofs=0; - tooltip_obj=NULL; - line_numbers=false; - next_operation_is_complex=false; - auto_brace_completion_enabled=false; - brace_matching_enabled=false; - + + current_op.type=TextOperation::TYPE_NONE; + undo_enabled=true; + undo_stack_pos=NULL; + setting_text=false; + last_dblclk=0; + current_op.version=0; + version=0; + saved_version=0; + + completion_enabled=false; + completion_active=false; + completion_line_ofs=0; + tooltip_obj=NULL; + line_numbers=false; + next_operation_is_complex=false; + auto_brace_completion_enabled=false; + brace_matching_enabled=false; + } TextEdit::~TextEdit() diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index ed4d30a9d2a..1d57aef4161 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -63,6 +63,7 @@ class TextEdit : public Control { int from_line,from_column; int to_line,to_column; + bool shiftclick_left; } selection; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 7954ac65dff..1a7087b7efd 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -31,28 +31,37 @@ Size2 TextureButton::get_minimum_size() const { + Size2 rscale; if (normal.is_null()) { if (pressed.is_null()) { if (hover.is_null()) if (click_mask.is_null()) - return Size2(); + rscale= Size2(); else - return click_mask->get_size(); + rscale= click_mask->get_size(); else - return hover->get_size(); + rscale= hover->get_size(); } else - return pressed->get_size(); + rscale= pressed->get_size()*scale; } else - return normal->get_size(); + rscale= normal->get_size(); + + return rscale*scale; } bool TextureButton::has_point(const Point2& p_point) const { + if (scale[0] <= 0 || scale[1] <= 0) { + return false; + } + + Point2 ppos = p_point/scale; + if (click_mask.is_valid()) { - Point2i p =p_point; + Point2i p =ppos; if (p.x<0 || p.x>=click_mask->get_size().width || p.y<0 || p.y>=click_mask->get_size().height) return false; @@ -71,46 +80,57 @@ void TextureButton::_notification(int p_what) { DrawMode draw_mode = get_draw_mode(); // if (normal.is_null()) // break; + + Ref texdraw; + switch (draw_mode) { case DRAW_NORMAL: { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } break; case DRAW_PRESSED: { if (pressed.is_null()) { if (hover.is_null()) { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - hover->draw(canvas_item,Point2()); + texdraw=hover; } else - pressed->draw(canvas_item,Point2()); + texdraw=pressed; } break; case DRAW_HOVER: { if (hover.is_null()) { if (pressed.is_valid() && is_pressed()) - pressed->draw(canvas_item,Point2()); + texdraw=pressed; else if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - hover->draw(canvas_item,Point2()); + texdraw=hover; } break; case DRAW_DISABLED: { if (disabled.is_null()) { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - disabled->draw(canvas_item,Point2()); + texdraw=disabled; } break; } + + if (texdraw.is_valid()) { + Rect2 drect(Point2(),texdraw->get_size()*scale); + draw_texture_rect(texdraw,drect,false,modulate); + + } if (has_focus() && focused.is_valid()) { - focused->draw(canvas_item, Point2()); + Rect2 drect(Point2(),focused->get_size()*scale); + draw_texture_rect(focused,drect,false,modulate); + }; } break; @@ -125,6 +145,8 @@ void TextureButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_disabled_texture","texture:Texture"),&TextureButton::set_disabled_texture); ObjectTypeDB::bind_method(_MD("set_focused_texture","texture:Texture"),&TextureButton::set_focused_texture); ObjectTypeDB::bind_method(_MD("set_click_mask","mask:BitMap"),&TextureButton::set_click_mask); + ObjectTypeDB::bind_method(_MD("set_scale","scale"),&TextureButton::set_scale); + ObjectTypeDB::bind_method(_MD("set_modulate","color"),&TextureButton::set_modulate); ObjectTypeDB::bind_method(_MD("get_normal_texture:Texture"),&TextureButton::get_normal_texture); ObjectTypeDB::bind_method(_MD("get_pressed_texture:Texture"),&TextureButton::get_pressed_texture); @@ -132,6 +154,8 @@ void TextureButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_disabled_texture:Texture"),&TextureButton::get_disabled_texture); ObjectTypeDB::bind_method(_MD("get_focused_texture:Texture"),&TextureButton::get_focused_texture); ObjectTypeDB::bind_method(_MD("get_click_mask:BitMap"),&TextureButton::get_click_mask); + ObjectTypeDB::bind_method(_MD("get_scale"),&TextureButton::get_scale); + ObjectTypeDB::bind_method(_MD("get_modulate"),&TextureButton::get_modulate); ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture")); @@ -139,6 +163,8 @@ void TextureButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ; + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_scale"), _SCS("get_scale")); + ADD_PROPERTY(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate")); } @@ -206,6 +232,29 @@ void TextureButton::set_focused_texture(const Ref& p_focused) { focused = p_focused; }; +void TextureButton::set_scale(Size2 p_scale) { + + scale=p_scale; + minimum_size_changed(); + update(); +} + +Size2 TextureButton::get_scale() const{ + + return scale; +} + +void TextureButton::set_modulate(const Color& p_modulate) { + modulate=p_modulate; + update(); +} + +Color TextureButton::get_modulate() const { + return modulate; +} + TextureButton::TextureButton() { + scale=Size2(1.0, 1.0); + modulate=Color(1,1,1); } diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index d186966cb1f..94bc53b3ff6 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -41,6 +41,8 @@ class TextureButton : public BaseButton { Ref disabled; Ref focused; Ref click_mask; + Size2 scale; + Color modulate; protected: @@ -66,6 +68,11 @@ public: Ref get_focused_texture() const; Ref get_click_mask() const; + void set_scale(Size2 p_scale); + Size2 get_scale() const; + + void set_modulate(const Color& p_modulate); + Color get_modulate() const; TextureButton(); }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d9b208d6d3a..fbdc87a7cc0 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -382,6 +382,8 @@ bool Node::can_process() const { if (get_tree()->is_paused()) { + if (data.pause_mode==PAUSE_MODE_STOP) + return false; if (data.pause_mode==PAUSE_MODE_PROCESS) return true; if (data.pause_mode==PAUSE_MODE_INHERIT) { @@ -391,6 +393,9 @@ bool Node::can_process() const { if (data.pause_owner->data.pause_mode==PAUSE_MODE_PROCESS) return true; + + if (data.pause_owner->data.pause_mode==PAUSE_MODE_STOP) + return false; } } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 962e8c26e0d..cf499791189 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -39,7 +39,6 @@ #include "scene/main/viewport.h" #include "scene/gui/control.h" #include "scene/gui/texture_progress.h" -#include "scene/gui/empty_control.h" #include "scene/gui/button.h" #include "scene/gui/button_array.h" #include "scene/gui/button_group.h" @@ -76,6 +75,7 @@ #include "scene/gui/video_player.h" #include "scene/gui/reference_frame.h" #include "scene/gui/graph_node.h" +#include "scene/gui/graph_edit.h" #include "scene/resources/video_stream.h" #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" @@ -153,6 +153,8 @@ #include "scene/resources/mesh.h" #include "scene/resources/room.h" +#include "scene/resources/shader_graph.h" + #include "scene/resources/world.h" #include "scene/resources/world_2d.h" #include "scene/resources/volume.h" @@ -269,7 +271,8 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ObjectTypeDB::register_type(); - ObjectTypeDB::register_type(); +// ObjectTypeDB::register_type(); + ObjectTypeDB::add_compatibility_type("EmptyControl","control"); ObjectTypeDB::register_type