diff options
43 files changed, 1490 insertions, 642 deletions
diff --git a/.gitignore b/.gitignore index e1941b18df..f3a4e9714c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,17 +37,10 @@ platform/android/java/.gradle platform/android/java/.gradletasknamecache platform/android/java/local.properties platform/android/java/project.properties +platform/android/java/build.gradle platform/android/java/AndroidManifest.xml -platform/android/java/bin/* platform/android/java/libs/* -platform/android/java/gen/* platform/android/java/assets -platform/android/libs/apk_expansion/bin/* -platform/android/libs/apk_expansion/gen/* -platform/android/libs/google_play_services/bin/* -platform/android/libs/google_play_services/gen/* -platform/android/libs/play_licensing/bin/* -platform/android/libs/play_licensing/gen/* # General c++ generated files *.lib diff --git a/SConstruct b/SConstruct index 01b1f2ce8e..d168820f66 100644 --- a/SConstruct +++ b/SConstruct @@ -73,6 +73,7 @@ env_base.android_java_dirs=[] env_base.android_res_dirs=[] env_base.android_aidl_dirs=[] env_base.android_jni_dirs=[] +env_base.android_default_config=[] env_base.android_manifest_chunk="" env_base.android_permission_chunk="" env_base.android_appattributes_chunk="" @@ -88,6 +89,7 @@ env_base.__class__.android_add_java_dir=methods.android_add_java_dir env_base.__class__.android_add_res_dir=methods.android_add_res_dir env_base.__class__.android_add_aidl_dir=methods.android_add_aidl_dir env_base.__class__.android_add_jni_dir=methods.android_add_jni_dir +env_base.__class__.android_add_default_config=methods.android_add_default_config env_base.__class__.android_add_to_manifest = methods.android_add_to_manifest env_base.__class__.android_add_to_permissions = methods.android_add_to_permissions env_base.__class__.android_add_to_attributes = methods.android_add_to_attributes diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index ace7e7c7b7..6edc292b62 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -435,6 +435,18 @@ String _OS::get_locale() const { return OS::get_singleton()->get_locale(); } +String _OS::get_latin_keyboard_variant() const { + switch( OS::get_singleton()->get_latin_keyboard_variant() ) { + case OS::LATIN_KEYBOARD_QWERTY: return "QWERTY"; + case OS::LATIN_KEYBOARD_QWERTZ: return "QWERTZ"; + case OS::LATIN_KEYBOARD_AZERTY: return "AZERTY"; + case OS::LATIN_KEYBOARD_QZERTY: return "QZERTY"; + case OS::LATIN_KEYBOARD_DVORAK: return "DVORAK"; + case OS::LATIN_KEYBOARD_NEO : return "NEO"; + default: return "ERROR"; + } +} + String _OS::get_model_name() const { return OS::get_singleton()->get_model_name(); @@ -1097,6 +1109,7 @@ void _OS::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_ticks_msec"),&_OS::get_ticks_msec); ObjectTypeDB::bind_method(_MD("get_splash_tick_msec"),&_OS::get_splash_tick_msec); ObjectTypeDB::bind_method(_MD("get_locale"),&_OS::get_locale); + ObjectTypeDB::bind_method(_MD("get_latin_keyboard_variant"),&_OS::get_latin_keyboard_variant); ObjectTypeDB::bind_method(_MD("get_model_name"),&_OS::get_model_name); ObjectTypeDB::bind_method(_MD("get_custom_level"),&_OS::get_custom_level); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 856d942d02..5bd427578a 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -192,6 +192,8 @@ public: Vector<String> get_cmdline_args(); String get_locale() const; + String get_latin_keyboard_variant() const; + String get_model_name() const; MainLoop *get_main_loop() const; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index e549161de9..9182dcde1a 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -2911,6 +2911,14 @@ bool Variant::iter_init(Variant& r_iter,bool &valid) const { return ret; } break; + case STRING: { + + const String *str=reinterpret_cast<const String*>(_data._mem); + if (str->empty()) + return false; + r_iter = 0; + return true; + } break; case DICTIONARY: { const Dictionary *dic=reinterpret_cast<const Dictionary*>(_data._mem); @@ -3028,6 +3036,17 @@ bool Variant::iter_next(Variant& r_iter,bool &valid) const { return ret; } break; + + case STRING: { + + const String *str=reinterpret_cast<const String*>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= str->size()) + return false; + r_iter = idx; + return true; + } break; case DICTIONARY: { const Dictionary *dic=reinterpret_cast<const Dictionary*>(_data._mem); @@ -3158,6 +3177,11 @@ Variant Variant::iter_get(const Variant& r_iter,bool &r_valid) const { return ret; } break; + case STRING: { + + const String *str=reinterpret_cast<const String*>(_data._mem); + return str->substr(r_iter,1); + } break; case DICTIONARY: { return r_iter; //iterator is the same as the key diff --git a/doc/base/classes.xml b/doc/base/classes.xml index cffbd68939..dd00a0312c 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -6676,6 +6676,17 @@ Force the camera to update scroll immediately. </description> </method> + <method name="reset_smoothing"> + <description> + Set the camera's position immediately to its current smoothing destination. + This has no effect if smoothing is disabled. + </description> + </method> + <method name="align"> + <description> + Align the camera to the tracked node + </description> + </method> <method name="get_anchor_mode" qualifiers="const"> <return type="int"> </return> @@ -21677,6 +21688,12 @@ <description> </description> </method> + <method name="is_displayed_folded" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="is_fixed_processing" qualifiers="const"> <return type="bool"> </return> @@ -21802,6 +21819,12 @@ <description> </description> </method> + <method name="set_display_folded"> + <argument index="0" name="fold" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_filename"> <argument index="0" name="filename" type="String"> </argument> @@ -31551,6 +31574,13 @@ <description> </description> </method> + <method name="get_text"> + <return type="String"> + </return> + <description> + Returns the raw text, stripping out the formatting information. + </description> + </method> <method name="get_total_character_count" qualifiers="const"> <return type="int"> </return> diff --git a/main/input_default.cpp b/main/input_default.cpp index 4fcb450bce..e975d4141f 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -30,6 +30,7 @@ #include "servers/visual_server.h" #include "os/os.h" #include "input_map.h" +#include "scene/resources/texture.h" void InputDefault::SpeedTrack::update(const Vector2& p_delta_p) { @@ -463,9 +464,11 @@ void InputDefault::set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_ set_mouse_mode(MOUSE_MODE_VISIBLE); VisualServer::get_singleton()->cursor_set_visible(false); } else { + Ref<AtlasTexture> atex = custom_cursor; + Rect2 region = atex.is_valid() ? atex->get_region() : Rect2(); set_mouse_mode(MOUSE_MODE_HIDDEN); VisualServer::get_singleton()->cursor_set_visible(true); - VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(),p_hotspot); + VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(),p_hotspot, 0, region); VisualServer::get_singleton()->cursor_set_pos(get_mouse_pos()); } } diff --git a/methods.py b/methods.py index 7128b334ec..74c282b8cf 100755 --- a/methods.py +++ b/methods.py @@ -1326,7 +1326,9 @@ def android_add_aidl_dir(self,subpath): def android_add_jni_dir(self,subpath): base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath self.android_jni_dirs.append(base_path) - +def android_add_default_config(self,config): + self.android_default_config.append(config) + def android_add_to_manifest(self,file): base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file f = open(base_path,"rb") diff --git a/platform/android/SCsub b/platform/android/SCsub index c8feac8690..60bb4bd613 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -79,6 +79,11 @@ for x in env.android_jni_dirs: gradle_asset_dirs_text="" +gradle_default_config_text="" + +for x in env.android_default_config: + gradle_default_config_text+=x+"\n\t\t" + gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$",gradle_maven_repos_text) gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$",gradle_maven_dependencies_text) gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$",gradle_java_dirs_text) @@ -86,6 +91,7 @@ gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$",gradle_res_dirs_text) gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$",gradle_asset_dirs_text) gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$",gradle_aidl_dirs_text) gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$",gradle_jni_dirs_text) +gradle_text = gradle_text.replace("$$GRADLE_DEFAULT_CONFIG$$",gradle_default_config_text) gradle_baseout.write( gradle_text ) @@ -103,4 +109,22 @@ pp_baseout.write( manifest ) env_android.SharedLibrary("#bin/libgodot",[android_objects],SHLIBSUFFIX=env["SHLIBSUFFIX"]) -#env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so')) + +lib_arch_dir = '' +if env['android_arch'] == 'armv6': + lib_arch_dir = 'armeabi' +elif env['android_arch'] == 'armv7': + lib_arch_dir = 'armeabi-v7a' +elif env['android_arch'] == 'x86': + lib_arch_dir = 'x86' +else: + print 'WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin' + +if lib_arch_dir != '': + if env['target'] == 'release': + lib_type_dir = 'release' + else: # release_debug, debug + lib_type_dir = 'debug' + + out_dir = '#platform/android/java/libs/'+lib_type_dir+'/'+lib_arch_dir + env_android.Command(out_dir+'/libgodot_android.so', '#bin/libgodot'+env['SHLIBSUFFIX'], Move("$TARGET", "$SOURCE")) diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template index 1e1461ef29..24951b921b 100644 --- a/platform/android/build.gradle.template +++ b/platform/android/build.gradle.template @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:2.1.0' } } @@ -39,6 +39,12 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 + $$GRADLE_DEFAULT_CONFIG$$ + } + // Both signing and zip-aligning will be done at export time + buildTypes.all { buildType -> + buildType.zipAlignEnabled false + buildType.signingConfig null } sourceSets { main { @@ -65,8 +71,17 @@ android { $$GRADLE_JNI_DIRS$$ ] } - + debug.jniLibs.srcDirs = [ + 'libs/debug' + $$GRADLE_JNI_DIRS$$ + ] + release.jniLibs.srcDirs = [ + 'libs/release' + $$GRADLE_JNI_DIRS$$ + ] + } + applicationVariants.all { variant -> + // ApplicationVariant is undocumented, but this method is widely used; may break with another version of the Android Gradle plugin + variant.outputs.get(0).setOutputFile(new File("${projectDir}/../../../bin", "android_${variant.name}.apk")) } - - } diff --git a/platform/android/detect.py b/platform/android/detect.py index ba6b73a89f..6fd0b81d91 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -23,7 +23,7 @@ def get_opts(): ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)), ('NDK_TARGET', 'toolchain to use for the NDK',os.environ.get("NDK_TARGET", "arm-linux-androideabi-4.9")), ('NDK_TARGET_X86', 'toolchain to use for the NDK x86',os.environ.get("NDK_TARGET_X86", "x86-4.9")), - ('ndk_platform', 'compile for platform: (android-<api> , example: android-15)',"android-15"), + ('ndk_platform', 'compile for platform: (android-<api> , example: android-14)',"android-14"), ('android_arch', 'select compiler architecture: (armv7/armv6/x86)',"armv7"), ('android_neon','enable neon (armv7 only)',"yes"), ('android_stl','enable STL support in android port (for modules)',"no") diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 872f047c95..83f7292716 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -1166,7 +1166,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d skip=true; } - if (file=="lib/armeabi/libgodot_android.so" && !export_arm) { + if (file.match("lib/armeabi*/libgodot_android.so") && !export_arm) { skip=true; } diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties index 0c71e760dc..d57051703e 100644 --- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 89de969cff..b0a50ca4b8 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2178,6 +2178,68 @@ String OS_Windows::get_locale() const { return "en"; } + +OS::LatinKeyboardVariant OS_Windows::get_latin_keyboard_variant() const { + + unsigned long azerty[] = { + 0x00020401, // Arabic (102) AZERTY + 0x0001080c, // Belgian (Comma) + 0x0000080c, // Belgian French + 0x0000040c, // French + 0 // <--- STOP MARK + }; + unsigned long qwertz[] = { + 0x0000041a, // Croation + 0x00000405, // Czech + 0x00000407, // German + 0x00010407, // German (IBM) + 0x0000040e, // Hungarian + 0x0000046e, // Luxembourgish + 0x00010415, // Polish (214) + 0x00000418, // Romanian (Legacy) + 0x0000081a, // Serbian (Latin) + 0x0000041b, // Slovak + 0x00000424, // Slovenian + 0x0001042e, // Sorbian Extended + 0x0002042e, // Sorbian Standard + 0x0000042e, // Sorbian Standard (Legacy) + 0x0000100c, // Swiss French + 0x00000807, // Swiss German + 0 // <--- STOP MARK + }; + unsigned long dvorak[] = { + 0x00010409, // US-Dvorak + 0x00030409, // US-Dvorak for left hand + 0x00040409, // US-Dvorak for right hand + 0 // <--- STOP MARK + }; + + char name[ KL_NAMELENGTH + 1 ]; name[0] = 0; + GetKeyboardLayoutNameA( name ); + + unsigned long hex = strtoul(name, NULL, 16); + + int i=0; + while( azerty[i] != 0 ) { + if (azerty[i] == hex) return LATIN_KEYBOARD_AZERTY; + i++; + } + + i = 0; + while( qwertz[i] != 0 ) { + if (qwertz[i] == hex) return LATIN_KEYBOARD_QWERTZ; + i++; + } + + i = 0; + while( dvorak[i] != 0 ) { + if (dvorak[i] == hex) return LATIN_KEYBOARD_DVORAK; + i++; + } + + return LATIN_KEYBOARD_QWERTY; +} + void OS_Windows::release_rendering_thread() { gl_context->release_current(); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index d2249bf352..5acb300c0f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -266,6 +266,7 @@ public: virtual String get_executable_path() const; virtual String get_locale() const; + virtual LatinKeyboardVariant get_latin_keyboard_variant() const; virtual void move_window_to_foreground(); virtual String get_data_dir() const; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 27e07a35be..f98a50e3e0 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -408,6 +408,35 @@ void Camera2D::force_update_scroll() { _update_scroll(); } +void Camera2D::reset_smoothing() { + + smoothed_camera_pos = camera_pos; + _update_scroll(); +} + +void Camera2D::align() { + + Size2 screen_size = get_viewport_rect().size; + screen_size=get_viewport_rect().size; + Point2 current_camera_pos = get_global_transform().get_origin(); + if (anchor_mode==ANCHOR_MODE_DRAG_CENTER) { + if (h_ofs<0) { + camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; + } else { + camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; + } + if (v_ofs<0) { + camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; + } else { + camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; + } + } else if (anchor_mode==ANCHOR_MODE_FIXED_TOP_LEFT){ + + camera_pos=current_camera_pos; + } + + _update_scroll(); +} void Camera2D::set_follow_smoothing(float p_speed) { @@ -543,6 +572,8 @@ void Camera2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_follow_smoothing_enabled"),&Camera2D::is_follow_smoothing_enabled); ObjectTypeDB::bind_method(_MD("force_update_scroll"),&Camera2D::force_update_scroll); + ObjectTypeDB::bind_method(_MD("reset_smoothing"),&Camera2D::reset_smoothing); + ObjectTypeDB::bind_method(_MD("align"),&Camera2D::align); ObjectTypeDB::bind_method(_MD("_set_old_smoothing","follow_smoothing"),&Camera2D::_set_old_smoothing); diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 22e5bc382a..b3f55d798d 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -128,6 +128,8 @@ public: Vector2 get_camera_pos() const; void force_update_scroll(); + void reset_smoothing(); + void align(); Camera2D(); }; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 1f16b36466..1a4f88c30e 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -222,6 +222,10 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect Size2 s=p_sc; Vector2 offset = p_offset; + + if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) + offset.y+=cell_size.y; + if (s.y > s.x) { if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) @@ -240,7 +244,7 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect if (p_cell.flip_h) { xform.elements[0].x=-xform.elements[0].x; xform.elements[1].x=-xform.elements[1].x; - if (tile_origin==TILE_ORIGIN_TOP_LEFT) + if (tile_origin==TILE_ORIGIN_TOP_LEFT || tile_origin==TILE_ORIGIN_BOTTOM_LEFT) offset.x=s.x-offset.x; } if (p_cell.flip_v) { @@ -248,6 +252,12 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect xform.elements[1].y=-xform.elements[1].y; if (tile_origin==TILE_ORIGIN_TOP_LEFT) offset.y=s.y-offset.y; + else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) { + if(p_cell.transpose) + offset.y+=s.y; + else + offset.y-=s.y; + } } xform.elements[2].x+=offset.x; xform.elements[2].y+=offset.y; @@ -411,6 +421,24 @@ void TileMap::_update_dirty_quadrants() { if (tile_origin==TILE_ORIGIN_TOP_LEFT) { rect.pos+=tile_ofs; + + } else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) { + + rect.pos+=tile_ofs; + + if(c.transpose) + { + if(c.flip_h) + rect.pos.x-=cell_size.x; + else + rect.pos.x+=cell_size.x; + } else { + if(c.flip_v) + rect.pos.y-=cell_size.y; + else + rect.pos.y+=cell_size.y; + } + } else if (tile_origin==TILE_ORIGIN_CENTER) { rect.pos+=tcenter; @@ -584,6 +612,9 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const q.pos+=get_cell_draw_offset(); if (tile_origin==TILE_ORIGIN_CENTER) q.pos+=cell_size/2; + else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) + q.pos.y+=cell_size.y; + xform.set_origin( q.pos ); // q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); @@ -1242,7 +1273,7 @@ void TileMap::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size")); ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform")); ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center"),_SCS("set_tile_origin"),_SCS("get_tile_origin")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/tile_origin",PROPERTY_HINT_ENUM,"Top Left,Center,Bottom Left"),_SCS("set_tile_origin"),_SCS("get_tile_origin")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"cell/y_sort"),_SCS("set_y_sort_mode"),_SCS("is_y_sort_mode_enabled")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction")); @@ -1264,6 +1295,7 @@ void TileMap::_bind_methods() { BIND_CONSTANT( HALF_OFFSET_DISABLED ); BIND_CONSTANT( TILE_ORIGIN_TOP_LEFT ); BIND_CONSTANT( TILE_ORIGIN_CENTER ); + BIND_CONSTANT( TILE_ORIGIN_BOTTOM_LEFT ); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index cec5ac0a1b..b48fdde43f 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -54,7 +54,8 @@ public: enum TileOrigin { TILE_ORIGIN_TOP_LEFT, - TILE_ORIGIN_CENTER + TILE_ORIGIN_CENTER, + TILE_ORIGIN_BOTTOM_LEFT }; diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 628edf09de..9488ae37a8 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -445,8 +445,44 @@ void AnimationTreePlayer::_notification(int p_what) { } +void AnimationTreePlayer::_compute_weights(float *p_fallback_weight, HashMap<NodePath,float> *p_weights, float p_coeff, const HashMap<NodePath,bool> *p_filter, float p_filtered_coeff) { -float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_weight, float p_time, bool p_seek,const HashMap<NodePath,bool> *p_filter, float p_reverse_weight) { + if (p_filter != NULL) { + + List<NodePath> key_list; + p_filter->get_key_list(&key_list); + + for (List<NodePath>::Element *E = key_list.front();E; E=E->next()) { + + if ((*p_filter)[E->get()]) { + + if (p_weights->has(E->get())) { + (*p_weights)[E->get()] *= p_filtered_coeff; + } else { + p_weights->set(E->get(), *p_fallback_weight * p_filtered_coeff); + } + + } else if (p_weights->has(E->get())) { + (*p_weights)[E->get()] *= p_coeff; + } + } + } + + List<NodePath> key_list; + p_weights->get_key_list(&key_list); + + for (List<NodePath>::Element *E = key_list.front();E;E=E->next()) { + if (p_filter == NULL || !p_filter->has(E->get())) { + (*p_weights)[E->get()] *= p_coeff; + } + } + + *p_fallback_weight *= p_coeff; + +} + + +float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_time, bool p_seek, float p_fallback_weight, HashMap<NodePath,float>* p_weights) { ERR_FAIL_COND_V(!node_map.has(p_node), 0); NodeBase *nb=node_map[p_node]; @@ -458,7 +494,16 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode case NODE_OUTPUT: { NodeOut *on = static_cast<NodeOut*>(nb); - return _process_node(on->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek); + + for(TrackMap::Element *E=track_map.front();E;E=E->next()) { + E->get().total_weight = 0; + } + + HashMap<NodePath, float> weights; + + + + return _process_node(on->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, &weights); } break; case NODE_ANIMATION: { @@ -494,15 +539,21 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode } an->skip=true; + for (List<AnimationNode::TrackRef>::Element *E=an->tref.front();E;E=E->next()) { NodePath track_path = an->animation->track_get_path(E->get().local_track); - if (p_filter && p_filter->has(track_path)) { - E->get().weight = MAX(0, p_reverse_weight); - } else if(an->filter.has(track_path)) { + if (an->filter.has(track_path) && an->filter[track_path]) { E->get().weight = 0; - E->get().track->skip = true; + E->get().track->total_weight += p_fallback_weight; } else { - E->get().weight=p_weight; + if (p_weights->has(track_path)) { + float weight = (*p_weights)[track_path]; + E->get().weight = weight; + E->get().track->total_weight += weight; + } else { + E->get().weight = p_fallback_weight; + E->get().track->total_weight += p_fallback_weight; + } } if (E->get().weight>CMP_EPSILON) an->skip=false; @@ -531,7 +582,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode if (!osn->active) { //make it as if this node doesn't exist, pass input 0 by. - return _process_node(osn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); + return _process_node(osn->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, p_weights); } float os_seek = p_seek; @@ -563,16 +614,14 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode float main_rem; float os_rem; - float os_reverse_weight = p_reverse_weight; - if (!osn->filter.empty()) { - p_filter = &osn->filter; - p_reverse_weight = p_weight; - os_reverse_weight = -1; - } + HashMap<NodePath, float> os_weights(*p_weights); + float os_fallback_weight = p_fallback_weight; + _compute_weights(&p_fallback_weight, p_weights, osn->mix?1.0 : 1.0 - blend, &osn->filter, 1.0); + _compute_weights(&os_fallback_weight, &os_weights, blend, &osn->filter, 0.0); - main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,p_seek,p_filter,p_reverse_weight); - os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,os_seek,p_filter,os_reverse_weight); + main_rem = _process_node(osn->inputs[0].node,r_prev_anim,p_time,p_seek, p_fallback_weight, p_weights); + os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_time,os_seek, os_fallback_weight, &os_weights); if (osn->start) { osn->remaining=os_rem; @@ -591,9 +640,11 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode case NODE_MIX: { MixNode *mn = static_cast<MixNode*>(nb); - - float rem = _process_node(mn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); - _process_node(mn->inputs[1].node,r_prev_anim,p_weight*mn->amount,p_time,p_seek,p_filter,p_reverse_weight); + HashMap<NodePath, float> mn_weights(*p_weights); + float mn_fallback_weight = p_fallback_weight; + _compute_weights(&mn_fallback_weight, &mn_weights, mn->amount); + float rem = _process_node(mn->inputs[0].node,r_prev_anim, p_time,p_seek,p_fallback_weight,p_weights); + _process_node(mn->inputs[1].node,r_prev_anim,p_time,p_seek,mn_fallback_weight,&mn_weights); return rem; } break; @@ -601,16 +652,12 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode Blend2Node *bn = static_cast<Blend2Node*>(nb); - float rem; - if (!bn->filter.empty()) { - - rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,&bn->filter,p_weight); - _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,&bn->filter,-1); - - } else { - rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value)); - _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,p_filter,p_reverse_weight*bn->value); - } + HashMap<NodePath, float> bn_weights(*p_weights); + float bn_fallback_weight = p_fallback_weight; + _compute_weights(&p_fallback_weight,p_weights, 1.0 - bn->value, &bn->filter, 1.0); + _compute_weights(&bn_fallback_weight,&bn_weights, bn->value, &bn->filter, 0.0); + float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); + _process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,bn_fallback_weight,&bn_weights); return rem; } break; @@ -629,19 +676,39 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode upper_blend = bn->value; } - rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,p_seek,p_filter,p_reverse_weight*blend); - _process_node(bn->inputs[2].node,r_prev_anim,p_weight*upper_blend,p_time,p_seek,p_filter,p_reverse_weight*upper_blend); - _process_node(bn->inputs[0].node,r_prev_anim,p_weight*lower_blend,p_time,p_seek,p_filter,p_reverse_weight*lower_blend); + HashMap<NodePath, float> upper_weights(*p_weights); + float upper_fallback_weight = p_fallback_weight; + HashMap<NodePath, float> lower_weights(*p_weights); + float lower_fallback_weight = p_fallback_weight; + _compute_weights(&upper_fallback_weight,&upper_weights, upper_blend); + _compute_weights(&p_fallback_weight,p_weights, blend); + _compute_weights(&lower_fallback_weight,&lower_weights, lower_blend); + + rem = _process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); + _process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,lower_fallback_weight,&lower_weights); + _process_node(bn->inputs[2].node,r_prev_anim,p_time,p_seek,upper_fallback_weight,&upper_weights); return rem; } break; case NODE_BLEND4: { Blend4Node *bn = static_cast<Blend4Node*>(nb); - float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value.x),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.x)); - _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value.x,p_time,p_seek,p_filter,p_reverse_weight*bn->value.x); - float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_weight*(1.0-bn->value.y),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.y)); - _process_node(bn->inputs[3].node,r_prev_anim,p_weight*bn->value.y,p_time,p_seek,p_filter,p_reverse_weight*bn->value.y); + HashMap<NodePath, float> weights1(*p_weights); + float fallback_weight1 = p_fallback_weight; + HashMap<NodePath, float> weights2(*p_weights); + float fallback_weight2 = p_fallback_weight; + HashMap<NodePath, float> weights3(*p_weights); + float fallback_weight3 = p_fallback_weight; + + _compute_weights(&p_fallback_weight,p_weights, 1.0-bn->value.x); + _compute_weights(&fallback_weight1,&weights1, bn->value.x); + _compute_weights(&fallback_weight2,&weights2, 1.0-bn->value.y); + _compute_weights(&fallback_weight3,&weights3, bn->value.y); + + float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); + _process_node(bn->inputs[1].node,r_prev_anim,p_time,p_seek,fallback_weight1,&weights1); + float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_time,p_seek,fallback_weight2,&weights2); + _process_node(bn->inputs[3].node,r_prev_anim,p_time,p_seek,fallback_weight3,&weights3); return MAX(rem,rem2); @@ -650,9 +717,9 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode TimeScaleNode *tsn = static_cast<TimeScaleNode*>(nb); float rem; if (p_seek) - rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,true,p_filter,p_reverse_weight); + rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_time,true,p_fallback_weight,p_weights); else - rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time*tsn->scale,false,p_filter,p_reverse_weight); + rem = _process_node(tsn->inputs[0].node,r_prev_anim,p_time*tsn->scale,false,p_fallback_weight,p_weights); if (tsn->scale == 0) return INFINITY; else @@ -669,16 +736,18 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode } tsn->seek_pos=-1; - return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek, p_filter, p_reverse_weight); + return _process_node(tsn->inputs[0].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); } break; case NODE_TRANSITION: { TransitionNode *tn = static_cast<TransitionNode*>(nb); + HashMap<NodePath, float> prev_weights(*p_weights); + float prev_fallback_weight = p_fallback_weight; if (tn->prev<0) { // process current animation, check for transition - float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight); + float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); if (p_seek) tn->time=p_time; else @@ -698,22 +767,25 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode float rem; + _compute_weights(&p_fallback_weight,p_weights, 1.0-blend); + _compute_weights(&prev_fallback_weight,&prev_weights, blend); + if (!p_seek && tn->switched) { //just switched, seek to start of current - rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),0,true,p_filter,p_reverse_weight*(1.0-blend)); + rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,0,true,p_fallback_weight,p_weights); } else { - rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),p_time,p_seek,p_filter,p_reverse_weight*(1.0-blend)); + rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_time,p_seek,p_fallback_weight,p_weights); } tn->switched=false; if (p_seek) { // don't seek prev animation - _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,0,false,p_filter,p_reverse_weight*blend); + _process_node(tn->inputs[tn->prev].node,r_prev_anim,0,false,prev_fallback_weight,&prev_weights); tn->time=p_time; } else { - _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,p_time,false,p_filter,p_reverse_weight*blend); + _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_time,false,prev_fallback_weight,&prev_weights); tn->time+=p_time; tn->prev_xfading-=p_time; if (tn->prev_xfading<0) { @@ -750,10 +822,11 @@ void AnimationTreePlayer::_process_animation(float p_delta) { AnimationNode *prev=NULL; if (reset_request) { - _process_node(out_name,&prev, 1.0, 0, true); + + _process_node(out_name,&prev, 0, true); reset_request=false; } else - _process_node(out_name,&prev, 1.0, p_delta); + _process_node(out_name,&prev, p_delta); if (dirty_caches) { //some animation changed.. ignore this pass @@ -802,7 +875,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { if (tr.track==NULL || tr.local_track<0 || tr.weight < CMP_EPSILON) continue; - float blend=tr.weight; + float blend=tr.weight / tr.track->total_weight; switch(a->track_get_type(tr.local_track)) { case Animation::TYPE_TRANSFORM: { ///< Transform a node or a bone. @@ -1904,6 +1977,3 @@ AnimationTreePlayer::~AnimationTreePlayer() { node_map.erase( node_map.front() ); } } - - - diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index dae891b5ce..6b5350e9ee 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -111,6 +111,7 @@ private: Variant value; bool skip; + float total_weight; }; @@ -273,7 +274,7 @@ private: Map<StringName,NodeBase*> node_map; // return time left to finish animation - float _process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_weight,float p_step, bool p_seek=false,const HashMap<NodePath,bool> *p_filter=NULL, float p_reverse_weight=0); + float _process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_step, bool p_seek=false, float p_fallback_weight = 1.0, HashMap<NodePath,float>* p_weights = NULL); void _process_animation(float p_delta); bool reset_request; @@ -283,6 +284,8 @@ private: void _recompute_caches(); void _recompute_caches(const StringName& p_node); DVector<String> _get_node_list(); + + void _compute_weights(float *p_fallback_weight, HashMap<NodePath,float> *p_weights, float p_coeff, const HashMap<NodePath,bool> *p_filter = NULL, float p_filtered_coeff = 0); protected: diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 31cef85aa0..b4fa463cde 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -662,8 +662,7 @@ void RichTextLabel::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - if (use_bbcode) - parse_bbcode(bbcode); + set_bbcode(bbcode); main->first_invalid_line=0; //invalidate ALL update(); @@ -1440,7 +1439,6 @@ bool RichTextLabel::is_scroll_following() const { Error RichTextLabel::parse_bbcode(const String& p_bbcode) { - clear(); return append_bbcode(p_bbcode); } @@ -1858,6 +1856,10 @@ void RichTextLabel::set_bbcode(const String& p_bbcode) { bbcode=p_bbcode; if (is_inside_tree() && use_bbcode) parse_bbcode(p_bbcode); + else { // raw text + clear(); + add_text(p_bbcode); + } } String RichTextLabel::get_bbcode() const { @@ -1869,19 +1871,37 @@ void RichTextLabel::set_use_bbcode(bool p_enable) { if (use_bbcode==p_enable) return; use_bbcode=p_enable; - if (is_inside_tree() && use_bbcode) - parse_bbcode(bbcode); + set_bbcode(bbcode); } bool RichTextLabel::is_using_bbcode() const { return use_bbcode; } + +String RichTextLabel::get_text() { + String text = ""; + Item *it = main; + while (it) { + if (it->type == ITEM_TEXT) { + ItemText *t = static_cast<ItemText*>(it); + text += t->text; + } else if (it->type == ITEM_NEWLINE) { + text += "\n"; + } else if (it->type == ITEM_INDENT) { + text += "\t"; + } + it=_get_next_item(it,true); + } + return text; +} + void RichTextLabel::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&RichTextLabel::_input_event); ObjectTypeDB::bind_method(_MD("_scroll_changed"),&RichTextLabel::_scroll_changed); + ObjectTypeDB::bind_method(_MD("get_text"),&RichTextLabel::get_text); ObjectTypeDB::bind_method(_MD("add_text","text"),&RichTextLabel::add_text); ObjectTypeDB::bind_method(_MD("add_image","image:Texture"),&RichTextLabel::add_image); ObjectTypeDB::bind_method(_MD("newline"),&RichTextLabel::add_newline); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 635fe87ad4..5147905a0e 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -280,6 +280,7 @@ protected: public: + String get_text(); void add_text(const String& p_text); void add_image(const Ref<Texture>& p_image); void add_newline(); diff --git a/scene/resources/sample_library.cpp b/scene/resources/sample_library.cpp index 73517b180e..67481f267d 100644 --- a/scene/resources/sample_library.cpp +++ b/scene/resources/sample_library.cpp @@ -106,9 +106,9 @@ void SampleLibrary::remove_sample(const StringName& p_name) { sample_map.erase(p_name); } -void SampleLibrary::get_sample_list(List<StringName> *p_samples) { +void SampleLibrary::get_sample_list(List<StringName> *p_samples) const { - for(Map<StringName,SampleData >::Element *E=sample_map.front();E;E=E->next()) { + for(const Map<StringName,SampleData >::Element *E=sample_map.front();E;E=E->next()) { p_samples->push_back(E->key()); } @@ -177,7 +177,20 @@ float SampleLibrary::sample_get_pitch_scale(const StringName& p_name) const{ return sample_map[p_name].pitch_scale; } +Array SampleLibrary::_get_sample_list() const { + List<StringName> snames; + get_sample_list(&snames); + + snames.sort_custom<StringName::AlphCompare>(); + + Array ret; + for (List<StringName>::Element *E=snames.front();E;E=E->next()) { + ret.push_back(E->get()); + } + + return ret; +} void SampleLibrary::_bind_methods() { @@ -186,6 +199,8 @@ void SampleLibrary::_bind_methods() { ObjectTypeDB::bind_method(_MD("has_sample","name"),&SampleLibrary::has_sample ); ObjectTypeDB::bind_method(_MD("remove_sample","name"),&SampleLibrary::remove_sample ); + ObjectTypeDB::bind_method(_MD("get_sample_list"),&SampleLibrary::_get_sample_list ); + ObjectTypeDB::bind_method(_MD("sample_set_volume_db","name","db"),&SampleLibrary::sample_set_volume_db ); ObjectTypeDB::bind_method(_MD("sample_get_volume_db","name"),&SampleLibrary::sample_get_volume_db ); diff --git a/scene/resources/sample_library.h b/scene/resources/sample_library.h index 8377967106..e572aa215a 100644 --- a/scene/resources/sample_library.h +++ b/scene/resources/sample_library.h @@ -47,6 +47,8 @@ class SampleLibrary : public Resource { }; Map<StringName,SampleData > sample_map; + + Array _get_sample_list() const; protected: bool _set(const StringName& p_name, const Variant& p_value); @@ -66,7 +68,7 @@ public: void sample_set_pitch_scale(const StringName& p_name, float p_pitch); float sample_get_pitch_scale(const StringName& p_name) const; Ref<Sample> get_sample(const StringName& p_name) const; - void get_sample_list(List<StringName> *p_samples); + void get_sample_list(List<StringName> *p_samples) const; void remove_sample(const StringName& p_name); StringName get_sample_idx(int p_idx) const; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 526179c41f..d89ea887fa 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -4448,12 +4448,13 @@ void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor) { cursors[p_cursor].rot = p_rotation; }; -void VisualServerRaster::cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor) { +void VisualServerRaster::cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor, const Rect2 &p_region) { VS_CHANGED; ERR_FAIL_INDEX(p_cursor, MAX_CURSORS); cursors[p_cursor].texture = p_texture; cursors[p_cursor].center = p_center_offset; + cursors[p_cursor].region = p_region; }; void VisualServerRaster::cursor_set_visible(bool p_visible, int p_cursor) { @@ -7530,8 +7531,13 @@ void VisualServerRaster::_draw_cursors_and_margins() { RID tex = cursors[i].texture?cursors[i].texture:default_cursor_texture; ERR_CONTINUE( !tex ); - Point2 size(texture_get_width(tex), texture_get_height(tex)); - rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); + if (cursors[i].region.has_no_area()) { + Point2 size(texture_get_width(tex), texture_get_height(tex)); + rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1)); + } else { + Point2 size = cursors[i].region.size; + rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), Rasterizer::CANVAS_RECT_REGION, cursors[i].region, tex, Color(1, 1, 1, 1)); + } }; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 0480d9f5cb..228a4a7c44 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -544,10 +544,12 @@ class VisualServerRaster : public VisualServer { RID texture; Point2 center; bool visible; + Rect2 region; Cursor() { rot = 0; visible = false; + region = Rect2(); }; }; @@ -1240,7 +1242,7 @@ public: /* CURSOR */ virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians - virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0); + virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor=0, const Rect2 &p_region=Rect2()); virtual void cursor_set_visible(bool p_visible, int p_cursor = 0); virtual void cursor_set_pos(const Point2& p_pos, int p_cursor = 0); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index a97b232c03..8c39b0bea1 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -680,7 +680,7 @@ public: /* CURSOR */ FUNC2(cursor_set_rotation,float , int ); // radians - FUNC3(cursor_set_texture,RID , const Point2 &, int ); + FUNC4(cursor_set_texture,RID , const Point2 &, int, const Rect2 &); FUNC2(cursor_set_visible,bool , int ); FUNC2(cursor_set_pos,const Point2& , int ); diff --git a/servers/visual_server.h b/servers/visual_server.h index f330a6faee..64318dfd72 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -1110,7 +1110,7 @@ public: /* CURSOR */ virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0)=0; // radians - virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0)=0; + virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor=0, const Rect2 &p_region=Rect2())=0; virtual void cursor_set_visible(bool p_visible, int p_cursor = 0)=0; virtual void cursor_set_pos(const Point2& p_pos, int p_cursor = 0)=0; diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index c7b78b980f..9eb6b4013f 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -693,11 +693,103 @@ void AnimationKeyEditor::_menu_add_track(int p_type) { } } +void AnimationKeyEditor::_anim_duplicate_keys(bool transpose) { + //duplicait! + if (selection.size() && animation.is_valid() && selected_track>=0 && selected_track<animation->get_track_count()) { + + int top_track=0x7FFFFFFF; + float top_time = 1e10; + for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + + const SelectedKey &sk = E->key(); + + float t = animation->track_get_key_time(sk.track,sk.key); + if (t<top_time) + top_time=t; + if (sk.track<top_track) + top_track=sk.track; + + } + ERR_FAIL_COND( top_track == 0x7FFFFFFF || top_time==1e10 ); + + // + + int start_track = transpose ? selected_track : top_track; + + undo_redo->create_action(TTR("Anim Duplicate Keys")); + + List<Pair<int,float> > new_selection_values; + + for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + + const SelectedKey &sk = E->key(); + + float t = animation->track_get_key_time(sk.track,sk.key); + + float dst_time = t+(timeline_pos - top_time); + int dst_track = sk.track + (start_track - top_track); + + if (dst_track < 0 || dst_track>= animation->get_track_count()) + continue; + + if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track)) + continue; + + int existing_idx = animation->track_find_key(dst_track,dst_time,true); + + undo_redo->add_do_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); + undo_redo->add_undo_method(animation.ptr(),"track_remove_key_at_pos",dst_track,dst_time); + + Pair<int,float> p; + p.first=dst_track; + p.second=dst_time; + new_selection_values.push_back( p ); + + if (existing_idx!=-1) { + + undo_redo->add_undo_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(dst_track,existing_idx),animation->track_get_key_transition(dst_track,existing_idx)); + + } + + } + + undo_redo->commit_action(); + + //reselect duplicated + + Map<SelectedKey,KeyInfo> new_selection; + for (List<Pair<int,float> >::Element *E=new_selection_values.front();E;E=E->next()) { + + int track=E->get().first; + float time = E->get().second; + + int existing_idx = animation->track_find_key(track,time,true); + + if (existing_idx==-1) + continue; + SelectedKey sk2; + sk2.track=track; + sk2.key=existing_idx; + + KeyInfo ki; + ki.pos=time; + + new_selection[sk2]=ki; + + } + + + selection=new_selection; + track_editor->update(); + _edit_if_single_selection(); + + } +} + void AnimationKeyEditor::_menu_track(int p_type) { ERR_FAIL_COND(!animation.is_valid()); - last_menu_track_opt=p_type; switch(p_type) { @@ -765,108 +857,7 @@ void AnimationKeyEditor::_menu_track(int p_type) { case TRACK_MENU_DUPLICATE: case TRACK_MENU_DUPLICATE_TRANSPOSE: { - - //duplicait! - if (selection.size() && animation.is_valid() && selected_track>=0 && selected_track<animation->get_track_count()) { - - - int top_track=0x7FFFFFFF; - float top_time = 1e10; - for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - - const SelectedKey &sk = E->key(); - - float t = animation->track_get_key_time(sk.track,sk.key); - if (t<top_time) - top_time=t; - if (sk.track<top_track) - top_track=sk.track; - - - } - ERR_FAIL_COND( top_track == 0x7FFFFFFF || top_time==1e10 ); - - // - - int start_track = p_type==TRACK_MENU_DUPLICATE_TRANSPOSE ? selected_track : top_track; - - - undo_redo->create_action(TTR("Anim Duplicate Keys")); - - List<Pair<int,float> > new_selection_values; - - for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - - const SelectedKey &sk = E->key(); - - float t = animation->track_get_key_time(sk.track,sk.key); - - float dst_time = t+(timeline_pos - top_time); - int dst_track = sk.track + (start_track - top_track); - - if (dst_track < 0 || dst_track>= animation->get_track_count()) - continue; - - if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track)) - continue; - - int existing_idx = animation->track_find_key(dst_track,dst_time,true); - - undo_redo->add_do_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); - undo_redo->add_undo_method(animation.ptr(),"track_remove_key_at_pos",dst_track,dst_time); - - Pair<int,float> p; - p.first=dst_track; - p.second=dst_time; - new_selection_values.push_back( p ); - - if (existing_idx!=-1) { - - undo_redo->add_undo_method(animation.ptr(),"track_insert_key",dst_track,dst_time,animation->track_get_key_value(dst_track,existing_idx),animation->track_get_key_transition(dst_track,existing_idx)); - - } - - - - } - - undo_redo->commit_action(); - - //reselect duplicated - - Map<SelectedKey,KeyInfo> new_selection; - for (List<Pair<int,float> >::Element *E=new_selection_values.front();E;E=E->next()) { - - - int track=E->get().first; - float time = E->get().second; - - int existing_idx = animation->track_find_key(track,time,true); - - if (existing_idx==-1) - continue; - SelectedKey sk2; - sk2.track=track; - sk2.key=existing_idx; - - KeyInfo ki; - ki.pos=time; - - - new_selection[sk2]=ki; - - - } - - - selection=new_selection; - track_editor->update(); - _edit_if_single_selection(); - - - } - - + _anim_duplicate_keys(p_type==TRACK_MENU_DUPLICATE_TRANSPOSE); } break; case TRACK_MENU_SET_ALL_TRANS_LINEAR: case TRACK_MENU_SET_ALL_TRANS_CONSTANT: @@ -1618,9 +1609,7 @@ void AnimationKeyEditor::_track_menu_selected(int p_idx) { undo_redo->add_do_method(animation.ptr(),"track_set_interpolation_type",interp_editing,p_idx); undo_redo->add_undo_method(animation.ptr(),"track_set_interpolation_type",interp_editing,animation->track_get_interpolation_type(interp_editing)); undo_redo->commit_action(); - } - - if (cont_editing!=-1) { + } else if (cont_editing!=-1) { ERR_FAIL_INDEX(cont_editing,animation->get_track_count()); @@ -1628,6 +1617,16 @@ void AnimationKeyEditor::_track_menu_selected(int p_idx) { undo_redo->add_do_method(animation.ptr(),"value_track_set_update_mode",cont_editing,p_idx); undo_redo->add_undo_method(animation.ptr(),"value_track_set_update_mode",cont_editing,animation->value_track_get_update_mode(cont_editing)); undo_redo->commit_action(); + } else { + switch (p_idx) { + + case RIGHT_MENU_DUPLICATE: + _anim_duplicate_keys(); break; + case RIGHT_MENU_DUPLICATE_TRANSPOSE: + _anim_duplicate_keys(true); break; + case RIGHT_MENU_REMOVE: + _anim_delete_keys(); break; + } } } @@ -1789,6 +1788,25 @@ bool AnimationKeyEditor::_edit_if_single_selection() { } +void AnimationKeyEditor::_anim_delete_keys() { + if (selection.size()) { + undo_redo->create_action(TTR("Anim Delete Keys")); + + for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { + + undo_redo->add_do_method(animation.ptr(),"track_remove_key",E->key().track,E->key().key); + undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); + + } + undo_redo->add_do_method(this,"_clear_selection_for_anim",animation); + undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation); + undo_redo->commit_action(); + //selection.clear(); + accept_event(); + _edit_if_single_selection(); + } +} + void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { Control *te=track_editor; @@ -1859,22 +1877,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { } else if (p_input.key.scancode==KEY_DELETE && p_input.key.pressed && click.click==ClickOver::CLICK_NONE) { - if (selection.size()) { - undo_redo->create_action(TTR("Anim Delete Keys")); - - for(Map<SelectedKey,KeyInfo>::Element *E=selection.back();E;E=E->prev()) { - - undo_redo->add_do_method(animation.ptr(),"track_remove_key",E->key().track,E->key().key); - undo_redo->add_undo_method(animation.ptr(),"track_insert_key",E->key().track,E->get().pos,animation->track_get_key_value(E->key().track,E->key().key),animation->track_get_key_transition(E->key().track,E->key().key)); - - } - undo_redo->add_do_method(this,"_clear_selection_for_anim",animation); - undo_redo->add_undo_method(this,"_clear_selection_for_anim",animation); - undo_redo->commit_action(); - //selection.clear(); - accept_event(); - _edit_if_single_selection(); - } + _anim_delete_keys(); } else if (animation.is_valid() && animation->get_track_count()>0) { if (p_input.is_pressed() && (p_input.is_action("ui_up") || p_input.is_action("ui_page_up"))) { @@ -1934,6 +1937,116 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) { v_scroll->set_val( v_scroll->get_val() + v_scroll->get_page() / 8 ); } + if (mb.button_index==BUTTON_RIGHT && mb.pressed) { + + Point2 mpos = Point2(mb.x,mb.y)-ofs; + + if (selection.size() == 0) { + // Auto-select on right-click if nothing is selected + // Note: This code is pretty much duplicated from the left click code, + // both codes could be moved into a function to avoid the duplicated code. + Point2 mpos = Point2(mb.x,mb.y)-ofs; + + if (mpos.y < h ) { + return; + } + + mpos.y -= h; + + int idx = mpos.y / h; + idx+=v_scroll->get_val(); + if (idx <0 || idx>=animation->get_track_count()) + break; + + if (mpos.x < name_limit) { + } else if (mpos.x < settings_limit) { + float pos = mpos.x - name_limit; + pos/=_get_zoom_scale(); + pos+=h_scroll->get_val(); + float w_time = (type_icon[0]->get_width() / _get_zoom_scale())/2.0; + + int kidx = animation->track_find_key(idx,pos); + int kidx_n = kidx+1; + int key=-1; + + if (kidx>=0 && kidx<animation->track_get_key_count(idx)) { + + float kpos = animation->track_get_key_time(idx,kidx); + if (ABS(pos-kpos)<=w_time) { + + key=kidx; + } + } + + if (key==-1 && kidx_n>=0 && kidx_n<animation->track_get_key_count(idx)) { + + float kpos = animation->track_get_key_time(idx,kidx_n); + if (ABS(pos-kpos)<=w_time) { + + key=kidx_n; + } + } + + if (key==-1) { + + click.click=ClickOver::CLICK_SELECT_KEYS; + click.at=Point2(mb.x,mb.y); + click.to=click.at; + click.shift=mb.mod.shift; + selected_track=idx; + track_editor->update(); + //drag select region + return; + + } + + + + SelectedKey sk; + sk.track=idx; + sk.key=key; + KeyInfo ki; + ki.pos= animation->track_get_key_time(idx,key); + click.shift=mb.mod.shift; + click.selk=sk; + + + if (!mb.mod.shift && !selection.has(sk)) + _clear_selection(); + + selection.insert(sk,ki); + + click.click=ClickOver::CLICK_MOVE_KEYS; + click.at=Point2(mb.x,mb.y); + click.to=click.at; + update(); + selected_track=idx; + track_editor->update(); + + if (_edit_if_single_selection() && mb.mod.command) { + edit_button->set_pressed(true); + key_editor_tab->show(); + } + } + } + + if (selection.size()) { + // User has right clicked and we have a selection, show a popup menu with options + track_menu->clear(); + track_menu->set_size(Point2(1,1)); + track_menu->add_item(TTR("Duplicate Selection"), RIGHT_MENU_DUPLICATE); + track_menu->add_item(TTR("Duplicate Transposed"), RIGHT_MENU_DUPLICATE_TRANSPOSE); + track_menu->add_item(TTR("Remove Selection"), RIGHT_MENU_REMOVE); + + track_menu->set_pos(te->get_global_pos()+mpos); + + interp_editing=-1; + cont_editing=-1; + + track_menu->popup(); + } + } + if (mb.button_index==BUTTON_LEFT && !(mb.button_mask&~BUTTON_MASK_LEFT)) { diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 413c73b4b9..131100a205 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -99,6 +99,12 @@ class AnimationKeyEditor : public VBoxContainer { CURVE_SET_CONSTANT }; + enum { + RIGHT_MENU_DUPLICATE, + RIGHT_MENU_DUPLICATE_TRANSPOSE, + RIGHT_MENU_REMOVE + }; + struct MouseOver { enum Over { @@ -313,6 +319,9 @@ class AnimationKeyEditor : public VBoxContainer { void _add_call_track(const NodePath& p_base); + void _anim_duplicate_keys(bool transpose = false); + void _anim_delete_keys(); + void _root_removed(); protected: diff --git a/tools/editor/create_dialog.cpp b/tools/editor/create_dialog.cpp index 5275e1beeb..210b799f3d 100644 --- a/tools/editor/create_dialog.cpp +++ b/tools/editor/create_dialog.cpp @@ -42,12 +42,13 @@ void CreateDialog::popup(bool p_dontclear) { - popup_centered_ratio(0.6); + popup_centered_ratio(); if (p_dontclear) search_box->select_all(); else search_box->clear(); search_box->grab_focus(); + _update_search(); @@ -165,9 +166,10 @@ void CreateDialog::_update_search() { if (!ObjectTypeDB::can_instance(type)) continue; // cant create what can't be instanced - if (search_box->get_text()=="") + + if (search_box->get_text()=="") { add_type(type,types,root,&to_select); - else { + } else { bool found=false; String type=I->get(); @@ -186,7 +188,7 @@ void CreateDialog::_update_search() { add_type(I->get(),types,root,&to_select); } - if (EditorNode::get_editor_data().get_custom_types().has(type)) { + if (EditorNode::get_editor_data().get_custom_types().has(type) && ObjectTypeDB::is_type(type, base_type)) { //there are custom types based on this... cool. //print_line("there are custom types"); @@ -198,6 +200,7 @@ void CreateDialog::_update_search() { if (!show) continue; + if (!types.has(type)) add_type(type,types,root,&to_select); @@ -216,7 +219,7 @@ void CreateDialog::_update_search() { } - if (!to_select && (search_box->get_text()=="" || ct[i].name.findn(search_box->get_text())!=-1)) { + if (!to_select) { to_select=item; } @@ -246,7 +249,6 @@ void CreateDialog::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { connect("confirmed",this,"_confirmed"); - _update_search(); } if (p_what==NOTIFICATION_EXIT_TREE) { diff --git a/tools/editor/editor_autoload_settings.cpp b/tools/editor/editor_autoload_settings.cpp new file mode 100644 index 0000000000..1cf0090e7e --- /dev/null +++ b/tools/editor/editor_autoload_settings.cpp @@ -0,0 +1,618 @@ +/*************************************************************************/ +/* editor_autoload_settings.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "editor_autoload_settings.h" + +#include "globals.h" +#include "global_constants.h" + +#include "editor_node.h" + +#define PREVIEW_LIST_MAX_SIZE 10 + +StringName EditorAutoloadSettings::autoload_changed = StringName(); + +void EditorAutoloadSettings::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + List<String> afn; + ResourceLoader::get_recognized_extensions_for_type("Script", &afn); + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &afn); + + EditorFileDialog *file_dialog = autoload_add_path->get_file_dialog(); + + for (List<String>::Element *E = afn.front(); E; E = E->next()) { + + file_dialog->add_filter("*." + E->get()); + } + } +} + +bool EditorAutoloadSettings::_autoload_name_is_valid(const String& p_name, String* r_error) { + + if (!p_name.is_valid_identifier()) { + if (r_error) + *r_error = TTR("Invalid name.") + "\n" + TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"; + + return false; + } + + if (ObjectTypeDB::type_exists(p_name)) { + if (r_error) + *r_error = TTR("Invalid name. Must not collide with an existing engine class name."); + + return false; + } + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (Variant::get_type_name( Variant::Type(i) ) == p_name) { + if (r_error) + *r_error = TTR("Invalid name. Must not collide with an existing buit-in type name."); + + return false; + } + } + + for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { + if (GlobalConstants::get_global_constant_name(i) == p_name) { + if (r_error) + *r_error = TTR("Invalid name. Must not collide with an existing global constant name."); + + return false; + } + } + + return true; +} + +void EditorAutoloadSettings::_autoload_add() { + + String name = autoload_add_name->get_text(); + + String error; + if (!_autoload_name_is_valid(name, &error)) { + EditorNode::get_singleton()->show_warning(error); + return; + } + + String path = autoload_add_path->get_line_edit()->get_text(); + if (!FileAccess::exists(path)) { + EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n" + TTR("File does not exist.")); + return; + } + + if (!path.begins_with("res://")) { + EditorNode::get_singleton()->show_warning(TTR("Invalid Path.") + "\n"+ TTR("Not in resource path.")); + return; + } + + name = "autoload/" + name; + + UndoRedo* undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(TTR("Add AutoLoad")); + undo_redo->add_do_property(Globals::get_singleton(), name, "*" + path); + undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, true); + + if (Globals::get_singleton()->has(name)) { + undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); + } else { + undo_redo->add_undo_property(Globals::get_singleton(), name, Variant()); + } + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); + + autoload_add_path->get_line_edit()->set_text(""); + autoload_add_name->set_text(""); +} + +void EditorAutoloadSettings::_autoload_selected() { + + TreeItem *ti = tree->get_selected(); + + if (!ti) + return; + + selected_autoload = "autoload/" + ti->get_text(0); +} + +void EditorAutoloadSettings::_autoload_edited() { + + if (updating_autoload) + return; + + TreeItem *ti = tree->get_edited(); + int column = tree->get_edited_column(); + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + if (column == 0) { + String name = ti->get_text(0); + String old_name = selected_autoload.get_slice("/", 1); + + if (name == old_name) + return; + + String error; + if (!_autoload_name_is_valid(name, &error)) { + ti->set_text(0, old_name); + EditorNode::get_singleton()->show_warning(error); + return; + } + + if (Globals::get_singleton()->has("autoload/" + name)) { + ti->set_text(0, old_name); + EditorNode::get_singleton()->show_warning(vformat(TTR("Autoload '%s' already exists!"), name)); + return; + } + + updating_autoload = true; + + name = "autoload/" + name; + + bool persisting = Globals::get_singleton()->get(selected_autoload); + int order = Globals::get_singleton()->get(selected_autoload); + String path = Globals::get_singleton()->get(selected_autoload); + + undo_redo->create_action(TTR("Rename Autoload")); + + undo_redo->add_do_property(Globals::get_singleton(), name, path); + undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, persisting); + undo_redo->add_do_method(Globals::get_singleton(), "set_order", name, order); + undo_redo->add_do_method(Globals::get_singleton(), "clear", selected_autoload); + + undo_redo->add_undo_property(Globals::get_singleton(), selected_autoload, path); + undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", selected_autoload, persisting); + undo_redo->add_undo_method(Globals::get_singleton(), "set_order", selected_autoload, order); + undo_redo->add_undo_method(Globals::get_singleton(), "clear", name); + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); + + selected_autoload = name; + } else if (column == 2) { + updating_autoload = true; + + bool checked = ti->is_checked(2); + String base = "autoload/" + ti->get_text(0); + + int order = Globals::get_singleton()->get_order(base); + String path = Globals::get_singleton()->get(base); + + if (path.begins_with("*")) + path = path.substr(1, path.length()); + + if (checked) + path = "*" + path; + + undo_redo->create_action(TTR("Toggle AutoLoad Globals")); + + undo_redo->add_do_property(Globals::get_singleton(), base, path); + undo_redo->add_undo_property(Globals::get_singleton(), base, Globals::get_singleton()->get(base)); + + undo_redo->add_do_method(Globals::get_singleton(),"set_order", base, order); + undo_redo->add_undo_method(Globals::get_singleton(),"set_order", base, order); + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); + } + + updating_autoload = false; +} + +void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_column, int p_button) { + + TreeItem *ti = p_item->cast_to<TreeItem>(); + + String name = "autoload/" + ti->get_text(0); + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + switch (p_button) { + + case BUTTON_MOVE_UP: + case BUTTON_MOVE_DOWN: { + + TreeItem *swap = NULL; + + if (p_button == BUTTON_MOVE_UP) { + swap = ti->get_prev(); + } else { + swap = ti->get_next(); + } + + if (!swap) + return; + + String swap_name = "autoload/" + swap->get_text(0); + + int order = Globals::get_singleton()->get_order(name); + int swap_order = Globals::get_singleton()->get_order(swap_name); + + undo_redo->create_action(TTR("Move Autoload")); + + undo_redo->add_do_method(Globals::get_singleton(), "set_order", name, swap_order); + undo_redo->add_undo_method(Globals::get_singleton(), "set_order", name, order); + + undo_redo->add_do_method(Globals::get_singleton(), "set_order", swap_name, order); + undo_redo->add_undo_method(Globals::get_singleton(), "set_order", swap_name, swap_order); + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); + } break; + case BUTTON_DELETE: { + + int order = Globals::get_singleton()->get_order(name); + + undo_redo->create_action(TTR("Remove Autoload")); + + undo_redo->add_do_property(Globals::get_singleton(), name, Variant()); + + undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); + undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", name, true); + undo_redo->add_undo_method(Globals::get_singleton(), "set_order", order); + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); + } break; + } +} + +void EditorAutoloadSettings::_autoload_file_callback(const String& p_path) { + + autoload_add_name->set_text(p_path.get_file().basename()); +} + +void EditorAutoloadSettings::update_autoload() { + + if (updating_autoload) + return; + + updating_autoload = true; + + autoload_cache.clear(); + + tree->clear(); + TreeItem *root = tree->create_item(); + + List<PropertyInfo> props; + Globals::get_singleton()->get_property_list(&props); + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + const PropertyInfo &pi = E->get(); + + if (!pi.name.begins_with("autoload/")) + continue; + + String name = pi.name.get_slice("/", 1); + String path = Globals::get_singleton()->get(pi.name); + + if (name.empty()) + continue; + + AutoLoadInfo info; + info.name = pi.name; + info.order = Globals::get_singleton()->get_order(pi.name); + + autoload_cache.push_back(info); + + bool global = false; + + if (path.begins_with("*")) { + global = true; + path = path.substr(1, path.length()); + } + + TreeItem *item = tree->create_item(root); + item->set_text(0, name); + item->set_editable(0, true); + + item->set_text(1, path); + item->set_selectable(1, false); + + item->set_cell_mode(2, TreeItem::CELL_MODE_CHECK); + item->set_editable(2, true); + item->set_text(2, TTR("Enable")); + item->set_checked(2, global); + + item->add_button(3, get_icon("MoveUp","EditorIcons"), BUTTON_MOVE_UP); + item->add_button(3, get_icon("MoveDown","EditorIcons"), BUTTON_MOVE_DOWN); + item->add_button(3, get_icon("Del","EditorIcons"), BUTTON_DELETE); + item->set_selectable(3, false); + } + + updating_autoload = false; +} + +Variant EditorAutoloadSettings::get_drag_data_fw(const Point2& p_point, Control *p_control) { + + if (autoload_cache.size() <= 1) + return false; + + StringArray autoloads; + + TreeItem *next = tree->get_next_selected(NULL); + + while (next) { + autoloads.push_back(next->get_text(0)); + next = tree->get_next_selected(next); + } + + if (autoloads.size() == 0 || autoloads.size() == autoload_cache.size()) + return Variant(); + + VBoxContainer *preview = memnew( VBoxContainer ); + + int max_size = MIN(PREVIEW_LIST_MAX_SIZE, autoloads.size()); + + for (int i = 0; i < max_size; i++) { + Label *label = memnew( Label(autoloads[i]) ); + label->set_self_opacity(Math::lerp(1, 0, float(i)/PREVIEW_LIST_MAX_SIZE)); + + preview->add_child(label); + } + + tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN); + tree->set_drag_preview(preview); + + Dictionary drop_data; + drop_data["type"] = "autoload"; + drop_data["autoloads"] = autoloads; + + return drop_data; +} + +bool EditorAutoloadSettings::can_drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_control) const { + if (updating_autoload) + return false; + + Dictionary drop_data = p_data; + + if (!drop_data.has("type")) + return false; + + if (drop_data.has("type")) { + TreeItem *ti = tree->get_item_at_pos(p_point); + + if (!ti) + return false; + + int section = tree->get_drop_section_at_pos(p_point); + + if (section < -1) + return false; + + return true; + } + + return false; +} + +void EditorAutoloadSettings::drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_control) { + + TreeItem *ti = tree->get_item_at_pos(p_point); + + if (!ti) + return; + + int section = tree->get_drop_section_at_pos(p_point); + + if (section < -1) + return; + + String name; + bool move_to_back = false; + + if (section < 0) { + name = ti->get_text(0); + } else if (ti->get_next()) { + name = ti->get_next()->get_text(0); + } else { + name = ti->get_text(0); + move_to_back = true; + } + + int order = Globals::get_singleton()->get_order("autoload/" + name); + + AutoLoadInfo aux; + List<AutoLoadInfo>::Element *E = NULL; + + if (!move_to_back) { + aux.order = order; + E = autoload_cache.find(aux); + } + + Dictionary drop_data = p_data; + StringArray autoloads = drop_data["autoloads"]; + + Vector<int> orders; + orders.resize(autoload_cache.size()); + + for (int i = 0; i < autoloads.size(); i++) { + aux.order = Globals::get_singleton()->get_order("autoload/" + autoloads[i]); + + List<AutoLoadInfo>::Element *I = autoload_cache.find(aux); + + if (move_to_back) { + autoload_cache.move_to_back(I); + } else if (E != I) { + autoload_cache.move_before(I, E); + } else if (E->next()) { + E = E->next(); + } else { + break; + } + } + + int i = 0; + + for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { + orders[i++] = E->get().order; + } + + orders.sort(); + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + undo_redo->create_action(TTR("Rearrange Autoloads")); + + i = 0; + + for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { + undo_redo->add_do_method(Globals::get_singleton(), "set_order", E->get().name, orders[i++]); + undo_redo->add_undo_method(Globals::get_singleton(), "set_order", E->get().name, E->get().order); + } + + orders.clear(); + + undo_redo->add_do_method(this, "update_autoload"); + undo_redo->add_undo_method(this, "update_autoload"); + + undo_redo->add_do_method(this, "emit_signal", autoload_changed); + undo_redo->add_undo_method(this, "emit_signal", autoload_changed); + + undo_redo->commit_action(); +} + +void EditorAutoloadSettings::_bind_methods() { + + ObjectTypeDB::bind_method("_autoload_add", &EditorAutoloadSettings::_autoload_add); + ObjectTypeDB::bind_method("_autoload_selected", &EditorAutoloadSettings::_autoload_selected); + ObjectTypeDB::bind_method("_autoload_edited", &EditorAutoloadSettings::_autoload_edited); + ObjectTypeDB::bind_method("_autoload_button_pressed", &EditorAutoloadSettings::_autoload_button_pressed); + ObjectTypeDB::bind_method("_autoload_file_callback", &EditorAutoloadSettings::_autoload_file_callback); + + ObjectTypeDB::bind_method("get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw); + ObjectTypeDB::bind_method("can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw); + ObjectTypeDB::bind_method("drop_data_fw", &EditorAutoloadSettings::drop_data_fw); + + ObjectTypeDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload); + + ADD_SIGNAL(MethodInfo("autoload_changed")); +} + +EditorAutoloadSettings::EditorAutoloadSettings() { + + autoload_changed = "autoload_changed"; + + updating_autoload = false; + selected_autoload = ""; + + HBoxContainer *hbc = memnew( HBoxContainer ); + add_child(hbc); + + VBoxContainer *vbc_path = memnew( VBoxContainer ); + vbc_path->set_h_size_flags(SIZE_EXPAND_FILL); + + autoload_add_path = memnew( EditorLineEditFileChooser ); + autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL); + + autoload_add_path->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE); + autoload_add_path->get_file_dialog()->connect("file_selected", this, "_autoload_file_callback"); + + vbc_path->add_margin_child(TTR("Path:"), autoload_add_path); + hbc->add_child(vbc_path); + + VBoxContainer *vbc_name = memnew( VBoxContainer ); + vbc_name->set_h_size_flags(SIZE_EXPAND_FILL); + + HBoxContainer *hbc_name = memnew( HBoxContainer ); + + autoload_add_name = memnew( LineEdit ); + autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); + hbc_name->add_child(autoload_add_name); + + Button *add_autoload = memnew( Button ); + add_autoload->set_text(TTR("Add")); + hbc_name->add_child(add_autoload); + add_autoload->connect("pressed", this, "_autoload_add"); + + vbc_name->add_margin_child(TTR("Node Name:"), hbc_name); + hbc->add_child(vbc_name); + + tree = memnew( Tree ); + tree->set_hide_root(true); + tree->set_select_mode(Tree::SELECT_MULTI); + tree->set_single_select_cell_editing_only_when_already_selected(true); + + tree->set_drag_forwarding(this); + + tree->set_columns(4); + tree->set_column_titles_visible(true); + + tree->set_column_title(0,TTR("Name")); + tree->set_column_expand(0,true); + tree->set_column_min_width(0,100); + + tree->set_column_title(1,TTR("Path")); + tree->set_column_expand(1,true); + tree->set_column_min_width(1,100); + + tree->set_column_title(2,TTR("Singleton")); + tree->set_column_expand(2,false); + tree->set_column_min_width(2,80); + + tree->set_column_expand(3,false); + tree->set_column_min_width(3,80); + + tree->connect("cell_selected", this, "_autoload_selected"); + tree->connect("item_edited", this, "_autoload_edited"); + tree->connect("button_pressed", this, "_autoload_button_pressed"); + + add_margin_child(TTR("List:"), tree, true); +} + diff --git a/tools/editor/editor_autoload_settings.h b/tools/editor/editor_autoload_settings.h new file mode 100644 index 0000000000..b8825f807c --- /dev/null +++ b/tools/editor/editor_autoload_settings.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* editor_autoload_settings.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef EDITOR_AUTOLOAD_SETTINGS_H +#define EDITOR_AUTOLOAD_SETTINGS_H + +#include "scene/gui/tree.h" + +#include "editor_file_dialog.h" + +class EditorAutoloadSettings : public VBoxContainer { + + OBJ_TYPE( EditorAutoloadSettings, VBoxContainer ); + + enum { + BUTTON_MOVE_UP, + BUTTON_MOVE_DOWN, + BUTTON_DELETE + }; + + static StringName autoload_changed; + + struct AutoLoadInfo { + String name; + int order; + + bool operator==(const AutoLoadInfo& p_info) { + return order == p_info.order; + } + }; + + List<AutoLoadInfo> autoload_cache; + + bool updating_autoload; + int number_of_autoloads; + String selected_autoload; + + Tree *tree; + EditorLineEditFileChooser *autoload_add_path; + LineEdit *autoload_add_name; + + bool _autoload_name_is_valid(const String& p_string, String *r_error = NULL); + + void _autoload_add(); + void _autoload_selected(); + void _autoload_edited(); + void _autoload_button_pressed(Object *p_item, int p_column, int p_button); + void _autoload_file_callback(const String& p_path); + + Variant get_drag_data_fw(const Point2& p_point, Control *p_from); + bool can_drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_from) const; + void drop_data_fw(const Point2& p_point, const Variant& p_data, Control *p_from); + +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void update_autoload(); + + EditorAutoloadSettings(); + +}; + +#endif + diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 89d7f8f3ce..c0887d7b71 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -2494,7 +2494,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { #endif case RESOURCE_NEW: { - create_dialog->popup_centered_ratio(); + create_dialog->popup(true); } break; case RESOURCE_LOAD: { diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 91a347c69b..a70df78697 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -77,21 +77,30 @@ void SpatialEditorViewport::_update_camera() { String SpatialEditorGizmo::get_handle_name(int p_idx) const { + if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) + return get_script_instance()->call("get_handle_name", p_idx); + return ""; } Variant SpatialEditorGizmo::get_handle_value(int p_idx) const{ + if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) + return get_script_instance()->call("get_handle_value", p_idx); + return Variant(); } void SpatialEditorGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point) { + if (get_script_instance() && get_script_instance()->has_method("set_handle")) + get_script_instance()->call("set_handle", p_idx, p_camera, p_point); } void SpatialEditorGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){ - + if (get_script_instance() && get_script_instance()->has_method("commit_handle")) + get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel); } bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum) { diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp index 9d27ac8aa3..d686c37d1a 100644 --- a/tools/editor/plugins/tile_map_editor_plugin.cpp +++ b/tools/editor/plugins/tile_map_editor_plugin.cpp @@ -412,6 +412,24 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i& p_point, bool p_flip_h if (node->get_tile_origin()==TileMap::TILE_ORIGIN_TOP_LEFT) { rect.pos+=tile_ofs; + } else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_BOTTOM_LEFT) { + Size2 cell_size = node->get_cell_size(); + + rect.pos+=tile_ofs; + + if(p_transpose) + { + if(p_flip_h) + rect.pos.x-=cell_size.x; + else + rect.pos.x+=cell_size.x; + } else { + if(p_flip_v) + rect.pos.y-=cell_size.y; + else + rect.pos.y+=cell_size.y; + } + } else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_CENTER) { rect.pos+=node->get_cell_size()/2; Vector2 s = r.size; diff --git a/tools/editor/plugins/tile_set_editor_plugin.cpp b/tools/editor/plugins/tile_set_editor_plugin.cpp index a2c7147bf3..39a15189e7 100644 --- a/tools/editor/plugins/tile_set_editor_plugin.cpp +++ b/tools/editor/plugins/tile_set_editor_plugin.cpp @@ -73,24 +73,24 @@ void TileSetEditor::_import_scene(Node *scene, Ref<TileSet> p_library, bool p_me p_library->tile_set_name(id,mi->get_name()); } - - p_library->tile_set_texture(id,texture); p_library->tile_set_material(id,material); Vector2 phys_offset; + Size2 s; - if (mi->is_centered()) { - Size2 s; - if (mi->is_region()) { - s=mi->get_region_rect().size; - } else { - s=texture->get_size(); - } - phys_offset+=-s/2; - } if (mi->is_region()) { + s=mi->get_region_rect().size; p_library->tile_set_region(id,mi->get_region_rect()); + } else { + const int frame = mi->get_frame(); + const int hframes = mi->get_hframes(); + s=texture->get_size()/Size2(hframes,mi->get_vframes()); + p_library->tile_set_region(id,Rect2(Vector2(frame%hframes,frame/hframes)*s,s)); + } + + if (mi->is_centered()) { + phys_offset+=-s/2; } Vector<Ref<Shape2D> >collisions; diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp index 6822e50b73..6be1abf52f 100644 --- a/tools/editor/project_settings.cpp +++ b/tools/editor/project_settings.cpp @@ -100,16 +100,6 @@ void ProjectSettings::_notification(int p_what) { translation_res_file_open->add_filter("*."+E->get()); translation_res_option_file_open->add_filter("*."+E->get()); } - - List<String> afn; - ResourceLoader::get_recognized_extensions_for_type("Script",&afn); - ResourceLoader::get_recognized_extensions_for_type("PackedScene",&afn); - - for (List<String>::Element *E=afn.front();E;E=E->next()) { - - autoload_file_open->add_filter("*."+E->get()); - } - } } @@ -564,7 +554,7 @@ void ProjectSettings::popup_project_settings() { popup_centered_ratio(); globals_editor->update_category_list(); _update_translations(); - _update_autoload(); + autoload_settings->update_autoload(); plugin_settings->update_plugins(); } @@ -616,10 +606,26 @@ void ProjectSettings::_item_add() { String name = catname!="" ? catname+"/"+propname : propname; - Globals::get_singleton()->set(name,value); + undo_redo->create_action("Add Global Property"); + + undo_redo->add_do_property(Globals::get_singleton(), name, value); + undo_redo->add_do_method(Globals::get_singleton(), "set_persisting", name, true); + + if (Globals::get_singleton()->has(name)) { + undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); + } else { + undo_redo->add_undo_property(Globals::get_singleton(), name, Variant()); + } + + undo_redo->add_do_method(globals_editor, "update_category_list"); + undo_redo->add_undo_method(globals_editor, "update_category_list"); + + undo_redo->add_do_method(this, "_settings_changed"); + undo_redo->add_undo_method(this, "_settings_changed"); + + undo_redo->commit_action(); globals_editor->set_current_section(catname); - globals_editor->update_category_list(); _settings_changed(); } @@ -633,10 +639,20 @@ void ProjectSettings::_item_del() { String name = catname!="" ? catname+"/"+propname : propname; - Globals::get_singleton()->set(name,Variant()); + undo_redo->create_action("Delete Global Property"); - globals_editor->set_current_section(catname); - globals_editor->update_category_list(); + undo_redo->add_do_property(Globals::get_singleton(), name, Variant()); + + undo_redo->add_undo_property(Globals::get_singleton(), name, Globals::get_singleton()->get(name)); + undo_redo->add_undo_method(Globals::get_singleton(), "set_persisting", name, Globals::get_singleton()->is_persisting(name)); + + undo_redo->add_do_method(globals_editor, "update_category_list"); + undo_redo->add_undo_method(globals_editor, "update_category_list"); + + undo_redo->add_do_method(this, "_settings_changed"); + undo_redo->add_undo_method(this, "_settings_changed"); + + undo_redo->commit_action(); _settings_changed(); } @@ -811,263 +827,6 @@ void ProjectSettings::_translation_file_open() { translation_file_open->popup_centered_ratio(); } - -void ProjectSettings::_autoload_file_callback(const String& p_path) { - - autoload_add_path->set_text(p_path); - //if (autoload_add_name->get_text().strip_edges()==String()) { - - autoload_add_name->set_text( p_path.get_file().basename() ); - //} - - //_translation_add(p_translation); -} - -void ProjectSettings::_autoload_file_open() { - - autoload_file_open->popup_centered_ratio(); -} - -void ProjectSettings::_autoload_edited() { - - if (updating_autoload) - return; - - TreeItem *ti = autoload_list->get_edited(); - int column = autoload_list->get_edited_column(); - - if (!ti || (column != 0 && column != 2)) - return; - - if (column == 0) { - String name = ti->get_text(0); - String old_name = selected_autoload.substr(selected_autoload.find("/")+1,selected_autoload.length()); - - if (!name.is_valid_identifier()) { - ti->set_text(0,old_name); - message->set_text(TTR("Invalid name.")+"\n"+TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"); - message->popup_centered(Size2(300,100)); - return; - } - - if (ObjectTypeDB::type_exists(name)) { - ti->set_text(0,old_name); - message->set_text(TTR("Invalid name. Must not collide with an existing engine class name.")); - message->popup_centered(Size2(400,100)); - return; - } - - for(int i=0;i<Variant::VARIANT_MAX;i++) { - if (Variant::get_type_name(Variant::Type(i))==name) { - ti->set_text(0,old_name); - message->set_text(TTR("Invalid name. Must not collide with an existing buit-in type name.")); - message->popup_centered(Size2(400,100)); - return; - } - } - - for(int i=0;i<GlobalConstants::get_global_constant_count();i++) { - if (GlobalConstants::get_global_constant_name(i)==name) { - ti->set_text(0,old_name); - message->set_text(TTR("Invalid name. Must not collide with an existing global constant name.")); - message->popup_centered(Size2(400,100)); - return; - } - } - - if (Globals::get_singleton()->has("autoload/"+name)) { - ti->set_text(0,old_name); - message->set_text(vformat(TTR("Autoload '%s' already exists!"),name)); - message->popup_centered(Size2(300,100)); - return; - } - - updating_autoload = true; - - name = "autoload/"+name; - String path = Globals::get_singleton()->get(selected_autoload); - bool is_persisting = Globals::get_singleton()->is_persisting(selected_autoload); - int order = Globals::get_singleton()->get_order(selected_autoload); - - undo_redo->create_action(TTR("Rename Autoload")); - undo_redo->add_do_property(Globals::get_singleton(),name,path); - undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",name,is_persisting); - undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,order); - undo_redo->add_do_method(Globals::get_singleton(),"clear",selected_autoload); - undo_redo->add_undo_property(Globals::get_singleton(),selected_autoload,path); - undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",selected_autoload,is_persisting); - undo_redo->add_undo_method(Globals::get_singleton(),"set_order",selected_autoload,order); - undo_redo->add_undo_method(Globals::get_singleton(),"clear",name); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); - - selected_autoload = name; - } else if (column == 2) { - updating_autoload = true; - - bool checked = ti->is_checked(2); - String base = "autoload/"+ti->get_text(0); - String path = Globals::get_singleton()->get(base); - int order = Globals::get_singleton()->get_order(base); - - if (path.begins_with("*")) - path = path.substr(1,path.length()); - - if (checked) - path = "*" + path; - - undo_redo->create_action(TTR("Toggle AutoLoad Globals")); - undo_redo->add_do_property(Globals::get_singleton(),base,path); - undo_redo->add_undo_property(Globals::get_singleton(),base,Globals::get_singleton()->get(base)); - undo_redo->add_do_method(Globals::get_singleton(),"set_order",base,order); // keep order, as config order matters for these - undo_redo->add_undo_method(Globals::get_singleton(),"set_order",base,order); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); - } - - updating_autoload = false; -} - -void ProjectSettings::_autoload_add() { - - String name = autoload_add_name->get_text(); - if (!name.is_valid_identifier()) { - message->set_text(TTR("Invalid name.")+"\n"+TTR("Valid characters:")+" a-z, A-Z, 0-9 or _"); - message->popup_centered(Size2(300,100)); - return; - - } - - if (ObjectTypeDB::type_exists(name)) { - - message->set_text(TTR("Invalid name. Must not collide with an existing engine class name.")); - message->popup_centered(Size2(300,100)); - return; - - } - - for(int i=0;i<Variant::VARIANT_MAX;i++) { - if (Variant::get_type_name(Variant::Type(i))==name) { - - message->set_text(TTR("Invalid name. Must not collide with an existing buit-in type name.")); - message->popup_centered(Size2(300,100)); - return; - - } - } - - for(int i=0;i<GlobalConstants::get_global_constant_count();i++) { - - if (GlobalConstants::get_global_constant_name(i)==name) { - - message->set_text(TTR("Invalid name. Must not collide with an existing global constant name.")); - message->popup_centered(Size2(300,100)); - return; - } - - } - - String path = autoload_add_path->get_text(); - if (!FileAccess::exists(path)) { - message->set_text("Invalid Path.\nFile does not exist."); - message->popup_centered(Size2(300,100)); - return; - - } - if (!path.begins_with("res://")) { - message->set_text("Invalid Path.\nNot in resource path."); - message->popup_centered(Size2(300,100)); - return; - - } - - undo_redo->create_action(TTR("Add Autoload")); - name = "autoload/"+name; - undo_redo->add_do_property(Globals::get_singleton(),name,"*"+path); - if (Globals::get_singleton()->has(name)) - undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); - else - undo_redo->add_undo_property(Globals::get_singleton(),name,Variant()); - - undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",name,true); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); - - autoload_add_path->set_text(""); - autoload_add_name->set_text(""); - - //autoload_file_open->popup_centered_ratio(); -} - -void ProjectSettings::_autoload_delete(Object *p_item,int p_column, int p_button) { - - - TreeItem *ti=p_item->cast_to<TreeItem>(); - String name = "autoload/"+ti->get_text(0); - - if (p_button==0) { - //delete - int order = Globals::get_singleton()->get_order(name); - undo_redo->create_action(TTR("Remove Autoload")); - undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); - undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); - undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); - undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,order); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); - } else { - - TreeItem *swap = NULL; - - if (p_button==1) { - swap=ti->get_prev(); - } else if (p_button==2) { - swap=ti->get_next(); - } - if (!swap) - return; - - String swap_name= "autoload/"+swap->get_text(0); - - int order = Globals::get_singleton()->get_order(name); - int swap_order = Globals::get_singleton()->get_order(swap_name); - - undo_redo->create_action(TTR("Move Autoload")); - undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,order); - undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,swap_order); - undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,swap_order); - undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,order); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); - - } - -} - -void ProjectSettings::_autoload_selected() { - TreeItem *ti = autoload_list->get_selected(); - - if (!ti) - return; - - selected_autoload = "autoload/"+ti->get_text(0); -} - void ProjectSettings::_translation_delete(Object *p_item,int p_column, int p_button) { TreeItem *ti = p_item->cast_to<TreeItem>(); @@ -1393,55 +1152,6 @@ void ProjectSettings::_update_translations() { } -void ProjectSettings::_update_autoload() { - - if (updating_autoload) - return; - - updating_autoload=true; - - autoload_list->clear(); - TreeItem *root = autoload_list->create_item(); - autoload_list->set_hide_root(true); - - List<PropertyInfo> props; - Globals::get_singleton()->get_property_list(&props); - - for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { - - const PropertyInfo &pi=E->get(); - if (!pi.name.begins_with("autoload/")) - continue; - - String name = pi.name.get_slice("/",1); - String path = Globals::get_singleton()->get(pi.name); - - if (name=="") - continue; - bool global=false; - if (path.begins_with("*")) { - path=path.substr(1,path.length()); - global=true; - } - TreeItem *t = autoload_list->create_item(root); - t->set_text(0,name); - t->set_editable(0,true); - t->set_text(1,path); - t->set_cell_mode(2,TreeItem::CELL_MODE_CHECK); - t->set_editable(2,true); - t->set_text(2,TTR("Enable")); - t->set_checked(2,global); - t->add_button(3,get_icon("MoveUp","EditorIcons"),1); - t->add_button(3,get_icon("MoveDown","EditorIcons"),2); - t->add_button(3,get_icon("Del","EditorIcons"),0); - - - } - - updating_autoload=false; - -} - void ProjectSettings::_toggle_search_bar(bool p_pressed) { globals_editor->get_property_editor()->set_use_filter(p_pressed); @@ -1508,14 +1218,6 @@ void ProjectSettings::_bind_methods() { ObjectTypeDB::bind_method(_MD("_translation_res_delete"),&ProjectSettings::_translation_res_delete); ObjectTypeDB::bind_method(_MD("_translation_res_option_delete"),&ProjectSettings::_translation_res_option_delete); - ObjectTypeDB::bind_method(_MD("_autoload_add"),&ProjectSettings::_autoload_add); - ObjectTypeDB::bind_method(_MD("_autoload_file_open"),&ProjectSettings::_autoload_file_open); - ObjectTypeDB::bind_method(_MD("_autoload_file_callback"),&ProjectSettings::_autoload_file_callback); - ObjectTypeDB::bind_method(_MD("_update_autoload"),&ProjectSettings::_update_autoload); - ObjectTypeDB::bind_method(_MD("_autoload_delete"),&ProjectSettings::_autoload_delete); - ObjectTypeDB::bind_method(_MD("_autoload_edited"),&ProjectSettings::_autoload_edited); - ObjectTypeDB::bind_method(_MD("_autoload_selected"),&ProjectSettings::_autoload_selected); - ObjectTypeDB::bind_method(_MD("_clear_search_box"),&ProjectSettings::_clear_search_box); ObjectTypeDB::bind_method(_MD("_toggle_search_bar"),&ProjectSettings::_toggle_search_bar); @@ -1858,69 +1560,10 @@ ProjectSettings::ProjectSettings(EditorData *p_data) { { - VBoxContainer *avb = memnew( VBoxContainer ); - tab_container->add_child(avb); - avb->set_name(TTR("AutoLoad")); - HBoxContainer *ahb = memnew( HBoxContainer); - avb->add_child(ahb); - - - VBoxContainer *avb_path = memnew( VBoxContainer ); - avb_path->set_h_size_flags(SIZE_EXPAND_FILL); - HBoxContainer *ahb_path = memnew( HBoxContainer ); - autoload_add_path = memnew(LineEdit); - autoload_add_path->set_h_size_flags(SIZE_EXPAND_FILL); - ahb_path->add_child(autoload_add_path); - Button *browseaa = memnew( Button("..") ); - ahb_path->add_child(browseaa); - browseaa->connect("pressed",this,"_autoload_file_open"); - - avb_path->add_margin_child(TTR("Path:"),ahb_path); - ahb->add_child(avb_path); - - VBoxContainer *avb_name = memnew( VBoxContainer ); - avb_name->set_h_size_flags(SIZE_EXPAND_FILL); - - HBoxContainer *ahb_name = memnew( HBoxContainer ); - autoload_add_name = memnew(LineEdit); - autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); - ahb_name->add_child(autoload_add_name); - avb_name->add_margin_child(TTR("Node Name:"),ahb_name); - Button *addaa = memnew( Button(TTR("Add")) ); - ahb_name->add_child(addaa); - addaa->connect("pressed",this,"_autoload_add"); - - ahb->add_child(avb_name); - - autoload_list = memnew( Tree ); - autoload_list->set_v_size_flags(SIZE_EXPAND_FILL); - avb->add_margin_child(TTR("List:"),autoload_list,true); - - autoload_file_open=memnew( EditorFileDialog ); - add_child(autoload_file_open); - autoload_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE); - autoload_file_open->connect("file_selected",this,"_autoload_file_callback"); - - autoload_list->set_columns(4); - autoload_list->set_column_titles_visible(true); - autoload_list->set_column_title(0,TTR("Name")); - autoload_list->set_column_expand(0,true); - autoload_list->set_column_min_width(0,100); - autoload_list->set_column_title(1,TTR("Path")); - autoload_list->set_column_expand(1,true); - autoload_list->set_column_min_width(1,100); - autoload_list->set_column_title(2,TTR("Singleton")); - autoload_list->set_column_expand(2,false); - autoload_list->set_column_min_width(2,80); - autoload_list->set_column_expand(3,false); - autoload_list->set_column_min_width(3,80); - - autoload_list->connect("button_pressed",this,"_autoload_delete"); - autoload_list->connect("item_edited",this,"_autoload_edited"); - autoload_list->connect("cell_selected", this, "_autoload_selected"); - - updating_autoload=false; - + autoload_settings = memnew( EditorAutoloadSettings ); + autoload_settings->set_name(TTR("AutoLoad")); + tab_container->add_child(autoload_settings); + autoload_settings->connect("autoload_changed", this, "_settings_changed"); } { diff --git a/tools/editor/project_settings.h b/tools/editor/project_settings.h index 79e1acf75e..46e98f69ad 100644 --- a/tools/editor/project_settings.h +++ b/tools/editor/project_settings.h @@ -34,6 +34,7 @@ #include "undo_redo.h" #include "editor_data.h" #include "scene/gui/tab_container.h" +#include "editor_autoload_settings.h" #include "editor_plugin_settings.h" //#include "project_export_settings.h" @@ -88,26 +89,10 @@ class ProjectSettings : public AcceptDialog { Tree *translation_remap; Tree *translation_remap_options; - - Tree *autoload_list; - String selected_autoload; - EditorFileDialog *autoload_file_open; - LineEdit *autoload_add_name; - LineEdit *autoload_add_path; - + EditorAutoloadSettings *autoload_settings; EditorPluginSettings *plugin_settings; - void _update_autoload(); - void _autoload_file_callback(const String& p_path); - void _autoload_add(); - void _autoload_edited(); - void _autoload_file_open(); - void _autoload_delete(Object *p_item,int p_column, int p_button); - void _autoload_selected(); - bool updating_autoload; - - void _item_selected(); void _item_adds(String); void _item_add(); diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 7816dd9bc7..ceb62d5ff0 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -4187,6 +4187,8 @@ public: void SectionedPropertyEditor::_bind_methods() { ObjectTypeDB::bind_method("_section_selected",&SectionedPropertyEditor::_section_selected); + + ObjectTypeDB::bind_method("update_category_list", &SectionedPropertyEditor::update_category_list); } void SectionedPropertyEditor::_section_selected(int p_which) { diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 4526fa26aa..2e7d65eadc 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -243,7 +243,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { //if (!_validate_no_foreign()) // break; - create_dialog->popup_centered_ratio(); + create_dialog->popup(true); } break; case TOOL_INSTANCE: { @@ -281,7 +281,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } break; case TOOL_REPLACE: { - create_dialog->popup_centered_ratio(); + create_dialog->popup(false); } break; case TOOL_CONNECT: { diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index edc2fc513d..480d33fd0a 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -623,12 +623,11 @@ void EditorSpatialGizmo::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_unscaled_billboard","material:Material","default_scale"),&EditorSpatialGizmo::add_unscaled_billboard,DEFVAL(1)); ObjectTypeDB::bind_method(_MD("add_handles","handles","billboard","secondary"),&EditorSpatialGizmo::add_handles,DEFVAL(false),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("set_spatial_node","node:Spatial"),&EditorSpatialGizmo::_set_spatial_node); + ObjectTypeDB::bind_method(_MD("clear"),&EditorSpatialGizmo::clear); BIND_VMETHOD( MethodInfo("redraw")); BIND_VMETHOD( MethodInfo(Variant::STRING,"get_handle_name",PropertyInfo(Variant::INT,"index"))); - { - BIND_VMETHOD( MethodInfo("get_handle_value:Variant",PropertyInfo(Variant::INT,"index"))); - } + BIND_VMETHOD( MethodInfo("get_handle_value:Variant",PropertyInfo(Variant::INT,"index"))); BIND_VMETHOD( MethodInfo("set_handle",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::OBJECT,"camera:Camera"),PropertyInfo(Variant::VECTOR2,"point"))); MethodInfo cm = MethodInfo("commit_handle",PropertyInfo(Variant::INT,"index"),PropertyInfo(Variant::NIL,"restore:Variant"),PropertyInfo(Variant::BOOL,"cancel")); cm.default_arguments.push_back(false); |