diff options
44 files changed, 1546 insertions, 170 deletions
diff --git a/core/ustring.cpp b/core/ustring.cpp index 730f7cfa3b..1f0eadc03f 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2867,25 +2867,29 @@ CharType String::ord_at(int p_idx) const { return operator[](p_idx); } -String String::strip_edges() const { +String String::strip_edges(bool left, bool right) const { int len=length(); int beg=0,end=len; - for (int i=0;i<length();i++) { + if(left) { + for (int i=0;i<len;i++) { - if (operator[](i)<=32) - beg++; - else - break; + if (operator[](i)<=32) + beg++; + else + break; + } } - for (int i=(int)(length()-1);i>=0;i--) { + if(right) { + for (int i=(int)(len-1);i>=0;i--) { - if (operator[](i)<=32) - end--; - else - break; + if (operator[](i)<=32) + end--; + else + break; + } } if (beg==0 && end==len) diff --git a/core/ustring.h b/core/ustring.h index ec0932e54d..78c041fb92 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -169,7 +169,7 @@ public: String left(int p_pos) const; String right(int p_pos) const; - String strip_edges() const; + String strip_edges(bool left = true, bool right = true) const; String strip_escapes() const; String extension() const; String basename() const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 01550a1593..4be763a511 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -257,7 +257,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var VCALL_LOCALMEM0R(String,to_lower); VCALL_LOCALMEM1R(String,left); VCALL_LOCALMEM1R(String,right); - VCALL_LOCALMEM0R(String,strip_edges); + VCALL_LOCALMEM2R(String,strip_edges); VCALL_LOCALMEM0R(String,extension); VCALL_LOCALMEM0R(String,basename); VCALL_LOCALMEM1R(String,plus_file); @@ -1277,7 +1277,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl ADDFUNC1(STRING,STRING,String,left,INT,"pos",varray()); ADDFUNC1(STRING,STRING,String,right,INT,"pos",varray()); - ADDFUNC0(STRING,STRING,String,strip_edges,varray()); + ADDFUNC2(STRING,STRING,String,strip_edges,BOOL,"left",BOOL,"right",varray(true,true)); ADDFUNC0(STRING,STRING,String,extension,varray()); ADDFUNC0(STRING,STRING,String,basename,varray()); ADDFUNC1(STRING,STRING,String,plus_file,STRING,"file",varray()); diff --git a/demos/misc/joysticks/joysticks.gd b/demos/misc/joysticks/joysticks.gd index f5466012e6..a6b90241b2 100644 --- a/demos/misc/joysticks/joysticks.gd +++ b/demos/misc/joysticks/joysticks.gd @@ -12,7 +12,6 @@ extends Node2D var joy_num var cur_joy var axis_value -var btn_state const DEADZONE = 0.2 @@ -26,11 +25,12 @@ func _fixed_process(delta): get_node("joy_name").set_text(Input.get_joy_name(joy_num)) # Loop through the axes and show their current values - for axis in range(0, 8): + for axis in range(JOY_ANALOG_0_X, JOY_AXIS_MAX): axis_value = Input.get_joy_axis(joy_num, axis) get_node("axis_prog" + str(axis)).set_value(100*axis_value) get_node("axis_val" + str(axis)).set_text(str(axis_value)) - if (axis < 4): + # Show joystick direction indicators + if (axis <= JOY_ANALOG_1_Y): if (abs(axis_value) < DEADZONE): get_node("diagram/axes/" + str(axis) + "+").hide() get_node("diagram/axes/" + str(axis) + "-").hide() @@ -40,8 +40,7 @@ func _fixed_process(delta): get_node("diagram/axes/" + str(axis) + "-").show() # Loop through the buttons and highlight the ones that are pressed - for btn in range(0, 16): - btn_state = 1 + for btn in range(JOY_BUTTON_0, JOY_BUTTON_MAX): if (Input.is_joy_button_pressed(joy_num, btn)): get_node("btn" + str(btn)).add_color_override("font_color", Color(1, 1, 1, 1)) get_node("diagram/buttons/" + str(btn)).show() diff --git a/demos/misc/tween/main.gd b/demos/misc/tween/main.gd index 512271311e..b899825d55 100644 --- a/demos/misc/tween/main.gd +++ b/demos/misc/tween/main.gd @@ -108,7 +108,7 @@ func reset_tween(): sprite.set_scale(Vector2(1,1)) if get_node("modes/rotate").is_pressed(): - tween.interpolate_method(sprite, "_set_rotd", 0, 360, 2, state.trans, state.eases) + tween.interpolate_method(sprite, "set_rotd", 0, 360, 2, state.trans, state.eases) tween.interpolate_property(sprite, "transform/rot", 360, 0, 2, state.trans, state.eases, 2) if get_node("modes/callback").is_pressed(): diff --git a/doc/base/classes.xml b/doc/base/classes.xml index 529601c741..643658fbb9 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -2680,6 +2680,22 @@ Get the list of names of the animations stored in the player. </description> </method> + <method name="animation_set_next"> + <argument index="0" name="anim_from" type="String"> + </argument> + <argument index="1" name="anim_to" type="String"> + </argument> + <description> + </description> + </method> + <method name="animation_get_next" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="anim_from" type="String"> + </argument> + <description> + </description> + </method> <method name="set_blend_time"> <argument index="0" name="anim_from" type="String"> </argument> @@ -6766,9 +6782,9 @@ </argument> <argument index="1" name="colors" type="ColorArray"> </argument> - <argument index="2" name="uvs" type="Vector2Array" default="Array()"> + <argument index="2" name="uvs" type="Vector2Array"> </argument> - <argument index="3" name="texture" type="Texture" default="Object()"> + <argument index="3" name="texture" type="Texture" default="NULL"> </argument> <argument index="4" name="width" type="float" default="1"> </argument> @@ -6781,9 +6797,9 @@ </argument> <argument index="1" name="colors" type="ColorArray"> </argument> - <argument index="2" name="uvs" type="Vector2Array" default="Array()"> + <argument index="2" name="uvs" type="Vector2Array" default="Vector2Array()"> </argument> - <argument index="3" name="texture" type="Texture" default="Object()"> + <argument index="3" name="texture" type="Texture" default="NULL"> </argument> <description> Draw a polygon of any amount of points, convex or concave. @@ -6794,9 +6810,9 @@ </argument> <argument index="1" name="color" type="Color"> </argument> - <argument index="2" name="uvs" type="Vector2Array" default="Array()"> + <argument index="2" name="uvs" type="Vector2Array" default="Vector2Array()"> </argument> - <argument index="3" name="texture" type="Texture" default="Object()"> + <argument index="3" name="texture" type="Texture" default="NULL"> </argument> <description> Draw a colored polygon of any amount of points, convex or concave. @@ -7118,7 +7134,7 @@ </description> </method> <method name="set_rotation"> - <argument index="0" name="rotation" type="float"> + <argument index="0" name="radians" type="float"> </argument> <description> Set the base rotation for this layer (helper). @@ -7131,6 +7147,18 @@ Return the base rotation for this layer (helper). </description> </method> + <method name="set_rotationd"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> + <method name="get_rotationd" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="set_scale"> <argument index="0" name="scale" type="Vector2"> </argument> @@ -7146,7 +7174,7 @@ </description> </method> <method name="get_world_2d" qualifiers="const"> - <return type="Canvas"> + <return type="World2D"> </return> <description> Return the [World2D] used by this layer. @@ -8779,7 +8807,13 @@ </description> </method> <method name="set_rotation"> - <argument index="0" name="rotation" type="float"> + <argument index="0" name="radians" type="float"> + </argument> + <description> + </description> + </method> + <method name="set_rotation_deg"> + <argument index="0" name="degrees" type="float"> </argument> <description> </description> @@ -8832,6 +8866,12 @@ <description> </description> </method> + <method name="get_rotation_deg" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_scale" qualifiers="const"> <return type="Vector2"> </return> @@ -9175,6 +9215,12 @@ <description> </description> </method> + <method name="set_drag_forwarding"> + <argument index="0" name="target" type="Control"> + </argument> + <description> + </description> + </method> <method name="set_drag_preview"> <argument index="0" name="control" type="Control"> </argument> @@ -14065,6 +14111,20 @@ Returns an empty String "" at the end of the list. <description> </description> </method> + <method name="request_raw"> + <return type="int"> + </return> + <argument index="0" name="method" type="int"> + </argument> + <argument index="1" name="url" type="String"> + </argument> + <argument index="2" name="headers" type="StringArray"> + </argument> + <argument index="3" name="body" type="RawArray" default=""""> + </argument> + <description> + </description> + </method> <method name="request"> <return type="int"> </return> @@ -14688,6 +14748,10 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <description> </description> </method> + <method name="fix_alpha_edges"> + <description> + </description> + </method> <method name="get_data"> <return type="RawArray"> </return> @@ -15208,13 +15272,13 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) </signals> <constants> <constant name="MOUSE_MODE_VISIBLE" value="0"> - Makes the mouse cursor visible if it is hidden. + Makes the mouse cursor visible if it is hidden. </constant> <constant name="MOUSE_MODE_HIDDEN" value="1"> - Makes the mouse cursor hidden if it is visible. + Makes the mouse cursor hidden if it is visible. </constant> <constant name="MOUSE_MODE_CAPTURED" value="2"> - Captures the mouse. The mouse will be hidden and unable to leave the game window. But it will still register movement and mouse button presses. + Captures the mouse. The mouse will be hidden and unable to leave the game window. But it will still register movement and mouse button presses. </constant> </constants> </class> @@ -16377,7 +16441,7 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <method name="add_item"> <argument index="0" name="text" type="String"> </argument> - <argument index="1" name="icon" type="Texture" default="Object()"> + <argument index="1" name="icon" type="Texture" default="NULL"> </argument> <argument index="2" name="selectable" type="bool" default="true"> </argument> @@ -17963,38 +18027,38 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) </class> <class name="LinkButton" inherits="BaseButton" category="Core"> <brief_description> - Simple button used to represent a link to some resource + Simple button used to represent a link to some resource </brief_description> <description> - This kind of buttons are primarily used when the interaction with the button causes a context change (like linking to a web page). + This kind of buttons are primarily used when the interaction with the button causes a context change (like linking to a web page). </description> <methods> <method name="set_text"> <argument index="0" name="text" type="String"> </argument> <description> - Sets the text of the button. + Sets the text of the button. </description> </method> <method name="get_text" qualifiers="const"> <return type="String"> </return> <description> - Returns the text of the button. + Returns the text of the button. </description> </method> <method name="set_underline_mode"> <argument index="0" name="underline_mode" type="int"> </argument> <description> - Sets the underline mode for this button, the argument must be one of the [LinkButton] constants (see constants section). + Sets the underline mode for this button, the argument must be one of the [LinkButton] constants (see constants section). </description> </method> <method name="get_underline_mode" qualifiers="const"> <return type="int"> </return> <description> - Returns the underline mode for this button. + Returns the underline mode for this button. </description> </method> </methods> @@ -20246,7 +20310,7 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) </description> </method> <method name="get_parent" qualifiers="const"> - <return type="Parent"> + <return type="Node"> </return> <description> Return the parent [Node] of the current [Node], or an empty Object if the node lacks a parent. @@ -20639,12 +20703,18 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) </description> </method> <method name="set_rot"> - <argument index="0" name="rot" type="float"> + <argument index="0" name="radians" type="float"> </argument> <description> Set the rotation of the 2D node. </description> </method> + <method name="set_rotd"> + <argument index="0" name="degrees" type="float"> + </argument> + <description> + </description> + </method> <method name="set_scale"> <argument index="0" name="scale" type="Vector2"> </argument> @@ -20666,6 +20736,12 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) Return the rotation of the 2D node. </description> </method> + <method name="get_rotd" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_scale" qualifiers="const"> <return type="Vector2"> </return> @@ -21029,7 +21105,7 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <argument index="0" name="size" type="Vector2"> </argument> <description> - Sets the window size to the specified size. + Sets the window size to the specified size. </description> </method> <method name="set_window_fullscreen"> @@ -21107,7 +21183,7 @@ Example: (content-length:12), (Content-Type:application/json; charset=UTF-8) <return type="int"> </return> <description> - Returns the current screen orientation, the return value will be one of the SCREEN_ORIENTATION constants in this class. + Returns the current screen orientation, the return value will be one of the SCREEN_ORIENTATION constants in this class. </description> </method> <method name="set_keep_screen_on"> @@ -25033,7 +25109,7 @@ This method controls whether the position between two cached points is interpola </argument> <argument index="1" name="param" type="int"> </argument> - <argument index="2" name="value" type="float" default="RID()"> + <argument index="2" name="value" type="float"> </argument> <description> </description> @@ -33787,7 +33863,7 @@ This method controls whether the position between two cached points is interpola </description> </method> <method name="set_rotation"> - <argument index="0" name="rotation" type="Vector3"> + <argument index="0" name="rotation_rad" type="Vector3"> </argument> <description> </description> @@ -33798,6 +33874,18 @@ This method controls whether the position between two cached points is interpola <description> </description> </method> + <method name="set_rotation_deg"> + <argument index="0" name="rotation_deg" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="get_rotation_deg" qualifiers="const"> + <return type="Vector3"> + </return> + <description> + </description> + </method> <method name="set_scale"> <argument index="0" name="scale" type="Vector3"> </argument> @@ -34183,13 +34271,13 @@ This method controls whether the position between two cached points is interpola </description> <methods> <method name="set_stream"> - <argument index="0" name="stream" type="Stream"> + <argument index="0" name="stream" type="AudioStream"> </argument> <description> </description> </method> <method name="get_stream" qualifiers="const"> - <return type="Stream"> + <return type="AudioStream"> </return> <description> </description> @@ -36479,11 +36567,11 @@ This method controls whether the position between two cached points is interpola <method name="add_triangle_fan"> <argument index="0" name="vertexes" type="Vector3Array"> </argument> - <argument index="1" name="uvs" type="Vector2Array" default="[Vector2Array]"> + <argument index="1" name="uvs" type="Vector2Array" default="Vector2Array()"> </argument> <argument index="2" name="colors" type="ColorArray" default="ColorArray([ColorArray])"> </argument> - <argument index="3" name="uv2s" type="Vector2Array" default="[Vector2Array]"> + <argument index="3" name="uv2s" type="Vector2Array" default="Vector2Array()"> </argument> <argument index="4" name="normals" type="Vector3Array" default="Vector3Array()"> </argument> @@ -36513,7 +36601,7 @@ This method controls whether the position between two cached points is interpola <method name="commit"> <return type="Mesh"> </return> - <argument index="0" name="existing" type="Mesh" default="Object()"> + <argument index="0" name="existing" type="Mesh" default="NULL"> </argument> <description> </description> @@ -39130,7 +39218,7 @@ This method controls whether the position between two cached points is interpola <method name="create_item"> <return type="TreeItem"> </return> - <argument index="0" name="parent" type="TreeItem" default="Object()"> + <argument index="0" name="parent" type="TreeItem" default="NULL"> </argument> <description> </description> @@ -41264,13 +41352,13 @@ This method controls whether the position between two cached points is interpola </description> <methods> <method name="set_stream"> - <argument index="0" name="stream" type="Stream"> + <argument index="0" name="stream" type="VideoStream"> </argument> <description> </description> </method> <method name="get_stream" qualifiers="const"> - <return type="Stream"> + <return type="VideoStream"> </return> <description> </description> @@ -42087,6 +42175,12 @@ This method controls whether the position between two cached points is interpola <description> </description> </method> + <method name="texture_set_shrink_all_x2_on_set_data"> + <argument index="0" name="shrink" type="bool"> + </argument> + <description> + </description> + </method> <method name="shader_create"> <return type="RID"> </return> diff --git a/drivers/builtin_openssl2/SCsub b/drivers/builtin_openssl2/SCsub index 38880030b1..a51b0a3ed6 100644 --- a/drivers/builtin_openssl2/SCsub +++ b/drivers/builtin_openssl2/SCsub @@ -650,6 +650,7 @@ env_ssl.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/asn1"]) env_ssl.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/modes"]) #env_ssl.Append(CPPPATH=["#drivers/builtin_openssl2/crypto/store"]) env_ssl.Append(CPPFLAGS=["-DOPENSSL_NO_ASM","-DOPENSSL_THREADS","-DL_ENDIAN"]) +env_ssl.Append(CFLAGS=["-Wno-error=implicit-function-declaration"]); env_ssl.add_source_files(env.drivers_sources,openssl_sources) diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 29c652051a..d88dd89002 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -184,7 +184,7 @@ public: virtual bool is_window_minimized() const; virtual void set_window_maximized(bool p_enabled); virtual bool is_window_maximized() const; - Size2 get_screen_size(int p_screen); + Size2 get_screen_size(int p_screen=0) const; void run(); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index c814932dc4..c443fc2d0e 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1354,7 +1354,7 @@ Point2 OS_OSX::get_screen_position(int p_screen) const { return screens[p_screen].pos; }; -Size2 OS_OSX::get_screen_size(int p_screen) { +Size2 OS_OSX::get_screen_size(int p_screen) const { ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2()); return screens[p_screen].size; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 352b7d645f..c9c7780a2a 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -705,6 +705,25 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) { joystick->probe_joysticks(); } break; + case WM_SETCURSOR: { + + if(LOWORD(lParam) == HTCLIENT) { + if(mouse_mode == MOUSE_MODE_HIDDEN) { + //Hide the cursor + if(hCursor == NULL) + hCursor = SetCursor(NULL); + else + SetCursor(NULL); + } + else { + if(hCursor != NULL) { + SetCursor(hCursor); + hCursor = NULL; + } + } + } + + } break; default: { @@ -1211,7 +1230,6 @@ void OS_Windows::set_mouse_mode(MouseMode p_mode) { if (mouse_mode==p_mode) return; - ShowCursor(p_mode==MOUSE_MODE_VISIBLE); mouse_mode=p_mode; if (p_mode==MOUSE_MODE_CAPTURED) { RECT clipRect; diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 81cf313849..adea26308f 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -103,6 +103,8 @@ class OS_Windows : public OS { HDC hDC; // Private GDI Device Context HINSTANCE hInstance; // Holds The Instance Of The Application HWND hWnd; + + HCURSOR hCursor; Size2 window_rect; VideoMode video_mode; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 7ef81306b6..134e0153b3 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -148,15 +148,28 @@ void Node2D::set_pos(const Point2& p_pos) { } -void Node2D::set_rot(float p_angle) { +void Node2D::set_rot(float p_radians) { if (_xform_dirty) ((Node2D*)this)->_update_xform_values(); - angle=p_angle; + angle=p_radians; _update_transform(); _change_notify("transform/rot"); } +void Node2D::set_rotd(float p_degrees) { + + set_rot(Math::deg2rad(p_degrees)); +} + +// Kept for compatibility after rename to set_rotd. +// Could be removed after a couple releases. +void Node2D::_set_rotd(float p_degrees) { + + WARN_PRINT("Deprecated method Node2D._set_rotd(): This method was renamed to set_rotd. Please adapt your code accordingly, as the old method will be obsoleted."); + set_rotd(p_degrees); +} + void Node2D::set_scale(const Size2& p_scale) { if (_xform_dirty) @@ -183,21 +196,22 @@ float Node2D::get_rot() const { return angle; } -Size2 Node2D::get_scale() const { - if (_xform_dirty) - ((Node2D*)this)->_update_xform_values(); +float Node2D::get_rotd() const { - return _scale; + return Math::rad2deg(get_rot()); } +// Kept for compatibility after rename to get_rotd. +// Could be removed after a couple releases. +float Node2D::_get_rotd() const { -void Node2D::_set_rotd(float p_angle) { - - set_rot(Math::deg2rad(p_angle)); + WARN_PRINT("Deprecated method Node2D._get_rotd(): This method was renamed to get_rotd. Please adapt your code accordingly, as the old method will be obsoleted."); + return get_rotd(); } +Size2 Node2D::get_scale() const { + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); -float Node2D::_get_rotd() const { - - return Math::rad2deg(get_rot()); + return _scale; } @@ -361,16 +375,18 @@ float Node2D::get_angle_to(const Vector2& p_pos) const { void Node2D::_bind_methods() { - + // TODO: Obsolete those two methods (old name) properly (GH-4397) ObjectTypeDB::bind_method(_MD("_get_rotd"),&Node2D::_get_rotd); - ObjectTypeDB::bind_method(_MD("_set_rotd"),&Node2D::_set_rotd); + ObjectTypeDB::bind_method(_MD("_set_rotd","degrees"),&Node2D::_set_rotd); ObjectTypeDB::bind_method(_MD("set_pos","pos"),&Node2D::set_pos); - ObjectTypeDB::bind_method(_MD("set_rot","rot"),&Node2D::set_rot); + ObjectTypeDB::bind_method(_MD("set_rot","radians"),&Node2D::set_rot); + ObjectTypeDB::bind_method(_MD("set_rotd","degrees"),&Node2D::set_rotd); ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Node2D::set_scale); ObjectTypeDB::bind_method(_MD("get_pos"),&Node2D::get_pos); ObjectTypeDB::bind_method(_MD("get_rot"),&Node2D::get_rot); + ObjectTypeDB::bind_method(_MD("get_rotd"),&Node2D::get_rotd); ObjectTypeDB::bind_method(_MD("get_scale"),&Node2D::get_scale); ObjectTypeDB::bind_method(_MD("rotate","radians"),&Node2D::rotate); @@ -400,7 +416,7 @@ void Node2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_relative_transform_to_parent","parent"),&Node2D::get_relative_transform_to_parent); ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos")); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd")); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("set_rotd"),_SCS("get_rotd")); ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale")); ADD_PROPERTYNZ(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z")); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative")); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 49d616fc1f..b0c628fd94 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -47,6 +47,7 @@ class Node2D : public CanvasItem { void _update_transform(); + // Deprecated, should be removed in a future version. void _set_rotd(float p_angle); float _get_rotd() const; @@ -69,7 +70,8 @@ public: virtual bool edit_has_pivot() const; void set_pos(const Point2& p_pos); - void set_rot(float p_angle); + void set_rot(float p_radians); + void set_rotd(float p_degrees); void set_scale(const Size2& p_scale); void rotate(float p_radians); @@ -81,6 +83,7 @@ public: Point2 get_pos() const; float get_rot() const; + float get_rotd() const; Size2 get_scale() const; Point2 get_global_pos() const; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index c2d318e8a7..6a9c655141 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -346,14 +346,14 @@ void Spatial::set_translation(const Vector3& p_translation) { } -void Spatial::set_rotation(const Vector3& p_euler){ +void Spatial::set_rotation(const Vector3& p_euler_rad){ if (data.dirty&DIRTY_VECTORS) { data.scale=data.local_transform.basis.get_scale(); data.dirty&=~DIRTY_VECTORS; } - data.rotation=p_euler; + data.rotation=p_euler_rad; data.dirty|=DIRTY_LOCAL; _propagate_transform_changed(this); if (data.notify_local_transform) { @@ -361,6 +361,18 @@ void Spatial::set_rotation(const Vector3& p_euler){ } } + +void Spatial::set_rotation_deg(const Vector3& p_euler_deg) { + + set_rotation(p_euler_deg * Math_PI / 180.0); +} + +void Spatial::_set_rotation_deg(const Vector3& p_euler_deg) { + + WARN_PRINT("Deprecated method Spatial._set_rotation_deg(): This method was renamed to set_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + set_rotation_deg(p_euler_deg); +} + void Spatial::set_scale(const Vector3& p_scale){ if (data.dirty&DIRTY_VECTORS) { @@ -381,6 +393,7 @@ Vector3 Spatial::get_translation() const{ return data.local_transform.origin; } + Vector3 Spatial::get_rotation() const{ if (data.dirty&DIRTY_VECTORS) { @@ -391,6 +404,20 @@ Vector3 Spatial::get_rotation() const{ return data.rotation; } + +Vector3 Spatial::get_rotation_deg() const { + + return get_rotation() * 180.0 / Math_PI; +} + +// Kept for compatibility after rename to set_rotd. +// Could be removed after a couple releases. +Vector3 Spatial::_get_rotation_deg() const { + + WARN_PRINT("Deprecated method Spatial._get_rotation_deg(): This method was renamed to get_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + return get_rotation_deg(); +} + Vector3 Spatial::get_scale() const{ if (data.dirty&DIRTY_VECTORS) { @@ -495,16 +522,6 @@ bool Spatial::is_set_as_toplevel() const{ return data.toplevel; } -void Spatial::_set_rotation_deg(const Vector3& p_deg) { - - set_rotation(p_deg * Math_PI / 180.0); -} - -Vector3 Spatial::_get_rotation_deg() const { - - return get_rotation() * 180.0 / Math_PI; -} - Ref<World> Spatial::get_world() const { ERR_FAIL_COND_V(!is_inside_world(),Ref<World>()); @@ -722,8 +739,10 @@ void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_transform"), &Spatial::get_transform); ObjectTypeDB::bind_method(_MD("set_translation","translation"), &Spatial::set_translation); ObjectTypeDB::bind_method(_MD("get_translation"), &Spatial::get_translation); - ObjectTypeDB::bind_method(_MD("set_rotation","rotation"), &Spatial::set_rotation); + ObjectTypeDB::bind_method(_MD("set_rotation","rotation_rad"), &Spatial::set_rotation); ObjectTypeDB::bind_method(_MD("get_rotation"), &Spatial::get_rotation); + ObjectTypeDB::bind_method(_MD("set_rotation_deg","rotation_deg"), &Spatial::set_rotation_deg); + ObjectTypeDB::bind_method(_MD("get_rotation_deg"), &Spatial::get_rotation_deg); ObjectTypeDB::bind_method(_MD("set_scale","scale"), &Spatial::set_scale); ObjectTypeDB::bind_method(_MD("get_scale"), &Spatial::get_scale); ObjectTypeDB::bind_method(_MD("set_global_transform","global"), &Spatial::set_global_transform); @@ -732,9 +751,11 @@ void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_ignore_transform_notification","enabled"), &Spatial::set_ignore_transform_notification); ObjectTypeDB::bind_method(_MD("set_as_toplevel","enable"), &Spatial::set_as_toplevel); ObjectTypeDB::bind_method(_MD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); + ObjectTypeDB::bind_method(_MD("get_world:World"), &Spatial::get_world); + + // TODO: Obsolete those two methods (old name) properly (GH-4397) ObjectTypeDB::bind_method(_MD("_set_rotation_deg","rotation_deg"), &Spatial::_set_rotation_deg); ObjectTypeDB::bind_method(_MD("_get_rotation_deg"), &Spatial::_get_rotation_deg); - ObjectTypeDB::bind_method(_MD("get_world:World"), &Spatial::get_world); #ifdef TOOLS_ENABLED ObjectTypeDB::bind_method(_MD("_update_gizmo"), &Spatial::_update_gizmo); @@ -789,7 +810,7 @@ void Spatial::_bind_methods() { //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") ); ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/translation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_translation"), _SCS("get_translation") ); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") ); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_rotation_deg"), _SCS("get_rotation_deg") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") ); ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") ); diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 50123b2d81..fdc9f95f0b 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -110,7 +110,8 @@ class Spatial : public Node { void _notify_dirty(); void _propagate_transform_changed(Spatial *p_origin); - void _set_rotation_deg(const Vector3& p_deg); + // Deprecated, should be removed in a future version. + void _set_rotation_deg(const Vector3& p_euler_deg); Vector3 _get_rotation_deg() const; void _propagate_visibility_changed(); @@ -144,11 +145,13 @@ public: Ref<World> get_world() const; void set_translation(const Vector3& p_translation); - void set_rotation(const Vector3& p_euler); + void set_rotation(const Vector3& p_euler_rad); + void set_rotation_deg(const Vector3& p_euler_deg); void set_scale(const Vector3& p_scale); Vector3 get_translation() const; Vector3 get_rotation() const; + Vector3 get_rotation_deg() const; Vector3 get_scale() const; void set_transform(const Transform& p_transform); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 7b3ac2a815..73e7237058 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2156,17 +2156,9 @@ bool Control::is_text_field() const { } -void Control::_set_rotation_deg(float p_rot) { - set_rotation(Math::deg2rad(p_rot)); -} - -float Control::_get_rotation_deg() const { - return Math::rad2deg(get_rotation()); -} +void Control::set_rotation(float p_radians) { -void Control::set_rotation(float p_rotation) { - - data.rotation=p_rotation; + data.rotation=p_radians; update(); _notify_transform(); } @@ -2176,6 +2168,25 @@ float Control::get_rotation() const{ return data.rotation; } +void Control::set_rotation_deg(float p_degrees) { + set_rotation(Math::deg2rad(p_degrees)); +} + +float Control::get_rotation_deg() const { + return Math::rad2deg(get_rotation()); +} + +// Kept for compatibility after rename to {s,g}et_rotation_deg. +// Could be removed after a couple releases. +void Control::_set_rotation_deg(float p_degrees) { + WARN_PRINT("Deprecated method Control._set_rotation_deg(): This method was renamed to set_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + set_rotation_deg(p_degrees); +} +float Control::_get_rotation_deg() const { + WARN_PRINT("Deprecated method Control._get_rotation_deg(): This method was renamed to get_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted."); + return get_rotation_deg(); +} + void Control::set_scale(const Vector2& p_scale){ data.scale=p_scale; @@ -2231,8 +2242,10 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_size","size"),&Control::set_size); ObjectTypeDB::bind_method(_MD("set_custom_minimum_size","size"),&Control::set_custom_minimum_size); ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Control::set_global_pos); - ObjectTypeDB::bind_method(_MD("set_rotation","rotation"),&Control::set_rotation); - ObjectTypeDB::bind_method(_MD("_set_rotation_deg","rotation"),&Control::_set_rotation_deg); + ObjectTypeDB::bind_method(_MD("set_rotation","radians"),&Control::set_rotation); + ObjectTypeDB::bind_method(_MD("set_rotation_deg","degrees"),&Control::set_rotation_deg); + // TODO: Obsolete this method (old name) properly (GH-4397) + ObjectTypeDB::bind_method(_MD("_set_rotation_deg","degrees"),&Control::_set_rotation_deg); ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Control::set_scale); ObjectTypeDB::bind_method(_MD("get_margin","margin"),&Control::get_margin); ObjectTypeDB::bind_method(_MD("get_begin"),&Control::get_begin); @@ -2240,12 +2253,14 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_pos"),&Control::get_pos); ObjectTypeDB::bind_method(_MD("get_size"),&Control::get_size); ObjectTypeDB::bind_method(_MD("get_rotation"),&Control::get_rotation); + ObjectTypeDB::bind_method(_MD("get_rotation_deg"),&Control::get_rotation_deg); + // TODO: Obsolete this method (old name) properly (GH-4397) + ObjectTypeDB::bind_method(_MD("_get_rotation_deg"),&Control::_get_rotation_deg); ObjectTypeDB::bind_method(_MD("get_scale"),&Control::get_scale); ObjectTypeDB::bind_method(_MD("get_custom_minimum_size"),&Control::get_custom_minimum_size); ObjectTypeDB::bind_method(_MD("get_parent_area_size"),&Control::get_size); ObjectTypeDB::bind_method(_MD("get_global_pos"),&Control::get_global_pos); ObjectTypeDB::bind_method(_MD("get_rect"),&Control::get_rect); - ObjectTypeDB::bind_method(_MD("_get_rotation_deg"),&Control::_get_rotation_deg); ObjectTypeDB::bind_method(_MD("get_global_rect"),&Control::get_global_rect); ObjectTypeDB::bind_method(_MD("set_area_as_parent_rect","margin"),&Control::set_area_as_parent_rect,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("show_modal","exclusive"),&Control::show_modal,DEFVAL(false)); @@ -2304,7 +2319,7 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("grab_click_focus"),&Control::grab_click_focus); - ObjectTypeDB::bind_method(_MD("set_drag_forwarding;","target:Control"),&Control::set_drag_forwarding); + ObjectTypeDB::bind_method(_MD("set_drag_forwarding","target:Control"),&Control::set_drag_forwarding); ObjectTypeDB::bind_method(_MD("set_drag_preview","control:Control"),&Control::set_drag_preview); ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"),&Control::warp_mouse); @@ -2324,7 +2339,7 @@ void Control::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/pos", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_pos"),_SCS("get_pos") ); ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/size", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_size"),_SCS("get_size") ); ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/min_size"), _SCS("set_custom_minimum_size"),_SCS("get_custom_minimum_size") ); - ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"rect/rotation",PROPERTY_HINT_RANGE,"-1080,1080,0.01"), _SCS("_set_rotation_deg"),_SCS("_get_rotation_deg") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"rect/rotation",PROPERTY_HINT_RANGE,"-1080,1080,0.01"), _SCS("set_rotation_deg"),_SCS("get_rotation_deg") ); ADD_PROPERTYNO( PropertyInfo(Variant::VECTOR2,"rect/scale"), _SCS("set_scale"),_SCS("get_scale") ); ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"hint/tooltip", PROPERTY_HINT_MULTILINE_TEXT), _SCS("set_tooltip"),_SCS("_get_tooltip") ); ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT ); diff --git a/scene/gui/control.h b/scene/gui/control.h index aa9a7612a5..f720185c9d 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -180,7 +180,8 @@ private: void _size_changed(); String _get_tooltip() const; - void _set_rotation_deg(float p_rot); + // Deprecated, should be removed in a future version. + void _set_rotation_deg(float p_degrees); float _get_rotation_deg() const; friend class Viewport; @@ -275,8 +276,10 @@ public: Rect2 get_global_rect() const; Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server - void set_rotation(float p_rotation); + void set_rotation(float p_radians); + void set_rotation_deg(float p_degrees); float get_rotation() const; + float get_rotation_deg() const; void set_scale(const Vector2& p_scale); Vector2 get_scale() const; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 6a251a5ac5..64f1de42af 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1044,8 +1044,7 @@ void ItemList::_scroll_changed(double) { update(); } - -String ItemList::get_tooltip(const Point2& p_pos) const { +int ItemList::get_item_at_pos(const Point2& p_pos) const { Vector2 pos=p_pos; Ref<StyleBox> bg = get_stylebox("bg"); @@ -1074,6 +1073,13 @@ String ItemList::get_tooltip(const Point2& p_pos) const { } } + return closest; +} + +String ItemList::get_tooltip(const Point2& p_pos) const { + + int closest = get_item_at_pos(p_pos); + if (closest!=-1) { if (items[closest].tooltip!="") { return items[closest].tooltip; @@ -1084,8 +1090,6 @@ String ItemList::get_tooltip(const Point2& p_pos) const { } return Control::get_tooltip(p_pos); - - } void ItemList::sort_items_by_text() { @@ -1170,6 +1174,8 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_min_icon_size","size"),&ItemList::set_min_icon_size); ObjectTypeDB::bind_method(_MD("get_min_icon_size"),&ItemList::get_min_icon_size); + ObjectTypeDB::bind_method(_MD("get_item_at_pos","pos"),&ItemList::get_item_at_pos); + ObjectTypeDB::bind_method(_MD("ensure_current_is_visible"),&ItemList::ensure_current_is_visible); ObjectTypeDB::bind_method(_MD("_scroll_changed"),&ItemList::_scroll_changed); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 5aec946686..fcb4dfae5a 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -140,6 +140,7 @@ public: int find_metadata(const Variant& p_metadata) const; virtual String get_tooltip(const Point2& p_pos) const; + int get_item_at_pos(const Point2& p_pos) const; ItemList(); ~ItemList(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index bf8aff0f44..1a465baf49 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -921,14 +921,18 @@ void TextEdit::_notification(int p_what) { if (cursor.column==j && cursor.line==line) { cursor_pos = Point2i( char_ofs+char_margin, ofs_y ); + if (insert_mode) { cursor_pos.y += get_row_height(); - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color); - } else { - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); } - + if (draw_caret) { + if (insert_mode) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); + } + } } char_ofs+=char_w; @@ -937,12 +941,18 @@ void TextEdit::_notification(int p_what) { if (cursor.column==str.length() && cursor.line==line && (char_ofs+char_margin)>=xmargin_beg) { cursor_pos=Point2i( char_ofs+char_margin, ofs_y ); + if (insert_mode) { cursor_pos.y += get_row_height(); - int char_w = cache.font->get_char_size(' ').width; - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color); - } else { - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); + } + + if (draw_caret) { + if (insert_mode) { + int char_w = cache.font->get_char_size(' ').width; + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(char_w,1)),cache.caret_color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.caret_color); + } } } } @@ -1390,6 +1400,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } if (mb.button_index==BUTTON_LEFT) { + _reset_caret_blink_timer(); + int row,col; _get_mouse_pos(Point2i(mb.x,mb.y), row,col); @@ -1524,6 +1536,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (selection.selecting_mode!=Selection::MODE_NONE) { + _reset_caret_blink_timer(); + int row,col; _get_mouse_pos(Point2i(mm.x,mm.y), row,col); @@ -1644,6 +1658,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.scancode==KEY_BACKSPACE) { + _reset_caret_blink_timer(); + backspace_at_cursor(); _update_completion_candidates(); accept_event(); @@ -1659,6 +1675,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.unicode>32) { + _reset_caret_blink_timer(); + const CharType chr[2] = {(CharType)k.unicode, 0}; if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); @@ -1705,6 +1723,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { k.mod.shift=false; } + if (!k.mod.command) { + _reset_caret_blink_timer(); + } // save here for insert mode, just in case it is cleared in the following section bool had_selection = selection.active; @@ -2902,6 +2923,30 @@ int TextEdit::cursor_get_line() const { return cursor.line; } +bool TextEdit::cursor_get_blink_enabled() const { + return caret_blink_enabled; +} + +void TextEdit::cursor_set_blink_enabled(const bool p_enabled) { + caret_blink_enabled = p_enabled; + + if (p_enabled) { + caret_blink_timer->start(); + } else { + caret_blink_timer->stop(); + } + draw_caret = true; +} + + +float TextEdit::cursor_get_blink_speed() const { + return caret_blink_timer->get_wait_time(); +} + +void TextEdit::cursor_set_blink_speed(const float p_speed) { + ERR_FAIL_COND(p_speed <= 0); + caret_blink_timer->set_wait_time(p_speed); +} void TextEdit::_scroll_moved(double p_to_val) { @@ -3117,6 +3162,20 @@ void TextEdit::set_max_chars(int p_max_chars) { max_chars=p_max_chars; } +void TextEdit::_reset_caret_blink_timer() { + if (caret_blink_enabled) { + caret_blink_timer->stop(); + caret_blink_timer->start(); + draw_caret = true; + update(); + } +} + +void TextEdit::_toggle_draw_caret() { + draw_caret = !draw_caret; + update(); +} + void TextEdit::_update_caches() { cache.style_normal=get_stylebox("normal"); @@ -4096,6 +4155,7 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); ObjectTypeDB::bind_method(_MD("_click_selection_held"),&TextEdit::_click_selection_held); + ObjectTypeDB::bind_method(_MD("_toggle_draw_caret"),&TextEdit::_toggle_draw_caret); BIND_CONSTANT( SEARCH_MATCH_CASE ); BIND_CONSTANT( SEARCH_WHOLE_WORDS ); @@ -4165,6 +4225,7 @@ TextEdit::TextEdit() { readonly=false; setting_row=false; draw_tabs=false; + draw_caret=true; max_chars=0; clear(); wrap=false; @@ -4204,6 +4265,13 @@ TextEdit::TextEdit() { selection.active=false; syntax_coloring=false; + caret_blink_enabled=false; + caret_blink_timer = memnew(Timer); + add_child(caret_blink_timer); + caret_blink_timer->set_wait_time(0.65); + caret_blink_timer->connect("timeout", this,"_toggle_draw_caret"); + cursor_set_blink_enabled(false); + custom_bg_color=Color(0,0,0,0); idle_detect = memnew( Timer ); add_child(idle_detect); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 193dd236d1..ea4f148e91 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -210,6 +210,10 @@ class TextEdit : public Control { bool syntax_coloring; int tab_size; + Timer *caret_blink_timer; + bool caret_blink_enabled; + bool draw_caret; + bool setting_row; bool wrap; bool draw_tabs; @@ -267,6 +271,9 @@ class TextEdit : public Control { int get_row_height() const; + void _reset_caret_blink_timer(); + void _toggle_draw_caret(); + void _update_caches(); void _cursor_changed_emit(); void _text_changed_emit(); @@ -364,6 +371,12 @@ public: int cursor_get_column() const; int cursor_get_line() const; + bool cursor_get_blink_enabled() const; + void cursor_set_blink_enabled(const bool p_enabled); + + float cursor_get_blink_speed() const; + void cursor_set_blink_speed(const float p_speed); + void set_readonly(bool p_readonly); void set_max_chars(int p_max_chars); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index c4efe82eaa..c141635bbf 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -604,10 +604,11 @@ String TreeItem::get_tooltip(int p_column) const{ return cells[p_column].tooltip; } -void TreeItem::set_custom_bg_color(int p_column,const Color& p_color) { +void TreeItem::set_custom_bg_color(int p_column,const Color& p_color,bool p_bg_outline) { ERR_FAIL_INDEX( p_column, cells.size() ); cells[p_column].custom_bg_color=true; + cells[p_column].custom_bg_outline=p_bg_outline; cells[p_column].bg_color=p_color; _changed_notify(p_column); } @@ -685,7 +686,7 @@ void TreeItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_custom_color","column","color"),&TreeItem::set_custom_color); ObjectTypeDB::bind_method(_MD("clear_custom_color","column"),&TreeItem::clear_custom_color); - ObjectTypeDB::bind_method(_MD("set_custom_bg_color","column","color"),&TreeItem::set_custom_bg_color); + ObjectTypeDB::bind_method(_MD("set_custom_bg_color","column","color","just_outline"),&TreeItem::set_custom_bg_color,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("clear_custom_bg_color","column"),&TreeItem::clear_custom_bg_color); ObjectTypeDB::bind_method(_MD("get_custom_bg_color","column"),&TreeItem::get_custom_bg_color); @@ -757,6 +758,13 @@ TreeItem::~TreeItem() { if (tree && tree->selected_item==this) tree->selected_item=NULL; + + if (tree && tree->drop_mode_over==this) + tree->drop_mode_over=NULL; + + if (tree && tree->single_select_defer==this) + tree->single_select_defer=NULL; + if (tree && tree->edited_item==this) { tree->edited_item=NULL; tree->pressing_for_editor=false; @@ -797,17 +805,13 @@ void Tree::update_cache() { cache.font_color=get_color("font_color"); cache.font_color_selected=get_color("font_color_selected"); cache.guide_color=get_color("guide_color"); + cache.drop_position_color=get_color("drop_position_color"); cache.hseparation=get_constant("hseparation"); cache.vseparation=get_constant("vseparation"); cache.item_margin=get_constant("item_margin"); cache.button_margin=get_constant("button_margin"); cache.guide_width=get_constant("guide_width"); - Ref<StyleBox> title_button; - Ref<StyleBox> title_button_hover; - Ref<StyleBox> title_button_pressed; - Color title_button_color; - cache.title_button = get_stylebox("title_button_normal"); cache.title_button_pressed = get_stylebox("title_button_pressed"); cache.title_button_hover = get_stylebox("title_button_hover"); @@ -1087,7 +1091,34 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& Rect2 r=cell_rect; r.pos.x-=cache.hseparation; r.size.x+=cache.hseparation; - VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color); + if (p_item->cells[i].custom_bg_outline) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,r.size.x,1),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y+r.size.y-1,r.size.x,1),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,1,r.size.y),p_item->cells[i].bg_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x+r.size.x-1,r.pos.y,1,r.size.y),p_item->cells[i].bg_color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color); + } + } + + if (drop_mode_flags && drop_mode_over==p_item) { + + Rect2 r=cell_rect; + + if (drop_mode_section==-1 || drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,r.size.x,1),cache.drop_position_color); + + } + + if (drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y,1,r.size.y),cache.drop_position_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x+r.size.x-1,r.pos.y,1,r.size.y),cache.drop_position_color); + + } + + if (drop_mode_section==1 || drop_mode_section==0) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(r.pos.x,r.pos.y+r.size.y,r.size.x,1),cache.drop_position_color); + } } Color col=p_item->cells[i].custom_color?p_item->cells[i].color:get_color( p_item->cells[i].selected?"font_color_selected":"font_color"); @@ -1280,6 +1311,25 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& } +int Tree::_count_selected_items(TreeItem* p_from) const { + + int count=0; + for(int i=0;i<columns.size();i++) { + if (p_from->is_selected(i)) + count++; + } + + if (p_from->get_children()) { + count+=_count_selected_items(p_from->get_children()); + } + + if (p_from->get_next()) { + count+=_count_selected_items(p_from->get_next()); + } + + return count; + +} void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col,TreeItem *p_prev,bool *r_in_range) { TreeItem::Cell &selected_cell=p_selected->cells[p_col]; @@ -1548,7 +1598,15 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ select_single_item( p_item, root, col,selected_item,&inrange ); } else { - select_single_item( p_item, root, col ); + + int icount = _count_selected_items(root); + + if (select_mode==SELECT_MULTI && icount>1) { + single_select_defer=p_item; + single_select_defer_column=col; + } else { + select_single_item( p_item, root, col ); + } } //if (!c.selected && select_mode==SELECT_MULTI) { @@ -2159,6 +2217,31 @@ void Tree::_input_event(InputEvent p_event) { } + if (drop_mode_flags && root) { + + Point2 mpos=Point2(b.x,b.y); + mpos -= cache.bg->get_offset(); + mpos.y-=_get_title_button_height(); + if (mpos.y>=0) { + + if (h_scroll->is_visible()) + mpos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + mpos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,mpos,col,h,section); + + if (it!=drop_mode_over || section!=drop_mode_section) { + drop_mode_over=it; + drop_mode_section=section; + update(); + } + } + } + + + if (cache.hover_type!=old_hover || cache.hover_index!=old_index) { update(); } @@ -2211,6 +2294,12 @@ void Tree::_input_event(InputEvent p_event) { if (b.button_index==BUTTON_LEFT) { + + if (single_select_defer) { + select_single_item( single_select_defer, root, single_select_defer_column ); + single_select_defer=NULL; + } + range_click_timer->stop(); if (pressing_for_editor) { @@ -2522,6 +2611,15 @@ void Tree::_notification(int p_what) { update_cache();; } + if (p_what==NOTIFICATION_DRAG_END) { + + drop_mode_flags=0; + update(); + } + if (p_what==NOTIFICATION_DRAG_BEGIN) { + + single_select_defer=NULL; + } if (p_what==NOTIFICATION_FIXED_PROCESS) { if (drag_touching) { @@ -3135,7 +3233,7 @@ void Tree::_do_incr_search(const String& p_add) { } -TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_column,int &h) const { +TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_column,int &h,int §ion) const { Point2 pos = p_pos; @@ -3145,15 +3243,33 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co h = compute_item_height(p_item)+cache.vseparation;; if (pos.y<h) { + if (drop_mode_flags==DROP_MODE_ON_ITEM) { + section=0; + } else if (drop_mode_flags==DROP_MODE_INBETWEEN) { + section=pos.y<h/2?-1:1; + } else if (pos.y<h/4) { + section=-1; + } else if (pos.y>=(h*3/4)) { + section=1; + } else { + section=0; + } + for(int i=0;i<columns.size();i++) { int w = get_column_width(i); if (pos.x < w) { r_column=i; + + return p_item; } pos.x-=w; } + + + + return NULL; } else { @@ -3172,7 +3288,7 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co int ch; - TreeItem *r = _find_item_at_pos(n,pos,r_column,ch); + TreeItem *r = _find_item_at_pos(n,pos,r_column,ch,section); pos.y-=ch; h+=ch; if (r) @@ -3184,6 +3300,88 @@ TreeItem* Tree::_find_item_at_pos(TreeItem*p_item, const Point2& p_pos,int& r_co } +int Tree::get_column_at_pos(const Point2& p_pos) const { + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return -1; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + return col; + } + } + + return -1; + +} + +int Tree::get_drop_section_at_pos(const Point2& p_pos) const { + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return -100; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + return section; + } + } + + return -100; + +} +TreeItem* Tree::get_item_at_pos(const Point2& p_pos) const { + + + if (root) { + + Point2 pos=p_pos; + pos -= cache.bg->get_offset(); + pos.y-=_get_title_button_height(); + if (pos.y<0) + return NULL; + + if (h_scroll->is_visible()) + pos.x+=h_scroll->get_val(); + if (v_scroll->is_visible()) + pos.y+=v_scroll->get_val(); + + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); + + if (it) { + + return it; + } + } + + return NULL; + +} + String Tree::get_tooltip(const Point2& p_pos) const { if (root) { @@ -3199,8 +3397,8 @@ String Tree::get_tooltip(const Point2& p_pos) const { if (v_scroll->is_visible()) pos.y+=v_scroll->get_val(); - int col,h; - TreeItem *it = _find_item_at_pos(root,pos,col,h); + int col,h,section; + TreeItem *it = _find_item_at_pos(root,pos,col,h,section); if (it) { @@ -3241,6 +3439,20 @@ void Tree::set_value_evaluator(ValueEvaluator *p_evaluator) { evaluator = p_evaluator; } +void Tree::set_drop_mode_flags(int p_flags) { + drop_mode_flags=p_flags; + if (drop_mode_flags==0) { + drop_mode_over=NULL; + } + + update(); +} + +int Tree::get_drop_mode_flags() const { + + return drop_mode_flags; +} + void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&Tree::_range_click_timeout); @@ -3273,6 +3485,8 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_edited_column"),&Tree::get_edited_column); ObjectTypeDB::bind_method(_MD("get_custom_popup_rect"),&Tree::get_custom_popup_rect); ObjectTypeDB::bind_method(_MD("get_item_area_rect","item:TreeItem","column"),&Tree::_get_item_rect,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("get_item_at_pos:TreeItem","pos"),&Tree::get_item_at_pos); + ObjectTypeDB::bind_method(_MD("get_column_at_pos","pos"),&Tree::get_column_at_pos); ObjectTypeDB::bind_method(_MD("ensure_cursor_is_visible"),&Tree::ensure_cursor_is_visible); @@ -3286,6 +3500,9 @@ void Tree::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_hide_folding","hide"),&Tree::set_hide_folding); ObjectTypeDB::bind_method(_MD("is_folding_hidden"),&Tree::is_folding_hidden); + ObjectTypeDB::bind_method(_MD("set_drop_mode_flags","flags"),&Tree::set_drop_mode_flags); + ObjectTypeDB::bind_method(_MD("get_drop_mode_flags"),&Tree::get_drop_mode_flags); + ADD_SIGNAL( MethodInfo("item_selected")); ADD_SIGNAL( MethodInfo("cell_selected")); @@ -3300,6 +3517,11 @@ void Tree::_bind_methods() { BIND_CONSTANT( SELECT_SINGLE ); BIND_CONSTANT( SELECT_ROW ); BIND_CONSTANT( SELECT_MULTI ); + + BIND_CONSTANT( DROP_MODE_DISABLED ); + BIND_CONSTANT( DROP_MODE_ON_ITEM ); + BIND_CONSTANT( DROP_MODE_INBETWEEN ); + } Tree::Tree() { @@ -3381,6 +3603,11 @@ Tree::Tree() { hide_folding=false; evaluator=NULL; + + drop_mode_flags=0; + drop_mode_over=NULL; + drop_mode_section=0; + single_select_defer=NULL; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 75bcfd8e33..43a913392e 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -79,7 +79,9 @@ friend class Tree; bool custom_color; Color color; bool custom_bg_color; + bool custom_bg_outline; Color bg_color; + Variant meta; String tooltip; @@ -226,7 +228,7 @@ public: Color get_custom_color(int p_column) const; void clear_custom_color(int p_column); - void set_custom_bg_color(int p_column,const Color& p_color); + void set_custom_bg_color(int p_column, const Color& p_color, bool p_bg_outline=false); void clear_custom_bg_color(int p_column); Color get_custom_bg_color(int p_column) const; @@ -257,6 +259,12 @@ public: SELECT_MULTI }; + enum DropModeFlags { + DROP_MODE_DISABLED=0, + DROP_MODE_ON_ITEM=1, + DROP_MODE_INBETWEEN=2 + }; + private: friend class TreeItem; @@ -265,6 +273,11 @@ friend class TreeItem; TreeItem *selected_item; TreeItem *edited_item; + TreeItem *drop_mode_over; + int drop_mode_section; + + TreeItem *single_select_defer; + int single_select_defer_column; int pressed_button; bool pressing_for_editor; @@ -289,6 +302,8 @@ friend class TreeItem; int blocked; + int drop_mode_flags; + struct ColumnInfo { int min_width; @@ -361,6 +376,8 @@ friend class TreeItem; Color font_color; Color font_color_selected; Color guide_color; + Color drop_position_color; + int hseparation; int vseparation; int item_margin; @@ -405,7 +422,7 @@ friend class TreeItem; TreeItem* _search_item_text(TreeItem *p_at, const String& p_find,int *r_col,bool p_selectable,bool p_backwards=false); - TreeItem* _find_item_at_pos(TreeItem *p_current, const Point2& p_pos,int& r_column,int &h) const; + TreeItem* _find_item_at_pos(TreeItem *p_current, const Point2& p_pos, int& r_column, int &h, int §ion) const; /* float drag_speed; float drag_accum; @@ -426,6 +443,8 @@ friend class TreeItem; ValueEvaluator *evaluator; + int _count_selected_items(TreeItem* p_from) const; + protected: static void _bind_methods(); @@ -433,10 +452,16 @@ protected: Object* _create_item(Object *p_parent) { return create_item(p_parent->cast_to<TreeItem>() ); } TreeItem *_get_next_selected(Object *p_item) { return get_next_selected(p_item->cast_to<TreeItem>() ); } Rect2 _get_item_rect(Object *p_item,int p_column) const { return get_item_rect(p_item->cast_to<TreeItem>(),p_column ); } + + public: virtual String get_tooltip(const Point2& p_pos) const; + TreeItem* get_item_at_pos(const Point2& p_pos) const; + int get_column_at_pos(const Point2& p_pos) const; + int get_drop_section_at_pos(const Point2& p_pos) const; + void clear(); TreeItem* create_item(TreeItem *p_parent=0); @@ -486,6 +511,9 @@ public: void set_hide_folding(bool p_hide); bool is_folding_hidden() const; + void set_drop_mode_flags(int p_flags); + int get_drop_mode_flags() const; + void set_value_evaluator(ValueEvaluator *p_evaluator); Tree(); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index bc37cde4a2..c31a57f819 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -94,13 +94,13 @@ Vector2 CanvasLayer::get_offset() const { } -void CanvasLayer::set_rotation(real_t p_rotation) { +void CanvasLayer::set_rotation(real_t p_radians) { if (locrotscale_dirty) _update_locrotscale(); - rot=p_rotation; + rot=p_radians; _update_xform(); } @@ -113,6 +113,29 @@ real_t CanvasLayer::get_rotation() const { return rot; } +void CanvasLayer::set_rotationd(real_t p_degrees) { + + set_rotation(Math::deg2rad(p_degrees)); +} + +real_t CanvasLayer::get_rotationd() const { + + return Math::rad2deg(get_rotation()); +} + +// Kept for compatibility after rename to {s,g}et_rotationd. +// Could be removed after a couple releases. +void CanvasLayer::_set_rotationd(real_t p_degrees) { + + WARN_PRINT("Deprecated method CanvasLayer._set_rotationd(): This method was renamed to set_rotationd. Please adapt your code accordingly, as the old method will be obsoleted."); + set_rotationd(p_degrees); +} + +real_t CanvasLayer::_get_rotationd() const { + + WARN_PRINT("Deprecated method CanvasLayer._get_rotationd(): This method was renamed to get_rotationd. Please adapt your code accordingly, as the old method will be obsoleted."); + return get_rotationd(); +} void CanvasLayer::set_scale(const Vector2& p_scale) { @@ -122,7 +145,6 @@ void CanvasLayer::set_scale(const Vector2& p_scale) { scale=p_scale; _update_xform(); - } Vector2 CanvasLayer::get_scale() const { @@ -193,16 +215,6 @@ RID CanvasLayer::get_viewport() const { return viewport; } -void CanvasLayer::_set_rotationd(real_t p_rotation) { - - set_rotation(Math::deg2rad(p_rotation)); -} - -real_t CanvasLayer::_get_rotationd() const { - - return Math::rad2deg(get_rotation()); -} - void CanvasLayer::_bind_methods() { @@ -216,10 +228,14 @@ void CanvasLayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_offset","offset"),&CanvasLayer::set_offset); ObjectTypeDB::bind_method(_MD("get_offset"),&CanvasLayer::get_offset); - ObjectTypeDB::bind_method(_MD("set_rotation","rotation"),&CanvasLayer::set_rotation); + ObjectTypeDB::bind_method(_MD("set_rotation","radians"),&CanvasLayer::set_rotation); ObjectTypeDB::bind_method(_MD("get_rotation"),&CanvasLayer::get_rotation); - ObjectTypeDB::bind_method(_MD("_set_rotationd","rotationd"),&CanvasLayer::_set_rotationd); + ObjectTypeDB::bind_method(_MD("set_rotationd","degrees"),&CanvasLayer::set_rotationd); + ObjectTypeDB::bind_method(_MD("get_rotationd"),&CanvasLayer::get_rotationd); + + // TODO: Obsolete those two methods (old name) properly (GH-4397) + ObjectTypeDB::bind_method(_MD("_set_rotationd","degrees"),&CanvasLayer::_set_rotationd); ObjectTypeDB::bind_method(_MD("_get_rotationd"),&CanvasLayer::_get_rotationd); ObjectTypeDB::bind_method(_MD("set_scale","scale"),&CanvasLayer::set_scale); @@ -231,7 +247,7 @@ void CanvasLayer::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"layer",PROPERTY_HINT_RANGE,"-128,128,1"),_SCS("set_layer"),_SCS("get_layer") ); //ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"transform",PROPERTY_HINT_RANGE),_SCS("set_transform"),_SCS("get_transform") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset") ); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"rotation"),_SCS("_set_rotationd"),_SCS("_get_rotationd") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"rotation"),_SCS("set_rotationd"),_SCS("get_rotationd") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scale"),_SCS("set_scale"),_SCS("get_scale") ); } diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 809b3fae7f..a3e8211a43 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -48,7 +48,7 @@ class CanvasLayer : public Node { RID viewport; Viewport *vp; - + // Deprecated, should be removed in a future version. void _set_rotationd(real_t p_rotation); real_t _get_rotationd() const; @@ -70,9 +70,12 @@ public: void set_offset(const Vector2& p_offset); Vector2 get_offset() const; - void set_rotation(real_t p_rotation); + void set_rotation(real_t p_radians); real_t get_rotation() const; + void set_rotationd(real_t p_degrees); + real_t get_rotationd() const; + void set_scale(const Vector2& p_scale); Vector2 get_scale() const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 8475ca0b39..da14fa1111 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2095,6 +2095,8 @@ void Node::_bind_methods() { BIND_CONSTANT( NOTIFICATION_PAUSED ); BIND_CONSTANT( NOTIFICATION_UNPAUSED ); BIND_CONSTANT( NOTIFICATION_INSTANCED ); + BIND_CONSTANT( NOTIFICATION_DRAG_BEGIN ); + BIND_CONSTANT( NOTIFICATION_DRAG_END ); diff --git a/scene/main/node.h b/scene/main/node.h index 560a2e588a..83086bb0cf 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -180,6 +180,8 @@ public: NOTIFICATION_PARENTED=18, NOTIFICATION_UNPARENTED=19, NOTIFICATION_INSTANCED=20, + NOTIFICATION_DRAG_BEGIN=21, + NOTIFICATION_DRAG_END=22, }; /* NODE/TREE */ diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5017ae61ff..265ee53e58 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -985,6 +985,16 @@ void Viewport::_propagate_enter_world(Node *p_node) { } } +void Viewport::_propagate_viewport_notification(Node* p_node,int p_what) { + + p_node->notification(p_what); + for(int i=0;i<p_node->get_child_count();i++) { + Node *c = p_node->get_child(i); + if (c->cast_to<Viewport>()) + continue; + _propagate_viewport_notification(c,p_what); + } +} void Viewport::_propagate_exit_world(Node *p_node) { @@ -1676,6 +1686,9 @@ void Viewport::_gui_input_event(InputEvent p_event) { if (p_event.mouse_button.button_index==BUTTON_LEFT) { gui.drag_accum=Vector2(); gui.drag_attempted=false; + if (gui.drag_data.get_type()!=Variant::NIL) { + _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); + } gui.drag_data=Variant(); } @@ -1736,6 +1749,7 @@ void Viewport::_gui_input_event(InputEvent p_event) { gui.mouse_over->drop_data(pos,gui.drag_data); gui.drag_data=Variant(); + _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); //change mouse accordingly } @@ -1759,6 +1773,7 @@ void Viewport::_gui_input_event(InputEvent p_event) { } if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) { + _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); gui.drag_data=Variant(); //always clear } @@ -1790,6 +1805,10 @@ void Viewport::_gui_input_event(InputEvent p_event) { gui.mouse_focus=NULL; } gui.drag_attempted=true; + if (gui.drag_data.get_type()!=Variant::NIL) { + + _propagate_viewport_notification(this,NOTIFICATION_DRAG_BEGIN); + } } } @@ -1814,6 +1833,8 @@ void Viewport::_gui_input_event(InputEvent p_event) { } } + + if (over!=gui.mouse_over) { if (gui.mouse_over) @@ -1896,7 +1917,15 @@ void Viewport::_gui_input_event(InputEvent p_event) { if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) { - /*bool can_drop =*/ over->can_drop_data(pos,gui.drag_data); + + bool can_drop = over->can_drop_data(pos,gui.drag_data); + + if (!can_drop) { + OS::get_singleton()->set_cursor_shape( OS::CURSOR_FORBIDDEN ); + } else { + OS::get_singleton()->set_cursor_shape( OS::CURSOR_CAN_DROP ); + + } //change mouse accordingly i guess } @@ -2367,6 +2396,9 @@ bool Viewport::is_input_disabled() const { return disable_input; } +Variant Viewport::gui_get_drag_data() const { + return gui.drag_data; +} void Viewport::_bind_methods() { @@ -2452,6 +2484,7 @@ void Viewport::_bind_methods() { ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"), &Viewport::warp_mouse); ObjectTypeDB::bind_method(_MD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack); + ObjectTypeDB::bind_method(_MD("gui_get_drag_data:Variant"), &Viewport::gui_get_drag_data); ObjectTypeDB::bind_method(_MD("set_disable_input","disable"), &Viewport::set_disable_input); ObjectTypeDB::bind_method(_MD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index afabd499a9..6107cf570f 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -159,6 +159,7 @@ friend class RenderTargetTexture; void _propagate_enter_world(Node *p_node); void _propagate_exit_world(Node *p_node); + void _propagate_viewport_notification(Node *p_node, int p_what); void _update_stretch_transform(); @@ -361,6 +362,7 @@ public: bool gui_has_modal_stack() const; + Variant gui_get_drag_data() const; Viewport(); ~Viewport(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 727c8eee29..ade56c4f49 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -655,6 +655,7 @@ void make_default_theme() { t->set_color("selection_color","Tree", Color(0.1,0.1,1,0.8) ); t->set_color("cursor_color","Tree", Color(0,0,0) ); t->set_color("guide_color","Tree", Color(0,0,0,0.1) ); + t->set_color("drop_position_color","Tree", Color(1,0.3,0.2) ); t->set_constant("hseparation","Tree",4); t->set_constant("vseparation","Tree",4); diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 2736a75ac3..8e5087b405 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -523,7 +523,7 @@ void EditorNode::save_resource(const Ref<Resource>& p_resource) { } } -void EditorNode::save_resource_as(const Ref<Resource>& p_resource) { +void EditorNode::save_resource_as(const Ref<Resource>& p_resource,const String& p_at_path) { file->set_mode(EditorFileDialog::MODE_SAVE_FILE); bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool()); @@ -546,7 +546,21 @@ void EditorNode::save_resource_as(const Ref<Resource>& p_resource) { } //file->set_current_path(current_path); - if (p_resource->get_path()!="") { + + if (p_at_path!=String()) { + + file->set_current_dir(p_at_path); + if (p_resource->get_path().is_resource_file()) { + file->set_current_file(p_resource->get_path().get_file()); + } else { + if (extensions.size()) { + file->set_current_file("new_"+p_resource->get_type().to_lower()+"."+preferred.front()->get().to_lower()); + } else { + file->set_current_file(String()); + } + } + } else if (p_resource->get_path()!="") { + file->set_current_path(p_resource->get_path()); if (extensions.size()) { String ext=p_resource->get_path().extension().to_lower(); @@ -4881,6 +4895,114 @@ void EditorNode::remove_control_from_dock(Control* p_control) { _update_dock_slots_visibility(); } +Variant EditorNode::drag_resource(const Ref<Resource>& p_res,Control* p_from) { + + + Control *drag_control = memnew( Control ); + TextureFrame *drag_preview = memnew( TextureFrame ); + Label* label=memnew( Label ); + + Ref<Texture> preview; + + { + //todo make proper previews + Ref<ImageTexture> pic = gui_base->get_icon("FileBig","EditorIcons"); + Image img = pic->get_data(); + img.resize(48,48); //meh + Ref<ImageTexture> resized_pic = Ref<ImageTexture>( memnew( ImageTexture) ); + resized_pic->create_from_image(img); + preview=resized_pic; + } + + drag_preview->set_texture(preview); + drag_control->add_child(drag_preview); + if (p_res->get_path().is_resource_file()) { + label->set_text(p_res->get_path().get_file()); + } else if (p_res->get_name()!="") { + label->set_text(p_res->get_name()); + } else { + label->set_text(p_res->get_type()); + + } + + drag_control->add_child(label); + + p_from->set_drag_preview(drag_control); //wait until it enters scene + + label->set_pos( Point2((preview->get_width()-label->get_minimum_size().width)/2,preview->get_height()) ); + + Dictionary drag_data; + drag_data["type"]="resource"; + drag_data["resource"]=p_res; + drag_data["from"]=p_from; + + + return drag_data; + +} + +Variant EditorNode::drag_files(const Vector<String>& p_files, Control *p_from){ + + VBoxContainer *files = memnew( VBoxContainer ); + + int max_files=6; + + for(int i=0;i<MIN(max_files,p_files.size());i++) { + + Label* label=memnew( Label ); + label->set_text(p_files[i].get_file()); + files->add_child(label); + } + + if (p_files.size()>max_files) { + + Label* label=memnew( Label ); + label->set_text(itos(p_files.size()-max_files)+" "+TTR("More File(s)")); + files->add_child(label); + + } + Dictionary drag_data; + drag_data["type"]="files"; + drag_data["files"]=p_files; + drag_data["from"]=p_from; + + p_from->set_drag_preview(files); //wait until it enters scene + + return drag_data; + +} + +Variant EditorNode::drag_files_and_dirs(const Vector<String>& p_files, Control *p_from){ + + VBoxContainer *files = memnew( VBoxContainer ); + + int max_files=6; + + for(int i=0;i<MIN(max_files,p_files.size());i++) { + + Label* label=memnew( Label ); + label->set_text(p_files[i].get_file()); + files->add_child(label); + } + + if (p_files.size()>max_files) { + + Label* label=memnew( Label ); + label->set_text(itos(p_files.size()-max_files)+" "+TTR("More File(s) and/or Directory(s)")); + files->add_child(label); + + } + Dictionary drag_data; + drag_data["type"]="files_and_dirs"; + drag_data["files"]=p_files; + drag_data["from"]=p_from; + + p_from->set_drag_preview(files); //wait until it enters scene + + return drag_data; + +} + void EditorNode::_bind_methods() { diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index c3b7a817c5..b3faa21cf3 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -584,6 +584,9 @@ public: static void add_editor_plugin(EditorPlugin *p_editor); static void remove_editor_plugin(EditorPlugin *p_editor); + + + void add_control_to_dock(DockSlot p_slot,Control* p_control); void remove_control_from_dock(Control* p_control); @@ -599,7 +602,7 @@ public: void save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path); void save_resource(const Ref<Resource>& p_resource); - void save_resource_as(const Ref<Resource>& p_resource); + void save_resource_as(const Ref<Resource>& p_resource, const String &p_at_path=String()); static bool has_unsaved_changes() { return singleton->unsaved_cache; } @@ -696,6 +699,11 @@ public: void hide_bottom_panel(); void remove_bottom_panel_item(Control *p_item); + Variant drag_resource(const Ref<Resource>& p_res,Control* p_from); + Variant drag_files(const Vector<String>& p_files,Control* p_from); + Variant drag_files_and_dirs(const Vector<String>& p_files,Control* p_from); + + EditorNode(); ~EditorNode(); void get_singleton(const char* arg1, bool arg2); diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 4540419a19..b9b6dc5616 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -426,6 +426,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("text_editor/create_signal_callbacks",true); set("text_editor/autosave_interval_secs",0); + set("text_editor/caret_blink", false); + set("text_editor/caret_blink_speed", 0.65); + hints["text_editor/caret_blink_speed"]=PropertyInfo(Variant::REAL,"text_editor/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1, 10, 0.1"); + set("text_editor/font",""); hints["text_editor/font"]=PropertyInfo(Variant::STRING,"text_editor/font",PROPERTY_HINT_GLOBAL_FILE,"*.fnt"); set("text_editor/auto_brace_complete", false); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp index 7ece65e75a..0213dbda59 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.cpp +++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp @@ -572,6 +572,8 @@ bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_appe _append_canvas_item(item); viewport->update(); + return true; + } else { //regular selection diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index eaf08ca1c0..d8d5fddfe9 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -1967,6 +1967,8 @@ void ScriptEditor::edit(const Ref<Script>& p_script) { ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); ste->get_text_edit()->set_callhint_settings( EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"), EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset")); @@ -2114,6 +2116,8 @@ void ScriptEditor::_editor_settings_changed() { ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); } } diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index 3399114402..8a65a3641f 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/tools/editor/plugins/shader_editor_plugin.cpp @@ -368,6 +368,8 @@ void ShaderEditor::_editor_settings_changed() { vertex_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); vertex_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); vertex_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + vertex_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + vertex_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); fragment_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); fragment_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); @@ -376,6 +378,8 @@ void ShaderEditor::_editor_settings_changed() { fragment_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); fragment_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); fragment_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + fragment_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + fragment_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); light_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete")); light_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file")); @@ -384,6 +388,8 @@ void ShaderEditor::_editor_settings_changed() { light_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers")); light_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting")); light_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences")); + light_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink")); + light_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed")); } void ShaderEditor::_bind_methods() { diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 7c5aca579c..6f80910150 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -43,7 +43,8 @@ #include "array_property_edit.h" #include "editor_help.h" #include "scene/resources/packed_scene.h" - +#include "scene/main/viewport.h" +#include "editor_file_system.h" void CustomPropertyEditor::_notification(int p_what) { @@ -224,6 +225,10 @@ void CustomPropertyEditor::_menu_option(int p_which) { } +void CustomPropertyEditor::hide_menu() { + menu->hide(); +} + Variant CustomPropertyEditor::get_variant() const { return v; @@ -2257,6 +2262,179 @@ void PropertyEditor::_check_reload_status(const String&p_name, TreeItem* item) { } } + + +bool PropertyEditor::_is_drop_valid(const Dictionary& p_drag_data, const Dictionary& p_item_data) const { + + Dictionary d = p_item_data; + + if (d.has("type")) { + + int type = d["type"]; + if (type==Variant::OBJECT && d.has("hint") && d.has("hint_text") && int(d["hint"])==PROPERTY_HINT_RESOURCE_TYPE) { + + + String allowed_type=d["hint_text"]; + + Dictionary drag_data = p_drag_data; + if (drag_data.has("type") && String(drag_data["type"])=="resource") { + Ref<Resource> res = drag_data["resource"]; + for(int i=0;i<allowed_type.get_slice_count(",");i++) { + String at = allowed_type.get_slice(",",i).strip_edges(); + if (res.is_valid() && ObjectTypeDB::is_type(res->get_type(),at)) { + return true; + } + } + + } + if (drag_data.has("type") && String(drag_data["type"])=="files") { + + Vector<String> files = drag_data["files"]; + + if (files.size()==1) { + String file = files[0]; + String ftype = EditorFileSystem::get_singleton()->get_file_type(file); + if (ftype!="") { + + for(int i=0;i<allowed_type.get_slice_count(",");i++) { + String at = allowed_type.get_slice(",",i).strip_edges(); + if (ObjectTypeDB::is_type(ftype,at)) { + return true; + } + } + } + } + } + } + } + + + return false; + +} +void PropertyEditor::_mark_drop_fields(TreeItem* p_at) { + + if (_is_drop_valid(get_viewport()->gui_get_drag_data(),p_at->get_metadata(0))) + p_at->set_custom_bg_color(1,Color(0.7,0.5,0.2),true); + + if (p_at->get_children()) { + _mark_drop_fields(p_at->get_children()); + } + + if (p_at->get_next()) { + _mark_drop_fields(p_at->get_next()); + } +} + +Variant PropertyEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) { + + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return Variant(); + + int col = tree->get_column_at_pos(p_point); + if (col!=1) + return Variant(); + + + Dictionary d = item->get_metadata(0); + if (!d.has("name")) + return Variant(); + + Variant val = obj->get(d["name"]); + + if (val.get_type()==Variant::OBJECT) { + RES res = val; + if (res.is_valid()) { + + custom_editor->hide_menu(); + return EditorNode::get_singleton()->drag_resource(res,p_from); + } + } + + return Variant(); +} + +bool PropertyEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{ + + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return false; + + int col = tree->get_column_at_pos(p_point); + if (col!=1) + return false; + + return _is_drop_valid(p_data,item->get_metadata(0)); + +} +void PropertyEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){ + + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return; + + int col = tree->get_column_at_pos(p_point); + if (col!=1) + return; + + if (!_is_drop_valid(p_data,item->get_metadata(0))) + return; + + Dictionary d = item->get_metadata(0); + + if (!d.has("name")) + return; + + String name=d["name"]; + + Dictionary drag_data = p_data; + if (drag_data.has("type") && String(drag_data["type"])=="resource") { + Ref<Resource> res = drag_data["resource"]; + if (res.is_valid()) { + _edit_set(name,res); + return; + } + } + + if (drag_data.has("type") && String(drag_data["type"])=="files") { + + Vector<String> files = drag_data["files"]; + + if (files.size()==1) { + String file = files[0]; + RES res = ResourceLoader::load(file); + if (res.is_valid()) { + _edit_set(name,res); + return; + } + } + } +} + + +void PropertyEditor::_clear_drop_fields(TreeItem* p_at) { + + Dictionary d = p_at->get_metadata(0); + + if (d.has("type")) { + + int type = d["type"]; + if (type==Variant::OBJECT) { + p_at->clear_custom_bg_color(1); + } + + } + + if (p_at->get_children()) { + _clear_drop_fields(p_at->get_children()); + } + + if (p_at->get_next()) { + _clear_drop_fields(p_at->get_next()); + } +} + void PropertyEditor::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { @@ -2270,6 +2448,20 @@ void PropertyEditor::_notification(int p_what) { } + if (p_what==NOTIFICATION_DRAG_BEGIN) { + + if (is_visible() && tree->get_root()) { + _mark_drop_fields(tree->get_root()); + } + } + + if (p_what==NOTIFICATION_DRAG_END) { + if (is_visible() && tree->get_root()) { + _clear_drop_fields(tree->get_root()); + } + + } + if (p_what==NOTIFICATION_FIXED_PROCESS) { @@ -3661,6 +3853,10 @@ void PropertyEditor::_bind_methods() { ObjectTypeDB::bind_method( "_filter_changed",&PropertyEditor::_filter_changed); ObjectTypeDB::bind_method( "update_tree",&PropertyEditor::update_tree); + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &PropertyEditor::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &PropertyEditor::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &PropertyEditor::drop_data_fw); + ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value"))); ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) ); ADD_SIGNAL( MethodInfo("property_keyed",PropertyInfo( Variant::STRING, "property"))); @@ -3778,6 +3974,8 @@ PropertyEditor::PropertyEditor() { tree->connect("item_edited", this,"_item_edited",varray(),CONNECT_DEFERRED); tree->connect("cell_selected", this,"_item_selected"); + tree->set_drag_forwarding(this); + set_fixed_process(true); custom_editor = memnew( CustomPropertyEditor ); diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index 693bfb3efd..ac58011d43 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -137,6 +137,10 @@ protected: static void _bind_methods(); public: + + + void hide_menu(); + Variant get_variant() const; String get_name() const; @@ -219,6 +223,15 @@ class PropertyEditor : public Control { void _filter_changed(const String& p_text); + void _mark_drop_fields(TreeItem* p_at); + void _clear_drop_fields(TreeItem* p_at); + + bool _is_drop_valid(const Dictionary& p_drag_data, const Dictionary& p_item_data) const; + Variant get_drag_data_fw(const Point2& p_point,Control* p_from); + bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const; + void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from); + + UndoRedo *undo_redo; protected: diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 113d18ea73..252e7c890c 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -40,6 +40,9 @@ #include "tools/editor/plugins/animation_player_editor_plugin.h" #include "animation_editor.h" + + + void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { uint32_t sc = p_event.key.get_scancode_with_modifiers(); @@ -943,16 +946,37 @@ bool SceneTreeDock::_validate_no_foreign() { void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { - Node *node = scene_tree->get_selected(); - ERR_FAIL_COND(!node); - ERR_FAIL_COND(node==edited_scene); Node *new_parent = scene_root->get_node(p_path); ERR_FAIL_COND(!new_parent); + //ok all valid + + List<Node*> selection = editor_selection->get_selected_node_list(); + + if (selection.empty()) + return; //nothing to reparent + + Vector<Node*> nodes; + + for(List<Node*>::Element *E=selection.front();E;E=E->next()) { + nodes.push_back(E->get()); + } + + _do_reparent(new_parent,-1,nodes,p_keep_global_xform); + +} + + +void SceneTreeDock::_do_reparent(Node* p_new_parent,int p_position_in_parent,Vector<Node*> p_nodes,bool p_keep_global_xform) { + + + Node *new_parent = p_new_parent; + ERR_FAIL_COND(!new_parent); + Node *validate=new_parent; while(validate) { - if (editor_selection->is_selected(validate)) { + if (p_nodes.find(validate)!=-1) { ERR_EXPLAIN("Selection changed at some point.. can't reparent"); ERR_FAIL(); return; @@ -964,20 +988,20 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { List<Node*> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) + if (p_nodes.size()==0) return; //nothing to reparent //sort by tree order, so re-adding is easy - selection.sort_custom<Node::Comparator>(); + p_nodes.sort_custom<Node::Comparator>(); editor_data->get_undo_redo().create_action(TTR("Reparent Node")); List<Pair<NodePath,NodePath> > path_renames; - for(List<Node*>::Element *E=selection.front();E;E=E->next()) { + for(int ni=0;ni<p_nodes.size();ni++) { //no undo for now, sorry - Node *node = E->get(); + Node *node = p_nodes[ni]; fill_path_renames(node,new_parent,&path_renames); @@ -994,6 +1018,9 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { editor_data->get_undo_redo().add_do_method(node->get_parent(),"remove_child",node); editor_data->get_undo_redo().add_do_method(new_parent,"add_child",node); + if (p_position_in_parent>=0) + editor_data->get_undo_redo().add_do_method(new_parent,"move_child",node,p_position_in_parent+ni); + ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); String new_name = new_parent->validate_child_name(node->get_name()); editor_data->get_undo_redo().add_do_method(sed,"live_debug_reparent_node",edited_scene->get_path_to(node),edited_scene->get_path_to(new_parent),new_name,-1); @@ -1030,9 +1057,9 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { - for(List<Node*>::Element *E=selection.front();E;E=E->next()) { + for(int ni=0;ni<p_nodes.size();ni++) { - Node *node = E->get(); + Node *node = p_nodes[ni]; List<Node*> owned; node->get_owned_by(node->get_owner(),&owned); @@ -1078,7 +1105,6 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) { //node->set_owner(owner); } - void SceneTreeDock::_script_created(Ref<Script> p_script) { Node *selected = scene_tree->get_selected(); @@ -1431,6 +1457,161 @@ void SceneTreeDock::_new_scene_from(String p_file) { } +static bool _is_node_visible(Node* p_node) { + + if (!p_node->get_owner()) + return false; + if (p_node->get_owner()!=EditorNode::get_singleton()->get_edited_scene() && !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node->get_owner())) + return false; + + return true; + +} + +static bool _has_visible_children(Node* p_node) { + + bool collapsed = p_node->has_meta("_editor_collapsed") ? (bool)p_node->get_meta("_editor_collapsed") : false; + if (collapsed) + return false; + + for(int i=0;i<p_node->get_child_count();i++) { + + Node* child = p_node->get_child(i); + if (!_is_node_visible(p_node)) + continue; + + return true; + } + + return false; + +} + + +static Node* _find_last_visible(Node*p_node) { + + Node*last=NULL; + for(int i=0;i<p_node->get_child_count();i++) { + if (_is_node_visible(p_node->get_child(i))) { + last=p_node->get_child(i); + } + } + + if (last) { + Node* lastc=_find_last_visible(last); + if (lastc) + last=lastc; + + + } else { + last=p_node; + } + + return last; +} + +void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) { + + Vector<Node*> nodes; + Node *to_node; + + for(int i=0;i<p_nodes.size();i++) { + Node *n=get_node((p_nodes[i])); + nodes.push_back(n); + } + + if (nodes.size()==0) + return; + + to_node=get_node(p_to); + if (!to_node) + return; + + + int to_pos=-1; + + if (p_type==1 && to_node==EditorNode::get_singleton()->get_edited_scene()) { + //if at lower sibling of root node + to_pos=0; //just insert at begining of root node + } else if (p_type==-1) { + //drop at above selected node + ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene()); + Node* upper_sibling=NULL; + + for(int i=0;i<to_node->get_index();i++) { + Node *c =to_node->get_parent()->get_child(i); + if (_is_node_visible(c)) { + upper_sibling=c; + } + } + + + if (upper_sibling) { + //quite complicated, look for next visible in tree + upper_sibling=_find_last_visible(upper_sibling); + + if (upper_sibling->get_parent()==to_node->get_parent()) { + //just insert over this node because nothing is above at an upper level + to_pos=to_node->get_index(); + to_node=to_node->get_parent(); + } else { + to_pos=-1; //insert last in whathever is up + to_node=upper_sibling->get_parent(); //insert at a parent of whathever is up + } + + + } else { + //just insert over this node because nothing is above at the same level + to_pos=to_node->get_index(); + to_node=to_node->get_parent(); + } + + } else if (p_type==1) { + //drop at below selected node + ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene()); + + + Node* lower_sibling=NULL; + + for(int i=to_node->get_index()+1;i<to_node->get_parent()->get_child_count();i++) { + Node *c =to_node->get_parent()->get_child(i); + if (_is_node_visible(c)) { + lower_sibling=c; + } + } + + if (lower_sibling) { + to_pos=lower_sibling->get_index(); + } + + to_node=to_node->get_parent(); +#if 0 + //quite complicated, look for next visible in tree + upper_sibling=_find_last_visible(upper_sibling); + + if (upper_sibling->get_parent()==to_node->get_parent()) { + //just insert over this node because nothing is above at an upper level + to_pos=to_node->get_index(); + to_node=to_node->get_parent(); + } else { + to_pos=-1; //insert last in whathever is up + to_node=upper_sibling->get_parent(); //insert at a parent of whathever is up + } + + + } else { + //just insert over this node because nothing is above at the same level + to_pos=to_node->get_index(); + to_node=to_node->get_parent(); + } +#endif + + } + + _do_reparent(to_node,to_pos,nodes,true); + +} + void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_tool_selected"),&SceneTreeDock::_tool_selected); @@ -1449,6 +1630,8 @@ void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene); ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed); ObjectTypeDB::bind_method(_MD("_new_scene_from"),&SceneTreeDock::_new_scene_from); + ObjectTypeDB::bind_method(_MD("_nodes_dragged"),&SceneTreeDock::_nodes_dragged); + ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance); } @@ -1518,6 +1701,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec scene_tree->connect("node_prerename", this,"_node_prerenamed"); scene_tree->connect("open",this,"_load_request"); scene_tree->connect("open_script",this,"_script_open_request"); + scene_tree->connect("nodes_rearranged",this,"_nodes_dragged"); + scene_tree->set_undo_redo(&editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); @@ -1612,6 +1797,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec add_child(new_scene_from_dialog); new_scene_from_dialog->connect("file_selected",this,"_new_scene_from"); + + first_enter=true; diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index 114e2c5c97..264a05e23e 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -102,6 +102,8 @@ class SceneTreeDock : public VBoxContainer { Node *_duplicate(Node *p_node, Map<Node*,Node*> &duplimap); void _node_reparent(NodePath p_path, bool p_keep_global_xform); + void _do_reparent(Node* p_new_parent, int p_position_in_parent, Vector<Node*> p_nodes, bool p_keep_global_xform); + void _set_owners(Node *p_owner, const Array& p_nodes); void _load_request(const String& p_path); void _script_open_request(const Ref<Script>& p_script); @@ -128,6 +130,8 @@ class SceneTreeDock : public VBoxContainer { void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames); + void _nodes_dragged(Array p_nodes,NodePath p_to,int p_type); + protected: void _notification(int p_what); diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index 6d13f74e4d..720516bd7e 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/tools/editor/scene_tree_editor.cpp @@ -784,6 +784,96 @@ void SceneTreeEditor::_cell_collapsed(Object *p_obj) { } +Variant SceneTreeEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) { + if (!can_rename) + return Variant(); //not editable tree + + Vector<Node*> selected; + Vector<Ref<Texture> > icons; + TreeItem *next=tree->get_next_selected(NULL); + while (next) { + + NodePath np = next->get_metadata(0); + + Node *n=get_node(np); + if (n) { + + selected.push_back(n); + icons.push_back(next->get_icon(0)); + } + next=tree->get_next_selected(next); + } + + if (selected.empty()) + return Variant(); + + VBoxContainer *vb = memnew( VBoxContainer ); + Array objs; + for(int i=0;i<selected.size();i++) { + + HBoxContainer *hb = memnew( HBoxContainer ); + TextureFrame *tf = memnew(TextureFrame); + tf->set_texture(icons[i]); + hb->add_child(tf); + Label *label = memnew( Label( selected[i]->get_name() ) ); + hb->add_child(label); + vb->add_child(hb); + NodePath p = selected[i]->get_path(); + objs.push_back(p); + } + + set_drag_preview(vb); + Dictionary drag_data; + drag_data["type"]="nodes"; + drag_data["nodes"]=objs; + + tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN|Tree::DROP_MODE_ON_ITEM); + + + return drag_data; +} + +bool SceneTreeEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const { + + if (!can_rename) + return false; //not editable tree + + Dictionary d=p_data; + if (!d.has("type") || String(d["type"])!="nodes") + return false; + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return false; + int section = tree->get_drop_section_at_pos(p_point); + if (section<-1 || (section==-1 && !item->get_parent())) + return false; + + return true; +} +void SceneTreeEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) { + + if (!can_drop_data_fw(p_point,p_data,p_from)) + return; + + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return; + int section = tree->get_drop_section_at_pos(p_point); + if (section<-1) + return; + + NodePath np = item->get_metadata(0); + Node *n=get_node(np); + if (!n) + return; + + Dictionary d=p_data; + + Array nodes=d["nodes"]; + + emit_signal("nodes_rearranged",nodes,np,section); + +} void SceneTreeEditor::_bind_methods() { @@ -804,10 +894,15 @@ void SceneTreeEditor::_bind_methods() { ObjectTypeDB::bind_method("_node_script_changed",&SceneTreeEditor::_node_script_changed); ObjectTypeDB::bind_method("_node_visibility_changed",&SceneTreeEditor::_node_visibility_changed); + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &SceneTreeEditor::drop_data_fw); + ADD_SIGNAL( MethodInfo("node_selected") ); ADD_SIGNAL( MethodInfo("node_renamed") ); ADD_SIGNAL( MethodInfo("node_prerename") ); ADD_SIGNAL( MethodInfo("node_changed") ); + ADD_SIGNAL( MethodInfo("nodes_rearranged",PropertyInfo(Variant::ARRAY,"paths"),PropertyInfo(Variant::NODE_PATH,"to_path"),PropertyInfo(Variant::INT,"type") ) ); ADD_SIGNAL( MethodInfo("open") ); ADD_SIGNAL( MethodInfo("open_script") ); @@ -846,6 +941,8 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open add_child( tree ); + tree->set_drag_forwarding(this); + tree->connect("cell_selected", this,"_selected_changed"); tree->connect("item_edited", this,"_renamed",varray(),CONNECT_DEFERRED); tree->connect("multi_selected",this,"_cell_multi_selected"); diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h index 27ccaaae01..283db280ed 100644 --- a/tools/editor/scene_tree_editor.h +++ b/tools/editor/scene_tree_editor.h @@ -111,8 +111,14 @@ class SceneTreeEditor : public Control { void _node_visibility_changed(Node *p_node); void _subscene_option(int p_idx); + void _selection_changed(); Node *get_scene_node(); + + 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); + public: diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 7cb0a094b2..f44435d9b3 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -451,7 +451,7 @@ void ScenesDock::_update_files(bool p_keep_selection) { img.resize(thumbnail_size,thumbnail_size); Ref<ImageTexture> resized_folder = Ref<ImageTexture>( memnew( ImageTexture)); resized_folder->create_from_image(img,0); - Theme::get_default()->set_icon(TTR("ResizedFolder"),"EditorIcons",resized_folder); + Theme::get_default()->set_icon("ResizedFolder","EditorIcons",resized_folder); } folder_thumbnail = get_icon("ResizedFolder","EditorIcons"); @@ -462,7 +462,7 @@ void ScenesDock::_update_files(bool p_keep_selection) { img.resize(thumbnail_size,thumbnail_size); Ref<ImageTexture> resized_file = Ref<ImageTexture>( memnew( ImageTexture)); resized_file->create_from_image(img,0); - Theme::get_default()->set_icon(TTR("ResizedFile"),"EditorIcons",resized_file); + Theme::get_default()->set_icon("ResizedFile","EditorIcons",resized_file); } file_thumbnail = get_icon("ResizedFile","EditorIcons"); @@ -1073,6 +1073,142 @@ void ScenesDock::set_use_thumbnails(bool p_use) { display_mode->set_pressed(!p_use); } + +Variant ScenesDock::get_drag_data_fw(const Point2& p_point,Control* p_from) { + + if (p_from==files) { + + List<int> seldirs; + List<int> selfiles; + + for (int i = 0; i<files->get_item_count(); i++) { + if (files->is_selected(i)) { + String path = files->get_item_metadata(i); + if (path.ends_with("/")) + seldirs.push_back(i); + else + selfiles.push_back(i); + } + } + + if (seldirs.empty() && selfiles.empty()) + return Variant(); + //if (seldirs.size() && selfiles.size()) + // return Variant(); //can't really mix files and dirs (i think?) - yes you can, commenting + + /*if (selfiles.size()==1) { + Ref<Resource> resource = ResourceLoader::load(files->get_item_metadata(selfiles.front()->get())); + if (resource.is_valid()) { + return EditorNode::get_singleton()->drag_resource(resource,p_from); + } + }*/ + + if (selfiles.size()>0 && seldirs.size()==0) { + Vector<String> fnames; + for(List<int>::Element *E=selfiles.front();E;E=E->next()) { + fnames.push_back(files->get_item_metadata(E->get())); + } + return EditorNode::get_singleton()->drag_files(fnames,p_from); + } + + if (selfiles.size()>0 || seldirs.size()>0) { + Vector<String> fnames; + for(List<int>::Element *E=selfiles.front();E;E=E->next()) { + fnames.push_back(files->get_item_metadata(E->get())); + } + for(List<int>::Element *E=seldirs.front();E;E=E->next()) { + fnames.push_back(files->get_item_metadata(E->get())); + } + return EditorNode::get_singleton()->drag_files_and_dirs(fnames,p_from); + } + + } + + return Variant(); +} + +bool ScenesDock::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{ + + Dictionary drag_data = p_data; + + print_line("CAN IT DROP DATA?"); + if (drag_data.has("type") && String(drag_data["type"])=="resource") { + return true; + } + + if (drag_data.has("type") && ( String(drag_data["type"])=="files" || String(drag_data["type"])=="files_and_dirs")) { + + Vector<String> fnames = drag_data["files"]; + + if (p_from==files) { + + int at_pos = files->get_item_at_pos(p_point); + if (at_pos!=-1) { + + String dir = files->get_item_metadata(at_pos); + if (dir.ends_with("/")) + return true; + } + } + } + + return false; +} + +void ScenesDock::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){ + + if (!can_drop_data_fw(p_point,p_data,p_from)) + return; + Dictionary drag_data = p_data; + + if (drag_data.has("type") && String(drag_data["type"])=="resource") { + Ref<Resource> res = drag_data["resource"]; + + if (!res.is_valid()) { + return; + } + + String save_path=path; + + int at_pos = files->get_item_at_pos(p_point); + if (at_pos!=-1) { + String to_dir = files->get_item_metadata(at_pos); + if (to_dir.ends_with("/")) { + save_path=to_dir; + if (save_path!="res://") + save_path=save_path.substr(0,save_path.length()-1); + } + + } + + EditorNode::get_singleton()->save_resource_as(res,save_path); + return; + } + + if (drag_data.has("type") && ( String(drag_data["type"])=="files" || String(drag_data["type"])=="files_and_dirs")) { + + int at_pos = files->get_item_at_pos(p_point); + ERR_FAIL_COND(at_pos==-1); + String to_dir = files->get_item_metadata(at_pos); + ERR_FAIL_COND(!to_dir.ends_with("/")); + + Vector<String> fnames = drag_data["files"]; + move_files.clear(); + move_dirs.clear(); + + for(int i=0;i<fnames.size();i++) { + if (fnames[i].ends_with("/")) + move_dirs.push_back(fnames[i]); + else + move_files.push_back(fnames[i]); + } + + _move_operation(to_dir); + } + +} + + void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree); @@ -1096,6 +1232,10 @@ void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation); ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation); + ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &ScenesDock::get_drag_data_fw); + ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &ScenesDock::can_drop_data_fw); + ObjectTypeDB::bind_method(_MD("drop_data_fw"), &ScenesDock::drop_data_fw); + ADD_SIGNAL(MethodInfo("instance")); ADD_SIGNAL(MethodInfo("open")); @@ -1199,6 +1339,7 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { files = memnew( ItemList ); files->set_v_size_flags(SIZE_EXPAND_FILL); files->set_select_mode(ItemList::SELECT_MULTI); + files->set_drag_forwarding(this); path_hb = memnew( HBoxContainer ); button_back = memnew( ToolButton ); diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index a630d2506d..86196b7ccd 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -142,6 +142,9 @@ class ScenesDock : public VBoxContainer { void _instance_pressed(); void _open_pressed(); + 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); |