diff options
Diffstat (limited to 'scene')
26 files changed, 3395 insertions, 2797 deletions
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 57495b5cb0..1c0be60764 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -41,7 +41,6 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { bool solids=build_mode==BUILD_SOLIDS; - if (solids) { //here comes the sun, lalalala @@ -51,6 +50,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D ); convex->set_points(decomp[i]); co->add_shape(convex,get_transform()); + if (trigger) + co->set_shape_as_trigger(co->get_shape_count()-1,true); } @@ -71,6 +72,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { concave->set_segments(segments); co->add_shape(concave,get_transform()); + if (trigger) + co->set_shape_as_trigger(co->get_shape_count()-1,true); } @@ -166,6 +169,18 @@ Rect2 CollisionPolygon2D::get_item_rect() const { return aabb; } +void CollisionPolygon2D::set_trigger(bool p_trigger) { + + trigger=p_trigger; + _update_parent(); +} + +bool CollisionPolygon2D::is_trigger() const{ + + return trigger; +} + + void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object); @@ -175,14 +190,19 @@ void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode); ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode); + ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger); + ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger); + ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Segments"),_SCS("set_build_mode"),_SCS("get_build_mode")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); } CollisionPolygon2D::CollisionPolygon2D() { aabb=Rect2(-10,-10,20,20); build_mode=BUILD_SOLIDS; + trigger=false; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 09c2060088..b8e27b6fb4 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -50,6 +50,7 @@ protected: Rect2 aabb; BuildMode build_mode; Vector<Point2> polygon; + bool trigger; void _add_to_collision_object(Object *p_obj); void _update_parent(); @@ -60,6 +61,9 @@ protected: static void _bind_methods(); public: + void set_trigger(bool p_trigger); + bool is_trigger() const; + void set_build_mode(BuildMode p_mode); BuildMode get_build_mode() const; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 655c6e8bf6..9d10000d2b 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -858,7 +858,8 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { //motion recover for(int i=0;i<get_shape_count();i++) { - + if (is_shape_set_as_trigger(i)) + continue; if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) collided=true; @@ -902,6 +903,8 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; float lsafe,lunsafe; bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask); diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp index 99dfa67c27..a231acd13d 100644 --- a/scene/2d/sample_player_2d.cpp +++ b/scene/2d/sample_player_2d.cpp @@ -102,6 +102,7 @@ void SamplePlayer2D::_notification(int p_what) { void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const { diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp index a4206894ff..651d20ae71 100644 --- a/scene/3d/immediate_geometry.cpp +++ b/scene/3d/immediate_geometry.cpp @@ -127,7 +127,7 @@ void ImmediateGeometry::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color); ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv); ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2); - ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex); + ObjectTypeDB::bind_method(_MD("add_vertex","pos"),&ImmediateGeometry::add_vertex); ObjectTypeDB::bind_method(_MD("add_sphere","lats","lons","radius"),&ImmediateGeometry::add_sphere); ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end); ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 21ecac6e3d..f2806f2af2 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -852,6 +852,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { //motion recover for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) { collided=true; @@ -930,6 +932,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; float lsafe,lunsafe; PhysicsDirectSpaceState::ShapeRestInfo lrest; @@ -1041,6 +1045,8 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) { //fill exclude list.. for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask); if (col) diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp index b4a5d3bc1b..6dc71e06ad 100644 --- a/scene/3d/spatial_sample_player.cpp +++ b/scene/3d/spatial_sample_player.cpp @@ -103,6 +103,7 @@ void SpatialSamplePlayer::_notification(int p_what) { void SpatialSamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SpatialSamplePlayer::get_sample_library() const { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 77f2cf5cc1..35f6523c6a 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -497,7 +497,7 @@ void Sprite3D::set_frame(int p_frame) { frame=p_frame; _queue_update(); - ADD_SIGNAL(MethodInfo("frame_changed")); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index ec72123c98..5172907d18 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -83,7 +83,8 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value) ERR_FAIL_COND_V(nt==NODE_MAX,false); - add_node(nt,id); + if (nt!=NODE_OUTPUT) + add_node(nt,id); node_set_pos(id,pos); diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 59793815f5..f668e52590 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -124,32 +124,34 @@ void Tween::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode); ObjectTypeDB::bind_method(_MD("start"),&Tween::start ); - ObjectTypeDB::bind_method(_MD("reset","node","key"),&Tween::reset ); + ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset ); ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all ); - ObjectTypeDB::bind_method(_MD("stop","node","key"),&Tween::stop ); + ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop ); ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all ); - ObjectTypeDB::bind_method(_MD("resume","node","key"),&Tween::resume ); + ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume ); ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all ); - ObjectTypeDB::bind_method(_MD("remove","node","key"),&Tween::remove ); + ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove ); ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all ); ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek ); ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell ); ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime ); - ObjectTypeDB::bind_method(_MD("interpolate_property","node","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("interpolate_method","node","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("interpolate_callback","node","callback","times_in_sec","args"),&Tween::interpolate_callback, DEFVAL(Variant()) ); - ObjectTypeDB::bind_method(_MD("follow_property","node","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("follow_method","node","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("targeting_property","node","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("targeting_method","node","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","args"),&Tween::interpolate_callback, DEFVAL(Variant()) ); + ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) ); - ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) ); - ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) ); - ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) ); + ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) ); + ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) ); + ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) ); ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode")); - //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "activate"), _SCS("set_active"), _SCS("is_active")); + + BIND_CONSTANT(TWEEN_PROCESS_FIXED); + BIND_CONSTANT(TWEEN_PROCESS_IDLE); BIND_CONSTANT(TRANS_LINEAR); BIND_CONSTANT(TRANS_SINE); @@ -181,19 +183,19 @@ Variant& Tween::_get_initial_val(InterpolateData& p_data) { case TARGETING_PROPERTY: case TARGETING_METHOD: { - Node *node = get_node(p_data.target); - ERR_FAIL_COND_V(node == NULL,p_data.initial_val); + Object *object = ObjectDB::get_instance(p_data.target_id); + ERR_FAIL_COND_V(object == NULL,p_data.initial_val); static Variant initial_val; if(p_data.type == TARGETING_PROPERTY) { bool valid = false; - initial_val = node->get(p_data.target_key, &valid); + initial_val = object->get(p_data.target_key, &valid); ERR_FAIL_COND_V(!valid,p_data.initial_val); } else { Variant::CallError error; - initial_val = node->call(p_data.target_key, NULL, 0, error); + initial_val = object->call(p_data.target_key, NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val); } return initial_val; @@ -213,7 +215,7 @@ Variant& Tween::_get_delta_val(InterpolateData& p_data) { case FOLLOW_PROPERTY: case FOLLOW_METHOD: { - Node *target = get_node(p_data.target); + Object *target = ObjectDB::get_instance(p_data.target_id); ERR_FAIL_COND_V(target == NULL,p_data.initial_val); Variant final_val; @@ -264,6 +266,11 @@ Variant Tween::_run_equation(InterpolateData& p_data) { switch(initial_val.get_type()) { + + case Variant::BOOL: + result = ((int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec)) >= 0.5; + break; + case Variant::INT: result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec); break; @@ -409,7 +416,7 @@ Variant Tween::_run_equation(InterpolateData& p_data) { bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) { - Object *object = get_node(p_data.path); + Object *object = ObjectDB::get_instance(p_data.id); ERR_FAIL_COND_V(object == NULL, false); switch(p_data.type) { @@ -452,6 +459,7 @@ void Tween::_tween_process(float p_delta) { return; p_delta *= speed_scale; + pending_update ++; // if repeat and all interpolates was finished then reset all interpolates if(repeat) { bool all_finished = true; @@ -476,7 +484,7 @@ void Tween::_tween_process(float p_delta) { if(!data.active || data.finish) continue; - Object *object = get_node(data.path); + Object *object = ObjectDB::get_instance(data.id); if(object == NULL) continue; @@ -523,6 +531,7 @@ void Tween::_tween_process(float p_delta) { if(data.finish) emit_signal("tween_complete",object,data.key); } + pending_update --; } void Tween::set_tween_process_mode(TweenProcessMode p_mode) { @@ -598,16 +607,17 @@ bool Tween::start() { return true; } -bool Tween::reset(Node *p_node, String p_key) { +bool Tween::reset(Object *p_object, String p_key) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) { + if(object == p_object && data.key == p_key) { data.elapsed = 0; data.finish = false; @@ -615,11 +625,13 @@ bool Tween::reset(Node *p_node, String p_key) { _apply_tween_value(data, data.initial_val); } } + pending_update --; return true; } bool Tween::reset_all() { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); @@ -628,20 +640,23 @@ bool Tween::reset_all() { if(data.delay == 0) _apply_tween_value(data, data.initial_val); } + pending_update --; return true; } -bool Tween::stop(Node *p_node, String p_key) { +bool Tween::stop(Object *p_object, String p_key) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) + if(object == p_object && data.key == p_key) data.active = false; } + pending_update --; return true; } @@ -650,28 +665,32 @@ bool Tween::stop_all() { set_active(false); _set_process(false); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); data.active = false; } + pending_update --; return true; } -bool Tween::resume(Node *p_node, String p_key) { +bool Tween::resume(Object *p_object, String p_key) { set_active(true); _set_process(true); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) + if(object == p_object && data.key == p_key) data.active = true; } + pending_update --; return true; } @@ -680,23 +699,26 @@ bool Tween::resume_all() { set_active(true); _set_process(true); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); data.active = true; } + pending_update --; return true; } -bool Tween::remove(Node *p_node, String p_key) { +bool Tween::remove(Object *p_object, String p_key) { + ERR_FAIL_COND_V(pending_update != 0, false); for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) { + if(object == p_object && data.key == p_key) { interpolates.erase(E); return true; } @@ -706,6 +728,7 @@ bool Tween::remove(Node *p_node, String p_key) { bool Tween::remove_all() { + ERR_FAIL_COND_V(pending_update != 0, false); set_active(false); _set_process(false); interpolates.clear(); @@ -714,6 +737,7 @@ bool Tween::remove_all() { bool Tween::seek(real_t p_time) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); @@ -744,11 +768,13 @@ bool Tween::seek(real_t p_time) { _apply_tween_value(data, result); } + pending_update --; return true; } real_t Tween::tell() const { + pending_update ++; real_t pos = 0; for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { @@ -756,11 +782,13 @@ real_t Tween::tell() const { if(data.elapsed > pos) pos = data.elapsed; } + pending_update --; return pos; } real_t Tween::get_runtime() const { + pending_update ++; real_t runtime = 0; for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { @@ -769,6 +797,7 @@ real_t Tween::get_runtime() const { if(t > runtime) runtime = t; } + pending_update --; return runtime; } @@ -779,6 +808,12 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final Variant& delta_val = p_delta_val; switch(initial_val.get_type()) { + + case Variant::BOOL: + //delta_val = p_final_val; + delta_val = (int) p_final_val - (int) p_initial_val; + break; + case Variant::INT: delta_val = (int) final_val - (int) initial_val; break; @@ -873,7 +908,7 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final return true; } -bool Tween::interpolate_property(Node *p_node +bool Tween::interpolate_property(Object *p_object , String p_property , Variant p_initial_val , Variant p_final_val @@ -882,11 +917,12 @@ bool Tween::interpolate_property(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -894,7 +930,7 @@ bool Tween::interpolate_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); InterpolateData data; @@ -903,7 +939,7 @@ bool Tween::interpolate_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; data.initial_val = p_initial_val; data.final_val = p_final_val; @@ -919,7 +955,7 @@ bool Tween::interpolate_property(Node *p_node return true; } -bool Tween::interpolate_method(Node *p_node +bool Tween::interpolate_method(Object *p_object , String p_method , Variant p_initial_val , Variant p_final_val @@ -928,18 +964,19 @@ bool Tween::interpolate_method(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); InterpolateData data; data.active = true; @@ -947,7 +984,7 @@ bool Tween::interpolate_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; data.initial_val = p_initial_val; data.final_val = p_final_val; @@ -963,16 +1000,17 @@ bool Tween::interpolate_method(Node *p_node return true; } -bool Tween::interpolate_callback(Node *p_node - , String p_callback +bool Tween::interpolate_callback(Object *p_object , real_t p_times_in_sec + , String p_callback , Variant p_arg ) { - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(pending_update != 0, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_times_in_sec < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_callback), false); + ERR_FAIL_COND_V(!p_object->has_method(p_callback), false); InterpolateData data; data.active = true; @@ -980,30 +1018,33 @@ bool Tween::interpolate_callback(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_callback; data.times_in_sec = p_times_in_sec; data.delay = 0; data.arg = p_arg; + pending_update ++; interpolates.push_back(data); + pending_update --; return true; } -bool Tween::follow_property(Node *p_node +bool Tween::follow_property(Object *p_object , String p_property , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_property , real_t p_times_in_sec , TransitionType p_trans_type , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -1011,7 +1052,7 @@ bool Tween::follow_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); bool target_prop_valid = false; @@ -1028,10 +1069,10 @@ bool Tween::follow_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; data.initial_val = p_initial_val; - data.target = p_target->get_path(); + data.target_id = p_target->get_instance_ID(); data.target_key = p_target_property; data.times_in_sec = p_times_in_sec; data.trans_type = p_trans_type; @@ -1042,27 +1083,28 @@ bool Tween::follow_property(Node *p_node return true; } -bool Tween::follow_method(Node *p_node +bool Tween::follow_method(Object *p_object , String p_method , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_method , real_t p_times_in_sec , TransitionType p_trans_type , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false); Variant::CallError error; @@ -1079,10 +1121,10 @@ bool Tween::follow_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; data.initial_val = p_initial_val; - data.target = p_target->get_path(); + data.target_id = p_target->get_instance_ID(); data.target_key = p_target_method; data.times_in_sec = p_times_in_sec; data.trans_type = p_trans_type; @@ -1093,9 +1135,9 @@ bool Tween::follow_method(Node *p_node return true; } -bool Tween::targeting_property(Node *p_node +bool Tween::targeting_property(Object *p_object , String p_property - , Node *p_initial + , Object *p_initial , String p_initial_property , Variant p_final_val , real_t p_times_in_sec @@ -1103,10 +1145,11 @@ bool Tween::targeting_property(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -1114,7 +1157,7 @@ bool Tween::targeting_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); bool initial_prop_valid = false; @@ -1131,9 +1174,9 @@ bool Tween::targeting_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; - data.target = p_initial->get_path(); + data.target_id = p_initial->get_instance_ID(); data.target_key = p_initial_property; data.initial_val = initial_val; data.final_val = p_final_val; @@ -1150,9 +1193,9 @@ bool Tween::targeting_property(Node *p_node } -bool Tween::targeting_method(Node *p_node +bool Tween::targeting_method(Object *p_object , String p_method - , Node *p_initial + , Object *p_initial , String p_initial_method , Variant p_final_val , real_t p_times_in_sec @@ -1160,17 +1203,18 @@ bool Tween::targeting_method(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false); Variant::CallError error; @@ -1187,9 +1231,9 @@ bool Tween::targeting_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; - data.target = p_initial->get_path(); + data.target_id = p_initial->get_instance_ID(); data.target_key = p_initial_method; data.initial_val = initial_val; data.final_val = p_final_val; @@ -1213,6 +1257,7 @@ Tween::Tween() { active=false; repeat=false; speed_scale=1; + pending_update=0; } Tween::~Tween() { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index c9d9863397..3e23cc362a 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -54,15 +54,17 @@ public: TRANS_CIRC, TRANS_BOUNCE, TRANS_BACK, - TRANS_COUNT, + + TRANS_COUNT, }; enum EaseType { EASE_IN, EASE_OUT, EASE_IN_OUT, - EASE_OUT_IN, - EASE_COUNT, + EASE_OUT_IN, + + EASE_COUNT, }; private: @@ -82,12 +84,12 @@ private: InterpolateType type; bool finish; real_t elapsed; - NodePath path; + ObjectID id; StringName key; Variant initial_val; Variant delta_val; Variant final_val; - NodePath target; + ObjectID target_id; StringName target_key; real_t times_in_sec; TransitionType trans_type; @@ -102,6 +104,7 @@ private: bool active; bool repeat; float speed_scale; + mutable int pending_update; List<InterpolateData> interpolates; @@ -142,20 +145,20 @@ public: float get_speed() const; bool start(); - bool reset(Node *p_node, String p_key); + bool reset(Object *p_node, String p_key); bool reset_all(); - bool stop(Node *p_node, String p_key); + bool stop(Object *p_node, String p_key); bool stop_all(); - bool resume(Node *p_node, String p_key); + bool resume(Object *p_node, String p_key); bool resume_all(); - bool remove(Node *p_node, String p_key); + bool remove(Object *p_node, String p_key); bool remove_all(); bool seek(real_t p_time); real_t tell() const; real_t get_runtime() const; - bool interpolate_property(Node *p_node + bool interpolate_property(Object *p_node , String p_property , Variant p_initial_val , Variant p_final_val @@ -165,7 +168,7 @@ public: , real_t p_delay = 0 ); - bool interpolate_method(Node *p_node + bool interpolate_method(Object *p_node , String p_method , Variant p_initial_val , Variant p_final_val @@ -175,16 +178,16 @@ public: , real_t p_delay = 0 ); - bool interpolate_callback(Node *p_node - , String p_callback + bool interpolate_callback(Object *p_node , real_t p_times_in_sec + , String p_callback , Variant p_arg = Variant() ); - bool follow_property(Node *p_node + bool follow_property(Object *p_node , String p_property , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_property , real_t p_times_in_sec , TransitionType p_trans_type @@ -192,10 +195,10 @@ public: , real_t p_delay = 0 ); - bool follow_method(Node *p_node + bool follow_method(Object *p_node , String p_method , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_method , real_t p_times_in_sec , TransitionType p_trans_type @@ -203,9 +206,9 @@ public: , real_t p_delay = 0 ); - bool targeting_property(Node *p_node + bool targeting_property(Object *p_node , String p_property - , Node *p_initial + , Object *p_initial , String p_initial_property , Variant p_final_val , real_t p_times_in_sec @@ -214,9 +217,9 @@ public: , real_t p_delay = 0 ); - bool targeting_method(Node *p_node + bool targeting_method(Object *p_node , String p_method - , Node *p_initial + , Object *p_initial , String p_initial_method , Variant p_final_val , real_t p_times_in_sec diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp index 90994f01b4..bf1c5e97a3 100644 --- a/scene/audio/sample_player.cpp +++ b/scene/audio/sample_player.cpp @@ -498,6 +498,7 @@ bool SamplePlayer::is_active() const { void SamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SamplePlayer::get_sample_library() const { diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 216c6d7122..5ed60e88f8 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -44,7 +44,7 @@ void BoxContainer::_resort() { Size2i new_size=get_size();; - int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer"); + int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer"); bool first=true; int children_count=0; @@ -202,7 +202,7 @@ Size2 BoxContainer::get_minimum_size() const { /* Calculate MINIMUM SIZE */ Size2i minimum; - int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer"); + int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer"); bool first=true; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp new file mode 100644 index 0000000000..6e3afeefd0 --- /dev/null +++ b/scene/gui/graph_node.cpp @@ -0,0 +1,320 @@ +#include "graph_node.h" + + +bool GraphNode::_set(const StringName& p_name, const Variant& p_value) { + + if (!p_name.operator String().begins_with("slot/")) + return false; + + int idx=p_name.operator String().get_slice("/",1).to_int(); + String what = p_name.operator String().get_slice("/",2); + + + Slot si; + if (slot_info.has(idx)) + si=slot_info[idx]; + + + if (what=="left_enabled") + si.enable_left=p_value; + else if (what=="left_type") + si.type_left=p_value; + else if (what=="left_color") + si.color_left=p_value; + else if (what=="right_enabled") + si.enable_right=p_value; + else if (what=="right_type") + si.type_right=p_value; + else if (what=="right_color") + si.color_right=p_value; + else + return false; + + set_slot(idx,si.enable_left,si.type_left,si.color_left,si.enable_right,si.type_right,si.color_right); + update(); + return true; +} + +bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{ + + + print_line("get "+p_name.operator String()); + if (!p_name.operator String().begins_with("slot/")) { + print_line("no begins"); + return false; + } + + int idx=p_name.operator String().get_slice("/",1).to_int(); + String what = p_name.operator String().get_slice("/",2); + + + + Slot si; + if (slot_info.has(idx)) + si=slot_info[idx]; + + if (what=="left_enabled") + r_ret=si.enable_left; + else if (what=="left_type") + r_ret=si.type_left; + else if (what=="left_color") + r_ret=si.color_left; + else if (what=="right_enabled") + r_ret=si.enable_right; + else if (what=="right_type") + r_ret=si.type_right; + else if (what=="right_color") + r_ret=si.color_right; + else + return false; + + print_line("ask for: "+p_name.operator String()+" get: "+String(r_ret)); + return true; +} +void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{ + + int idx=0; + for(int i=0;i<get_child_count();i++) { + Control *c=get_child(i)->cast_to<Control>(); + if (!c || c->is_set_as_toplevel() || !c->get_owner()) + continue; + + String base="slot/"+itos(idx)+"/"; + + p_list->push_back(PropertyInfo(Variant::BOOL,base+"left_enabled")); + p_list->push_back(PropertyInfo(Variant::INT,base+"left_type")); + p_list->push_back(PropertyInfo(Variant::COLOR,base+"left_color")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"right_enabled")); + p_list->push_back(PropertyInfo(Variant::INT,base+"right_type")); + p_list->push_back(PropertyInfo(Variant::COLOR,base+"right_color")); + + idx++; + } +} + + +void GraphNode::_resort() { + + + + int sep=get_constant("separation"); + Ref<StyleBox> sb=get_stylebox("frame"); + bool first=true; + + Size2 minsize; + + for(int i=0;i<get_child_count();i++) { + Control *c=get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + + Size2i size=c->get_combined_minimum_size(); + + minsize.y+=size.y; + minsize.x=MAX(minsize.x,size.x); + + if (first) + first=false; + else + minsize.y+=sep; + + } + + int vofs=0; + int w = get_size().x - sb->get_minimum_size().x; + + + cache_y.clear(); + for(int i=0;i<get_child_count();i++) { + Control *c=get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_set_as_toplevel() || !c->get_owner()) + continue; + + Size2i size=c->get_combined_minimum_size(); + + Rect2 r(sb->get_margin(MARGIN_LEFT),sb->get_margin(MARGIN_TOP)+vofs,w,size.y); + + fit_child_in_rect(c,r); + cache_y.push_back(vofs+size.y*0.5); + + if (vofs>0) + vofs+=sep; + vofs+=size.y; + + + } + + _change_notify(); + update(); + +} + + +void GraphNode::_notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW) { + + Ref<StyleBox> sb=get_stylebox("frame"); + Ref<Texture> port =get_icon("port"); + Point2i icofs = -port->get_size()*0.5; + int edgeofs=3; + icofs.y+=sb->get_margin(MARGIN_TOP); + draw_style_box(sb,Rect2(Point2(),get_size())); + + for (Map<int,Slot>::Element *E=slot_info.front();E;E=E->next()) { + + if (E->key()>cache_y.size()) + continue; + if (!slot_info.has(E->key())) + continue; + const Slot &s=slot_info[E->key()]; + //left + if (s.enable_left) + port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left); + if (s.enable_right) + port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right); + + } + } + if (p_what==NOTIFICATION_SORT_CHILDREN) { + + _resort(); + } + +} + +void GraphNode::set_title(const String& p_title) { + + title=p_title; + update(); +} + +String GraphNode::get_title() const { + + return title; +} + +void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) { + + ERR_FAIL_COND(p_idx<0); + + if (!p_enable_left && p_type_left==0 && p_color_left==Color(1,1,1,1) && !p_enable_right && p_type_right==0 && p_color_right==Color(1,1,1,1)) { + slot_info.erase(p_idx); + return; + } + + Slot s; + s.enable_left=p_enable_left; + s.type_left=p_type_left; + s.color_left=p_color_left; + s.enable_right=p_enable_right; + s.type_right=p_type_right; + s.color_right=p_color_right; + slot_info[p_idx]=s; + update(); +} + +void GraphNode::clear_slot(int p_idx){ + + slot_info.erase(p_idx); + update(); +} +void GraphNode::clear_all_slots(){ + + slot_info.clear(); + update(); +} +bool GraphNode::is_slot_enabled_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return false; + return slot_info[p_idx].enable_left; + +} + +int GraphNode::get_slot_type_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return 0; + return slot_info[p_idx].type_left; + +} + +Color GraphNode::get_slot_color_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return Color(1,1,1,1); + return slot_info[p_idx].color_left; + +} + +bool GraphNode::is_slot_enabled_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return false; + return slot_info[p_idx].enable_right; + +} + + + +int GraphNode::get_slot_type_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return 0; + return slot_info[p_idx].type_right; + +} + +Color GraphNode::get_slot_color_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return Color(1,1,1,1); + return slot_info[p_idx].color_right; + +} + +Size2 GraphNode::get_minimum_size() const { + + int sep=get_constant("separation"); + Ref<StyleBox> sb=get_stylebox("frame"); + bool first=true; + + Size2 minsize; + + for(int i=0;i<get_child_count();i++) { + + Control *c=get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_set_as_toplevel() || !c->get_owner()) + continue; + + Size2i size=c->get_combined_minimum_size(); + + minsize.y+=size.y; + minsize.x=MAX(minsize.x,size.x); + + if (first) + first=false; + else + minsize.y+=sep; + } + + return minsize+sb->get_minimum_size(); +} + + +void GraphNode::_bind_methods() { + + +} + +GraphNode::GraphNode() { + + +} diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h new file mode 100644 index 0000000000..3b89da9f0f --- /dev/null +++ b/scene/gui/graph_node.h @@ -0,0 +1,61 @@ +#ifndef GRAPH_NODE_H +#define GRAPH_NODE_H + +#include "scene/gui/container.h" + +class GraphNode : public Container { + + OBJ_TYPE(GraphNode,Container); + + + String title; + struct Slot { + bool enable_left; + int type_left; + Color color_left; + bool enable_right; + int type_right; + Color color_right; + + + Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }; + }; + + Vector<int> cache_y; + + Map<int,Slot> slot_info; + + void _resort(); +protected: + + void _notification(int p_what); + static void _bind_methods(); + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + + + void set_title(const String& p_title); + String get_title() const; + + void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right); + void clear_slot(int p_idx); + void clear_all_slots(); + bool is_slot_enabled_left(int p_idx) const; + int get_slot_type_left(int p_idx) const; + Color get_slot_color_left(int p_idx) const; + bool is_slot_enabled_right(int p_idx) const; + int get_slot_type_right(int p_idx) const; + Color get_slot_color_right(int p_idx) const; + + virtual Size2 get_minimum_size() const; + + GraphNode(); +}; + + +#endif // GRAPH_NODE_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 71f0d926c3..933895a207 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -26,7 +26,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ - /*****f********************************************/ +/*****f********************************************/ /* text_edit.cpp */ /*************************************************/ /* This file is part of: */ @@ -47,343 +47,343 @@ #define TAB_PIXELS static bool _is_text_char(CharType c) { - - return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; + + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; } static bool _is_symbol(CharType c) { - - return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); + + return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); } static bool _is_pair_right_symbol(CharType c) { - return - c == '"' || - c == '\'' || - c == ')' || - c == ']' || - c == '}'; + return + c == '"' || + c == '\'' || + c == ')' || + c == ']' || + c == '}'; } static bool _is_pair_left_symbol(CharType c) { - return - c == '"' || - c == '\'' || - c == '(' || - c == '[' || - c == '{'; + return + c == '"' || + c == '\'' || + c == '(' || + c == '[' || + c == '{'; } static bool _is_pair_symbol(CharType c) { - return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); + return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); } static CharType _get_right_pair_symbol(CharType c) { - if(c == '"') - return '"'; - if(c == '\'') - return '\''; - if(c == '(') - return ')'; - if(c == '[') - return ']'; - if(c == '{') - return '}'; - return 0; + if(c == '"') + return '"'; + if(c == '\'') + return '\''; + if(c == '(') + return ')'; + if(c == '[') + return ']'; + if(c == '{') + return '}'; + return 0; } void TextEdit::Text::set_font(const Ref<Font>& p_font) { - - font=p_font; + + font=p_font; } void TextEdit::Text::set_tab_size(int p_tab_size) { - - tab_size=p_tab_size; + + tab_size=p_tab_size; } void TextEdit::Text::_update_line_cache(int p_line) const { - - int w =0; - int tab_w=font->get_char_size(' ').width; - - int len = text[p_line].data.length(); - const CharType *str = text[p_line].data.c_str(); - - //update width - - for(int i=0;i<len;i++) { - if (str[i]=='\t') { - - int left = w%tab_w; - if (left==0) - w+=tab_w; - else - w+=tab_w-w%tab_w; // is right... - - } else { - - w+=font->get_char_size(str[i],str[i+1]).width; - } - } - - - text[p_line].width_cache=w; - - //update regions - - text[p_line].region_info.clear(); - - for(int i=0;i<len;i++) { - - if (!_is_symbol(str[i])) - continue; - if (str[i]=='\\') { - i++; //skip quoted anything - continue; - } - - int left=len-i; - - for(int j=0;j<color_regions->size();j++) { - - const ColorRegion& cr=color_regions->operator [](j); - - /* BEGIN */ - - int lr=cr.begin_key.length(); - if (lr==0 || lr>left) - continue; - - const CharType* kc = cr.begin_key.c_str(); - - bool match=true; - - for(int k=0;k<lr;k++) { - if (kc[k]!=str[i+k]) { - match=false; - break; - } - } - - if (match) { - - ColorRegionInfo cri; - cri.end=false; - cri.region=j; - text[p_line].region_info[i]=cri; - i+=lr-1; - break; - } - - /* END */ - - lr=cr.end_key.length(); - if (lr==0 || lr>left) - continue; - - kc = cr.end_key.c_str(); - - match=true; - - for(int k=0;k<lr;k++) { - if (kc[k]!=str[i+k]) { - match=false; - break; - } - } - - if (match) { - - ColorRegionInfo cri; - cri.end=true; - cri.region=j; - text[p_line].region_info[i]=cri; - i+=lr-1; - break; - } - - } - } - - + + int w =0; + int tab_w=font->get_char_size(' ').width; + + int len = text[p_line].data.length(); + const CharType *str = text[p_line].data.c_str(); + + //update width + + for(int i=0;i<len;i++) { + if (str[i]=='\t') { + + int left = w%tab_w; + if (left==0) + w+=tab_w; + else + w+=tab_w-w%tab_w; // is right... + + } else { + + w+=font->get_char_size(str[i],str[i+1]).width; + } + } + + + text[p_line].width_cache=w; + + //update regions + + text[p_line].region_info.clear(); + + for(int i=0;i<len;i++) { + + if (!_is_symbol(str[i])) + continue; + if (str[i]=='\\') { + i++; //skip quoted anything + continue; + } + + int left=len-i; + + for(int j=0;j<color_regions->size();j++) { + + const ColorRegion& cr=color_regions->operator [](j); + + /* BEGIN */ + + int lr=cr.begin_key.length(); + if (lr==0 || lr>left) + continue; + + const CharType* kc = cr.begin_key.c_str(); + + bool match=true; + + for(int k=0;k<lr;k++) { + if (kc[k]!=str[i+k]) { + match=false; + break; + } + } + + if (match) { + + ColorRegionInfo cri; + cri.end=false; + cri.region=j; + text[p_line].region_info[i]=cri; + i+=lr-1; + break; + } + + /* END */ + + lr=cr.end_key.length(); + if (lr==0 || lr>left) + continue; + + kc = cr.end_key.c_str(); + + match=true; + + for(int k=0;k<lr;k++) { + if (kc[k]!=str[i+k]) { + match=false; + break; + } + } + + if (match) { + + ColorRegionInfo cri; + cri.end=true; + cri.region=j; + text[p_line].region_info[i]=cri; + i+=lr-1; + break; + } + + } + } + + } const Map<int,TextEdit::Text::ColorRegionInfo>& TextEdit::Text::get_color_region_info(int p_line) { - - Map<int,ColorRegionInfo> *cri=NULL; - ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash - - if (text[p_line].width_cache==-1) { - _update_line_cache(p_line); - } - - return text[p_line].region_info; + + Map<int,ColorRegionInfo> *cri=NULL; + ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash + + if (text[p_line].width_cache==-1) { + _update_line_cache(p_line); + } + + return text[p_line].region_info; } int TextEdit::Text::get_line_width(int p_line) const { - - ERR_FAIL_INDEX_V(p_line,text.size(),-1); - - if (text[p_line].width_cache==-1) { - _update_line_cache(p_line); - } - - return text[p_line].width_cache; + + ERR_FAIL_INDEX_V(p_line,text.size(),-1); + + if (text[p_line].width_cache==-1) { + _update_line_cache(p_line); + } + + return text[p_line].width_cache; } void TextEdit::Text::clear_caches() { - - for(int i=0;i<text.size();i++) - text[i].width_cache=-1; - + + for(int i=0;i<text.size();i++) + text[i].width_cache=-1; + } void TextEdit::Text::clear() { - - - text.clear();; - insert(0,""); + + + text.clear();; + insert(0,""); } int TextEdit::Text::get_max_width() const { - //quite some work.. but should be fast enough. - - int max = 0; - - for(int i=0;i<text.size();i++) - max=MAX(max,get_line_width(i)); - return max; - + //quite some work.. but should be fast enough. + + int max = 0; + + for(int i=0;i<text.size();i++) + max=MAX(max,get_line_width(i)); + return max; + } void TextEdit::Text::set(int p_line,const String& p_text) { - - ERR_FAIL_INDEX(p_line,text.size()); - - text[p_line].width_cache=-1; - text[p_line].data=p_text; + + ERR_FAIL_INDEX(p_line,text.size()); + + text[p_line].width_cache=-1; + text[p_line].data=p_text; } void TextEdit::Text::insert(int p_at,const String& p_text) { - - Line line; - line.marked=false; - line.breakpoint=false; - line.width_cache=-1; - line.data=p_text; - text.insert(p_at,line); + + Line line; + line.marked=false; + line.breakpoint=false; + line.width_cache=-1; + line.data=p_text; + text.insert(p_at,line); } void TextEdit::Text::remove(int p_at) { - - text.remove(p_at); + + text.remove(p_at); } void TextEdit::_update_scrollbars() { - - - Size2 size = get_size(); - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); - - - - v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) ); - v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM)) ); - - h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); - h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); - - - int hscroll_rows = ((hmin.height-1)/get_row_height())+1; - int visible_rows = get_visible_rows(); - int total_rows = text.size() * cache.line_spacing; - - int vscroll_pixels = v_scroll->get_combined_minimum_size().width; - int visible_width = size.width - cache.style_normal->get_minimum_size().width; - int total_width = text.get_max_width(); - - bool use_hscroll=true; - bool use_vscroll=true; - - if (total_rows <= visible_rows && total_width <= visible_width) { - //thanks yessopie for this clever bit of logic - use_hscroll=false; - use_vscroll=false; - - } else { - - if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) { - //thanks yessopie for this clever bit of logic - use_hscroll=false; - } - - if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) { - //thanks yessopie for this clever bit of logic - use_vscroll=false; - } - } - - updating_scrolls=true; - - if (use_vscroll) { - - v_scroll->show(); - v_scroll->set_max(total_rows); - v_scroll->set_page(visible_rows); - - v_scroll->set_val(cursor.line_ofs); - - } else { - cursor.line_ofs = 0; - v_scroll->hide(); - } - - if (use_hscroll) { - - h_scroll->show(); - h_scroll->set_max(total_width); - h_scroll->set_page(visible_width); - h_scroll->set_val(cursor.x_ofs); - } else { - - h_scroll->hide(); - } - - - - updating_scrolls=false; + + + Size2 size = get_size(); + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + + + + v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) ); + v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM)) ); + + h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); + h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); + + + int hscroll_rows = ((hmin.height-1)/get_row_height())+1; + int visible_rows = get_visible_rows(); + int total_rows = text.size() * cache.line_spacing; + + int vscroll_pixels = v_scroll->get_combined_minimum_size().width; + int visible_width = size.width - cache.style_normal->get_minimum_size().width; + int total_width = text.get_max_width(); + + bool use_hscroll=true; + bool use_vscroll=true; + + if (total_rows <= visible_rows && total_width <= visible_width) { + //thanks yessopie for this clever bit of logic + use_hscroll=false; + use_vscroll=false; + + } else { + + if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) { + //thanks yessopie for this clever bit of logic + use_hscroll=false; + } + + if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) { + //thanks yessopie for this clever bit of logic + use_vscroll=false; + } + } + + updating_scrolls=true; + + if (use_vscroll) { + + v_scroll->show(); + v_scroll->set_max(total_rows); + v_scroll->set_page(visible_rows); + + v_scroll->set_val(cursor.line_ofs); + + } else { + cursor.line_ofs = 0; + v_scroll->hide(); + } + + if (use_hscroll) { + + h_scroll->show(); + h_scroll->set_max(total_width); + h_scroll->set_page(visible_width); + h_scroll->set_val(cursor.x_ofs); + } else { + + h_scroll->hide(); + } + + + + updating_scrolls=false; } void TextEdit::_notification(int p_what) { - + switch(p_what) { case NOTIFICATION_ENTER_TREE: { - + _update_caches(); if (cursor_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); if (text_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); - + } break; case NOTIFICATION_RESIZED: { - + cache.size=get_size(); adjust_viewport_to_cursor(); - - + + } break; case NOTIFICATION_THEME_CHANGED: { - + _update_caches(); }; case NOTIFICATION_DRAW: { - + int line_number_char_count=0; - + { int lc=text.size()+1; cache.line_number_w=0; @@ -391,20 +391,20 @@ void TextEdit::_notification(int p_what) { cache.line_number_w+=1; lc/=10; }; - + if (line_numbers) { - + line_number_char_count=cache.line_number_w; cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width; } else { cache.line_number_w=0; } - - + + } _update_scrollbars(); - - + + RID ci = get_canvas_item(); int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w; int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT); @@ -412,56 +412,56 @@ void TextEdit::_notification(int p_what) { cache.style_normal->draw(ci,Rect2(Point2(),cache.size)); if (has_focus()) cache.style_focus->draw(ci,Rect2(Point2(),cache.size)); - - + + int ascent=cache.font->get_ascent(); - + int visible_rows = get_visible_rows(); - + int tab_w = cache.font->get_char_size(' ').width*tab_size; - + Color color = cache.font_color; int in_region=-1; - + if (syntax_coloring) { - + if (custom_bg_color.a>0.01) { - + Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0; VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color); } //compute actual region to start (may be inside say, a comment). //slow in very large documments :( but ok for source! - + for(int i=0;i<cursor.line_ofs;i++) { - + const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i); - + if (in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) { - + const Text::ColorRegionInfo &cri=E->get(); - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + in_region=-1; } } } } } - + int brace_open_match_line=-1; int brace_open_match_column=-1; bool brace_open_matching=false; @@ -470,15 +470,15 @@ void TextEdit::_notification(int p_what) { int brace_close_match_column=-1; bool brace_close_matching=false; bool brace_close_mismatch=false; - - + + if (brace_matching_enabled) { - + if (cursor.column<text[cursor.line].length()) { //check for open CharType c = text[cursor.line][cursor.column]; CharType closec=0; - + if (c=='[') { closec=']'; } else if (c=='{') { @@ -486,48 +486,48 @@ void TextEdit::_notification(int p_what) { } else if (c=='(') { closec=')'; } - + if (closec!=0) { - + int stack=1; - - + + for(int i=cursor.line;i<text.size();i++) { - + int from = i==cursor.line?cursor.column+1:0; for(int j=from;j<text[i].length();j++) { - + CharType cc = text[i][j]; if (cc==c) stack++; else if (cc==closec) stack--; - + if (stack==0) { brace_open_match_line=i; brace_open_match_column=j; brace_open_matching=true; - + break; } } if (brace_open_match_line!=-1) break; } - + if (!brace_open_matching) brace_open_mismatch=true; - - + + } } - + if (cursor.column>0) { CharType c = text[cursor.line][cursor.column-1]; CharType closec=0; - - - + + + if (c==']') { closec='['; } else if (c=='}') { @@ -535,65 +535,65 @@ void TextEdit::_notification(int p_what) { } else if (c==')') { closec='('; } - + if (closec!=0) { - + int stack=1; - - + + for(int i=cursor.line;i>=0;i--) { - + int from = i==cursor.line?cursor.column-2:text[i].length()-1; for(int j=from;j>=0;j--) { - + CharType cc = text[i][j]; if (cc==c) stack++; else if (cc==closec) stack--; - + if (stack==0) { brace_close_match_line=i; brace_close_match_column=j; brace_close_matching=true; - + break; } } if (brace_close_match_line!=-1) break; } - + if (!brace_close_matching) brace_close_mismatch=true; - - + + } - - + + } } - - + + int deregion=0; //force it to clear inrgion Point2 cursor_pos; - + for (int i=0;i<visible_rows;i++) { - + int line=i+cursor.line_ofs; - + if (line<0 || line>=(int)text.size()) continue; - + const String &str=text[line]; - + int char_margin=xmargin_beg-cursor.x_ofs; int char_ofs=0; int ofs_y=i*get_row_height()+cache.line_spacing/2; bool prev_is_char=false; bool in_keyword=false; Color keyword_color; - + if (cache.line_number_w) { Color fcol = cache.font_color; fcol.a*=0.4; @@ -601,191 +601,191 @@ void TextEdit::_notification(int p_what) { while (fc.length() < line_number_char_count) { fc="0"+fc; } - + cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol); } - + const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line); - - + + if (text.is_marked(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color); } - + if (text.is_breakpoint(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color); } - - + + if (line==cursor.line) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color); - + } for (int j=0;j<str.length();j++) { - + //look for keyword - + if (deregion>0) { deregion--; if (deregion==0) in_region=-1; } if (syntax_coloring && deregion==0) { - - + + color = cache.font_color; //reset //find keyword bool is_char = _is_text_char(str[j]); bool is_symbol=_is_symbol(str[j]); - + if (j==0 && in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + if (is_symbol && cri_map.has(j)) { - - + + const Text::ColorRegionInfo &cri=cri_map[j]; - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length(); } } } - + if (!is_char) in_keyword=false; - + if (in_region==-1 && !in_keyword && is_char && !prev_is_char) { - + int to=j; while(_is_text_char(str[to]) && to<str.length()) to++; - + uint32_t hash = String::hash(&str[j],to-j); StrRange range(&str[j],to-j); - + const Color *col=keywords.custom_getptr(range,hash); - + if (col) { - + in_keyword=true; keyword_color=*col; } } - - + + if (in_region>=0) color=color_regions[in_region].color; else if (in_keyword) color=keyword_color; else if (is_symbol) color=symbol_color; - + prev_is_char=is_char; - + } int char_w; - + //handle tabulator - - + + if (str[j]=='\t') { int left = char_ofs%tab_w; if (left==0) char_w=tab_w; else char_w=tab_w-char_ofs%tab_w; // is right... - + } else { char_w=cache.font->get_char_size(str[j],str[j+1]).width; } - + if ( (char_ofs+char_margin)<xmargin_beg) { char_ofs+=char_w; continue; } - + if ( (char_ofs+char_margin+char_w)>=xmargin_end) { if (syntax_coloring) continue; else break; } - + bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column)); - - + + if (in_selection) { //inside selection! VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } - - + + if (brace_matching_enabled) { if ( (brace_open_match_line==line && brace_open_match_column==j) || - (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) { - + (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) { + if (brace_open_mismatch) color=cache.brace_mismatch_color; cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); - + } - + if ( - (brace_close_match_line==line && brace_close_match_column==j) || - (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) { - - + (brace_close_match_line==line && brace_close_match_column==j) || + (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) { + + if (brace_close_mismatch) color=cache.brace_mismatch_color; cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); - + } } - - + + if (str[j]>=32) cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color); - + else if (draw_tabs && str[j]=='\t') { int yofs= (get_row_height() - cache.tab_icon->get_height())/2; cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color); } - - + + if (cursor.column==j && cursor.line==line) { - + cursor_pos = Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - - + + } char_ofs+=char_w; - + } - + if (cursor.column==str.length() && cursor.line==line) { - + cursor_pos=Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - + } } - - + + if (completion_active) { // code completion box Ref<StyleBox> csb = get_stylebox("completion"); @@ -793,17 +793,18 @@ void TextEdit::_notification(int p_what) { int maxlines = get_constant("completion_lines"); int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x; Color existing = get_color("completion_existing"); + existing.a=0.2; int scrollw = get_constant("completion_scroll_width"); Color scrollc = get_color("completion_scroll_color"); - - - + + + int lines = MIN(completion_options.size(),maxlines); int w=0; int h=lines*get_row_height(); int nofs = cache.font->get_string_size(completion_base).width; - - + + if (completion_options.size() < 50) { for(int i=0;i<completion_options.size();i++) { int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width); @@ -813,65 +814,74 @@ void TextEdit::_notification(int p_what) { } else { w=cmax_width; } - + int th = h + csb->get_minimum_size().y; if (cursor_pos.y+get_row_height()+th > get_size().height) { completion_rect.pos.y=cursor_pos.y-th; } else { completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y; - + } - + if (cursor_pos.x-nofs+w+scrollw > get_size().width) { completion_rect.pos.x=get_size().width-w-scrollw; } else { completion_rect.pos.x=cursor_pos.x-nofs; } - - completion_rect.size.width=w; + + completion_rect.size.width=w+2; completion_rect.size.height=h; if (completion_options.size()<=maxlines) scrollw=0; - + draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0))); - - + + int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines); draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height()))); - + draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing); - + + + + for(int i=0;i<lines;i++) { - + int l = line_from + i; ERR_CONTINUE( l < 0 || l>= completion_options.size()); - draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width); + Color text_color = cache.font_color; + for(int j=0;j<color_regions.size();j++) { + if (completion_options[l].begins_with(color_regions[j].begin_key)) { + text_color=color_regions[j].color; + } + } + draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],text_color,completion_rect.size.width); } - + if (scrollw) { //draw a small scroll rectangle to show a position in the options float r = maxlines / (float)completion_options.size(); float o = line_from / (float)completion_options.size(); draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc); } - + completion_line_ofs=line_from; - + } - + if (completion_hint!="") { - + Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel"); Ref<Font> font = cache.font; Color font_color = get_color("font_color","TooltipLabel"); - - + + int max_w=0; int sc = completion_hint.get_slice_count("\n"); int offset=0; int spacing=0; for(int i=0;i<sc;i++) { - + String l = completion_hint.get_slice("\n",i); int len = font->get_string_size(l).x; max_w = MAX(len,max_w); @@ -880,35 +890,35 @@ void TextEdit::_notification(int p_what) { } else { spacing+=cache.line_spacing; } - - + + } - - - + + + Size2 size = Size2(max_w,sc*font->get_height()+spacing); Size2 minsize = size+sb->get_minimum_size(); - - + + if (completion_hint_offset==-0xFFFF) { completion_hint_offset=cursor_pos.x-offset; } - - + + Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y); draw_style_box(sb,Rect2(hint_ofs,minsize)); - + spacing=0; for(int i=0;i<sc;i++) { int begin=0; int end=0; String l = completion_hint.get_slice("\n",i); - + if (l.find(String::chr(0xFFFF))!=-1) { begin = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x; end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x; } - + draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color); if (end>0) { Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1); @@ -917,1477 +927,1523 @@ void TextEdit::_notification(int p_what) { spacing+=cache.line_spacing; } } - - + + } break; case NOTIFICATION_FOCUS_ENTER: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect()); - + } break; case NOTIFICATION_FOCUS_EXIT: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->hide_virtual_keyboard(); - + } break; - + } } void TextEdit::_consume_pair_symbol(CharType ch) { - - int cursor_position_to_move = cursor_get_column() + 1; - - CharType ch_single[2] = {ch, 0}; - CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; - CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; - - if(is_selection_active()) { - - int new_column,new_line; - - _begin_compex_operation(); - _insert_text(get_selection_from_line(), get_selection_from_column(), - ch_single, - &new_line, &new_column); - - int to_col_offset = 0; - if(get_selection_from_line() == get_selection_to_line()) - to_col_offset = 1; - - _insert_text(get_selection_to_line(), - get_selection_to_column() + to_col_offset, - ch_single_pair, - &new_line,&new_column); - _end_compex_operation(); - - cursor_set_line(get_selection_to_line()); - cursor_set_column(get_selection_to_column() + to_col_offset); - - deselect(); - update(); - return; - } - - if( (ch == '\'' || ch == '"') && - cursor_get_column() > 0 && - _is_text_char(text[cursor.line][cursor_get_column() - 1]) - ) { - insert_text_at_cursor(ch_single); - cursor_set_column(cursor_position_to_move); - return; - } - - if(cursor_get_column() < text[cursor.line].length()) { - if(_is_text_char(text[cursor.line][cursor_get_column()])) { - insert_text_at_cursor(ch_single); - cursor_set_column(cursor_position_to_move); - return; - } - if( _is_pair_right_symbol(ch) && - text[cursor.line][cursor_get_column()] == ch - ) { - cursor_set_column(cursor_position_to_move); - return; - } - } - - - insert_text_at_cursor(ch_pair); - cursor_set_column(cursor_position_to_move); - return; - + + int cursor_position_to_move = cursor_get_column() + 1; + + CharType ch_single[2] = {ch, 0}; + CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; + CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; + + if(is_selection_active()) { + + int new_column,new_line; + + _begin_compex_operation(); + _insert_text(get_selection_from_line(), get_selection_from_column(), + ch_single, + &new_line, &new_column); + + int to_col_offset = 0; + if(get_selection_from_line() == get_selection_to_line()) + to_col_offset = 1; + + _insert_text(get_selection_to_line(), + get_selection_to_column() + to_col_offset, + ch_single_pair, + &new_line,&new_column); + _end_compex_operation(); + + cursor_set_line(get_selection_to_line()); + cursor_set_column(get_selection_to_column() + to_col_offset); + + deselect(); + update(); + return; + } + + if( (ch == '\'' || ch == '"') && + cursor_get_column() > 0 && + _is_text_char(text[cursor.line][cursor_get_column() - 1]) + ) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + + if(cursor_get_column() < text[cursor.line].length()) { + if(_is_text_char(text[cursor.line][cursor_get_column()])) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + if( _is_pair_right_symbol(ch) && + text[cursor.line][cursor_get_column()] == ch + ) { + cursor_set_column(cursor_position_to_move); + return; + } + } + + + insert_text_at_cursor(ch_pair); + cursor_set_column(cursor_position_to_move); + return; + } void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column) { - - bool remove_right_symbol = false; - - if(cursor.column < text[cursor.line].length() && cursor.column > 0) { - - CharType left_char = text[cursor.line][cursor.column - 1]; - CharType right_char = text[cursor.line][cursor.column]; - - if(right_char == _get_right_pair_symbol(left_char)) { - remove_right_symbol = true; - } - - } - if(remove_right_symbol) { - _remove_text(prev_line,prev_column,cursor.line,cursor.column + 1); - } else { - _remove_text(prev_line,prev_column,cursor.line,cursor.column); - } - + + bool remove_right_symbol = false; + + if(cursor.column < text[cursor.line].length() && cursor.column > 0) { + + CharType left_char = text[cursor.line][cursor.column - 1]; + CharType right_char = text[cursor.line][cursor.column]; + + if(right_char == _get_right_pair_symbol(left_char)) { + remove_right_symbol = true; + } + + } + if(remove_right_symbol) { + _remove_text(prev_line,prev_column,cursor.line,cursor.column + 1); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + } void TextEdit::backspace_at_cursor() { - - if (cursor.column==0 && cursor.line==0) - return; - - int prev_line = cursor.column?cursor.line:cursor.line-1; - int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); - if(auto_brace_completion_enabled && - cursor.column > 0 && - _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { - _consume_backspace_for_pair_symbol(prev_line, prev_column); - } else { - _remove_text(prev_line,prev_column,cursor.line,cursor.column); - } - - cursor_set_line(prev_line); - cursor_set_column(prev_column); - + if (readonly) + return; + + if (cursor.column==0 && cursor.line==0) + return; + + int prev_line = cursor.column?cursor.line:cursor.line-1; + int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); + if(auto_brace_completion_enabled && + cursor.column > 0 && + _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { + _consume_backspace_for_pair_symbol(prev_line, prev_column); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + + cursor_set_line(prev_line); + cursor_set_column(prev_column); + } bool TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const { - - int row=p_mouse.y; - row-=cache.style_normal->get_margin(MARGIN_TOP); - row/=get_row_height(); - - if (row<0 || row>=get_visible_rows()) - return false; - - row+=cursor.line_ofs; - int col=0; - - if (row>=text.size()) { - - row=text.size()-1; - col=text[row].size(); - } else { - - col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); - col+=cursor.x_ofs; - col=get_char_pos_for( col, get_line(row) ); - } - - r_row=row; - r_col=col; - return true; + + int row=p_mouse.y; + row-=cache.style_normal->get_margin(MARGIN_TOP); + row/=get_row_height(); + + if (row<0 || row>=get_visible_rows()) + return false; + + row+=cursor.line_ofs; + int col=0; + + if (row>=text.size()) { + + row=text.size()-1; + col=text[row].size(); + } else { + + col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); + col+=cursor.x_ofs; + col=get_char_pos_for( col, get_line(row) ); + } + + r_row=row; + r_col=col; + return true; } void TextEdit::_input_event(const InputEvent& p_input_event) { + + switch(p_input_event.type) { + + case InputEvent::MOUSE_BUTTON: { + + const InputEventMouseButton &mb=p_input_event.mouse_button; + + if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) { + + if (!mb.pressed) + return; + + if (mb.button_index==BUTTON_WHEEL_UP) { + if (completion_index>0) { + completion_index--; + completion_current=completion_options[completion_index]; + update(); + } + + } + if (mb.button_index==BUTTON_WHEEL_DOWN) { + + if (completion_index<completion_options.size()-1) { + completion_index++; + completion_current=completion_options[completion_index]; + update(); + } + } + + if (mb.button_index==BUTTON_LEFT) { + + completion_index=CLAMP(completion_line_ofs+(mb.y-completion_rect.pos.y)/get_row_height(),0,completion_options.size()-1); + + completion_current=completion_options[completion_index]; + update(); + if (mb.doubleclick) + _confirm_completion(); + } + return; + } else { + _cancel_completion(); + _cancel_code_hint(); + } + + if (mb.pressed) { + if (mb.button_index==BUTTON_WHEEL_UP) { + v_scroll->set_val( v_scroll->get_val() -3 ); + } + if (mb.button_index==BUTTON_WHEEL_DOWN) { + v_scroll->set_val( v_scroll->get_val() +3 ); + } + if (mb.button_index==BUTTON_LEFT) { + + int row,col; + if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col)) + return; + + int prev_col=cursor.column; + int prev_line=cursor.line; + + + + cursor_set_line( row ); + cursor_set_column( col ); + + if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { + + if (!selection.active) { + selection.active=true; + selection.selecting_mode=Selection::MODE_POINTER; + selection.from_column=prev_col; + selection.from_line=prev_line; + selection.to_column=cursor.column; + selection.to_line=cursor.line; + + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + selection.shiftclick_left=false; + } else { + selection.shiftclick_left=true; + } + selection.selecting_line=prev_line; + selection.selecting_column=prev_col; + update(); + } else { + + if (cursor.line<selection.from_line || (cursor.line==selection.from_line && cursor.column<=selection.from_column)) { + selection.from_column=cursor.column; + selection.from_line=cursor.line; + } else if (cursor.line>selection.to_line || (cursor.line==selection.to_line && cursor.column>=selection.to_column)) { + selection.to_column=cursor.column; + selection.to_line=cursor.line; + + } else if (!selection.shiftclick_left) { + + selection.from_column=cursor.column; + selection.from_line=cursor.line; + } else { + + selection.to_column=cursor.column; + selection.to_line=cursor.line; + } - switch(p_input_event.type) { - - case InputEvent::MOUSE_BUTTON: { - - const InputEventMouseButton &mb=p_input_event.mouse_button; - - if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) { - - if (!mb.pressed) - return; - - if (mb.button_index==BUTTON_WHEEL_UP) { - if (completion_index>0) { - completion_index--; - completion_current=completion_options[completion_index]; - update(); - } - - } - if (mb.button_index==BUTTON_WHEEL_DOWN) { - - if (completion_index<completion_options.size()-1) { - completion_index++; - completion_current=completion_options[completion_index]; - update(); - } - } - - if (mb.button_index==BUTTON_LEFT) { - - completion_index=CLAMP(completion_line_ofs+(mb.y-completion_rect.pos.y)/get_row_height(),0,completion_options.size()-1); - - completion_current=completion_options[completion_index]; - update(); - if (mb.doubleclick) - _confirm_completion(); - } - return; - } else { - _cancel_completion(); - _cancel_code_hint(); - } - - if (mb.pressed) { - if (mb.button_index==BUTTON_WHEEL_UP) { - v_scroll->set_val( v_scroll->get_val() -3 ); - } - if (mb.button_index==BUTTON_WHEEL_DOWN) { - v_scroll->set_val( v_scroll->get_val() +3 ); - } - if (mb.button_index==BUTTON_LEFT) { - - int row,col; - if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col)) - return; - - int prev_col=cursor.column; - int prev_line=cursor.line; - - - - cursor_set_line( row ); - cursor_set_column( col ); - - if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { - - selection.active=true; - selection.selecting_mode=Selection::MODE_POINTER; - selection.from_column=prev_col; - selection.from_line=prev_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - if (selection.from_column>selection.to_column) { - SWAP(selection.from_column,selection.to_column); - SWAP(selection.from_line,selection.to_line); - } - selection.selecting_line=prev_line; - selection.selecting_column=prev_col; - update(); - - } else { - - //if sel active and dblick last time < something - - //else - selection.active=false; - selection.selecting_mode=Selection::MODE_POINTER; - selection.selecting_line=row; - selection.selecting_column=col; - } - - - if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) { - //tripleclick select line - select(cursor.line,0,cursor.line,text[cursor.line].length()); - last_dblclk=0; - - } else if (mb.doubleclick && text[cursor.line].length()) { - - //doubleclick select world - String s = text[cursor.line]; - int beg=CLAMP(cursor.column,0,s.length()); - int end=beg; - - if (s[beg]>32 || beg==s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { - beg--; - } - while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { - end++; - } - - if (end<s.length()) - end+=1; - - select(cursor.line,beg,cursor.line,end); - } - - last_dblclk = OS::get_singleton()->get_ticks_msec(); - - } - - update(); - } - } else { - - selection.selecting_mode=Selection::MODE_NONE; - // notify to show soft keyboard - notification(NOTIFICATION_FOCUS_ENTER); - } - - } break; - case InputEvent::MOUSE_MOTION: { - - const InputEventMouseMotion &mm=p_input_event.mouse_motion; - - if (mm.button_mask&BUTTON_MASK_LEFT) { - - int row,col; - if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col)) - return; - - if (selection.selecting_mode==Selection::MODE_POINTER) { - - select(selection.selecting_line,selection.selecting_column,row,col); - - cursor_set_line( row ); - cursor_set_column( col ); - update(); - - } - - } - - } break; - - case InputEvent::KEY: { - - InputEventKey k=p_input_event.key; - - if (!k.pressed) - return; - - if (completion_active) { - - bool valid=true; - if (k.mod.command || k.mod.alt || k.mod.meta) - valid=false; - - if (valid) { - - if (k.scancode==KEY_UP) { - - if (completion_index>0) { - completion_index--; - completion_current=completion_options[completion_index]; - update(); - } - accept_event(); - return; - } - - - if (k.scancode==KEY_DOWN) { - - if (completion_index<completion_options.size()-1) { - completion_index++; - completion_current=completion_options[completion_index]; - update(); - } - accept_event(); - return; - } - - if (k.scancode==KEY_PAGEUP) { - - completion_index-=get_constant("completion_lines"); - if (completion_index<0) - completion_index=0; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - - if (k.scancode==KEY_PAGEDOWN) { - - completion_index+=get_constant("completion_lines"); - if (completion_index>=completion_options.size()) - completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_HOME) { - - completion_index=0; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_END) { - - completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - - if (k.scancode==KEY_DOWN) { - - if (completion_index<completion_options.size()-1) { - completion_index++; - completion_current=completion_options[completion_index]; - update(); - } - accept_event(); - return; - } - - if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) { - - _confirm_completion(); - accept_event(); - return; - } + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + } + update(); + } - if (k.scancode==KEY_BACKSPACE) { - backspace_at_cursor(); - _update_completion_candidates(); - accept_event(); - return; - } - if (k.scancode==KEY_SHIFT) { - accept_event(); - return; - } - if (k.unicode>32) { - - if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) { - //same char, move ahead - cursor_set_column(cursor.column+1); - - } else { - //different char, go back - const CharType chr[2] = {k.unicode, 0}; - if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { - _consume_pair_symbol(chr[0]); - } else { - _insert_text_at_cursor(chr); - } - } - - _update_completion_candidates(); - accept_event(); - - return; - } - } - - _cancel_completion(); - - } - - /* TEST CONTROL FIRST!! */ - - // some remaps for duplicate functions.. - if (k.mod.command && !k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { - - k.scancode=KEY_C; - } - if (!k.mod.command && k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { - - k.scancode=KEY_V; - k.mod.command=true; - k.mod.shift=false; - } - - // stuff to do when selection is active.. - - if (selection.active) { - - bool clear=false; - bool unselect=false; - bool dobreak=false; - - switch(k.scancode) { - - case KEY_TAB: { - - String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - String prev_txt=txt; - - if (k.mod.shift) { - - for(int i=0;i<txt.length();i++) { - if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { - txt.remove(i); - //i--; - } - } - } else { - - for(int i=0;i<txt.length();i++) { - - if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { - txt=txt.insert(i,"\t"); - //i--; - } - } - } - - if (txt!=prev_txt) { - - int sel_line=selection.from_line; - int sel_column=selection.from_column; - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - _begin_compex_operation(); - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - _insert_text_at_cursor(txt); - _end_compex_operation(); - selection.active=true; - selection.from_column=sel_column; - selection.from_line=sel_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - update(); - } - - dobreak=true; - accept_event(); - - } break; - case KEY_X: - case KEY_C: - //special keys often used with control, wait... - clear=(!k.mod.command || k.mod.shift || k.mod.alt ); - break; - case KEY_DELETE: - case KEY_BACKSPACE: - accept_event(); - clear=true; dobreak=true; - break; - case KEY_LEFT: - case KEY_RIGHT: - case KEY_UP: - case KEY_DOWN: - case KEY_PAGEUP: - case KEY_PAGEDOWN: - case KEY_HOME: - case KEY_END: - // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) - if (k.mod.command || k.mod.shift || k.mod.alt || k.mod.command) - break; - unselect=true; - break; - - default: - if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) - clear=true; - if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) - clear=false; - } - - if (unselect) { - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - } - if (clear) { - - selection.active=false; - update(); - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - update(); - } - if (dobreak) - break; - } - - selection.selecting_test=false; - - bool scancode_handled=true; - - // special scancode test... - - switch (k.scancode) { - - case KEY_ENTER: - case KEY_RETURN: { - - String ins="\n"; - - //keep indentation - for(int i=0;i<text[cursor.line].length();i++) { - if (text[cursor.line][i]=='\t') - ins+="\t"; - else - break; - } - - _insert_text_at_cursor(ins); - _push_current_op(); - - } break; - case KEY_ESCAPE: { - if (completion_hint!="") { - completion_hint=""; - update(); - - } - } break; - case KEY_TAB: { - - if (readonly) - break; - - if (selection.active) { - - - } else { - if (k.mod.shift) { - - int cc = cursor.column; - if (cc>0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') { - //simple unindent - - backspace_at_cursor(); - } - } else { - //simple indent - _insert_text_at_cursor("\t"); - } - } - - } break; - case KEY_BACKSPACE: { - if (readonly) - break; - backspace_at_cursor(); - - } break; - case KEY_LEFT: { - - if (k.mod.shift) - _pre_shift_selection(); + + } else { + + //if sel active and dblick last time < something + + //else + selection.active=false; + selection.selecting_mode=Selection::MODE_POINTER; + selection.selecting_line=row; + selection.selecting_column=col; + } + + + if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) { + //tripleclick select line + select(cursor.line,0,cursor.line,text[cursor.line].length()); + last_dblclk=0; + + } else if (mb.doubleclick && text[cursor.line].length()) { + + //doubleclick select world + String s = text[cursor.line]; + int beg=CLAMP(cursor.column,0,s.length()); + int end=beg; + + if (s[beg]>32 || beg==s.length()) { + + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { + beg--; + } + while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { + end++; + } + + if (end<s.length()) + end+=1; + + select(cursor.line,beg,cursor.line,end); + } + + last_dblclk = OS::get_singleton()->get_ticks_msec(); + + } + + update(); + } + } else { + + selection.selecting_mode=Selection::MODE_NONE; + // notify to show soft keyboard + notification(NOTIFICATION_FOCUS_ENTER); + } + + } break; + case InputEvent::MOUSE_MOTION: { + + const InputEventMouseMotion &mm=p_input_event.mouse_motion; + + if (mm.button_mask&BUTTON_MASK_LEFT) { + + int row,col; + if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col)) + return; + + if (selection.selecting_mode==Selection::MODE_POINTER) { + + select(selection.selecting_line,selection.selecting_column,row,col); + + cursor_set_line( row ); + cursor_set_column( col ); + update(); + + } + + } + + } break; + + case InputEvent::KEY: { + + InputEventKey k=p_input_event.key; + + if (!k.pressed) + return; + + if (completion_active) { + if (readonly) + break; + + bool valid=true; + if (k.mod.command || k.mod.alt || k.mod.meta) + valid=false; + + if (valid) { + + if (k.scancode==KEY_UP) { + + if (completion_index>0) { + completion_index--; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + + + if (k.scancode==KEY_DOWN) { + + if (completion_index<completion_options.size()-1) { + completion_index++; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + + if (k.scancode==KEY_PAGEUP) { + + completion_index-=get_constant("completion_lines"); + if (completion_index<0) + completion_index=0; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + + if (k.scancode==KEY_PAGEDOWN) { + + completion_index+=get_constant("completion_lines"); + if (completion_index>=completion_options.size()) + completion_index=completion_options.size()-1; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + if (k.scancode==KEY_HOME) { + + completion_index=0; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + if (k.scancode==KEY_END) { + + completion_index=completion_options.size()-1; + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } + + + if (k.scancode==KEY_DOWN) { + + if (completion_index<completion_options.size()-1) { + completion_index++; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + + if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) { + + _confirm_completion(); + accept_event(); + return; + } + + if (k.scancode==KEY_BACKSPACE) { + + backspace_at_cursor(); + _update_completion_candidates(); + accept_event(); + return; + } + + + if (k.scancode==KEY_SHIFT) { + accept_event(); + return; + } + + if (k.unicode>32) { + + if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) { + //same char, move ahead + cursor_set_column(cursor.column+1); + + } else { + //different char, go back + const CharType chr[2] = {k.unicode, 0}; + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } + } + + _update_completion_candidates(); + accept_event(); + + return; + } + } + + _cancel_completion(); + + } + + /* TEST CONTROL FIRST!! */ + + // some remaps for duplicate functions.. + if (k.mod.command && !k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { + + k.scancode=KEY_C; + } + if (!k.mod.command && k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { + + k.scancode=KEY_V; + k.mod.command=true; + k.mod.shift=false; + } + + // stuff to do when selection is active.. + + if (selection.active) { + + if (readonly) + break; + + bool clear=false; + bool unselect=false; + bool dobreak=false; + + switch(k.scancode) { + + case KEY_TAB: { + + String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + String prev_txt=txt; + + if (k.mod.shift) { + + for(int i=0;i<txt.length();i++) { + if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { + txt.remove(i); + //i--; + } + } + } else { + + for(int i=0;i<txt.length();i++) { + + if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { + txt=txt.insert(i,"\t"); + //i--; + } + } + } + + if (txt!=prev_txt) { + + int sel_line=selection.from_line; + int sel_column=selection.from_column; + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + _begin_compex_operation(); + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + _insert_text_at_cursor(txt); + _end_compex_operation(); + selection.active=true; + selection.from_column=sel_column; + selection.from_line=sel_line; + selection.to_column=cursor.column; + selection.to_line=cursor.line; + update(); + } + + dobreak=true; + accept_event(); + + } break; + case KEY_X: + case KEY_C: + //special keys often used with control, wait... + clear=(!k.mod.command || k.mod.shift || k.mod.alt ); + break; + case KEY_DELETE: + case KEY_BACKSPACE: + accept_event(); + clear=true; dobreak=true; + break; + case KEY_LEFT: + case KEY_RIGHT: + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + case KEY_HOME: + case KEY_END: + // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) + if (k.mod.command || k.mod.shift || k.mod.alt || k.mod.command) + break; + unselect=true; + break; + + default: + if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) + clear=true; + if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) + clear=false; + } + + if (unselect) { + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + } + if (clear) { + + selection.active=false; + update(); + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + update(); + } + if (dobreak) + break; + } + + selection.selecting_test=false; + + bool scancode_handled=true; + + // special scancode test... + + switch (k.scancode) { + + case KEY_ENTER: + case KEY_RETURN: { + + if (readonly) + break; + + String ins="\n"; + + //keep indentation + for(int i=0;i<text[cursor.line].length();i++) { + if (text[cursor.line][i]=='\t') + ins+="\t"; + else + break; + } + + _insert_text_at_cursor(ins); + _push_current_op(); + + } break; + case KEY_ESCAPE: { + if (completion_hint!="") { + completion_hint=""; + update(); + + } + } break; + case KEY_TAB: { + + if (readonly) + break; + + if (selection.active) { + + + } else { + if (k.mod.shift) { + + int cc = cursor.column; + if (cc>0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') { + //simple unindent + + backspace_at_cursor(); + } + } else { + //simple indent + _insert_text_at_cursor("\t"); + } + } + + } break; + case KEY_BACKSPACE: { + if (readonly) + break; + backspace_at_cursor(); + + } break; + case KEY_LEFT: { + + if (k.mod.shift) + _pre_shift_selection(); + #ifdef APPLE_STYLE_KEYS - if (k.mod.command) { - cursor_set_column(0); - } else if (k.mod.alt) { - + if (k.mod.command) { + cursor_set_column(0); + } else if (k.mod.alt) { + #else - if (k.mod.alt) { - scancode_handled=false; - break; - } else if (k.mod.command) { + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { #endif - bool prev_char=false; - int cc=cursor.column; - while (cc>0) { - - bool ischar=_is_text_char(text[cursor.line][cc-1]); - - if (prev_char && !ischar) - break; - - prev_char=ischar; - cc--; - - } - - cursor_set_column(cc); - - } else if (cursor.column==0) { - - if (cursor.line>0) { - cursor_set_line(cursor.line-1); - cursor_set_column(text[cursor.line].length()); - } - } else { - cursor_set_column(cursor_get_column()-1); - } - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_RIGHT: { - - if (k.mod.shift) - _pre_shift_selection(); - + bool prev_char=false; + int cc=cursor.column; + while (cc>0) { + + bool ischar=_is_text_char(text[cursor.line][cc-1]); + + if (prev_char && !ischar) + break; + + prev_char=ischar; + cc--; + + } + + cursor_set_column(cc); + + } else if (cursor.column==0) { + + if (cursor.line>0) { + cursor_set_line(cursor.line-1); + cursor_set_column(text[cursor.line].length()); + } + } else { + cursor_set_column(cursor_get_column()-1); + } + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_RIGHT: { + + if (k.mod.shift) + _pre_shift_selection(); + #ifdef APPLE_STYLE_KEYS - if (k.mod.command) { - cursor_set_column(text[cursor.line].length()); - } else if (k.mod.alt) { + if (k.mod.command) { + cursor_set_column(text[cursor.line].length()); + } else if (k.mod.alt) { #else - if (k.mod.alt) { - scancode_handled=false; - break; - } else if (k.mod.command) { + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { #endif - bool prev_char=false; - int cc=cursor.column; - while (cc<text[cursor.line].length()) { - - bool ischar=_is_text_char(text[cursor.line][cc]); - - if (prev_char && !ischar) - break; - prev_char=ischar; - cc++; - } - - cursor_set_column(cc); - - } else if (cursor.column==text[cursor.line].length()) { - - if (cursor.line<text.size()-1) { - cursor_set_line(cursor.line+1); - cursor_set_column(0); - } - } else { - cursor_set_column(cursor_get_column()+1); - } - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_UP: { - - if (k.mod.shift) - _pre_shift_selection(); - if (k.mod.alt) { - scancode_handled=false; - break; - } + bool prev_char=false; + int cc=cursor.column; + while (cc<text[cursor.line].length()) { + + bool ischar=_is_text_char(text[cursor.line][cc]); + + if (prev_char && !ischar) + break; + prev_char=ischar; + cc++; + } + + cursor_set_column(cc); + + } else if (cursor.column==text[cursor.line].length()) { + + if (cursor.line<text.size()-1) { + cursor_set_line(cursor.line+1); + cursor_set_column(0); + } + } else { + cursor_set_column(cursor_get_column()+1); + } + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_UP: { + + if (k.mod.shift) + _pre_shift_selection(); + if (k.mod.alt) { + scancode_handled=false; + break; + } #ifdef APPLE_STYLE_KEYS - if (k.mod.command) - cursor_set_line(0); - else + if (k.mod.command) + cursor_set_line(0); + else #endif - cursor_set_line(cursor_get_line()-1); - - if (k.mod.shift) - _post_shift_selection(); - _cancel_code_hint(); - - } break; - case KEY_DOWN: { - - if (k.mod.shift) - _pre_shift_selection(); - if (k.mod.alt) { - scancode_handled=false; - break; - } + cursor_set_line(cursor_get_line()-1); + + if (k.mod.shift) + _post_shift_selection(); + _cancel_code_hint(); + + } break; + case KEY_DOWN: { + + if (k.mod.shift) + _pre_shift_selection(); + if (k.mod.alt) { + scancode_handled=false; + break; + } #ifdef APPLE_STYLE_KEYS - if (k.mod.command) - cursor_set_line(text.size()-1); - else + if (k.mod.command) + cursor_set_line(text.size()-1); + else #endif - cursor_set_line(cursor_get_line()+1); - - if (k.mod.shift) - _post_shift_selection(); - _cancel_code_hint(); - - } break; - - case KEY_DELETE: { - - if (readonly) - break; - int curline_len = text[cursor.line].length(); - - if (cursor.line==text.size()-1 && cursor.column==curline_len) - break; //nothing to do - - int next_line = cursor.column<curline_len?cursor.line:cursor.line+1; - int next_column = cursor.column<curline_len?(cursor.column+1):0; - _remove_text(cursor.line,cursor.column,next_line,next_column); - update(); - } break; + cursor_set_line(cursor_get_line()+1); + + if (k.mod.shift) + _post_shift_selection(); + _cancel_code_hint(); + + } break; + + case KEY_DELETE: { + + if (readonly) + break; + int curline_len = text[cursor.line].length(); + + if (cursor.line==text.size()-1 && cursor.column==curline_len) + break; //nothing to do + + int next_line = cursor.column<curline_len?cursor.line:cursor.line+1; + int next_column = cursor.column<curline_len?(cursor.column+1):0; + _remove_text(cursor.line,cursor.column,next_line,next_column); + update(); + } break; #ifdef APPLE_STYLE_KEYS - case KEY_HOME: { - - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(0); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_END: { - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(text.size()-1); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - + case KEY_HOME: { + + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(0); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_END: { + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(text.size()-1); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + #else - case KEY_HOME: { - - - if (k.mod.shift) - _pre_shift_selection(); - - // compute whitespace symbols seq length - int current_line_whitespace_len = 0; - while(current_line_whitespace_len < text[cursor.line].length()) { - CharType c = text[cursor.line][current_line_whitespace_len]; - if(c != '\t' && c != ' ') - break; - current_line_whitespace_len++; - } - - if(cursor_get_column() == current_line_whitespace_len) - cursor_set_column(0); - else - cursor_set_column(current_line_whitespace_len); - - if (k.mod.command) - cursor_set_line(0); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_END: { - - if (k.mod.shift) - _pre_shift_selection(); - - if (k.mod.command) - cursor_set_line(text.size()-1); - cursor_set_column(text[cursor.line].length()); - - if (k.mod.shift) - _post_shift_selection(); - - } break; + case KEY_HOME: { + + + if (k.mod.shift) + _pre_shift_selection(); + + // compute whitespace symbols seq length + int current_line_whitespace_len = 0; + while(current_line_whitespace_len < text[cursor.line].length()) { + CharType c = text[cursor.line][current_line_whitespace_len]; + if(c != '\t' && c != ' ') + break; + current_line_whitespace_len++; + } + + if(cursor_get_column() == current_line_whitespace_len) + cursor_set_column(0); + else + cursor_set_column(current_line_whitespace_len); + + if (k.mod.command) + cursor_set_line(0); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_END: { + + if (k.mod.shift) + _pre_shift_selection(); + + if (k.mod.command) + cursor_set_line(text.size()-1); + cursor_set_column(text[cursor.line].length()); + + if (k.mod.shift) + _post_shift_selection(); + + } break; #endif - case KEY_PAGEUP: { - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(cursor_get_line()-get_visible_rows()); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_PAGEDOWN: { - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(cursor_get_line()+get_visible_rows()); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_A: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - if (text.size()==1 && text[0].length()==0) - break; - selection.active=true; - selection.from_line=0; - selection.from_column=0; - selection.to_line=text.size()-1; - selection.to_column=text[selection.to_line].size(); - selection.selecting_mode=Selection::MODE_NONE; - update(); - - } break; - case KEY_X: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - if (!selection.active){ - - String clipboard = text[cursor.line]; - OS::get_singleton()->set_clipboard(clipboard); - cursor_set_line(cursor.line); - cursor_set_column(0); - _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); - - backspace_at_cursor(); - update(); - cursor_set_line(cursor.line+1); - cut_copy_line = true; - - } - else - { - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - cut_copy_line = false; - } - - } break; - case KEY_C: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - if (!selection.active){ - String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = true; - } - else{ - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = false; - } - } break; - case KEY_Z: { - - if (!k.mod.command) { - scancode_handled=false; - break; - } - - if (k.mod.shift) - redo(); - else - undo(); - } break; - case KEY_V: { - - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - - String clipboard = OS::get_singleton()->get_clipboard(); - - if (selection.active) { - selection.active=false; - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - } - else if (cut_copy_line) - { - cursor_set_column(0); - String ins="\n"; - clipboard += ins; - } - - _insert_text_at_cursor(clipboard); - - update(); - } break; - case KEY_SPACE: { - if (completion_enabled && k.mod.command) { - - query_code_comple(); - scancode_handled=true; - } else { - scancode_handled=false; - } - - } break; - - case KEY_U:{ - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - else { - if (selection.active) { - int ini = selection.from_line; - int end = selection.to_line; - for (int i=ini; i<= end; i++) - { - if (text[i][0] == '#') - _remove_text(i,0,i,1); - } - } - else{ - if (text[cursor.line][0] == '#') - _remove_text(cursor.line,0,cursor.line,1); - } - update(); - } - break;} - - default: { - - scancode_handled=false; - } break; - - } - - if (scancode_handled) - accept_event(); -/* - if (!scancode_handled && !k.mod.command && !k.mod.alt) { - - if (k.unicode>=32) { - - if (readonly) - break; - - accept_event(); - } else { - - break; - } - } + case KEY_PAGEUP: { + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(cursor_get_line()-get_visible_rows()); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_PAGEDOWN: { + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(cursor_get_line()+get_visible_rows()); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_A: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + if (text.size()==1 && text[0].length()==0) + break; + selection.active=true; + selection.from_line=0; + selection.from_column=0; + selection.to_line=text.size()-1; + selection.to_column=text[selection.to_line].size(); + selection.selecting_mode=Selection::MODE_NONE; + update(); + + } break; + case KEY_X: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + if (!selection.active){ + + String clipboard = text[cursor.line]; + OS::get_singleton()->set_clipboard(clipboard); + cursor_set_line(cursor.line); + cursor_set_column(0); + _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); + + backspace_at_cursor(); + update(); + cursor_set_line(cursor.line+1); + cut_copy_line = true; + + } + else + { + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + cut_copy_line = false; + } + + } break; + case KEY_C: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + if (!selection.active){ + String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = true; + } + else{ + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = false; + } + } break; + case KEY_Z: { + + if (!k.mod.command) { + scancode_handled=false; + break; + } + + if (k.mod.shift) + redo(); + else + undo(); + } break; + case KEY_V: { + + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + + String clipboard = OS::get_singleton()->get_clipboard(); + + if (selection.active) { + selection.active=false; + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + } + else if (cut_copy_line) + { + cursor_set_column(0); + String ins="\n"; + clipboard += ins; + } + + _insert_text_at_cursor(clipboard); + + update(); + } break; + case KEY_SPACE: { + if (completion_enabled && k.mod.command) { + + query_code_comple(); + scancode_handled=true; + } else { + scancode_handled=false; + } + + } break; + + case KEY_U:{ + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + else { + if (selection.active) { + int ini = selection.from_line; + int end = selection.to_line; + for (int i=ini; i<= end; i++) + { + if (text[i][0] == '#') + _remove_text(i,0,i,1); + } + } + else{ + if (text[cursor.line][0] == '#') + _remove_text(cursor.line,0,cursor.line,1); + } + update(); + } + break;} + + default: { + + scancode_handled=false; + } break; + + } + + if (scancode_handled) + accept_event(); + /* + if (!scancode_handled && !k.mod.command && !k.mod.alt) { + + if (k.unicode>=32) { + + if (readonly) + break; + + accept_event(); + } else { + + break; + } + } */ - if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds - - if (k.unicode>=32) { - - if (readonly) - break; - - const CharType chr[2] = {k.unicode, 0}; - - if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { - _consume_pair_symbol(chr[0]); - } else { - _insert_text_at_cursor(chr); - } - - accept_event(); - } else { - - break; - } - } - - - if (!selection.selecting_test) { - - selection.selecting_mode=Selection::MODE_NONE; - } - - return; - } break; - - } - + if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds + + if (k.unicode>=32) { + + if (readonly) + break; + + const CharType chr[2] = {k.unicode, 0}; + + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } + + accept_event(); + } else { + + break; + } + } + + + if (!selection.selecting_test) { + + selection.selecting_mode=Selection::MODE_NONE; + } + + return; + } break; + + } + } void TextEdit::_pre_shift_selection() { - - - if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) { - - selection.selecting_line=cursor.line; - selection.selecting_column=cursor.column; - selection.active=true; - selection.selecting_mode=Selection::MODE_SHIFT; - } + + + if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) { + + selection.selecting_line=cursor.line; + selection.selecting_column=cursor.column; + selection.active=true; + selection.selecting_mode=Selection::MODE_SHIFT; + } } void TextEdit::_post_shift_selection() { - - - if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) { - - select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column); - update(); - } - - - selection.selecting_test=true; + + + if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) { + + select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column); + update(); + } + + + selection.selecting_test=true; } /**** TEXT EDIT CORE API ****/ void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) { - - //save for undo... - ERR_FAIL_INDEX(p_line,text.size()); - ERR_FAIL_COND(p_char<0); - - /* STEP 1 add spaces if the char is greater than the end of the line */ - while(p_char>text[p_line].length()) { - - text.set(p_line,text[p_line]+String::chr(' ')); - } - - /* STEP 2 separate dest string in pre and post text */ - - String preinsert_text = text[p_line].substr(0,p_char); - String postinsert_text = text[p_line].substr(p_char,text[p_line].size()); - - /* STEP 3 remove \r from source text and separate in substrings */ - - //buh bye \r and split - Vector<String> substrings = p_text.replace("\r","").split("\n"); - - - for(int i=0;i<substrings.size();i++) { - //insert the substrings - - if (i==0) { - - text.set(p_line,preinsert_text+substrings[i]); - } else { - - text.insert(p_line+i,substrings[i]); - } - - if (i==substrings.size()-1){ - - text.set(p_line+i,text[p_line+i]+postinsert_text); - } - } - - r_end_line=p_line+substrings.size()-1; - r_end_column=text[r_end_line].length()-postinsert_text.length(); - - if (!text_changed_dirty && !setting_text) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); - text_changed_dirty=true; - } - + + //save for undo... + ERR_FAIL_INDEX(p_line,text.size()); + ERR_FAIL_COND(p_char<0); + + /* STEP 1 add spaces if the char is greater than the end of the line */ + while(p_char>text[p_line].length()) { + + text.set(p_line,text[p_line]+String::chr(' ')); + } + + /* STEP 2 separate dest string in pre and post text */ + + String preinsert_text = text[p_line].substr(0,p_char); + String postinsert_text = text[p_line].substr(p_char,text[p_line].size()); + + /* STEP 3 remove \r from source text and separate in substrings */ + + //buh bye \r and split + Vector<String> substrings = p_text.replace("\r","").split("\n"); + + + for(int i=0;i<substrings.size();i++) { + //insert the substrings + + if (i==0) { + + text.set(p_line,preinsert_text+substrings[i]); + } else { + + text.insert(p_line+i,substrings[i]); + } + + if (i==substrings.size()-1){ + + text.set(p_line+i,text[p_line+i]+postinsert_text); + } + } + + r_end_line=p_line+substrings.size()-1; + r_end_column=text[r_end_line].length()-postinsert_text.length(); + + if (!text_changed_dirty && !setting_text) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); + text_changed_dirty=true; + } + } String TextEdit::_base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const { - - ERR_FAIL_INDEX_V(p_from_line,text.size(),String()); - ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String()); - ERR_FAIL_INDEX_V(p_to_line,text.size(),String()); - ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String()); - ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to - ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column<p_from_column,String()); // from > to - - String ret; - - for(int i=p_from_line;i<=p_to_line;i++) { - - int begin = (i==p_from_line)?p_from_column:0; - int end = (i==p_to_line)?p_to_column:text[i].length(); - - if (i>p_from_line) - ret+="\n"; - ret+=text[i].substr(begin,end-begin); - } - - return ret; + + ERR_FAIL_INDEX_V(p_from_line,text.size(),String()); + ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String()); + ERR_FAIL_INDEX_V(p_to_line,text.size(),String()); + ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String()); + ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to + ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column<p_from_column,String()); // from > to + + String ret; + + for(int i=p_from_line;i<=p_to_line;i++) { + + int begin = (i==p_from_line)?p_from_column:0; + int end = (i==p_to_line)?p_to_column:text[i].length(); + + if (i>p_from_line) + ret+="\n"; + ret+=text[i].substr(begin,end-begin); + } + + return ret; } void TextEdit::_base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - - ERR_FAIL_INDEX(p_from_line,text.size()); - ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1); - ERR_FAIL_INDEX(p_to_line,text.size()); - ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1); - ERR_FAIL_COND(p_to_line < p_from_line ); // from > to - ERR_FAIL_COND(p_to_line == p_from_line && p_to_column<p_from_column); // from > to - - - String pre_text = text[p_from_line].substr(0,p_from_column); - String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length()); - - for(int i=p_from_line;i<p_to_line;i++) { - - text.remove(p_from_line+1); - } - - text.set(p_from_line,pre_text+post_text); - - if (!text_changed_dirty && !setting_text) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); - text_changed_dirty=true; - } + + ERR_FAIL_INDEX(p_from_line,text.size()); + ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1); + ERR_FAIL_INDEX(p_to_line,text.size()); + ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1); + ERR_FAIL_COND(p_to_line < p_from_line ); // from > to + ERR_FAIL_COND(p_to_line == p_from_line && p_to_column<p_from_column); // from > to + + + String pre_text = text[p_from_line].substr(0,p_from_column); + String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length()); + + for(int i=p_from_line;i<p_to_line;i++) { + + text.remove(p_from_line+1); + } + + text.set(p_from_line,pre_text+post_text); + + if (!text_changed_dirty && !setting_text) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); + text_changed_dirty=true; + } } void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_end_line,int *r_end_column) { - - if (!setting_text) - idle_detect->start(); - - if (undo_enabled) { - _clear_redo(); - } - - int retline,retchar; - _base_insert_text(p_line,p_char,p_text,retline,retchar); - if (r_end_line) - *r_end_line=retline; - if (r_end_column) - *r_end_column=retchar; - - if (!undo_enabled) - return; - - /* UNDO!! */ - TextOperation op; - op.type=TextOperation::TYPE_INSERT; - op.from_line=p_line; - op.from_column=p_char; - op.to_line=retline; - op.to_column=retchar; - op.text=p_text; - op.version=++version; - op.chain_forward=false; - op.chain_backward=false; - - //see if it shold just be set as current op - if (current_op.type!=op.type) { - _push_current_op(); - current_op=op; - - return; //set as current op, return - } - //see if it can be merged - if (current_op.to_line!=p_line || current_op.to_column!=p_char) { - _push_current_op(); - current_op=op; - return; //set as current op, return - } - //merge current op - - current_op.text+=p_text; - current_op.to_column=retchar; - current_op.to_line=retline; - current_op.version=op.version; - + + if (!setting_text) + idle_detect->start(); + + if (undo_enabled) { + _clear_redo(); + } + + int retline,retchar; + _base_insert_text(p_line,p_char,p_text,retline,retchar); + if (r_end_line) + *r_end_line=retline; + if (r_end_column) + *r_end_column=retchar; + + if (!undo_enabled) + return; + + /* UNDO!! */ + TextOperation op; + op.type=TextOperation::TYPE_INSERT; + op.from_line=p_line; + op.from_column=p_char; + op.to_line=retline; + op.to_column=retchar; + op.text=p_text; + op.version=++version; + op.chain_forward=false; + op.chain_backward=false; + + //see if it shold just be set as current op + if (current_op.type!=op.type) { + _push_current_op(); + current_op=op; + + return; //set as current op, return + } + //see if it can be merged + if (current_op.to_line!=p_line || current_op.to_column!=p_char) { + _push_current_op(); + current_op=op; + return; //set as current op, return + } + //merge current op + + current_op.text+=p_text; + current_op.to_column=retchar; + current_op.to_line=retline; + current_op.version=op.version; + } void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - - if (!setting_text) - idle_detect->start(); - - String text; - if (undo_enabled) { - _clear_redo(); - text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column); - } - - _base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column); - - if (!undo_enabled) - return; - - /* UNDO!! */ - TextOperation op; - op.type=TextOperation::TYPE_REMOVE; - op.from_line=p_from_line; - op.from_column=p_from_column; - op.to_line=p_to_line; - op.to_column=p_to_column; - op.text=text; - op.version=++version; - op.chain_forward=false; - op.chain_backward=false; - - //see if it shold just be set as current op - if (current_op.type!=op.type) { - _push_current_op(); - current_op=op; - return; //set as current op, return - } - //see if it can be merged - if (current_op.from_line==p_to_line && current_op.from_column==p_to_column) { - //basckace or similar - current_op.text=text+current_op.text; - current_op.from_line=p_from_line; - current_op.from_column=p_from_column; - return; //update current op - } - if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) { - - //current_op.text=text+current_op.text; - //current_op.from_line=p_from_line; - //current_op.from_column=p_from_column; - //return; //update current op - } - - _push_current_op(); - current_op=op; - + + if (!setting_text) + idle_detect->start(); + + String text; + if (undo_enabled) { + _clear_redo(); + text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column); + } + + _base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column); + + if (!undo_enabled) + return; + + /* UNDO!! */ + TextOperation op; + op.type=TextOperation::TYPE_REMOVE; + op.from_line=p_from_line; + op.from_column=p_from_column; + op.to_line=p_to_line; + op.to_column=p_to_column; + op.text=text; + op.version=++version; + op.chain_forward=false; + op.chain_backward=false; + + //see if it shold just be set as current op + if (current_op.type!=op.type) { + _push_current_op(); + current_op=op; + return; //set as current op, return + } + //see if it can be merged + if (current_op.from_line==p_to_line && current_op.from_column==p_to_column) { + //basckace or similar + current_op.text=text+current_op.text; + current_op.from_line=p_from_line; + current_op.from_column=p_from_column; + return; //update current op + } + if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) { + + //current_op.text=text+current_op.text; + //current_op.from_line=p_from_line; + //current_op.from_column=p_from_column; + //return; //update current op + } + + _push_current_op(); + current_op=op; + } void TextEdit::_insert_text_at_cursor(const String& p_text) { - - int new_column,new_line; - _insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column); - cursor_set_line(new_line); - cursor_set_column(new_column); - - update(); + + int new_column,new_line; + _insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column); + cursor_set_line(new_line); + cursor_set_column(new_column); + + update(); } int TextEdit::get_char_count() { - - int totalsize=0; - - for (int i=0;i<text.size();i++) { - - if (i>0) - totalsize++; // incliude \n - totalsize+=text[i].length(); - } - - return totalsize; // omit last \n + + int totalsize=0; + + for (int i=0;i<text.size();i++) { + + if (i>0) + totalsize++; // incliude \n + totalsize+=text[i].length(); + } + + return totalsize; // omit last \n } Size2 TextEdit::get_minimum_size() { - - return cache.style_normal->get_minimum_size(); + + return cache.style_normal->get_minimum_size(); } int TextEdit::get_visible_rows() const { - - int total=cache.size.height; - total-=cache.style_normal->get_minimum_size().height; - total/=get_row_height(); - return total; + + int total=cache.size.height; + total-=cache.style_normal->get_minimum_size().height; + total/=get_row_height(); + return total; } void TextEdit::adjust_viewport_to_cursor() { - - if (cursor.line_ofs>cursor.line) - cursor.line_ofs=cursor.line; - - int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w; - if (v_scroll->is_visible()) - visible_width-=v_scroll->get_combined_minimum_size().width; - visible_width-=20; // give it a little more space - - - //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); - - int visible_rows = get_visible_rows(); - if (h_scroll->is_visible()) - visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height()); - - if (cursor.line>=(cursor.line_ofs+visible_rows)) - cursor.line_ofs=cursor.line-visible_rows+1; - if (cursor.line<cursor.line_ofs) - cursor.line_ofs=cursor.line; - - int cursor_x = get_column_x_offset( cursor.column, text[cursor.line] ); - - if (cursor_x>(cursor.x_ofs+visible_width)) - cursor.x_ofs=cursor_x-visible_width+1; - - if (cursor_x < cursor.x_ofs) - cursor.x_ofs=cursor_x; - - update(); -/* + + if (cursor.line_ofs>cursor.line) + cursor.line_ofs=cursor.line; + + int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w; + if (v_scroll->is_visible()) + visible_width-=v_scroll->get_combined_minimum_size().width; + visible_width-=20; // give it a little more space + + + //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); + + int visible_rows = get_visible_rows(); + if (h_scroll->is_visible()) + visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height()); + + if (cursor.line>=(cursor.line_ofs+visible_rows)) + cursor.line_ofs=cursor.line-visible_rows+1; + if (cursor.line<cursor.line_ofs) + cursor.line_ofs=cursor.line; + + int cursor_x = get_column_x_offset( cursor.column, text[cursor.line] ); + + if (cursor_x>(cursor.x_ofs+visible_width)) + cursor.x_ofs=cursor_x-visible_width+1; + + if (cursor_x < cursor.x_ofs) + cursor.x_ofs=cursor_x; + + update(); + /* get_range()->set_max(text.size()); - + get_range()->set_page(get_visible_rows()); - + get_range()->set((int)cursor.line_ofs); */ - - + + } void TextEdit::cursor_set_column(int p_col) { - - if (p_col<0) - p_col=0; - - cursor.column=p_col; - if (cursor.column > get_line( cursor.line ).length()) - cursor.column=get_line( cursor.line ).length(); - - cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line)); - - adjust_viewport_to_cursor(); - - if (!cursor_changed_dirty) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); - cursor_changed_dirty=true; - } - + + if (p_col<0) + p_col=0; + + cursor.column=p_col; + if (cursor.column > get_line( cursor.line ).length()) + cursor.column=get_line( cursor.line ).length(); + + cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line)); + + adjust_viewport_to_cursor(); + + if (!cursor_changed_dirty) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); + cursor_changed_dirty=true; + } + } void TextEdit::cursor_set_line(int p_row) { - - if (setting_row) - return; - - setting_row=true; - if (p_row<0) - p_row=0; - - - if (p_row>=(int)text.size()) - p_row=(int)text.size()-1; - - cursor.line=p_row; - cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) ); - - - adjust_viewport_to_cursor(); - - setting_row=false; - - - if (!cursor_changed_dirty) { - if (is_inside_tree()) - MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); - cursor_changed_dirty=true; - } - + + if (setting_row) + return; + + setting_row=true; + if (p_row<0) + p_row=0; + + + if (p_row>=(int)text.size()) + p_row=(int)text.size()-1; + + cursor.line=p_row; + cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) ); + + + adjust_viewport_to_cursor(); + + setting_row=false; + + + if (!cursor_changed_dirty) { + if (is_inside_tree()) + MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); + cursor_changed_dirty=true; + } + } int TextEdit::cursor_get_column() const { - - return cursor.column; + + return cursor.column; } int TextEdit::cursor_get_line() const { - - return cursor.line; + + return cursor.line; } void TextEdit::_scroll_moved(double p_to_val) { - - if (updating_scrolls) - return; - - if (h_scroll->is_visible()) - cursor.x_ofs=h_scroll->get_val(); - if (v_scroll->is_visible()) - cursor.line_ofs=v_scroll->get_val(); - update(); + + if (updating_scrolls) + return; + + if (h_scroll->is_visible()) + cursor.x_ofs=h_scroll->get_val(); + if (v_scroll->is_visible()) + cursor.line_ofs=v_scroll->get_val(); + update(); } @@ -2395,798 +2451,798 @@ void TextEdit::_scroll_moved(double p_to_val) { int TextEdit::get_row_height() const { - - return cache.font->get_height()+cache.line_spacing; + + return cache.font->get_height()+cache.line_spacing; } int TextEdit::get_char_pos_for(int p_px,String p_str) const { - - int px=0; - int c=0; - - int tab_w = cache.font->get_char_size(' ').width*tab_size; - - while (c<p_str.length()) { - - int w=0; - - if (p_str[c]=='\t') { - - int left = px%tab_w; - if (left==0) - w=tab_w; - else - w=tab_w-px%tab_w; // is right... - - } else { - - w=cache.font->get_char_size(p_str[c],p_str[c+1]).width; - } - - if (p_px<(px+w/2)) - break; - px+=w; - c++; - } - - return c; + + int px=0; + int c=0; + + int tab_w = cache.font->get_char_size(' ').width*tab_size; + + while (c<p_str.length()) { + + int w=0; + + if (p_str[c]=='\t') { + + int left = px%tab_w; + if (left==0) + w=tab_w; + else + w=tab_w-px%tab_w; // is right... + + } else { + + w=cache.font->get_char_size(p_str[c],p_str[c+1]).width; + } + + if (p_px<(px+w/2)) + break; + px+=w; + c++; + } + + return c; } int TextEdit::get_column_x_offset(int p_char,String p_str) { - - int px=0; - - int tab_w = cache.font->get_char_size(' ').width*tab_size; - - for (int i=0;i<p_char;i++) { - - if (i>=p_str.length()) - break; - - if (p_str[i]=='\t') { - - int left = px%tab_w; - if (left==0) - px+=tab_w; - else - px+=tab_w-px%tab_w; // is right... - - } else { - px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width; - } - } - - return px; - + + int px=0; + + int tab_w = cache.font->get_char_size(' ').width*tab_size; + + for (int i=0;i<p_char;i++) { + + if (i>=p_str.length()) + break; + + if (p_str[i]=='\t') { + + int left = px%tab_w; + if (left==0) + px+=tab_w; + else + px+=tab_w-px%tab_w; // is right... + + } else { + px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width; + } + } + + return px; + } void TextEdit::insert_text_at_cursor(const String& p_text) { - - if (selection.active) { - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - - } - - _insert_text_at_cursor(p_text); - update(); - + + if (selection.active) { + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + + } + + _insert_text_at_cursor(p_text); + update(); + } Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { - if(completion_active && completion_rect.has_point(p_pos)) { - return CURSOR_ARROW; - } - return CURSOR_IBEAM; + if(completion_active && completion_rect.has_point(p_pos)) { + return CURSOR_ARROW; + } + return CURSOR_IBEAM; } void TextEdit::set_text(String p_text){ - - setting_text=true; - _clear(); - _insert_text_at_cursor(p_text); - - cursor.column=0; - cursor.line=0; - cursor.x_ofs=0; - cursor.line_ofs=0; - cursor.last_fit_x=0; - cursor_set_line(0); - cursor_set_column(0); - update(); - setting_text=false; - - //get_range()->set(0); + + setting_text=true; + _clear(); + _insert_text_at_cursor(p_text); + + cursor.column=0; + cursor.line=0; + cursor.x_ofs=0; + cursor.line_ofs=0; + cursor.last_fit_x=0; + cursor_set_line(0); + cursor_set_column(0); + update(); + setting_text=false; + + //get_range()->set(0); }; String TextEdit::get_text() { - String longthing; - int len = text.size(); - for (int i=0;i<len;i++) { - - - longthing+=text[i]; - if (i!=len-1) - longthing+="\n"; - } - - return longthing; - + String longthing; + int len = text.size(); + for (int i=0;i<len;i++) { + + + longthing+=text[i]; + if (i!=len-1) + longthing+="\n"; + } + + return longthing; + }; String TextEdit::get_text_for_completion() { - - String longthing; - int len = text.size(); - for (int i=0;i<len;i++) { - - if (i==cursor.line) { - longthing+=text[i].substr(0,cursor.column); - longthing+=String::chr(0xFFFF); //not unicode, represents the cursor - longthing+=text[i].substr(cursor.column,text[i].size()); - } else { - - longthing+=text[i]; + + String longthing; + int len = text.size(); + for (int i=0;i<len;i++) { + + if (i==cursor.line) { + longthing+=text[i].substr(0,cursor.column); + longthing+=String::chr(0xFFFF); //not unicode, represents the cursor + longthing+=text[i].substr(cursor.column,text[i].size()); + } else { + + longthing+=text[i]; + } + + + if (i!=len-1) + longthing+="\n"; } - - - if (i!=len-1) - longthing+="\n"; - } - - return longthing; - + + return longthing; + }; String TextEdit::get_line(int line) const { - - if (line<0 || line>=text.size()) - return ""; - - return text[line]; - + + if (line<0 || line>=text.size()) + return ""; + + return text[line]; + }; void TextEdit::_clear() { - - clear_undo_history(); - text.clear(); - cursor.column=0; - cursor.line=0; - cursor.x_ofs=0; - cursor.line_ofs=0; - cursor.last_fit_x=0; + + clear_undo_history(); + text.clear(); + cursor.column=0; + cursor.line=0; + cursor.x_ofs=0; + cursor.line_ofs=0; + cursor.last_fit_x=0; } void TextEdit::clear() { - - setting_text=true; - _clear(); - setting_text=false; - + + setting_text=true; + _clear(); + setting_text=false; + }; void TextEdit::set_readonly(bool p_readonly) { - - - readonly=p_readonly; + + + readonly=p_readonly; } void TextEdit::set_wrap(bool p_wrap) { - - wrap=p_wrap; + + wrap=p_wrap; } void TextEdit::set_max_chars(int p_max_chars) { - - max_chars=p_max_chars; + + max_chars=p_max_chars; } void TextEdit::_update_caches() { - - cache.style_normal=get_stylebox("normal"); - cache.style_focus=get_stylebox("focus"); - cache.font=get_font("font"); - cache.font_color=get_color("font_color"); - cache.font_selected_color=get_color("font_selected_color"); - cache.keyword_color=get_color("keyword_color"); - cache.selection_color=get_color("selection_color"); - cache.mark_color=get_color("mark_color"); - cache.current_line_color=get_color("current_line_color"); - cache.breakpoint_color=get_color("breakpoint_color"); - cache.brace_mismatch_color=get_color("brace_mismatch_color"); - cache.line_spacing=get_constant("line_spacing"); - cache.row_height = cache.font->get_height() + cache.line_spacing; - cache.tab_icon=get_icon("tab"); - text.set_font(cache.font); - + + cache.style_normal=get_stylebox("normal"); + cache.style_focus=get_stylebox("focus"); + cache.font=get_font("font"); + cache.font_color=get_color("font_color"); + cache.font_selected_color=get_color("font_selected_color"); + cache.keyword_color=get_color("keyword_color"); + cache.selection_color=get_color("selection_color"); + cache.mark_color=get_color("mark_color"); + cache.current_line_color=get_color("current_line_color"); + cache.breakpoint_color=get_color("breakpoint_color"); + cache.brace_mismatch_color=get_color("brace_mismatch_color"); + cache.line_spacing=get_constant("line_spacing"); + cache.row_height = cache.font->get_height() + cache.line_spacing; + cache.tab_icon=get_icon("tab"); + text.set_font(cache.font); + } void TextEdit::clear_colors() { - - keywords.clear(); - color_regions.clear();; - text.clear_caches(); - custom_bg_color=Color(0,0,0,0); + + keywords.clear(); + color_regions.clear();; + text.clear_caches(); + custom_bg_color=Color(0,0,0,0); } void TextEdit::set_custom_bg_color(const Color& p_color) { - - custom_bg_color=p_color; - update(); + + custom_bg_color=p_color; + update(); } void TextEdit::add_keyword_color(const String& p_keyword,const Color& p_color) { - - keywords[p_keyword]=p_color; - update(); - + + keywords[p_keyword]=p_color; + update(); + } void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_key,const Color &p_color,bool p_line_only) { - - color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only)); - text.clear_caches(); - update(); - + + color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only)); + text.clear_caches(); + update(); + } void TextEdit::set_symbol_color(const Color& p_color) { - - symbol_color=p_color; - update(); + + symbol_color=p_color; + update(); } void TextEdit::set_syntax_coloring(bool p_enabled) { - - syntax_coloring=p_enabled; - update(); + + syntax_coloring=p_enabled; + update(); } bool TextEdit::is_syntax_coloring_enabled() const { - - return syntax_coloring; + + return syntax_coloring; } void TextEdit::cut() { - - if (!selection.active) - return; - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - + + if (!selection.active) + return; + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + } void TextEdit::copy() { - - if (!selection.active) - return; - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - + + if (!selection.active) + return; + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + } void TextEdit::paste() { - - if (selection.active) { - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - - } - - String clipboard = OS::get_singleton()->get_clipboard(); - _insert_text_at_cursor(clipboard); - update(); - + + if (selection.active) { + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + + } + + String clipboard = OS::get_singleton()->get_clipboard(); + _insert_text_at_cursor(clipboard); + update(); + } void TextEdit::select_all() { - - if (text.size()==1 && text[0].length()==0) - return; - selection.active=true; - selection.from_line=0; - selection.from_column=0; - selection.to_line=text.size()-1; - selection.to_column=text[selection.to_line].size(); - selection.selecting_mode=Selection::MODE_NONE; - update(); - + + if (text.size()==1 && text[0].length()==0) + return; + selection.active=true; + selection.from_line=0; + selection.from_column=0; + selection.to_line=text.size()-1; + selection.to_column=text[selection.to_line].size(); + selection.selecting_mode=Selection::MODE_NONE; + update(); + } void TextEdit::deselect() { - - selection.active=false; - update(); + + selection.active=false; + update(); } void TextEdit::select(int p_from_line,int p_from_column,int p_to_line,int p_to_column) { - - if (p_from_line>=text.size()) - p_from_line=text.size()-1; - if (p_from_column>=text[p_from_line].length()) - p_from_column=text[p_from_line].length(); - - if (p_to_line>=text.size()) - p_to_line=text.size()-1; - if (p_to_column>=text[p_to_line].length()) - p_to_column=text[p_to_line].length(); - - selection.from_line=p_from_line; - selection.from_column=p_from_column; - selection.to_line=p_to_line; - selection.to_column=p_to_column; - - selection.active=true; - - if (selection.from_line==selection.to_line) { - - if (selection.from_column==selection.to_column) { - - selection.active=false; - - } else if (selection.from_column>selection.to_column) { - - SWAP( selection.from_column, selection.to_column ); - } - } else if (selection.from_line>selection.to_line) { - - SWAP( selection.from_line, selection.to_line ); - SWAP( selection.from_column, selection.to_column ); - } - - - update(); + + if (p_from_line>=text.size()) + p_from_line=text.size()-1; + if (p_from_column>=text[p_from_line].length()) + p_from_column=text[p_from_line].length(); + + if (p_to_line>=text.size()) + p_to_line=text.size()-1; + if (p_to_column>=text[p_to_line].length()) + p_to_column=text[p_to_line].length(); + + selection.from_line=p_from_line; + selection.from_column=p_from_column; + selection.to_line=p_to_line; + selection.to_column=p_to_column; + + selection.active=true; + + if (selection.from_line==selection.to_line) { + + if (selection.from_column==selection.to_column) { + + selection.active=false; + + } else if (selection.from_column>selection.to_column) { + + SWAP( selection.from_column, selection.to_column ); + } + } else if (selection.from_line>selection.to_line) { + + SWAP( selection.from_line, selection.to_line ); + SWAP( selection.from_column, selection.to_column ); + } + + + update(); } bool TextEdit::is_selection_active() const { - - return selection.active; + + return selection.active; } int TextEdit::get_selection_from_line() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.from_line; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.from_line; + } int TextEdit::get_selection_from_column() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.from_column; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.from_column; + } int TextEdit::get_selection_to_line() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.to_line; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.to_line; + } int TextEdit::get_selection_to_column() const { - - ERR_FAIL_COND_V(!selection.active,-1); - return selection.to_column; - + + ERR_FAIL_COND_V(!selection.active,-1); + return selection.to_column; + } String TextEdit::get_selection_text() const { - - if (!selection.active) - return ""; - - return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - + + if (!selection.active) + return ""; + + return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + } String TextEdit::get_word_under_cursor() const { - - int prev_cc = cursor.column; - while(prev_cc >0) { - bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); - if (!is_char) - break; - --prev_cc; - } - - int next_cc = cursor.column; - while(next_cc<text[cursor.line].length()) { - bool is_char = _is_text_char(text[cursor.line][next_cc]); - if(!is_char) - break; - ++ next_cc; - } - if (prev_cc == cursor.column || next_cc == cursor.column) - return ""; - return text[cursor.line].substr(prev_cc, next_cc-prev_cc); + + int prev_cc = cursor.column; + while(prev_cc >0) { + bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); + if (!is_char) + break; + --prev_cc; + } + + int next_cc = cursor.column; + while(next_cc<text[cursor.line].length()) { + bool is_char = _is_text_char(text[cursor.line][next_cc]); + if(!is_char) + break; + ++ next_cc; + } + if (prev_cc == cursor.column || next_cc == cursor.column) + return ""; + return text[cursor.line].substr(prev_cc, next_cc-prev_cc); } DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const { - - int col,line; - if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) { - DVector<int> result; - result.resize(2); - result.set(0,line); - result.set(1,col); - return result; - - } else { - - return DVector<int>(); - } + + int col,line; + if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) { + DVector<int> result; + result.resize(2); + result.set(0,line); + result.set(1,col); + return result; + + } else { + + return DVector<int>(); + } } bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_line, int p_from_column,int &r_line,int &r_column) const { - - if (p_key.length()==0) - return false; - ERR_FAIL_INDEX_V(p_from_line,text.size(),false); - ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false); - - //search through the whole documment, but start by current line - - int line=-1; - int pos=-1; - - line=p_from_line; - - for(int i=0;i<text.size()+1;i++) { - //backwards is broken... - //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch - - - if (line<0) { - line=text.size()-1; - } - if (line==text.size()) { - line=0; - } - - String text_line = text[line]; - int from_column=0; - if (line==p_from_line) { - - if (i==text.size()) { - //wrapped - - if (p_search_flags&SEARCH_BACKWARDS) { - text_line=text_line.substr(from_column,text_line.length()); - from_column=text_line.length(); - } else { - text_line=text_line.substr(0,from_column); - from_column=0; - } - - } else { - - from_column=p_from_column; - } - - - } else { - //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining. - if (p_search_flags&SEARCH_BACKWARDS) - from_column=text_line.length()-1; - else - from_column=0; - } - - pos=-1; - - if (!(p_search_flags&SEARCH_BACKWARDS)) { - - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); - } else { - - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); - } - - if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { - //validate for whole words - if (pos>0 && _is_text_char(text_line[pos-1])) - pos=-1; - else if (_is_text_char(text_line[pos+p_key.length()])) - pos=-1; - } - - if (pos!=-1) - break; - - if (p_search_flags&SEARCH_BACKWARDS) - line--; - else - line++; - - } - - if (pos==-1) { - r_line=-1; - r_column=-1; - return false; - } - - r_line=line; - r_column=pos; - - - return true; + + if (p_key.length()==0) + return false; + ERR_FAIL_INDEX_V(p_from_line,text.size(),false); + ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false); + + //search through the whole documment, but start by current line + + int line=-1; + int pos=-1; + + line=p_from_line; + + for(int i=0;i<text.size()+1;i++) { + //backwards is broken... + //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch + + + if (line<0) { + line=text.size()-1; + } + if (line==text.size()) { + line=0; + } + + String text_line = text[line]; + int from_column=0; + if (line==p_from_line) { + + if (i==text.size()) { + //wrapped + + if (p_search_flags&SEARCH_BACKWARDS) { + text_line=text_line.substr(from_column,text_line.length()); + from_column=text_line.length(); + } else { + text_line=text_line.substr(0,from_column); + from_column=0; + } + + } else { + + from_column=p_from_column; + } + + + } else { + //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining. + if (p_search_flags&SEARCH_BACKWARDS) + from_column=text_line.length()-1; + else + from_column=0; + } + + pos=-1; + + if (!(p_search_flags&SEARCH_BACKWARDS)) { + + pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); + } else { + + pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); + } + + if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { + //validate for whole words + if (pos>0 && _is_text_char(text_line[pos-1])) + pos=-1; + else if (_is_text_char(text_line[pos+p_key.length()])) + pos=-1; + } + + if (pos!=-1) + break; + + if (p_search_flags&SEARCH_BACKWARDS) + line--; + else + line++; + + } + + if (pos==-1) { + r_line=-1; + r_column=-1; + return false; + } + + r_line=line; + r_column=pos; + + + return true; } void TextEdit::_cursor_changed_emit() { - - emit_signal("cursor_changed"); - cursor_changed_dirty=false; + + emit_signal("cursor_changed"); + cursor_changed_dirty=false; } void TextEdit::_text_changed_emit() { - - emit_signal("text_changed"); - text_changed_dirty=false; + + emit_signal("text_changed"); + text_changed_dirty=false; } void TextEdit::set_line_as_marked(int p_line,bool p_marked) { - - ERR_FAIL_INDEX(p_line,text.size()); - text.set_marked(p_line,p_marked); - update(); + + ERR_FAIL_INDEX(p_line,text.size()); + text.set_marked(p_line,p_marked); + update(); } bool TextEdit::is_line_set_as_breakpoint(int p_line) const { - - ERR_FAIL_INDEX_V(p_line,text.size(),false); - return text.is_breakpoint(p_line); - + + ERR_FAIL_INDEX_V(p_line,text.size(),false); + return text.is_breakpoint(p_line); + } void TextEdit::set_line_as_breakpoint(int p_line,bool p_breakpoint) { - - - ERR_FAIL_INDEX(p_line,text.size()); - text.set_breakpoint(p_line,p_breakpoint); - update(); + + + ERR_FAIL_INDEX(p_line,text.size()); + text.set_breakpoint(p_line,p_breakpoint); + update(); } void TextEdit::get_breakpoints(List<int> *p_breakpoints) const { - - for(int i=0;i<text.size();i++) { - if (text.is_breakpoint(i)) - p_breakpoints->push_back(i); - } + + for(int i=0;i<text.size();i++) { + if (text.is_breakpoint(i)) + p_breakpoints->push_back(i); + } } int TextEdit::get_line_count() const { - - return text.size(); + + return text.size(); } void TextEdit::_do_text_op(const TextOperation& p_op, bool p_reverse) { - - ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE); - - bool insert = p_op.type==TextOperation::TYPE_INSERT; - if (p_reverse) - insert=!insert; - - if (insert) { - - int check_line; - int check_column; - _base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column); - ERR_FAIL_COND( check_line != p_op.to_line ); // BUG - ERR_FAIL_COND( check_column != p_op.to_column ); // BUG - } else { - - _base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column); - } - + + ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE); + + bool insert = p_op.type==TextOperation::TYPE_INSERT; + if (p_reverse) + insert=!insert; + + if (insert) { + + int check_line; + int check_column; + _base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column); + ERR_FAIL_COND( check_line != p_op.to_line ); // BUG + ERR_FAIL_COND( check_column != p_op.to_column ); // BUG + } else { + + _base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column); + } + } void TextEdit::_clear_redo() { - - if (undo_stack_pos==NULL) - return; //nothing to clear - - _push_current_op(); - - while (undo_stack_pos) { - List<TextOperation>::Element *elem = undo_stack_pos; - undo_stack_pos=undo_stack_pos->next(); - undo_stack.erase(elem); - } + + if (undo_stack_pos==NULL) + return; //nothing to clear + + _push_current_op(); + + while (undo_stack_pos) { + List<TextOperation>::Element *elem = undo_stack_pos; + undo_stack_pos=undo_stack_pos->next(); + undo_stack.erase(elem); + } } void TextEdit::undo() { - - _push_current_op(); - - if (undo_stack_pos==NULL) { - - if (!undo_stack.size()) - return; //nothing to undo - - undo_stack_pos=undo_stack.back(); - - } else if (undo_stack_pos==undo_stack.front()) - return; // at the bottom of the undo stack - else - undo_stack_pos=undo_stack_pos->prev(); - - _do_text_op( undo_stack_pos->get(),true); - if(undo_stack_pos->get().chain_backward) { - do { - undo_stack_pos = undo_stack_pos->prev(); - _do_text_op(undo_stack_pos->get(), true); - } while(!undo_stack_pos->get().chain_forward); - } - - cursor_set_line(undo_stack_pos->get().from_line); - cursor_set_column(undo_stack_pos->get().from_column); - update(); + + _push_current_op(); + + if (undo_stack_pos==NULL) { + + if (!undo_stack.size()) + return; //nothing to undo + + undo_stack_pos=undo_stack.back(); + + } else if (undo_stack_pos==undo_stack.front()) + return; // at the bottom of the undo stack + else + undo_stack_pos=undo_stack_pos->prev(); + + _do_text_op( undo_stack_pos->get(),true); + if(undo_stack_pos->get().chain_backward) { + do { + undo_stack_pos = undo_stack_pos->prev(); + _do_text_op(undo_stack_pos->get(), true); + } while(!undo_stack_pos->get().chain_forward); + } + + cursor_set_line(undo_stack_pos->get().from_line); + cursor_set_column(undo_stack_pos->get().from_column); + update(); } void TextEdit::redo() { - - _push_current_op(); - - if (undo_stack_pos==NULL) - return; //nothing to do. - - _do_text_op(undo_stack_pos->get(), false); - if(undo_stack_pos->get().chain_forward) { - do { - undo_stack_pos=undo_stack_pos->next(); - _do_text_op(undo_stack_pos->get(), false); - } while(!undo_stack_pos->get().chain_backward); - } - cursor_set_line(undo_stack_pos->get().from_line); - cursor_set_column(undo_stack_pos->get().from_column); - undo_stack_pos=undo_stack_pos->next(); - update(); + + _push_current_op(); + + if (undo_stack_pos==NULL) + return; //nothing to do. + + _do_text_op(undo_stack_pos->get(), false); + if(undo_stack_pos->get().chain_forward) { + do { + undo_stack_pos=undo_stack_pos->next(); + _do_text_op(undo_stack_pos->get(), false); + } while(!undo_stack_pos->get().chain_backward); + } + cursor_set_line(undo_stack_pos->get().from_line); + cursor_set_column(undo_stack_pos->get().from_column); + undo_stack_pos=undo_stack_pos->next(); + update(); } void TextEdit::clear_undo_history() { - - saved_version=0; - current_op.type=TextOperation::TYPE_NONE; - undo_stack_pos=NULL; - undo_stack.clear(); - + + saved_version=0; + current_op.type=TextOperation::TYPE_NONE; + undo_stack_pos=NULL; + undo_stack.clear(); + } void TextEdit::_begin_compex_operation() { - _push_current_op(); - next_operation_is_complex=true; + _push_current_op(); + next_operation_is_complex=true; } void TextEdit::_end_compex_operation() { - - _push_current_op(); - ERR_FAIL_COND(undo_stack.size() == 0); - - if(undo_stack.back()->get().chain_forward) { - undo_stack.back()->get().chain_forward=false; - return; - } - - undo_stack.back()->get().chain_backward=true; + + _push_current_op(); + ERR_FAIL_COND(undo_stack.size() == 0); + + if(undo_stack.back()->get().chain_forward) { + undo_stack.back()->get().chain_forward=false; + return; + } + + undo_stack.back()->get().chain_backward=true; } void TextEdit::_push_current_op() { - - if (current_op.type==TextOperation::TYPE_NONE) - return; // do nothing - - if(next_operation_is_complex) { - current_op.chain_forward=true; - next_operation_is_complex=false; - } - - undo_stack.push_back(current_op); - current_op.type=TextOperation::TYPE_NONE; - current_op.text=""; - current_op.chain_forward=false; - + + if (current_op.type==TextOperation::TYPE_NONE) + return; // do nothing + + if(next_operation_is_complex) { + current_op.chain_forward=true; + next_operation_is_complex=false; + } + + undo_stack.push_back(current_op); + current_op.type=TextOperation::TYPE_NONE; + current_op.text=""; + current_op.chain_forward=false; + } void TextEdit::set_draw_tabs(bool p_draw) { - - draw_tabs=p_draw; + + draw_tabs=p_draw; } bool TextEdit::is_drawing_tabs() const{ - - return draw_tabs; + + return draw_tabs; } uint32_t TextEdit::get_version() const { - return current_op.version; + return current_op.version; } uint32_t TextEdit::get_saved_version() const { - - return saved_version; + + return saved_version; } void TextEdit::tag_saved_version() { - - saved_version=get_version(); + + saved_version=get_version(); } int TextEdit::get_v_scroll() const { - - return v_scroll->get_val(); + + return v_scroll->get_val(); } void TextEdit::set_v_scroll(int p_scroll) { - - v_scroll->set_val(p_scroll); - cursor.line_ofs=p_scroll; + + v_scroll->set_val(p_scroll); + cursor.line_ofs=p_scroll; } int TextEdit::get_h_scroll() const { - - return h_scroll->get_val(); + + return h_scroll->get_val(); } void TextEdit::set_h_scroll(int p_scroll) { - - h_scroll->set_val(p_scroll); + + h_scroll->set_val(p_scroll); } void TextEdit::set_completion(bool p_enabled,const Vector<String>& p_prefixes) { - - completion_prefixes.clear(); - completion_enabled=p_enabled; - for(int i=0;i<p_prefixes.size();i++) - completion_prefixes.insert(p_prefixes[i]); + + completion_prefixes.clear(); + completion_enabled=p_enabled; + for(int i=0;i<p_prefixes.size();i++) + completion_prefixes.insert(p_prefixes[i]); } void TextEdit::_confirm_completion() { - - String remaining=completion_current.substr(completion_base.length(),completion_current.length()-completion_base.length()); - String l = text[cursor.line]; - bool same=true; - //if what is going to be inserted is the same as what it is, don't change it - for(int i=0;i<remaining.length();i++) { - int c=i+cursor.column; - if (c>=l.length() || l[c]!=remaining[i]) { - same=false; - break; - } - } - - if (same) - cursor_set_column(cursor.column+remaining.length()); - else { - insert_text_at_cursor(remaining); - if (remaining.ends_with("(") && auto_brace_completion_enabled) { - insert_text_at_cursor(")"); - cursor.column--; + + String remaining=completion_current.substr(completion_base.length(),completion_current.length()-completion_base.length()); + String l = text[cursor.line]; + bool same=true; + //if what is going to be inserted is the same as what it is, don't change it + for(int i=0;i<remaining.length();i++) { + int c=i+cursor.column; + if (c>=l.length() || l[c]!=remaining[i]) { + same=false; + break; + } } - } - - _cancel_completion(); + + if (same) + cursor_set_column(cursor.column+remaining.length()); + else { + insert_text_at_cursor(remaining); + if (remaining.ends_with("(") && auto_brace_completion_enabled) { + insert_text_at_cursor(")"); + cursor.column--; + } + } + + _cancel_completion(); } @@ -3196,185 +3252,185 @@ void TextEdit::_cancel_code_hint() { } void TextEdit::_cancel_completion() { - - if (!completion_active) - return; - - completion_active=false; - update(); - + + if (!completion_active) + return; + + completion_active=false; + update(); + } static bool _is_completable(CharType c) { - + return !_is_symbol(c) || c=='"' || c=='\''; } void TextEdit::_update_completion_candidates() { - - String l = text[cursor.line]; - int cofs = CLAMP(cursor.column,0,l.length()); - - - String s; - - while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) { - s=String::chr(l[cofs-1])+s; - if (l[cofs-1]=='\'' || l[cofs-1]=='"') - break; - - cofs--; - } - - - update(); - - if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { - //none to complete, cancel - _cancel_completion(); - return; - } - - completion_options.clear(); - completion_index=0; - completion_base=s; - int ci_match=0; - for(int i=0;i<completion_strings.size();i++) { - if (completion_strings[i].begins_with(s)) { - completion_options.push_back(completion_strings[i]); - int m=0; - int max=MIN(completion_current.length(),completion_strings[i].length()); - if (max<ci_match) - continue; - for(int j=0;j<max;j++) { - - if (j>=completion_strings[i].length()) - break; - if (completion_current[j]!=completion_strings[i][j]) - break; - m++; - } - if (m>ci_match) { - ci_match=m; - completion_index=completion_options.size()-1; - } - - } - } - - - - if (completion_options.size()==0) { - //no options to complete, cancel - _cancel_completion(); - return; - - } - - completion_current=completion_options[completion_index]; - + + String l = text[cursor.line]; + int cofs = CLAMP(cursor.column,0,l.length()); + + + String s; + + while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) { + s=String::chr(l[cofs-1])+s; + if (l[cofs-1]=='\'' || l[cofs-1]=='"') + break; + + cofs--; + } + + + update(); + + if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { + //none to complete, cancel + _cancel_completion(); + return; + } + + completion_options.clear(); + completion_index=0; + completion_base=s; + int ci_match=0; + for(int i=0;i<completion_strings.size();i++) { + if (completion_strings[i].begins_with(s)) { + completion_options.push_back(completion_strings[i]); + int m=0; + int max=MIN(completion_current.length(),completion_strings[i].length()); + if (max<ci_match) + continue; + for(int j=0;j<max;j++) { + + if (j>=completion_strings[i].length()) + break; + if (completion_current[j]!=completion_strings[i][j]) + break; + m++; + } + if (m>ci_match) { + ci_match=m; + completion_index=completion_options.size()-1; + } + + } + } + + + + if (completion_options.size()==0) { + //no options to complete, cancel + _cancel_completion(); + return; + + } + + completion_current=completion_options[completion_index]; + #if 0 // even there's only one option, user still get the chance to choose using it or not - if (completion_options.size()==1) { - //one option to complete, just complete it automagically - _confirm_completion(); -// insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); - _cancel_completion(); - return; - - } + if (completion_options.size()==1) { + //one option to complete, just complete it automagically + _confirm_completion(); + // insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); + _cancel_completion(); + return; + + } #endif - if (completion_options.size()==1 && s==completion_options[0]) - _cancel_completion(); - - completion_enabled=true; + if (completion_options.size()==1 && s==completion_options[0]) + _cancel_completion(); + + completion_enabled=true; } void TextEdit::query_code_comple() { - + String l = text[cursor.line]; int ofs = CLAMP(cursor.column,0,l.length()); - + if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1])))) emit_signal("request_completion"); - + } void TextEdit::set_code_hint(const String& p_hint) { - + completion_hint=p_hint; completion_hint_offset=-0xFFFF; update(); } void TextEdit::code_complete(const Vector<String> &p_strings) { - - - completion_strings=p_strings; - completion_active=true; - completion_current=""; - completion_index=0; - _update_completion_candidates(); -// + + + completion_strings=p_strings; + completion_active=true; + completion_current=""; + completion_index=0; + _update_completion_candidates(); + // } String TextEdit::get_tooltip(const Point2& p_pos) const { - - if (!tooltip_obj) - return Control::get_tooltip(p_pos); - int row,col; - if (!_get_mouse_pos(p_pos, row,col)) { - return Control::get_tooltip(p_pos); - } - - String s = text[row]; - if (s.length()==0) - return Control::get_tooltip(p_pos); - int beg=CLAMP(col,0,s.length()); - int end=beg; - - - if (s[beg]>32 || beg==s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { - beg--; - } - while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { - end++; - } - - if (end<s.length()) - end+=1; - - String tt = tooltip_obj->call(tooltip_func,s.substr(beg,end-beg),tooltip_ud); - - return tt; - - } - - return Control::get_tooltip(p_pos); - + + if (!tooltip_obj) + return Control::get_tooltip(p_pos); + int row,col; + if (!_get_mouse_pos(p_pos, row,col)) { + return Control::get_tooltip(p_pos); + } + + String s = text[row]; + if (s.length()==0) + return Control::get_tooltip(p_pos); + int beg=CLAMP(col,0,s.length()); + int end=beg; + + + if (s[beg]>32 || beg==s.length()) { + + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { + beg--; + } + while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { + end++; + } + + if (end<s.length()) + end+=1; + + String tt = tooltip_obj->call(tooltip_func,s.substr(beg,end-beg),tooltip_ud); + + return tt; + + } + + return Control::get_tooltip(p_pos); + } void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName& p_function,const Variant& p_udata) { - - tooltip_obj=p_obj; - tooltip_func=p_function; - tooltip_ud=p_udata; + + tooltip_obj=p_obj; + tooltip_func=p_function; + tooltip_ud=p_udata; } void TextEdit::set_line(int line, String new_text) { - if (line < 0 || line > text.size()) - return; - _remove_text(line, 0, line, text[line].length()); - _insert_text(line, 0, new_text); + if (line < 0 || line > text.size()) + return; + _remove_text(line, 0, line, text[line].length()); + _insert_text(line, 0, new_text); } void TextEdit::insert_at(const String &p_text, int at) @@ -3385,167 +3441,167 @@ void TextEdit::insert_at(const String &p_text, int at) } void TextEdit::set_show_line_numbers(bool p_show) { - - line_numbers=p_show; - update(); + + line_numbers=p_show; + update(); } void TextEdit::_bind_methods() { - - - ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event); - ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved); - ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit); - ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); - ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); - - BIND_CONSTANT( SEARCH_MATCH_CASE ); - BIND_CONSTANT( SEARCH_WHOLE_WORDS ); - BIND_CONSTANT( SEARCH_BACKWARDS ); - -/* + + + ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event); + ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved); + ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit); + ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); + ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); + + BIND_CONSTANT( SEARCH_MATCH_CASE ); + BIND_CONSTANT( SEARCH_WHOLE_WORDS ); + BIND_CONSTANT( SEARCH_BACKWARDS ); + + /* ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char); ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line); */ - - ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text); - ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor); - - ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count); - ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text); - ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line); - - ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column); - ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line); - - ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); - ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); - - - ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly); - ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); - ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars); - - ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut); - ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy); - ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste); - ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all); - ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select); - - ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active); - ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line); - ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column); - ObjectTypeDB::bind_method(_MD("get_selection_to_line"),&TextEdit::get_selection_to_line); - ObjectTypeDB::bind_method(_MD("get_selection_to_column"),&TextEdit::get_selection_to_column); - ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); - ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); - ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); - - ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); - ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo); - ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); - - ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring); - ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); - - - ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color); - ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false)); - ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); - ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); - ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); - - - ADD_SIGNAL(MethodInfo("cursor_changed")); - ADD_SIGNAL(MethodInfo("text_changed")); - ADD_SIGNAL(MethodInfo("request_completion")); - + + ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text); + ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor); + + ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count); + ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text); + ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line); + + ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column); + ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line); + + ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); + ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); + + + ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly); + ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); + ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars); + + ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut); + ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy); + ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste); + ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all); + ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select); + + ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active); + ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line); + ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column); + ObjectTypeDB::bind_method(_MD("get_selection_to_line"),&TextEdit::get_selection_to_line); + ObjectTypeDB::bind_method(_MD("get_selection_to_column"),&TextEdit::get_selection_to_column); + ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); + ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); + ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); + + ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); + ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo); + ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); + + ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring); + ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); + + + ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color); + ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); + ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); + ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); + + + ADD_SIGNAL(MethodInfo("cursor_changed")); + ADD_SIGNAL(MethodInfo("text_changed")); + ADD_SIGNAL(MethodInfo("request_completion")); + } TextEdit::TextEdit() { - - readonly=false; - setting_row=false; - draw_tabs=false; - max_chars=0; - clear(); - wrap=false; - set_focus_mode(FOCUS_ALL); - _update_caches(); - cache.size=Size2(1,1); - tab_size=4; - text.set_tab_size(tab_size); - text.clear(); -// text.insert(1,"Mongolia.."); -// text.insert(2,"PAIS GENEROSO!!"); - text.set_color_regions(&color_regions); - - h_scroll = memnew( HScrollBar ); - v_scroll = memnew( VScrollBar ); - - add_child(h_scroll); - add_child(v_scroll); - - updating_scrolls=false; - selection.active=false; - - h_scroll->connect("value_changed", this,"_scroll_moved"); - v_scroll->connect("value_changed", this,"_scroll_moved"); - - cursor_changed_dirty=false; - text_changed_dirty=false; - - selection.selecting_mode=Selection::MODE_NONE; - selection.selecting_line=0; - selection.selecting_column=0; - selection.selecting_test=false; - selection.active=false; - syntax_coloring=false; - - custom_bg_color=Color(0,0,0,0); - idle_detect = memnew( Timer ); - add_child(idle_detect); - idle_detect->set_one_shot(true); - idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3)); - idle_detect->connect("timeout", this,"_push_current_op"); - + + readonly=false; + setting_row=false; + draw_tabs=false; + max_chars=0; + clear(); + wrap=false; + set_focus_mode(FOCUS_ALL); + _update_caches(); + cache.size=Size2(1,1); + tab_size=4; + text.set_tab_size(tab_size); + text.clear(); + // text.insert(1,"Mongolia.."); + // text.insert(2,"PAIS GENEROSO!!"); + text.set_color_regions(&color_regions); + + h_scroll = memnew( HScrollBar ); + v_scroll = memnew( VScrollBar ); + + add_child(h_scroll); + add_child(v_scroll); + + updating_scrolls=false; + selection.active=false; + + h_scroll->connect("value_changed", this,"_scroll_moved"); + v_scroll->connect("value_changed", this,"_scroll_moved"); + + cursor_changed_dirty=false; + text_changed_dirty=false; + + selection.selecting_mode=Selection::MODE_NONE; + selection.selecting_line=0; + selection.selecting_column=0; + selection.selecting_test=false; + selection.active=false; + syntax_coloring=false; + + custom_bg_color=Color(0,0,0,0); + idle_detect = memnew( Timer ); + add_child(idle_detect); + idle_detect->set_one_shot(true); + idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3)); + idle_detect->connect("timeout", this,"_push_current_op"); + #if 0 - syntax_coloring=true; - keywords["void"]=Color(0.3,0.0,0.1); - keywords["int"]=Color(0.3,0.0,0.1); - keywords["function"]=Color(0.3,0.0,0.1); - keywords["class"]=Color(0.3,0.0,0.1); - keywords["extends"]=Color(0.3,0.0,0.1); - keywords["constructor"]=Color(0.3,0.0,0.1); - symbol_color=Color(0.1,0.0,0.3,1.0); - - color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4))); - color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4))); - color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7))); - color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8))); - color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2))); - + syntax_coloring=true; + keywords["void"]=Color(0.3,0.0,0.1); + keywords["int"]=Color(0.3,0.0,0.1); + keywords["function"]=Color(0.3,0.0,0.1); + keywords["class"]=Color(0.3,0.0,0.1); + keywords["extends"]=Color(0.3,0.0,0.1); + keywords["constructor"]=Color(0.3,0.0,0.1); + symbol_color=Color(0.1,0.0,0.3,1.0); + + color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4))); + color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4))); + color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7))); + color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8))); + color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2))); + #endif - - current_op.type=TextOperation::TYPE_NONE; - undo_enabled=true; - undo_stack_pos=NULL; - setting_text=false; - last_dblclk=0; - current_op.version=0; - version=0; - saved_version=0; - - completion_enabled=false; - completion_active=false; - completion_line_ofs=0; - tooltip_obj=NULL; - line_numbers=false; - next_operation_is_complex=false; - auto_brace_completion_enabled=false; - brace_matching_enabled=false; - + + current_op.type=TextOperation::TYPE_NONE; + undo_enabled=true; + undo_stack_pos=NULL; + setting_text=false; + last_dblclk=0; + current_op.version=0; + version=0; + saved_version=0; + + completion_enabled=false; + completion_active=false; + completion_line_ofs=0; + tooltip_obj=NULL; + line_numbers=false; + next_operation_is_complex=false; + auto_brace_completion_enabled=false; + brace_matching_enabled=false; + } TextEdit::~TextEdit() diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index ed4d30a9d2..1d57aef416 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -63,6 +63,7 @@ class TextEdit : public Control { int from_line,from_column; int to_line,to_column; + bool shiftclick_left; } selection; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d9b208d6d3..fbdc87a7cc 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -382,6 +382,8 @@ bool Node::can_process() const { if (get_tree()->is_paused()) { + if (data.pause_mode==PAUSE_MODE_STOP) + return false; if (data.pause_mode==PAUSE_MODE_PROCESS) return true; if (data.pause_mode==PAUSE_MODE_INHERIT) { @@ -391,6 +393,9 @@ bool Node::can_process() const { if (data.pause_owner->data.pause_mode==PAUSE_MODE_PROCESS) return true; + + if (data.pause_owner->data.pause_mode==PAUSE_MODE_STOP) + return false; } } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 741deccdbe..962e8c26e0 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -75,6 +75,7 @@ #include "scene/gui/split_container.h" #include "scene/gui/video_player.h" #include "scene/gui/reference_frame.h" +#include "scene/gui/graph_node.h" #include "scene/resources/video_stream.h" #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" @@ -303,6 +304,7 @@ void register_scene_types() { ObjectTypeDB::register_virtual_type<SplitContainer>(); ObjectTypeDB::register_type<HSplitContainer>(); ObjectTypeDB::register_type<VSplitContainer>(); + ObjectTypeDB::register_type<GraphNode>(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index f27cfb9511..050e462902 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -65,7 +65,7 @@ static Ref<Texture> make_icon(T p_src) { Ref<ImageTexture> texture( memnew( ImageTexture ) ); - texture->create_from_image( Image(p_src) ); + texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER ); return texture; } @@ -416,7 +416,15 @@ void make_default_theme() { t->set_color("font_color_hover","PopupMenu", control_font_color ); t->set_constant("hseparation","PopupMenu",2); t->set_constant("vseparation","PopupMenu",1); - + + Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,21,6,5,16,21,16,5); + //graphsb->set_expand_margin_size(MARGIN_LEFT,10); + //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); + t->set_stylebox("frame","GraphNode", graphsb ); + t->set_constant("separation","GraphNode", 1 ); + t->set_icon("port","GraphNode", make_icon( graph_port_png ) ); + + t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) ); t->set_stylebox("bg_focus","Tree", focus ); Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4); diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png Binary files differnew file mode 100644 index 0000000000..3adccf2c3b --- /dev/null +++ b/scene/resources/default_theme/graph_node.png diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differnew file mode 100644 index 0000000000..92f425f977 --- /dev/null +++ b/scene/resources/default_theme/graph_port.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 9cef0265ee..9fe77b3223 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -99,6 +99,16 @@ static const unsigned char full_panel_bg_png[]={ }; +static const unsigned char graph_node_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x10,0x3,0x2e,0x15,0xb6,0x7,0x4a,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char graph_port_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + static const unsigned char hscroll_bg_png[]={ 0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdd,0x9,0x1b,0x12,0x30,0x1c,0x3c,0x99,0xa,0x1c,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x53,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0xc9,0xd,0x80,0x20,0x0,0xc0,0xca,0x21,0xe8,0x5f,0x12,0x89,0x84,0xfd,0x5c,0x48,0x26,0x34,0x3e,0x74,0x2,0xa2,0xe8,0x2,0x40,0xbf,0xed,0xa7,0xc2,0xbb,0xb0,0x3,0x1b,0x75,0x92,0xf0,0x2e,0x7c,0x46,0x9b,0xaa,0xcd,0x4f,0x46,0x3,0x8c,0x76,0xea,0x7,0x4a,0x29,0x5a,0x68,0x0,0x29,0x65,0x3f,0x30,0x83,0xed,0x6,0xe9,0xbc,0x8e,0xf6,0x45,0x79,0xb,0xc0,0x5c,0xb3,0xeb,0x12,0xef,0x1f,0xc6,0x6f,0x12,0x2,0xa,0xbd,0xc9,0x5d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index afb0ae1815..9f691d6ad3 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -142,6 +142,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector if (d<closest_dist) { ignore_from_edge=E->get(); closest_dist=d; + closest_point=closest; } } @@ -168,6 +169,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector if (d<closest_dist) { ignore_to_edge=E->get(); closest_dist=d; + closest_point=closest; } } @@ -529,7 +531,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const { float d = p_point.distance_squared_to(points[i].pos); if (d<closest_dist) { - d=closest_dist; + closest_dist=d; closest_idx=i; } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 6d65da3782..cc6bed3148 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -120,6 +120,13 @@ Dictionary Shader::_get_code() { c["vertex_ofs"]=0; c["light"]=ls; c["light_ofs"]=0; + Array arr; + for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) { + arr.push_back(E->key()); + arr.push_back(E->get()); + } + if (arr.size()) + c["default_tex"]=arr; return c; } @@ -132,8 +139,41 @@ void Shader::_set_code(const Dictionary& p_string) { light=p_string["light"]; set_code(p_string["vertex"],p_string["fragment"],light); + if (p_string.has("default_tex")) { + Array arr=p_string["default_tex"]; + if ((arr.size()&1)==0) { + for(int i=0;i<arr.size();i+=2) + set_default_texture_param(arr[i],arr[i+1]); + } + } +} + +void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) { + + if (p_texture.is_valid()) + default_textures[p_param]=p_texture; + else + default_textures.erase(p_param); +} + +Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{ + + if (default_textures.has(p_param)) + return default_textures[p_param]; + else + return Ref<Texture>(); } +void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{ + + for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) { + + r_textures->push_back(E->key()); + } + +} + + void Shader::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode); @@ -144,6 +184,9 @@ void Shader::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_fragment_code"),&Shader::get_fragment_code); ObjectTypeDB::bind_method(_MD("get_light_code"),&Shader::get_light_code); + ObjectTypeDB::bind_method(_MD("set_default_texture_param","param","texture:Texture"),&Shader::set_default_texture_param); + ObjectTypeDB::bind_method(_MD("get_default_texture_param:Texture","param"),&Shader::get_default_texture_param); + ObjectTypeDB::bind_method(_MD("has_param","name"),&Shader::has_param); ObjectTypeDB::bind_method(_MD("_set_code","code"),&Shader::_set_code); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index fff6f1d28a..e1b8288c51 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -31,7 +31,7 @@ #include "resource.h" #include "io/resource_loader.h" - +#include "scene/resources/texture.h" class Shader : public Resource { OBJ_TYPE(Shader,Resource); @@ -48,6 +48,7 @@ class Shader : public Resource { // convertion fast and save memory. mutable bool params_cache_dirty; mutable Map<StringName,StringName> params_cache; //map a shader param to a material param.. + Map<StringName,Ref<Texture> > default_textures; protected: @@ -72,6 +73,10 @@ public: void get_param_list(List<PropertyInfo> *p_params) const; bool has_param(const StringName& p_param) const; + void set_default_texture_param(const StringName& p_param, const Ref<Texture> &p_texture); + Ref<Texture> get_default_texture_param(const StringName& p_param) const; + void get_default_texture_param_list(List<StringName>* r_textures) const; + virtual RID get_rid() const; Shader(); |