diff options
Diffstat (limited to 'scene')
67 files changed, 2859 insertions, 566 deletions
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 8b7aff3b7a..71728966fd 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -660,9 +660,9 @@ void Area2D::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.001"),_SCS("set_gravity"),_SCS("get_gravity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,100,0.01"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,100,0.01"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable")); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 21615b7f55..17e5503a2d 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -455,20 +455,15 @@ void CanvasItem::_enter_canvas() { if ((!get_parent() || !get_parent()->cast_to<CanvasItem>()) || toplevel) { Node *n = this; - Viewport *viewport=NULL; + canvas_layer=NULL; while(n) { - if (n->cast_to<Viewport>()) { - - viewport = n->cast_to<Viewport>(); + canvas_layer = n->cast_to<CanvasLayer>(); + if (canvas_layer) { break; } - if (!canvas_layer && n->cast_to<CanvasLayer>()) { - - canvas_layer = n->cast_to<CanvasLayer>(); - } n=n->get_parent(); } @@ -476,7 +471,7 @@ void CanvasItem::_enter_canvas() { if (canvas_layer) canvas=canvas_layer->get_world_2d()->get_canvas(); else - canvas=viewport->find_world_2d()->get_canvas(); + canvas=get_viewport()->find_world_2d()->get_canvas(); VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,canvas); @@ -488,6 +483,7 @@ void CanvasItem::_enter_canvas() { } else { CanvasItem *parent = get_parent_item(); + canvas_layer=parent->canvas_layer; VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent->get_canvas_item()); parent->_queue_sort_children(); } @@ -1176,12 +1172,10 @@ Matrix32 CanvasItem::get_viewport_transform() const { return canvas_layer->get_transform(); } - } else if (get_viewport()) { + } else { return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform(); } - return Matrix32(); - } diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index cc0db2da77..6a74cb1d91 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -62,7 +62,7 @@ String CanvasModulate::get_configuration_warning() const { get_tree()->get_nodes_in_group("_canvas_modulate_"+itos(get_canvas().get_id()),&nodes); if (nodes.size()>1) { - return TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first one created will work, while the rest will be ignored."); + return TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."); } return String(); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index b79c07360b..1cb34075bb 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -357,11 +357,11 @@ void Light2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,50,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale")); ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy"),_SCS("set_energy"),_SCS("get_energy")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy",PROPERTY_HINT_RANGE,"0.01,100,0.01"),_SCS("set_energy"),_SCS("get_energy")); ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix,Mask"),_SCS("set_mode"),_SCS("get_mode")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height",PROPERTY_HINT_RANGE,"-100,100,0.1"),_SCS("set_height"),_SCS("get_height")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_min",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_min"),_SCS("get_layer_range_min")); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index dee67a829f..41ca7b1d0f 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -243,7 +243,7 @@ String PathFollow2D::get_configuration_warning() const { return String(); if (!get_parent() || !get_parent()->cast_to<Path2D>()) { - return TTR("PathFolow2D only works when set as a child of a Path2D node."); + return TTR("PathFollow2D only works when set as a child of a Path2D node."); } return String(); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index fc6986327f..03ced12c55 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -145,7 +145,18 @@ void Polygon2D::_notification(int p_what) { Vector<Color> colors; - colors.push_back(color); + int color_len=vertex_colors.size(); + colors.resize(len); + { + DVector<Color>::Read color_r=vertex_colors.read(); + for(int i=0;i<color_len && i<len;i++){ + colors[i]=color_r[i]; + } + for(int i=color_len;i<len;i++){ + colors[i]=color; + } + } + Vector<int> indices = Geometry::triangulate_polygon(points); VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(),indices,points,colors,uvs,texture.is_valid()?texture->get_rid():RID()); @@ -188,6 +199,16 @@ Color Polygon2D::get_color() const{ return color; } +void Polygon2D::set_vertex_colors(const DVector<Color>& p_colors){ + + vertex_colors=p_colors; + update(); +} +DVector<Color> Polygon2D::get_vertex_colors() const{ + + return vertex_colors; +} + void Polygon2D::set_texture(const Ref<Texture>& p_texture){ texture=p_texture; @@ -293,6 +314,9 @@ void Polygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_color","color"),&Polygon2D::set_color); ObjectTypeDB::bind_method(_MD("get_color"),&Polygon2D::get_color); + ObjectTypeDB::bind_method(_MD("set_vertex_colors","vertex_colors"),&Polygon2D::set_vertex_colors); + ObjectTypeDB::bind_method(_MD("get_vertex_colors"),&Polygon2D::get_vertex_colors); + ObjectTypeDB::bind_method(_MD("set_texture","texture"),&Polygon2D::set_texture); ObjectTypeDB::bind_method(_MD("get_texture"),&Polygon2D::get_texture); @@ -323,6 +347,7 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"uv"),_SCS("set_uv"),_SCS("get_uv")); ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color")); + ADD_PROPERTY( PropertyInfo(Variant::COLOR_ARRAY,"vertex_colors"),_SCS("set_vertex_colors"),_SCS("get_vertex_colors")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"texture/offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index 517b623ccd..eaa642787c 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -9,6 +9,7 @@ class Polygon2D : public Node2D { DVector<Vector2> polygon; DVector<Vector2> uv; + DVector<Color> vertex_colors; Color color; Ref<Texture> texture; Vector2 tex_scale; @@ -40,6 +41,9 @@ public: void set_color(const Color& p_color); Color get_color() const; + void set_vertex_colors(const DVector<Color>& p_colors); + DVector<Color> get_vertex_colors() const; + void set_texture(const Ref<Texture>& p_texture); Ref<Texture> get_texture() const; diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index aebb9a4c28..3e6384ea2c 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -540,7 +540,7 @@ String ViewportSprite::get_configuration_warning() const { Viewport *vp = n->cast_to<Viewport>(); if (!vp->is_set_as_render_target()) { - return TTR("The Viewport set in the path property must be set as 'render taget' in order for this sprite to work"); + return TTR("The Viewport set in the path property must be set as 'render target' in order for this sprite to work."); } } } diff --git a/scene/3d/listener.cpp b/scene/3d/listener.cpp new file mode 100644 index 0000000000..bf42a5c92e --- /dev/null +++ b/scene/3d/listener.cpp @@ -0,0 +1,167 @@ +#include "listener.h" + +#include "scene/resources/mesh.h" + +void Listener::_update_audio_listener_state() { + + +} + +void Listener::_request_listener_update() { + + _update_listener(); +} + +bool Listener::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name == "current") { + if (p_value.operator bool()) { + make_current(); + } + else { + clear_current(); + } + } + else + return false; + + return true; +} +bool Listener::_get(const StringName& p_name,Variant &r_ret) const { + + if (p_name == "current") { + if (is_inside_tree() && get_tree()->is_node_being_edited(this)) { + r_ret = current; + } + else { + r_ret = is_current(); + } + } + else + return false; + + return true; +} + +void Listener::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) ); +} + +void Listener::_update_listener() { + + if (is_inside_tree() && is_current()) { + get_viewport()->_listener_transform_changed_notify(); + + } +} + +void Listener::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_WORLD: { + bool first_listener = get_viewport()->_listener_add(this); + if (!get_tree()->is_node_being_edited(this) && (current || first_listener)) + make_current(); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + _request_listener_update(); + } break; + case NOTIFICATION_EXIT_WORLD: { + + if (!get_tree()->is_node_being_edited(this)) { + if (is_current()) { + clear_current(); + current=true; //keep it true + + } else { + current=false; + } + } + + get_viewport()->_listener_remove(this); + + + } break; + + + } + +} + + +Transform Listener::get_listener_transform() const { + + return get_global_transform().orthonormalized(); +} + +void Listener::make_current() { + + current=true; + + if (!is_inside_tree()) + return; + + get_viewport()->_listener_set(this); +} + + + + +void Listener::clear_current() { + + current=false; + if (!is_inside_tree()) + return; + + if (get_viewport()->get_listener()==this) { + get_viewport()->_listener_set(NULL); + get_viewport()->_listener_make_next_current(this); + } + +} + +bool Listener::is_current() const { + + if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) { + + return get_viewport()->get_listener()==this; + } else + return current; + + return false; +} + +bool Listener::_can_gizmo_scale() const { + + return false; +} + +RES Listener::_get_gizmo_geometry() const { + Ref<Mesh> mesh = memnew(Mesh); + + return mesh; +} + +void Listener::_bind_methods() { + + ObjectTypeDB::bind_method( _MD("make_current"),&Listener::make_current ); + ObjectTypeDB::bind_method( _MD("clear_current"),&Listener::clear_current ); + ObjectTypeDB::bind_method( _MD("is_current"),&Listener::is_current ); + ObjectTypeDB::bind_method( _MD("get_listener_transform"),&Listener::get_listener_transform ); +} + +Listener::Listener() { + + current=false; + force_change=false; + //active=false; +} + + +Listener::~Listener() { + +} + + diff --git a/scene/3d/listener.h b/scene/3d/listener.h new file mode 100644 index 0000000000..bf0281a8e0 --- /dev/null +++ b/scene/3d/listener.h @@ -0,0 +1,53 @@ +#ifndef LISTENER_H +#define LISTENER_H + + +#include "scene/3d/spatial.h" +#include "scene/main/viewport.h" + +class Listener : public Spatial { + + OBJ_TYPE(Listener, Spatial); +private: + + bool force_change; + bool current; + + RID scenario_id; + + virtual bool _can_gizmo_scale() const; + virtual RES _get_gizmo_geometry() const; + +friend class Viewport; + void _update_audio_listener_state(); +protected: + + void _update_listener(); + virtual void _request_listener_update(); + + 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; + void _notification(int p_what); + + static void _bind_methods(); + +public: + + void make_current(); + void clear_current(); + bool is_current() const; + + virtual Transform get_listener_transform() const; + + void set_visible_layers(uint32_t p_layers); + uint32_t get_visible_layers() const; + + Vector<Plane> get_frustum() const; + + Listener(); + ~Listener(); + +}; + +#endif diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index cfe273fa20..ef956e8ad9 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -31,8 +31,8 @@ #include "skeleton.h" #include "physics_body.h" #include "body_shape.h" - - +#include "scene/scene_string_names.h" +#include "core_string_names.h" bool MeshInstance::_set(const StringName& p_name, const Variant& p_value) { //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else. @@ -43,13 +43,22 @@ bool MeshInstance::_set(const StringName& p_name, const Variant& p_value) { Map<StringName,MorphTrack>::Element *E = morph_tracks.find(p_name); - if (!E) - return false; + if (E) { + E->get().value=p_value; + VisualServer::get_singleton()->instance_set_morph_target_weight(get_instance(),E->get().idx,E->get().value); + return true; + } - E->get().value=p_value; - VisualServer::get_singleton()->instance_set_morph_target_weight(get_instance(),E->get().idx,E->get().value); + if (p_name.operator String().begins_with("material/")) { + int idx = p_name.operator String().get_slicec('/',1).to_int(); + if (idx>=materials.size() || idx<0) + return false; - return true; + set_surface_material(idx,p_value); + return true; + } + + return false; } bool MeshInstance::_get(const StringName& p_name,Variant &r_ret) const { @@ -59,12 +68,19 @@ bool MeshInstance::_get(const StringName& p_name,Variant &r_ret) const { return false; const Map<StringName,MorphTrack>::Element *E = morph_tracks.find(p_name); - if (!E) - return false; - - r_ret = E->get().value; + if (E) { + r_ret = E->get().value; + return true; + } - return true; + if (p_name.operator String().begins_with("material/")) { + int idx = p_name.operator String().get_slicec('/',1).to_int(); + if (idx>=materials.size() || idx<0) + return false; + r_ret=materials[idx]; + return true; + } + return false; } void MeshInstance::_get_property_list( List<PropertyInfo> *p_list) const { @@ -80,6 +96,12 @@ void MeshInstance::_get_property_list( List<PropertyInfo> *p_list) const { for(List<String>::Element *E=ls.front();E;E=E->next()) { p_list->push_back( PropertyInfo(Variant::REAL,E->get(),PROPERTY_HINT_RANGE,"0,1,0.01")); } + + if (mesh.is_valid()) { + for(int i=0;i<mesh->get_surface_count();i++) { + p_list->push_back( PropertyInfo(Variant::OBJECT, "material/"+itos(i), PROPERTY_HINT_RESOURCE_TYPE, "Material")); + } + } } @@ -87,6 +109,14 @@ void MeshInstance::_get_property_list( List<PropertyInfo> *p_list) const { void MeshInstance::set_mesh(const Ref<Mesh>& p_mesh) { + if (mesh==p_mesh) + return; + + if (mesh.is_valid()) { + mesh->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_mesh_changed); + materials.clear(); + } + mesh=p_mesh; morph_tracks.clear(); @@ -100,13 +130,17 @@ void MeshInstance::set_mesh(const Ref<Mesh>& p_mesh) { mt.value=0; morph_tracks["morph/"+String(mesh->get_morph_target_name(i))]=mt; } + + mesh->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_mesh_changed); + materials.resize(mesh->get_surface_count()); + set_base(mesh->get_rid()); } else { set_base(RID()); } - _change_notify("mesh"); + _change_notify(); } Ref<Mesh> MeshInstance::get_mesh() const { @@ -232,6 +266,32 @@ void MeshInstance::_notification(int p_what) { } +void MeshInstance::set_surface_material(int p_surface,const Ref<Material>& p_material) { + + ERR_FAIL_INDEX(p_surface,materials.size()); + + materials[p_surface]=p_material; + + if (materials[p_surface].is_valid()) + VS::get_singleton()->instance_set_surface_material(get_instance(),p_surface,materials[p_surface]->get_rid()); + else + VS::get_singleton()->instance_set_surface_material(get_instance(),p_surface,RID()); + +} + +Ref<Material> MeshInstance::get_surface_material(int p_surface) const { + + ERR_FAIL_INDEX_V(p_surface,materials.size(),Ref<Material>()); + + return materials[p_surface]; +} + + +void MeshInstance::_mesh_changed() { + + materials.resize( mesh->get_surface_count() ); +} + void MeshInstance::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_mesh","mesh:Mesh"),&MeshInstance::set_mesh); @@ -243,6 +303,7 @@ void MeshInstance::_bind_methods() { ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT); ObjectTypeDB::bind_method(_MD("create_convex_collision"),&MeshInstance::create_convex_collision); ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT); + ObjectTypeDB::bind_method(_MD("_mesh_changed"),&MeshInstance::_mesh_changed); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "mesh/mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh" ), _SCS("set_mesh"), _SCS("get_mesh")); ADD_PROPERTY( PropertyInfo (Variant::NODE_PATH, "mesh/skeleton"), _SCS("set_skeleton_path"), _SCS("get_skeleton_path")); } diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index 7c605c2d6d..fd8faf38b4 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -50,7 +50,9 @@ class MeshInstance : public GeometryInstance { }; Map<StringName,MorphTrack> morph_tracks; + Vector<Ref<Material> > materials; + void _mesh_changed(); void _resolve_skeleton_path(); protected: @@ -69,6 +71,9 @@ public: void set_skeleton_path(const NodePath& p_skeleton); NodePath get_skeleton_path(); + void set_surface_material(int p_surface,const Ref<Material>& p_material); + Ref<Material> get_surface_material(int p_surface) const; + Node* create_trimesh_collision_node(); void create_trimesh_collision(); diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index ba30c118f0..e35ba11e84 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -936,7 +936,7 @@ void VehicleBody::_direct_state_changed(Object *p_state) { wheel.m_deltaRotation *= real_t(0.99);//damping of rotation when not in contact } - + linear_velocity = s->get_linear_velocity(); } void VehicleBody::set_mass(real_t p_mass) { @@ -990,6 +990,10 @@ float VehicleBody::get_steering() const{ return m_steeringValue; } +Vector3 VehicleBody::get_linear_velocity() +{ + return linear_velocity; +} void VehicleBody::_bind_methods(){ @@ -1008,6 +1012,8 @@ void VehicleBody::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_steering","steering"),&VehicleBody::set_steering); ObjectTypeDB::bind_method(_MD("get_steering"),&VehicleBody::get_steering); + ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&VehicleBody::get_linear_velocity); + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed); ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/engine_force",PROPERTY_HINT_RANGE,"0.00,1024.0,0.01"),_SCS("set_engine_force"),_SCS("get_engine_force")); diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 285cca142d..b6ad88f15e 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -178,6 +178,7 @@ public: void set_steering(float p_steering); float get_steering() const; + Vector3 get_linear_velocity(); VehicleBody(); }; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index cecdd2bc40..2399bee539 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1012,7 +1012,7 @@ void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float queued.clear(); _set_process(true); // always process when starting an animation playing = true; - + emit_signal(SceneStringNames::get_singleton()->animation_started, c.assigned); if (is_inside_tree() && get_tree()->is_editor_hint()) diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 3bcc60b86a..2200cac5da 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -289,7 +289,7 @@ void BaseButton::set_disabled(bool p_disabled) { if (p_disabled) set_focus_mode(FOCUS_NONE); else - set_focus_mode(FOCUS_ALL); + set_focus_mode(enabled_focus_mode); } bool BaseButton::is_disabled() const { @@ -377,12 +377,56 @@ bool BaseButton::get_click_on_press() const { return status.click_on_press; } +void BaseButton::set_enabled_focus_mode(FocusMode p_mode) { + enabled_focus_mode = p_mode; + if (!status.disabled) { + set_focus_mode( p_mode ); + } +} + +Control::FocusMode BaseButton::get_enabled_focus_mode() const { + + return enabled_focus_mode; +} + +void BaseButton::set_shortcut(const Ref<ShortCut>& p_shortcut) { + + if (shortcut.is_null() == p_shortcut.is_null()) + return; + + shortcut=p_shortcut; + set_process_unhandled_input(shortcut.is_valid()); +} +Ref<ShortCut> BaseButton:: get_shortcut() const { + return shortcut; +} + +void BaseButton::_unhandled_input(InputEvent p_event) { + + if (!is_disabled() && is_visible() && shortcut.is_valid() && shortcut->is_shortcut(p_event)) { + if (is_toggle_mode()) { + set_pressed(!is_pressed()); + emit_signal("toggled",is_pressed()); + } + + emit_signal("pressed"); + } +} + +String BaseButton::get_tooltip(const Point2& p_pos) const { + + String tooltip=Control::get_tooltip(p_pos); + if (shortcut.is_valid() && shortcut->is_valid()) + tooltip+=" ("+shortcut->get_as_text()+")"; + return tooltip; +} void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&BaseButton::_input_event); + ObjectTypeDB::bind_method(_MD("_unhandled_input"),&BaseButton::_unhandled_input); ObjectTypeDB::bind_method(_MD("set_pressed","pressed"),&BaseButton::set_pressed); ObjectTypeDB::bind_method(_MD("is_pressed"),&BaseButton::is_pressed); ObjectTypeDB::bind_method(_MD("is_hovered"),&BaseButton::is_hovered); @@ -393,6 +437,10 @@ void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_click_on_press","enable"),&BaseButton::set_click_on_press); ObjectTypeDB::bind_method(_MD("get_click_on_press"),&BaseButton::get_click_on_press); ObjectTypeDB::bind_method(_MD("get_draw_mode"),&BaseButton::get_draw_mode); + ObjectTypeDB::bind_method(_MD("set_enabled_focus_mode","mode"),&BaseButton::set_enabled_focus_mode); + ObjectTypeDB::bind_method(_MD("get_enabled_focus_mode"),&BaseButton::get_enabled_focus_mode); + ObjectTypeDB::bind_method(_MD("set_shortcut","shortcut"),&BaseButton::set_shortcut); + ObjectTypeDB::bind_method(_MD("get_shortcut"),&BaseButton::get_shortcut); BIND_VMETHOD(MethodInfo("_pressed")); BIND_VMETHOD(MethodInfo("_toggled",PropertyInfo(Variant::BOOL,"pressed"))); @@ -404,6 +452,8 @@ void BaseButton::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed")); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press")); + ADD_PROPERTY( PropertyInfo( Variant::INT,"enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_enabled_focus_mode"), _SCS("get_enabled_focus_mode") ); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shortcut",PROPERTY_HINT_RESOURCE_TYPE,"ShortCut"), _SCS("set_shortcut"), _SCS("get_shortcut")); BIND_CONSTANT( DRAW_NORMAL ); @@ -424,6 +474,7 @@ BaseButton::BaseButton() { status.click_on_press=false; status.pressing_button=0; set_focus_mode( FOCUS_ALL ); + enabled_focus_mode = FOCUS_ALL; group=NULL; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 9a5213d971..0056b00f33 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -42,6 +42,8 @@ class BaseButton : public Control { OBJ_TYPE( BaseButton, Control ); bool toggle_mode; + FocusMode enabled_focus_mode; + Ref<ShortCut> shortcut; struct Status { @@ -56,6 +58,7 @@ class BaseButton : public Control { } status; + ButtonGroup *group; @@ -68,6 +71,7 @@ protected: virtual void toggled(bool p_pressed); static void _bind_methods(); virtual void _input_event(InputEvent p_event); + virtual void _unhandled_input(InputEvent p_event); void _notification(int p_what); public: @@ -97,6 +101,13 @@ public: void set_click_on_press(bool p_click_on_press); bool get_click_on_press() const; + void set_enabled_focus_mode(FocusMode p_mode); + FocusMode get_enabled_focus_mode() const; + + void set_shortcut(const Ref<ShortCut>& p_shortcut); + Ref<ShortCut> get_shortcut() const; + + virtual String get_tooltip(const Point2& p_pos) const; BaseButton(); ~BaseButton(); diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index a9522cf248..a6ffc30a83 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -280,6 +280,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const { void BoxContainer::add_spacer(bool p_begin) { Control *c = memnew( Control ); + c->set_stop_mouse(false); if (vertical) c->set_v_size_flags(SIZE_EXPAND_FILL); else diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 0f1622a838..579f6e08c9 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -213,7 +213,6 @@ Button::TextAlign Button::get_text_align() const { return align; } - void Button::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_text","text"),&Button::set_text); diff --git a/scene/gui/button.h b/scene/gui/button.h index 8a17a164a0..c39237c9af 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -54,7 +54,6 @@ private: TextAlign align; - protected: virtual Size2 get_minimum_size() const; @@ -62,6 +61,8 @@ protected: static void _bind_methods(); public: // + + void set_text(const String& p_text); String get_text() const; @@ -77,6 +78,7 @@ public: void set_text_align(TextAlign p_align); TextAlign get_text_align() const; + Button(const String& p_text=String()); ~Button(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 73e7237058..bd56369746 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -770,7 +770,7 @@ Size2 Control::get_minimum_size() const { Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Texture>* tex = data.icon_override.getptr(p_name); if (tex) @@ -800,7 +800,7 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type } Ref<Shader> Control::get_shader(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Shader>* sdr = data.shader_override.getptr(p_name); if (sdr) @@ -830,7 +830,7 @@ Ref<Shader> Control::get_shader(const StringName& p_name,const StringName& p_typ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<StyleBox>* style = data.style_override.getptr(p_name); if (style) return *style; @@ -858,7 +858,7 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p } Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Ref<Font>* font = data.font_override.getptr(p_name); if (font) return *font; @@ -889,7 +889,7 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c } Color Control::get_color(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const Color* color = data.color_override.getptr(p_name); if (color) return *color; @@ -918,7 +918,7 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons int Control::get_constant(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { + if (p_type==StringName() || p_type=="") { const int* constant = data.constant_override.getptr(p_name); if (constant) return *constant; @@ -946,12 +946,64 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con } +bool Control::has_icon_override(const StringName& p_name) const { + + const Ref<Texture>* tex = data.icon_override.getptr(p_name); + if (tex) + return true; + else + return false; +} + +bool Control::has_shader_override(const StringName &p_name) const { + + const Ref<Shader>* sdr = data.shader_override.getptr(p_name); + if (sdr) + return true; + else + return false; +} + +bool Control::has_stylebox_override(const StringName& p_name) const { + + const Ref<StyleBox>* style = data.style_override.getptr(p_name); + if (style) + return true; + else + return false; +} + +bool Control::has_font_override(const StringName& p_name) const { + + const Ref<Font>* font = data.font_override.getptr(p_name); + if (font) + return true; + else + return false; +} + +bool Control::has_color_override(const StringName& p_name) const { + + const Color* color = data.color_override.getptr(p_name); + if (color) + return true; + else + return false; +} + +bool Control::has_constant_override(const StringName& p_name) const { + + const int* constant = data.constant_override.getptr(p_name); + if (constant) + return true; + else + return false; +} bool Control::has_icon(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<Texture>* tex = data.icon_override.getptr(p_name); - if (tex) + if (p_type==StringName() || p_type=="") { + if (has_icon_override(p_name) == true) return true; } @@ -977,11 +1029,10 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const } -bool Control::has_shader(const StringName &p_name, const StringName &p_type) const -{ - if (p_type==StringName()) { - const Ref<Shader>* sdr = data.shader_override.getptr(p_name); - if (sdr) +bool Control::has_shader(const StringName &p_name, const StringName &p_type) const { + + if (p_type==StringName() || p_type=="") { + if (has_shader_override(p_name)==true) return true; } @@ -1008,10 +1059,8 @@ bool Control::has_shader(const StringName &p_name, const StringName &p_type) con } bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<StyleBox>* style = data.style_override.getptr(p_name); - - if (style) + if (p_type==StringName() || p_type=="") { + if (has_stylebox_override(p_name)==true) return true; } @@ -1038,9 +1087,8 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co } bool Control::has_font(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Ref<Font>* font = data.font_override.getptr(p_name); - if (font) + if (p_type==StringName() || p_type=="") { + if (has_font_override(p_name)==true) return true; } @@ -1066,11 +1114,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const return Theme::get_default()->has_font( p_name, type ); } -bool Control::has_color(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - const Color* color = data.color_override.getptr(p_name); - if (color) +bool Control::has_color(const StringName& p_name, const StringName& p_type) const { + + if (p_type==StringName() || p_type=="") { + if (has_color_override(p_name)==true) return true; } @@ -1098,10 +1146,8 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const bool Control::has_constant(const StringName& p_name,const StringName& p_type) const { - if (p_type==StringName()) { - - const int* constant = data.constant_override.getptr(p_name); - if (constant) + if (p_type==StringName() || p_type=="") { + if (has_constant_override(p_name) == true) return true; } @@ -1810,6 +1856,7 @@ void Control::_propagate_theme_changed(Control *p_owner) { void Control::set_theme(const Ref<Theme>& p_theme) { + data.theme=p_theme; if (!p_theme.is_null()) { @@ -2265,6 +2312,7 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_area_as_parent_rect","margin"),&Control::set_area_as_parent_rect,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("show_modal","exclusive"),&Control::show_modal,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("set_focus_mode","mode"),&Control::set_focus_mode); + ObjectTypeDB::bind_method(_MD("get_focus_mode"),&Control::get_focus_mode); ObjectTypeDB::bind_method(_MD("has_focus"),&Control::has_focus); ObjectTypeDB::bind_method(_MD("grab_focus"),&Control::grab_focus); ObjectTypeDB::bind_method(_MD("release_focus"),&Control::release_focus); @@ -2295,6 +2343,17 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_color","name","type"),&Control::get_color,DEFVAL("")); ObjectTypeDB::bind_method(_MD("get_constant","name","type"),&Control::get_constant,DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_icon_override", "name"), &Control::has_icon_override); + ObjectTypeDB::bind_method(_MD("has_stylebox_override", "name"), &Control::has_stylebox_override); + ObjectTypeDB::bind_method(_MD("has_font_override", "name"), &Control::has_font_override); + ObjectTypeDB::bind_method(_MD("has_color_override", "name"), &Control::has_color_override); + ObjectTypeDB::bind_method(_MD("has_constant_override", "name"), &Control::has_constant_override); + + ObjectTypeDB::bind_method(_MD("has_icon", "name", "type"), &Control::has_icon, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_stylebox", "name", "type"), &Control::has_stylebox, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_font", "name", "type"), &Control::has_font, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_color", "name", "type"), &Control::has_color, DEFVAL("")); + ObjectTypeDB::bind_method(_MD("has_constant", "name", "type"), &Control::has_constant, DEFVAL("")); ObjectTypeDB::bind_method(_MD("get_parent_control:Control"),&Control::get_parent_control); @@ -2324,6 +2383,7 @@ void Control::_bind_methods() { ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"),&Control::warp_mouse); + ObjectTypeDB::bind_method(_MD("minimum_size_changed"), &Control::minimum_size_changed); BIND_VMETHOD(MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2,"get_minimum_size")); diff --git a/scene/gui/control.h b/scene/gui/control.h index f720185c9d..59704ae29b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -35,7 +35,7 @@ #include "scene/2d/canvas_item.h" #include "math_2d.h" #include "rid.h" - +#include "scene/gui/input_action.h" /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -341,6 +341,13 @@ public: Color get_color(const StringName& p_name,const StringName& p_type=StringName()) const; int get_constant(const StringName& p_name,const StringName& p_type=StringName()) const; + bool has_icon_override(const StringName& p_name) const; + bool has_shader_override(const StringName& p_name) const; + bool has_stylebox_override(const StringName& p_name) const; + bool has_font_override(const StringName& p_name) const; + bool has_color_override(const StringName& p_name) const; + bool has_constant_override(const StringName& p_name) const; + bool has_icon(const StringName& p_name,const StringName& p_type=StringName()) const; bool has_shader(const StringName& p_name,const StringName& p_type=StringName()) const; bool has_stylebox(const StringName& p_name,const StringName& p_type=StringName()) const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 51242d89bd..6342391383 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -118,6 +118,16 @@ void WindowDialog::set_title(const String& p_title) { update(); } +Size2 WindowDialog::get_minimum_size() const { + + Ref<Font> font = get_font("title_font","WindowDialog"); + int msx=close_button->get_combined_minimum_size().x; + msx+=font->get_string_size(title).x; + + return Size2(msx,1); +} + + String WindowDialog::get_title() const { return title; @@ -192,11 +202,9 @@ void AcceptDialog::_notification(int p_what) { if (p_what==NOTIFICATION_MODAL_CLOSE) { cancel_pressed(); - } if (p_what==NOTIFICATION_DRAW) { - - - + } if (p_what==NOTIFICATION_RESIZED) { + _update_child_rect(); } } @@ -244,12 +252,69 @@ void AcceptDialog::register_text_enter(Node *p_line_edit) { p_line_edit->connect("text_entered", this,"_builtin_text_entered"); } +void AcceptDialog::_update_child_rect() { + + int margin = get_constant("margin","Dialogs"); + Size2 size = get_size(); + Size2 hminsize = hbc->get_combined_minimum_size(); + + Vector2 cpos(margin,margin); + Vector2 csize(size.x-margin*2,size.y-margin*3-hminsize.y); + label->set_pos(cpos); + label->set_size(csize); + + if (child) { + + child->set_pos(cpos); + child->set_size(csize); + } + + cpos.y+=csize.y+margin; + csize.y=hminsize.y; + + hbc->set_pos(cpos); + hbc->set_size(csize); + +} + +Size2 AcceptDialog::get_minimum_size() const { + + int margin = get_constant("margin","Dialogs"); + Size2 minsize = label->get_combined_minimum_size(); + if (child) { + + Size2 cminsize = child->get_combined_minimum_size(); + minsize.x=MAX(cminsize.x,minsize.x); + minsize.y=MAX(cminsize.y,minsize.y); + } + + Size2 hminsize = hbc->get_combined_minimum_size(); + minsize.x = MAX(hminsize.x,minsize.x); + minsize.y+=hminsize.y; + minsize.x+=margin*2; + minsize.y+=margin*3; //one as separation between hbc and child + + Size2 wmsize = WindowDialog::get_minimum_size(); + minsize.x=MAX(wmsize.x,minsize.x); + return minsize; +} + + void AcceptDialog::set_child_rect(Control *p_child) { ERR_FAIL_COND(p_child->get_parent()!=this); - p_child->set_area_as_parent_rect(get_constant("margin","Dialogs")); - p_child->set_margin(MARGIN_BOTTOM, get_constant("button_margin","Dialogs")+10); + //p_child->set_area_as_parent_rect(get_constant("margin","Dialogs")); + child=p_child; + minimum_size_changed(); + _update_child_rect(); +} + +void AcceptDialog::remove_child_notify(Node *p_child) { + + if (p_child==child) { + child=NULL; + } } void AcceptDialog::_custom_action(const String& p_action) { @@ -284,7 +349,7 @@ Button* AcceptDialog::add_cancel(const String &p_cancel) { String c = p_cancel; if (p_cancel=="") - c="Cancel"; + c=RTR("Cancel"); Button *b = swap_ok_cancel ? add_button(c,true) : add_button(c); b->connect("pressed",this,"_closed"); return b; @@ -341,7 +406,7 @@ AcceptDialog::AcceptDialog() { hbc->add_spacer(); ok = memnew( Button ); - ok->set_text("OK"); + ok->set_text(RTR("OK")); hbc->add_child(ok); hbc->add_spacer(); //add_child(ok); @@ -351,7 +416,9 @@ AcceptDialog::AcceptDialog() { set_as_toplevel(true); hide_on_ok=true; - set_title("Alert!"); + set_title(RTR("Alert!")); + + child=NULL; } @@ -372,6 +439,6 @@ Button *ConfirmationDialog::get_cancel() { ConfirmationDialog::ConfirmationDialog() { - set_title("Please Confirm..."); + set_title(RTR("Please Confirm...")); cancel = add_cancel(); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index f256c49aee..d00bb41ff6 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -64,6 +64,8 @@ public: void set_title(const String& p_title); String get_title() const; + Size2 get_minimum_size() const; + WindowDialog(); ~WindowDialog(); @@ -89,6 +91,7 @@ class AcceptDialog : public WindowDialog { OBJ_TYPE(AcceptDialog,WindowDialog); + Control *child; HBoxContainer *hbc; Label *label; Button *ok; @@ -100,10 +103,12 @@ class AcceptDialog : public WindowDialog { void _ok_pressed(); void _close_pressed(); void _builtin_text_entered(const String& p_text); + void _update_child_rect(); static bool swap_ok_cancel; + virtual void remove_child_notify(Node *p_child); protected: @@ -116,6 +121,8 @@ protected: virtual void custom_action(const String&) {} public: + Size2 get_minimum_size() const; + Label *get_label() { return label; } static void set_swap_ok_cancel(bool p_swap); diff --git a/scene/gui/input_action.cpp b/scene/gui/input_action.cpp new file mode 100644 index 0000000000..c4e7a75298 --- /dev/null +++ b/scene/gui/input_action.cpp @@ -0,0 +1,125 @@ +#include "input_action.h" +#include "os/keyboard.h" + +void ShortCut::set_shortcut(const InputEvent& p_shortcut){ + + shortcut=p_shortcut; + emit_changed(); +} + +InputEvent ShortCut::get_shortcut() const{ + + return shortcut; +} + +bool ShortCut::is_shortcut(const InputEvent& p_event) const { + + bool same=false; + + + switch(p_event.type) { + + case InputEvent::KEY: { + + same=(shortcut.key.scancode==p_event.key.scancode && shortcut.key.mod == p_event.key.mod); + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + same=(shortcut.joy_button.button_index==p_event.joy_button.button_index); + + } break; + case InputEvent::MOUSE_BUTTON: { + + same=(shortcut.mouse_button.button_index==p_event.mouse_button.button_index); + + } break; + case InputEvent::JOYSTICK_MOTION: { + + same=(shortcut.joy_motion.axis==p_event.joy_motion.axis && (shortcut.joy_motion.axis_value < 0) == (p_event.joy_motion.axis_value < 0)); + + } break; + default: {}; + } + + return same; +} + +String ShortCut::get_as_text() const { + + switch(shortcut.type) { + + case InputEvent::NONE: { + + return "None"; + } break; + case InputEvent::KEY: { + + String str; + if (shortcut.key.mod.shift) + str+=RTR("Shift+"); + if (shortcut.key.mod.alt) + str+=RTR("Alt+"); + if (shortcut.key.mod.control) + str+=RTR("Ctrl+"); + if (shortcut.key.mod.meta) + str+=RTR("Meta+"); + + str+=keycode_get_string(shortcut.key.scancode).capitalize(); + + return str; + } break; + case InputEvent::JOYSTICK_BUTTON: { + + String str = RTR("Device")+" "+itos(shortcut.device)+", "+RTR("Button")+" "+itos(shortcut.joy_button.button_index); + str+="."; + + return str; + } break; + case InputEvent::MOUSE_BUTTON: { + + String str = RTR("Device")+" "+itos(shortcut.device)+", "; + switch (shortcut.mouse_button.button_index) { + case BUTTON_LEFT: str+=RTR("Left Button."); break; + case BUTTON_RIGHT: str+=RTR("Right Button."); break; + case BUTTON_MIDDLE: str+=RTR("Middle Button."); break; + case BUTTON_WHEEL_UP: str+=RTR("Wheel Up."); break; + case BUTTON_WHEEL_DOWN: str+=RTR("Wheel Down."); break; + default: str+=RTR("Button")+" "+itos(shortcut.mouse_button.button_index)+"."; + } + + return str; + } break; + case InputEvent::JOYSTICK_MOTION: { + + int ax = shortcut.joy_motion.axis; + String str = RTR("Device")+" "+itos(shortcut.device)+", "+RTR("Axis")+" "+itos(ax)+"."; + + return str; + } break; + } + + return ""; +} + +bool ShortCut::is_valid() const { + + return shortcut.type!=InputEvent::NONE; +} + +void ShortCut::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shortcut","event"),&ShortCut::set_shortcut); + ObjectTypeDB::bind_method(_MD("get_shortcut"),&ShortCut::get_shortcut); + + ObjectTypeDB::bind_method(_MD("is_valid"),&ShortCut::is_valid); + + ObjectTypeDB::bind_method(_MD("is_shortcut","event"),&ShortCut::is_shortcut); + ObjectTypeDB::bind_method(_MD("get_as_text"),&ShortCut::get_as_text); + + ADD_PROPERTY(PropertyInfo(Variant::INPUT_EVENT,"shortcut"),_SCS("set_shortcut"),_SCS("get_shortcut")); +} + +ShortCut::ShortCut(){ + +} diff --git a/scene/gui/input_action.h b/scene/gui/input_action.h new file mode 100644 index 0000000000..8e0e1ef0bd --- /dev/null +++ b/scene/gui/input_action.h @@ -0,0 +1,26 @@ +#ifndef INPUTACTION_H +#define INPUTACTION_H + +#include "resource.h" + +class ShortCut : public Resource { + + OBJ_TYPE(ShortCut,Resource); + + InputEvent shortcut; +protected: + + static void _bind_methods(); +public: + + void set_shortcut(const InputEvent& p_shortcut); + InputEvent get_shortcut() const; + bool is_shortcut(const InputEvent& p_Event) const; + bool is_valid() const; + + String get_as_text() const; + + ShortCut(); +}; + +#endif // INPUTACTION_H diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index c1a0e43e49..fc4ab5f8ca 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -325,6 +325,18 @@ int ItemList::get_fixed_column_width() const{ return fixed_column_width; } +void ItemList::set_same_column_width(bool p_enable){ + + same_column_width=p_enable; + update(); + shape_changed=true; + +} +int ItemList::is_same_column_width() const{ + + return same_column_width; +} + void ItemList::set_max_text_lines(int p_lines){ ERR_FAIL_COND(p_lines<1); @@ -824,6 +836,8 @@ void ItemList::_notification(int p_what) { } if (shape_changed) { + + float max_column_width = 0; //1- compute item minimum sizes for(int i=0;i<items.size();i++) { @@ -831,7 +845,7 @@ void ItemList::_notification(int p_what) { Size2 minsize; if (items[i].icon.is_valid()) { - minsize=_adjust_to_max_size(items[i].get_icon_size(),max_icon_size); + minsize=_adjust_to_max_size(items[i].get_icon_size(),max_icon_size) * icon_scale; if (items[i].text!="") { if (icon_mode==ICON_MODE_TOP) { @@ -864,10 +878,11 @@ void ItemList::_notification(int p_what) { } - - items[i].rect_cache.size=minsize; if (fixed_column_width>0) - items[i].rect_cache.size.x=fixed_column_width; + minsize.x=fixed_column_width; + max_column_width=MAX(max_column_width,minsize.x); + items[i].rect_cache.size=minsize; + items[i].min_rect_cache.size=minsize; } @@ -896,17 +911,23 @@ void ItemList::_notification(int p_what) { break; } + items[i].rect_cache=items[i].min_rect_cache; + if(same_column_width) + items[i].rect_cache.size.x=max_column_width; items[i].rect_cache.pos=ofs; max_h=MAX(max_h,items[i].rect_cache.size.y); - ofs.x+=items[i].rect_cache.size.x; + ofs.x+=items[i].rect_cache.size.x + hseparation; //print_line("item "+itos(i)+" ofs "+rtos(items[i].rect_cache.size.x)); - if (col>0) - ofs.x+=hseparation; col++; if (col==current_columns) { if (i<items.size()-1) separators.push_back(ofs.y+max_h+vseparation/2); + + for(int j=i;j>=0 && col>0;j--, col--) { + items[j].rect_cache.size.y = max_h; + } + ofs.x=0; ofs.y+=max_h+vseparation; col=0; @@ -914,6 +935,10 @@ void ItemList::_notification(int p_what) { } } + for(int j=items.size()-1;j>=0 && col>0;j--, col--) { + items[j].rect_cache.size.y = max_h; + } + if (all_fit) { float max = MAX(page,ofs.y+max_h); scroll_bar->set_max(max); @@ -976,7 +1001,7 @@ void ItemList::_notification(int p_what) { Vector2 text_ofs; if (items[i].icon.is_valid()) { - Size2 icon_size = _adjust_to_max_size(items[i].get_icon_size(),max_icon_size); + Size2 icon_size = _adjust_to_max_size(items[i].get_icon_size(),max_icon_size) * icon_scale; Vector2 icon_ofs; if (min_icon_size!=Vector2()) { @@ -988,7 +1013,12 @@ void ItemList::_notification(int p_what) { if (icon_mode==ICON_MODE_TOP) { pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width)/2); + pos.y += MIN( + Math::floor((items[i].rect_cache.size.height - icon_size.height)/2), + items[i].rect_cache.size.height - items[i].min_rect_cache.size.height + ); text_ofs.y = MAX(icon_size.height, min_icon_size.y) + icon_margin; + text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height; } else { pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height)/2); @@ -1014,6 +1044,8 @@ void ItemList::_notification(int p_what) { Vector2 size = font->get_string_size(items[i].text); if (fixed_column_width) max_len=fixed_column_width; + else if(same_column_width) + max_len=items[i].rect_cache.size.x; else max_len=size.x; @@ -1201,6 +1233,14 @@ bool ItemList::get_allow_rmb_select() const { return allow_rmb_select; } +void ItemList::set_icon_scale(real_t p_scale) { + icon_scale = p_scale; +} + +real_t ItemList::get_icon_scale() const { + return icon_scale; +} + void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("add_item","text","icon:Texture","selectable"),&ItemList::add_item,DEFVAL(Variant()),DEFVAL(true)); @@ -1243,6 +1283,9 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_fixed_column_width","width"),&ItemList::set_fixed_column_width); ObjectTypeDB::bind_method(_MD("get_fixed_column_width"),&ItemList::get_fixed_column_width); + ObjectTypeDB::bind_method(_MD("set_same_column_width","enable"),&ItemList::set_same_column_width); + ObjectTypeDB::bind_method(_MD("is_same_column_width"),&ItemList::is_same_column_width); + ObjectTypeDB::bind_method(_MD("set_max_text_lines","lines"),&ItemList::set_max_text_lines); ObjectTypeDB::bind_method(_MD("get_max_text_lines"),&ItemList::get_max_text_lines); @@ -1261,6 +1304,9 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_max_icon_size","size"),&ItemList::set_max_icon_size); ObjectTypeDB::bind_method(_MD("get_max_icon_size"),&ItemList::get_max_icon_size); + ObjectTypeDB::bind_method(_MD("set_icon_scale","scale"),&ItemList::set_icon_scale); + ObjectTypeDB::bind_method(_MD("get_icon_scale"),&ItemList::get_icon_scale); + ObjectTypeDB::bind_method(_MD("set_allow_rmb_select","allow"),&ItemList::set_allow_rmb_select); ObjectTypeDB::bind_method(_MD("get_allow_rmb_select"),&ItemList::get_allow_rmb_select); @@ -1292,6 +1338,7 @@ ItemList::ItemList() { icon_mode=ICON_MODE_LEFT; fixed_column_width=0; + same_column_width = false; max_text_lines=1; max_columns=1; @@ -1308,6 +1355,7 @@ ItemList::ItemList() { defer_select_single=-1; allow_rmb_select=false; + icon_scale = 1.0f; } ItemList::~ItemList() { diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 59fa1d8270..087c585128 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -33,6 +33,7 @@ private: Color custom_bg; Rect2 rect_cache; + Rect2 min_rect_cache; Size2 get_icon_size() const; @@ -44,6 +45,7 @@ private: bool shape_changed; bool ensure_selected_visible; + bool same_column_width; Vector<Item> items; Vector<int> separators; @@ -59,12 +61,18 @@ private: int fixed_column_width; int max_text_lines; int max_columns; + Size2 min_icon_size; Size2 max_icon_size; + + Size2 max_item_size_cache; + int defer_select_single; bool allow_rmb_select; + real_t icon_scale; + void _scroll_changed(double); void _input_event(const InputEvent& p_event); protected: @@ -121,6 +129,9 @@ public: void set_fixed_column_width(int p_size); int get_fixed_column_width() const; + void set_same_column_width(bool p_enable); + int is_same_column_width() const; + void set_max_text_lines(int p_amount); int get_max_text_lines() const; @@ -150,6 +161,9 @@ public: virtual String get_tooltip(const Point2& p_pos) const; int get_item_at_pos(const Point2& p_pos,bool p_exact=false) const; + void set_icon_scale(real_t p_scale); + real_t get_icon_scale() const; + ItemList(); ~ItemList(); }; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 14dac454bd..44cc798447 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -454,7 +454,7 @@ void LineEdit::_notification(int p_what) { } break; } - int ofs_max=width-style->get_minimum_size().width; + int ofs_max=width-style->get_minimum_size().width+x_ofs; int char_ofs=window_pos; int y_area=height-style->get_minimum_size().height; @@ -799,8 +799,7 @@ Size2 LineEdit::get_minimum_size() const { Ref<Font> font=get_font("font"); Size2 min=style->get_minimum_size(); - min.height+=font->get_height(); - min.width+=get_constant("minimum_spaces")*font->get_char_size(' ').x; + min+=font->get_string_size(this->text); return min; } @@ -1027,7 +1026,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") ); ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") ); - + ADD_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") ); } diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 007d0a709e..065423ae2d 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -119,6 +119,6 @@ void LinkButton::_bind_methods() { LinkButton::LinkButton() { underline_mode=UNDERLINE_MODE_ALWAYS; - set_focus_mode(FOCUS_NONE); + set_enabled_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); } diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 0f415f013d..28d67287d5 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -32,30 +32,15 @@ void MenuButton::_unhandled_key_input(InputEvent p_event) { - //check accelerators - if (p_event.type==InputEvent::KEY && p_event.key.pressed) { + if (p_event.is_pressed() && !p_event.is_echo() && (p_event.type==InputEvent::KEY || p_event.type==InputEvent::ACTION || p_event.type==InputEvent::JOYSTICK_BUTTON)) { if (!get_parent() || !is_visible() || is_disabled()) return; - uint32_t code=p_event.key.scancode; - if (code==0) - code=p_event.key.unicode; - if (p_event.key.mod.control) - code|=KEY_MASK_CTRL; - if (p_event.key.mod.alt) - code|=KEY_MASK_ALT; - if (p_event.key.mod.meta) - code|=KEY_MASK_META; - if (p_event.key.mod.shift) - code|=KEY_MASK_SHIFT; - - - int item = popup->activate_item_by_accelerator(code); + int item = popup->activate_item_by_event(p_event); } - } @@ -123,7 +108,7 @@ MenuButton::MenuButton() { set_flat(true); - set_focus_mode(FOCUS_NONE); + set_enabled_focus_mode(FOCUS_NONE); popup = memnew( PopupMenu ); popup->hide(); add_child(popup); diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp index b6e261714c..3ecee7328b 100644 --- a/scene/gui/patch_9_frame.cpp +++ b/scene/gui/patch_9_frame.cpp @@ -9,10 +9,9 @@ void Patch9Frame::_notification(int p_what) { if (texture.is_null()) return; - Size2 s=get_size(); RID ci = get_canvas_item(); - VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); + VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),region_rect,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); // draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); /* @@ -47,12 +46,15 @@ void Patch9Frame::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate ); ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin ); ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin ); + ObjectTypeDB::bind_method(_MD("set_region_rect","rect"),&Patch9Frame::set_region_rect); + ObjectTypeDB::bind_method(_MD("get_region_rect"),&Patch9Frame::get_region_rect); ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center ); ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center ); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT ); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP ); ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT ); @@ -93,6 +95,20 @@ void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) { margin[p_margin]=p_size; update(); minimum_size_changed(); + switch (p_margin) { + case MARGIN_LEFT: + _change_notify("patch_margin/left"); + break; + case MARGIN_TOP: + _change_notify("patch_margin/top"); + break; + case MARGIN_RIGHT: + _change_notify("patch_margin/right"); + break; + case MARGIN_BOTTOM: + _change_notify("patch_margin/bottom"); + break; + } } int Patch9Frame::get_patch_margin(Margin p_margin) const{ @@ -101,6 +117,22 @@ int Patch9Frame::get_patch_margin(Margin p_margin) const{ return margin[p_margin]; } +void Patch9Frame::set_region_rect(const Rect2& p_region_rect) { + + if (region_rect==p_region_rect) + return; + + region_rect=p_region_rect; + + item_rect_changed(); + _change_notify("region_rect"); +} + +Rect2 Patch9Frame::get_region_rect() const { + + return region_rect; +} + void Patch9Frame::set_draw_center(bool p_draw) { draw_center=p_draw; @@ -128,5 +160,3 @@ Patch9Frame::Patch9Frame() { Patch9Frame::~Patch9Frame() { } - - diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h index 562a5b1d77..52e2324c3d 100644 --- a/scene/gui/patch_9_frame.h +++ b/scene/gui/patch_9_frame.h @@ -11,6 +11,7 @@ class Patch9Frame : public Control { bool draw_center; int margin[4]; + Rect2 region_rect; Color modulate; Ref<Texture> texture; protected: @@ -30,6 +31,9 @@ public: void set_patch_margin(Margin p_margin,int p_size); int get_patch_margin(Margin p_margin) const; + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + void set_draw_center(bool p_enable); bool get_draw_center() const; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 819885809b..b3f18bf8fa 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -32,9 +32,16 @@ #include "translation.h" #include "os/input.h" -String PopupMenu::_get_accel_text(uint32_t p_accel) const { +String PopupMenu::_get_accel_text(int p_item) const { + + ERR_FAIL_INDEX_V(p_item,items.size(),String()); + + if (items[p_item].shortcut.is_valid()) + return items[p_item].shortcut->get_as_text(); + else if (items[p_item].accel) + return keycode_get_string(items[p_item].accel); + return String(); - return keycode_get_string(p_accel); /* String atxt; if (p_accel&KEY_MASK_SHIFT) @@ -87,14 +94,15 @@ Size2 PopupMenu::get_minimum_size() const { size.width+=check_w+hseparation; } - size.width+=font->get_string_size(items[i].text).width; + String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].text; + size.width+=font->get_string_size(text).width; if (i>0) size.height+=vseparation; - if (items[i].accel) { + if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { int accel_w = hseparation*2; - accel_w+=font->get_string_size(_get_accel_text(items[i].accel)).width; + accel_w+=font->get_string_size(_get_accel_text(i)).width; accel_max_w = MAX( accel_w, accel_max_w ); } @@ -484,13 +492,15 @@ void PopupMenu::_notification(int p_what) { } item_ofs.y+=font->get_ascent(); - if (!items[i].separator) - font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),items[i].text,items[i].disabled?font_color_disabled:(i==mouse_over?font_color_hover:font_color)); + String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].text; + if (!items[i].separator) { + font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),text,items[i].disabled?font_color_disabled:(i==mouse_over?font_color_hover:font_color)); + } - if (items[i].accel) { + if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { //accelerator - String text = _get_accel_text(items[i].accel); + String text = _get_accel_text(i); item_ofs.x=size.width-style->get_margin(MARGIN_RIGHT)-font->get_string_size(text).width; font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),text,i==mouse_over?font_color_hover:font_color_accel); @@ -570,6 +580,64 @@ void PopupMenu::add_check_item(const String& p_label,int p_ID,uint32_t p_accel) update(); } + +void PopupMenu::add_icon_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID) { + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.icon=p_icon; + item.shortcut=p_shortcut; + items.push_back(item); + update(); + +} + +void PopupMenu::add_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + items.push_back(item); + update(); + +} +void PopupMenu::add_icon_check_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + item.checkable=true; + item.icon=p_icon; + items.push_back(item); + update(); +} + +void PopupMenu::add_check_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID){ + + ERR_FAIL_COND(p_shortcut.is_null()); + + _ref_shortcut(p_shortcut); + + Item item; + item.ID=p_ID; + item.shortcut=p_shortcut; + item.checkable=true; + items.push_back(item); + update(); +} + void PopupMenu::set_item_text(int p_idx,const String& p_text) { ERR_FAIL_INDEX(p_idx,items.size()); @@ -701,6 +769,12 @@ String PopupMenu::get_item_tooltip(int p_idx) const { return items[p_idx].tooltip; } +Ref<ShortCut> PopupMenu::get_item_shortcut(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<ShortCut>()); + return items[p_idx].shortcut; +} + void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx,items.size()); @@ -730,6 +804,21 @@ void PopupMenu::set_item_tooltip(int p_idx,const String& p_tooltip) { update(); } +void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut>& p_shortcut) { + ERR_FAIL_INDEX(p_idx,items.size()); + if (items[p_idx].shortcut.is_valid()) { + _unref_shortcut(items[p_idx].shortcut); + } + items[p_idx].shortcut=p_shortcut; + + if (items[p_idx].shortcut.is_valid()) { + _ref_shortcut(items[p_idx].shortcut); + } + + + update(); +} + bool PopupMenu::is_item_checkable(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,items.size(),false); return items[p_idx].checkable; @@ -740,14 +829,36 @@ int PopupMenu::get_item_count() const { return items.size(); } -bool PopupMenu::activate_item_by_accelerator(uint32_t p_accel) { +bool PopupMenu::activate_item_by_event(const InputEvent& p_event) { + + uint32_t code=0; + if (p_event.type==InputEvent::KEY) { + code=p_event.key.scancode; + if (code==0) + code=p_event.key.unicode; + if (p_event.key.mod.control) + code|=KEY_MASK_CTRL; + if (p_event.key.mod.alt) + code|=KEY_MASK_ALT; + if (p_event.key.mod.meta) + code|=KEY_MASK_META; + if (p_event.key.mod.shift) + code|=KEY_MASK_SHIFT; + } + int il=items.size(); for(int i=0;i<il;i++) { if (is_item_disabled(i)) continue; - if (items[i].accel==p_accel) { + + if (items[i].shortcut.is_valid() && items[i].shortcut->is_shortcut(p_event)) { + activate_item(i); + return true; + } + + if (code!=0 && items[i].accel==code) { activate_item(i); return true; } @@ -761,7 +872,7 @@ bool PopupMenu::activate_item_by_accelerator(uint32_t p_accel) { if(!pm) continue; - if(pm->activate_item_by_accelerator(p_accel)) { + if(pm->activate_item_by_event(p_event)) { return true; } } @@ -791,6 +902,12 @@ void PopupMenu::activate_item(int p_item) { void PopupMenu::remove_item(int p_idx) { + ERR_FAIL_INDEX(p_idx,items.size()); + + if (items[p_idx].shortcut.is_valid()) { + _unref_shortcut(items[p_idx].shortcut); + } + items.remove(p_idx); update(); } @@ -806,6 +923,11 @@ void PopupMenu::add_separator() { void PopupMenu::clear() { + for(int i=0;i<items.size();i++) { + if (items[i].shortcut.is_valid()) { + _unref_shortcut(items[i].shortcut); + } + } items.clear(); mouse_over=-1; update(); @@ -834,6 +956,27 @@ Array PopupMenu::_get_items() const { return items; } + +void PopupMenu::_ref_shortcut( Ref<ShortCut> p_sc) { + + if (!shortcut_refcount.has(p_sc)) { + shortcut_refcount[p_sc]=1; + p_sc->connect("changed",this,"update"); + } else { + shortcut_refcount[p_sc]+=1; + } +} + +void PopupMenu::_unref_shortcut(Ref<ShortCut> p_sc) { + + ERR_FAIL_COND(!shortcut_refcount.has(p_sc)); + shortcut_refcount[p_sc]--; + if (shortcut_refcount[p_sc]==0) { + p_sc->disconnect("changed",this,"update"); + shortcut_refcount.erase(p_sc); + } +} + void PopupMenu::_set_items(const Array& p_items){ ERR_FAIL_COND(p_items.size() % 10); @@ -912,12 +1055,20 @@ void PopupMenu::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_icon_check_item","texture","label","id","accel"),&PopupMenu::add_icon_check_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_check_item","label","id","accel"),&PopupMenu::add_check_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_submenu_item,DEFVAL(-1)); + + ObjectTypeDB::bind_method(_MD("add_icon_shortcut","texture","shortcut:ShortCut","id"),&PopupMenu::add_icon_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_shortcut","shortcut:ShortCut","id"),&PopupMenu::add_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_icon_check_shortcut","texture","shortcut:ShortCut","id"),&PopupMenu::add_icon_check_shortcut,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_check_shortcut","shortcut:ShortCut","id"),&PopupMenu::add_check_shortcut,DEFVAL(-1)); + + ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&PopupMenu::set_item_text); ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon"),&PopupMenu::set_item_icon); ObjectTypeDB::bind_method(_MD("set_item_accelerator","idx","accel"),&PopupMenu::set_item_accelerator); ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&PopupMenu::set_item_metadata); ObjectTypeDB::bind_method(_MD("set_item_checked","idx","checked"),&PopupMenu::set_item_checked); ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&PopupMenu::set_item_disabled); + ObjectTypeDB::bind_method(_MD("set_item_shortcut","idx","shortcut:ShortCut"),&PopupMenu::set_item_shortcut); ObjectTypeDB::bind_method(_MD("set_item_submenu","idx","submenu"),&PopupMenu::set_item_submenu); ObjectTypeDB::bind_method(_MD("set_item_as_separator","idx","enable"),&PopupMenu::set_item_as_separator); ObjectTypeDB::bind_method(_MD("set_item_as_checkable","idx","enable"),&PopupMenu::set_item_as_checkable); @@ -926,6 +1077,7 @@ void PopupMenu::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_item_icon","idx"),&PopupMenu::get_item_icon); ObjectTypeDB::bind_method(_MD("get_item_metadata","idx"),&PopupMenu::get_item_metadata); ObjectTypeDB::bind_method(_MD("get_item_accelerator","idx"),&PopupMenu::get_item_accelerator); + ObjectTypeDB::bind_method(_MD("get_item_shortcut:ShortCut","idx"),&PopupMenu::get_item_shortcut); ObjectTypeDB::bind_method(_MD("get_item_submenu","idx"),&PopupMenu::get_item_submenu); ObjectTypeDB::bind_method(_MD("is_item_separator","idx"),&PopupMenu::is_item_separator); ObjectTypeDB::bind_method(_MD("is_item_checkable","idx"),&PopupMenu::is_item_checkable); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index 0e98765dc4..f35e91d4e4 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -34,6 +34,9 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ + + + class PopupMenu : public Popup { OBJ_TYPE(PopupMenu, Popup ); @@ -51,6 +54,7 @@ class PopupMenu : public Popup { String tooltip; uint32_t accel; int _ofs_cache; + Ref<ShortCut> shortcut; Item() { checked=false; checkable=false; separator=false; accel=0; disabled=false; _ofs_cache=0; } }; @@ -62,7 +66,7 @@ class PopupMenu : public Popup { int mouse_over; int submenu_over; Rect2 parent_rect; - String _get_accel_text(uint32_t p_accel) const; + String _get_accel_text(int p_item) const; int _get_mouse_over(const Point2& p_over) const; virtual Size2 get_minimum_size() const; void _input_event(const InputEvent &p_event); @@ -75,6 +79,10 @@ class PopupMenu : public Popup { Array _get_items() const; void _set_items(const Array& p_items); + Map< Ref<ShortCut>, int> shortcut_refcount; + + void _ref_shortcut(Ref<ShortCut> p_sc); + void _unref_shortcut( Ref<ShortCut> p_sc); protected: virtual bool has_point(const Point2& p_point) const; @@ -90,6 +98,11 @@ public: void add_check_item(const String& p_label,int p_ID=-1,uint32_t p_accel=0); void add_submenu_item(const String& p_label,const String& p_submenu, int p_ID=-1); + void add_icon_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_icon_check_shortcut(const Ref<Texture>& p_icon,const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void add_check_shortcut(const Ref<ShortCut>& p_shortcut,int p_ID=-1); + void set_item_text(int p_idx,const String& p_text); void set_item_icon(int p_idx,const Ref<Texture>& p_icon); void set_item_checked(int p_idx,bool p_checked); @@ -101,6 +114,7 @@ public: void set_item_as_separator(int p_idx, bool p_separator); void set_item_as_checkable(int p_idx, bool p_checkable); void set_item_tooltip(int p_idx,const String& p_tooltip); + void set_item_shortcut(int p_idx, const Ref<ShortCut>& p_shortcut); String get_item_text(int p_idx) const; Ref<Texture> get_item_icon(int p_idx) const; @@ -114,10 +128,11 @@ public: bool is_item_separator(int p_idx) const; bool is_item_checkable(int p_idx) const; String get_item_tooltip(int p_idx) const; + Ref<ShortCut> get_item_shortcut(int p_idx) const; int get_item_count() const; - bool activate_item_by_accelerator(uint32_t p_accel); + bool activate_item_by_event(const InputEvent& p_event); void activate_item(int p_item); void remove_item(int p_idx); diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index f66f909517..d5d14ad649 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -237,6 +237,7 @@ void Slider::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::INT, "tick_count", PROPERTY_HINT_RANGE,"0,4096,1"), _SCS("set_ticks"), _SCS("get_ticks") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "ticks_on_borders" ), _SCS("set_ticks_on_borders"), _SCS("get_ticks_on_borders") ); + ADD_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") ); } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 1c6a97bab8..d19e5f0d60 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -411,6 +411,10 @@ void TabContainer::_notification(int p_what) { panel->draw(ci, Rect2( 0, top_size.height, size.width, size.height-top_size.height)); } break; + case NOTIFICATION_THEME_CHANGED: { + + call_deferred("set_current_tab",get_current_tab()); //wait until all changed theme + } break; } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 03024daff5..fe03b34105 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -314,6 +314,10 @@ void TextEdit::_update_scrollbars() { if (line_numbers) total_width += cache.line_number_w; + if (draw_breakpoint_gutter) { + total_width += cache.breakpoint_gutter_width; + } + bool use_hscroll=true; bool use_vscroll=true; @@ -412,9 +416,15 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { _update_caches(); - }; + } break; case NOTIFICATION_DRAW: { + if (draw_breakpoint_gutter) { + cache.breakpoint_gutter_width = breakpoint_gutter_width; + } else { + cache.breakpoint_gutter_width = 0; + } + int line_number_char_count=0; { @@ -439,7 +449,7 @@ void TextEdit::_notification(int p_what) { RID ci = get_canvas_item(); - int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w; + int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width; int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT); //let's do it easy for now: cache.style_normal->draw(ci,Rect2(Point2(),cache.size)); @@ -682,18 +692,13 @@ void TextEdit::_notification(int p_what) { // check if line contains highlighted word int highlighted_text_col = -1; - if (highlighted_text.length() != 0) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, 0); - } + int search_text_col = -1; - if (cache.line_number_w) { - String fc = String::num(line+1); - while (fc.length() < line_number_char_count) { - fc="0"+fc; - } + if (!search_text.empty()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0); - cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,cache.line_number_color); - } + if (highlighted_text.length() != 0 && highlighted_text != search_text) + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, 0); const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line); @@ -708,11 +713,28 @@ void TextEdit::_notification(int p_what) { 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(0, ofs_y,xmargin_end,get_row_height()),cache.current_line_color); + } + + // draw breakpoint marker + if (text.is_breakpoint(line)) { + if (draw_breakpoint_gutter) { + int vertical_gap = cache.breakpoint_gutter_width / 2; + int marker_size = cache.breakpoint_gutter_width - vertical_gap; + // no transparency on marker + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + 1, ofs_y + vertical_gap ,marker_size, marker_size),Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b)); + } + } - VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color); + if (cache.line_number_w) { + String fc = String::num(line+1); + while (fc.length() < line_number_char_count) { + fc="0"+fc; + } + + cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT)+cache.breakpoint_gutter_width,ofs_y+cache.font->get_ascent()),fc,cache.line_number_color); } for (int j=0;j<str.length();j++) { @@ -879,20 +901,45 @@ void TextEdit::_notification(int p_what) { 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)); + bool in_search_result=false; + + if (search_text_col != -1) { + // if we are at the end check for new search result on same line + if (j >= search_text_col+search_text.length()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j); + + in_search_result = j >= search_text_col && j < search_text_col+search_text.length(); + if (in_search_result) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w, get_row_height())),cache.search_result_color); + } + } + + 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 (in_search_result) { + Color border_color=(line==search_result_line && j>=search_result_col && j<search_result_col+search_text.length())?cache.font_color:cache.search_result_border_color; + + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,1)),border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y+get_row_height()-1 ), Size2i(char_w,1)),border_color); + + if (j==search_text_col) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(1,get_row_height())),border_color); + if (j==search_text_col+search_text.length()-1) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin+char_w-1, ofs_y ), Size2i(1,get_row_height())),border_color); + } + if (highlight_all_occurrences) { if (highlighted_text_col != -1) { // if we are at the end check for new word on same line if (j > highlighted_text_col+highlighted_text.length()) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, j); + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, j); } bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col+highlighted_text.length()); @@ -1347,7 +1394,7 @@ void TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) co col=text[row].size(); } else { - col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); + col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width); col+=cursor.x_ofs; col=get_char_pos_for( col, get_line(row) ); } @@ -1421,6 +1468,15 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { int row,col; _get_mouse_pos(Point2i(mb.x,mb.y), row,col); + // toggle breakpoint on gutter click + if (draw_breakpoint_gutter) { + int gutter=cache.style_normal->get_margin(MARGIN_LEFT); + if (mb.x > gutter && mb.x <= gutter + cache.breakpoint_gutter_width + 3) { + set_line_as_breakpoint(row, !is_line_set_as_breakpoint(row)); + return; + } + } + int prev_col=cursor.column; int prev_line=cursor.line; @@ -1820,7 +1876,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } if (clear) { - begin_complex_operation(); + if (!dobreak) { + begin_complex_operation(); + } selection.active=false; update(); _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); @@ -1892,7 +1950,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (completion_hint!="") { completion_hint=""; update(); - + } else { + scancode_handled=false; } } break; case KEY_TAB: { @@ -2846,7 +2905,7 @@ 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; + int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w-cache.breakpoint_gutter_width; if (v_scroll->is_visible()) visible_width-=v_scroll->get_combined_minimum_size().width; visible_width-=20; // give it a little more space @@ -3075,7 +3134,8 @@ void TextEdit::insert_text_at_cursor(const String& p_text) { } Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { - if(completion_active && completion_rect.has_point(p_pos)) { + int gutter=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w+cache.breakpoint_gutter_width; + if((completion_active && completion_rect.has_point(p_pos)) || p_pos.x < gutter) { return CURSOR_ARROW; } return CURSOR_IBEAM; @@ -3220,6 +3280,8 @@ void TextEdit::_update_caches() { cache.breakpoint_color=get_color("breakpoint_color"); cache.brace_mismatch_color=get_color("brace_mismatch_color"); cache.word_highlighted_color=get_color("word_highlighted_color"); + cache.search_result_color=get_color("search_result_color"); + cache.search_result_border_color=get_color("search_result_border_color"); cache.line_spacing=get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon=get_icon("tab"); @@ -3481,12 +3543,26 @@ String TextEdit::get_word_under_cursor() const { return text[cursor.line].substr(prev_cc, next_cc-prev_cc); } +void TextEdit::set_search_text(const String &p_search_text) { + search_text = p_search_text; +} + +void TextEdit::set_search_flags(uint32_t p_flags) { + search_flags = p_flags; +} + +void TextEdit::set_current_search_result(int line, int col) { + search_result_line = line; + search_result_col = col; + update(); +} + void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { highlight_all_occurrences = p_enabled; update(); } -int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column) { +int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) { int col = -1; if (p_key.length() > 0 && p_search.length() > 0) { @@ -3494,12 +3570,15 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc p_from_column = 0; } - while (col == -1 && p_from_column <= p_search.length()) { - // match case - col = p_search.findn(p_key, p_from_column); + while (col == -1 && p_from_column <= p_search.length()) { + if (p_search_flags&SEARCH_MATCH_CASE) { + col = p_search.find(p_key,p_from_column); + } else { + col = p_search.findn(p_key,p_from_column); + } // whole words only - if (col != -1) { + if (col != -1 && p_search_flags&SEARCH_WHOLE_WORDS) { p_from_column=col; if (col > 0 && _is_text_char(p_search[col-1])) { @@ -3565,10 +3644,8 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li //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; } @@ -3579,7 +3656,6 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li } 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 @@ -3588,12 +3664,25 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li pos=-1; - if (!(p_search_flags&SEARCH_BACKWARDS)) { + int pos_from=0; + int last_pos=-1; + while ((last_pos=(p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,pos_from):text_line.findn(p_key,pos_from))!=-1) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); - } else { + if (p_search_flags&SEARCH_BACKWARDS) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); + if (last_pos>from_column) + break; + pos=last_pos; + + } else { + + if (last_pos>=from_column) { + pos=last_pos; + break; + } + } + + pos_from=last_pos+p_key.length(); } if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { @@ -4167,6 +4256,24 @@ void TextEdit::set_show_line_numbers(bool p_show) { update(); } +void TextEdit::set_draw_breakpoint_gutter(bool p_draw) { + draw_breakpoint_gutter = p_draw; + update(); +} + +bool TextEdit::is_drawing_breakpoint_gutter() const { + return draw_breakpoint_gutter; +} + +void TextEdit::set_breakpoint_gutter_width(int p_gutter_width) { + breakpoint_gutter_width = p_gutter_width; + update(); +} + +int TextEdit::get_breakpoint_gutter_width() const { + return cache.breakpoint_gutter_width; +} + bool TextEdit::is_text_field() const { return true; @@ -4308,6 +4415,8 @@ TextEdit::TextEdit() { cache.row_height=1; cache.line_spacing=1; cache.line_number_w=1; + cache.breakpoint_gutter_width=0; + breakpoint_gutter_width = 0; tab_size=4; text.set_tab_size(tab_size); @@ -4389,6 +4498,7 @@ TextEdit::TextEdit() { completion_line_ofs=0; tooltip_obj=NULL; line_numbers=false; + draw_breakpoint_gutter=false; next_operation_is_complex=false; scroll_past_end_of_file_enabled=false; auto_brace_completion_enabled=false; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index dbe6293240..24a72afd48 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -88,10 +88,13 @@ class TextEdit : public Control { Color current_line_color; Color brace_mismatch_color; Color word_highlighted_color; + Color search_result_color; + Color search_result_border_color; int row_height; int line_spacing; int line_number_w; + int breakpoint_gutter_width; Size2 size; } cache; @@ -222,6 +225,8 @@ class TextEdit : public Control { bool text_changed_dirty; bool undo_enabled; bool line_numbers; + bool draw_breakpoint_gutter; + int breakpoint_gutter_width; bool highlight_all_occurrences; bool scroll_past_end_of_file_enabled; @@ -249,6 +254,11 @@ class TextEdit : public Control { bool callhint_below; Vector2 callhint_offset; + String search_text; + uint32_t search_flags; + int search_result_line; + int search_result_col; + int get_visible_rows() const; int get_char_count(); @@ -287,7 +297,7 @@ class TextEdit : public Control { String _base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const; void _base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column); - int _get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column); + int _get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column); DVector<int> _search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const; @@ -408,6 +418,10 @@ public: void select(int p_from_line,int p_from_column,int p_to_line,int p_to_column); void deselect(); + void set_search_text(const String& p_search_text); + void set_search_flags(uint32_t p_flags); + void set_current_search_result(int line, int col); + void set_highlight_all_occurrences(const bool p_enabled); bool is_selection_active() const; int get_selection_from_line() const; @@ -451,6 +465,12 @@ public: void set_show_line_numbers(bool p_show); + void set_draw_breakpoint_gutter(bool p_draw); + bool is_drawing_breakpoint_gutter() const; + + void set_breakpoint_gutter_width(int p_gutter_width); + int get_breakpoint_gutter_width() const; + void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata); void set_completion(bool p_enabled,const Vector<String>& p_prefixes); diff --git a/scene/gui/texture_frame.cpp b/scene/gui/texture_frame.cpp index 73fecf591a..2fe8735fda 100644 --- a/scene/gui/texture_frame.cpp +++ b/scene/gui/texture_frame.cpp @@ -37,9 +37,31 @@ void TextureFrame::_notification(int p_what) { return; - Size2 s=expand?get_size():texture->get_size(); + RID ci = get_canvas_item(); - draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + + switch(stretch_mode) { + case STRETCH_SCALE_ON_EXPAND: { + Size2 s=expand?get_size():texture->get_size(); + draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + } break; + case STRETCH_SCALE: { + draw_texture_rect(texture,Rect2(Point2(),get_size()),false,modulate); + } break; + case STRETCH_TILE: { + draw_texture_rect(texture,Rect2(Point2(),get_size()),true,modulate); + } break; + case STRETCH_KEEP: { + draw_texture_rect(texture,Rect2(Point2(),texture->get_size()),false,modulate); + + } break; + case STRETCH_KEEP_CENTERED: { + + Vector2 ofs = (get_size() - texture->get_size())/2; + draw_texture_rect(texture,Rect2(ofs,texture->get_size()),false,modulate); + } break; + } + /* Vector<Point2> points; @@ -76,11 +98,19 @@ void TextureFrame::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_modulate"), & TextureFrame::get_modulate ); ObjectTypeDB::bind_method(_MD("set_expand","enable"), & TextureFrame::set_expand ); ObjectTypeDB::bind_method(_MD("has_expand"), & TextureFrame::has_expand ); + ObjectTypeDB::bind_method(_MD("set_stretch_mode","stretch_mode"), & TextureFrame::set_stretch_mode ); + ObjectTypeDB::bind_method(_MD("get_stretch_mode"), & TextureFrame::get_stretch_mode ); ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "stretch_mode",PROPERTY_HINT_ENUM,"Scale On Expand (Compat),Scale,Tile,Keep,Keep Centered"), _SCS("set_stretch_mode"),_SCS("get_stretch_mode") ); + BIND_CONSTANT( STRETCH_SCALE_ON_EXPAND ); + BIND_CONSTANT( STRETCH_SCALE ); + BIND_CONSTANT( STRETCH_TILE ); + BIND_CONSTANT( STRETCH_KEEP ); + BIND_CONSTANT( STRETCH_KEEP_CENTERED ); } @@ -121,12 +151,24 @@ bool TextureFrame::has_expand() const { return expand; } +void TextureFrame::set_stretch_mode(StretchMode p_mode) { + + stretch_mode=p_mode; + update(); +} + +TextureFrame::StretchMode TextureFrame::get_stretch_mode() const { + + return stretch_mode; +} + TextureFrame::TextureFrame() { expand=false; modulate=Color(1,1,1,1); set_ignore_mouse(true); + stretch_mode=STRETCH_SCALE_ON_EXPAND; } diff --git a/scene/gui/texture_frame.h b/scene/gui/texture_frame.h index e1f0de92df..a4acf588ea 100644 --- a/scene/gui/texture_frame.h +++ b/scene/gui/texture_frame.h @@ -36,10 +36,19 @@ class TextureFrame : public Control { OBJ_TYPE(TextureFrame,Control); - +public: + enum StretchMode { + STRETCH_SCALE_ON_EXPAND, //default, for backwards compatibility + STRETCH_SCALE, + STRETCH_TILE, + STRETCH_KEEP, + STRETCH_KEEP_CENTERED, + }; +private: bool expand; Color modulate; Ref<Texture> texture; + StretchMode stretch_mode; protected: void _notification(int p_what); @@ -57,9 +66,13 @@ public: void set_expand(bool p_expand); bool has_expand() const; + void set_stretch_mode(StretchMode p_mode); + StretchMode get_stretch_mode() const; + TextureFrame(); ~TextureFrame(); }; +VARIANT_ENUM_CAST( TextureFrame::StretchMode ); #endif // TEXTURE_FRAME_H diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 89dacc6577..26227d6389 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -131,7 +131,7 @@ void VideoPlayer::_notification(int p_notification) { if (!playback->is_playing()) return; - double audio_time = OS::get_singleton()->get_ticks_usec()/1000000.0; //AudioServer::get_singleton()->get_mix_time(); + double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec()); //AudioServer::get_singleton()->get_mix_time(); double delta = last_audio_time==0?0:audio_time-last_audio_time; last_audio_time=audio_time; diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 6174d134a3..f3a0eaa8c4 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -108,7 +108,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_origin Error err = ImageLoader::load_image(p_path,&image); if (!err && debug_load_times) { - double total=(double)(OS::get_singleton()->get_ticks_usec()-begtime)/1000000.0; + double total=USEC_TO_SEC((OS::get_singleton()->get_ticks_usec()-begtime)); print_line("IMAGE: "+itos(image.get_width())+"x"+itos(image.get_height())); print_line(" -load: "+rtos(total)); } @@ -201,7 +201,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_origin if (debug_load_times) { - total=(double)(OS::get_singleton()->get_ticks_usec()-begtime)/1000000.0; + total=USEC_TO_SEC(OS::get_singleton()->get_ticks_usec()-begtime); print_line(" -make texture: "+rtos(total)); } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 90e3713799..2320616629 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -480,8 +480,9 @@ void HTTPRequest::_bind_methods() { BIND_CONSTANT( RESULT_NO_RESPONSE ); BIND_CONSTANT( RESULT_BODY_SIZE_LIMIT_EXCEEDED ); BIND_CONSTANT( RESULT_REQUEST_FAILED ); - BIND_CONSTANT( RESULT_REDIRECT_LIMIT_REACHED ); + BIND_CONSTANT( RESULT_DOWNLOAD_FILE_CANT_OPEN ); BIND_CONSTANT( RESULT_DOWNLOAD_FILE_WRITE_ERROR ); + BIND_CONSTANT( RESULT_REDIRECT_LIMIT_REACHED ); } @@ -494,7 +495,7 @@ HTTPRequest::HTTPRequest() max_redirects=8; body_len=-1; got_response=false; - validate_ssl=false; + validate_ssl=false; use_ssl=false; response_code=0; request_sent=false; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index f261693841..29925b62f5 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1244,7 +1244,19 @@ void Node::get_groups(List<GroupInfo> *p_groups) const { } +bool Node::has_persistent_groups() const { + const StringName *K=NULL; + + while ((K=data.grouped.next(K))) { + + if (data.grouped[*K].persistent) + return true; + } + + return false; + +} void Node::_print_tree(const Node *p_node) { print_line(String(p_node->get_path_to(this))); diff --git a/scene/main/node.h b/scene/main/node.h index a4683e602f..cf62e7cdea 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -223,6 +223,7 @@ public: }; void get_groups(List<GroupInfo> *p_groups) const; + bool has_persistent_groups() const; void move_child(Node *p_child,int p_pos); void raise(); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index b83ad7381e..d7f22c3228 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -1002,6 +1002,7 @@ static void _fill_array(Node *p_node, Array& array, int p_level) { array.push_back(p_level); array.push_back(p_node->get_name()); array.push_back(p_node->get_type()); + array.push_back(p_node->get_instance_ID()); for(int i=0;i<p_node->get_child_count();i++) { _fill_array(p_node->get_child(i),array,p_level+1); @@ -1592,6 +1593,14 @@ void SceneTree::_live_edit_reparent_node_func(const NodePath& p_at,const NodePat #endif + + +void SceneTree::drop_files(const Vector<String>& p_files,int p_from_screen) { + + emit_signal("files_dropped",p_files,p_from_screen); + MainLoop::drop_files(p_files,p_from_screen); +} + void SceneTree::_bind_methods() { @@ -1665,6 +1674,8 @@ void SceneTree::_bind_methods() { ADD_SIGNAL( MethodInfo("idle_frame")); ADD_SIGNAL( MethodInfo("fixed_frame")); + ADD_SIGNAL( MethodInfo("files_dropped",PropertyInfo(Variant::STRING_ARRAY,"files"),PropertyInfo(Variant::INT,"screen")) ); + BIND_CONSTANT( GROUP_CALL_DEFAULT ); BIND_CONSTANT( GROUP_CALL_REVERSE ); BIND_CONSTANT( GROUP_CALL_REALTIME ); diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index b6a015c9ed..5fc9e0c1ae 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -344,6 +344,7 @@ public: static SceneTree* get_singleton() { return singleton; } + void drop_files(const Vector<String>& p_files,int p_from_screen=0); SceneTree(); ~SceneTree(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index c9f61beba7..4083dc893d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -37,6 +37,7 @@ #include "servers/spatial_sound_2d_server.h" #include "scene/gui/control.h" #include "scene/3d/camera.h" +#include "scene/3d/listener.h" #include "scene/resources/mesh.h" #include "scene/3d/spatial_indexer.h" #include "scene/3d/collision_object.h" @@ -388,6 +389,19 @@ void Viewport::_notification(int p_what) { } break; case NOTIFICATION_READY: { #ifndef _3D_DISABLED + if (listeners.size() && !listener) { + Listener *first=NULL; + for(Set<Listener*>::Element *E=listeners.front();E;E=E->next()) { + + if (first==NULL || first->is_greater_than(E->get())) { + first=E->get(); + } + } + + if (first) + first->make_current(); + } + if (cameras.size() && !camera) { //there are cameras but no current camera, pick first in tree and make it current Camera *first=NULL; @@ -414,7 +428,7 @@ void Viewport::_notification(int p_what) { _vp_exit_tree(); VisualServer::get_singleton()->viewport_set_scenario(viewport,RID()); - SpatialSoundServer::get_singleton()->listener_set_space(listener,RID()); + SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID()); VisualServer::get_singleton()->viewport_remove_canvas(viewport,current_canvas); if (contact_2d_debug.is_valid()) { VisualServer::get_singleton()->free(contact_2d_debug); @@ -740,10 +754,10 @@ Rect2 Viewport::get_rect() const { void Viewport::_update_listener() { - if (is_inside_tree() && audio_listener && camera && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) { - SpatialSoundServer::get_singleton()->listener_set_space(listener,find_world()->get_sound_space()); + if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) { + SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, find_world()->get_sound_space()); } else { - SpatialSoundServer::get_singleton()->listener_set_space(listener,RID()); + SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID()); } @@ -752,9 +766,9 @@ void Viewport::_update_listener() { void Viewport::_update_listener_2d() { if (is_inside_tree() && audio_listener && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) - SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,find_world_2d()->get_sound_space()); + SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space()); else - SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,RID()); + SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID()); } @@ -798,11 +812,11 @@ void Viewport::set_canvas_transform(const Matrix32& p_transform) { Matrix32 xform = (global_canvas_transform * canvas_transform).affine_inverse(); Size2 ss = get_visible_rect().size; - SpatialSound2DServer::get_singleton()->listener_set_transform(listener_2d,Matrix32(0,xform.xform(ss*0.5))); + SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Matrix32(0, xform.xform(ss*0.5))); Vector2 ss2 = ss*xform.get_scale(); float panrange = MAX(ss2.x,ss2.y); - SpatialSound2DServer::get_singleton()->listener_set_param(listener_2d,SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE,panrange); + SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange); } @@ -823,11 +837,11 @@ void Viewport::_update_global_transform() { Matrix32 xform = (sxform * canvas_transform).affine_inverse(); Size2 ss = get_visible_rect().size; - SpatialSound2DServer::get_singleton()->listener_set_transform(listener_2d,Matrix32(0,xform.xform(ss*0.5))); + SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Matrix32(0, xform.xform(ss*0.5))); Vector2 ss2 = ss*xform.get_scale(); float panrange = MAX(ss2.x,ss2.y); - SpatialSound2DServer::get_singleton()->listener_set_param(listener_2d,SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE,panrange); + SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange); } @@ -846,12 +860,75 @@ Matrix32 Viewport::get_global_canvas_transform() const{ return global_canvas_transform; } +void Viewport::_listener_transform_changed_notify() { + +#ifndef _3D_DISABLED + if (listener) + SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, listener->get_listener_transform()); +#endif +} + +void Viewport::_listener_set(Listener* p_listener) { + +#ifndef _3D_DISABLED + + if (listener == p_listener) + return; + + listener = p_listener; + + _update_listener(); + _listener_transform_changed_notify(); +#endif +} + +bool Viewport::_listener_add(Listener* p_listener) { + + listeners.insert(p_listener); + return listeners.size() == 1; +} + +void Viewport::_listener_remove(Listener* p_listener) { + + listeners.erase(p_listener); + if (listener == p_listener) { + listener = NULL; + } +} + +#ifndef _3D_DISABLED +void Viewport::_listener_make_next_current(Listener* p_exclude) { + + if (listeners.size() > 0) { + for (Set<Listener*>::Element *E = listeners.front(); E; E = E->next()) { + + if (p_exclude == E->get()) + continue; + if (!E->get()->is_inside_tree()) + continue; + if (listener != NULL) + return; + + E->get()->make_current(); + + } + } + else { + // Attempt to reset listener to the camera position + if (camera != NULL) { + _update_listener(); + _camera_transform_changed_notify(); + } + } +} +#endif void Viewport::_camera_transform_changed_notify() { #ifndef _3D_DISABLED - if (camera) - SpatialSoundServer::get_singleton()->listener_set_transform(listener,camera->get_camera_transform()); + // If there is an active listener in the scene, it takes priority over the camera + if (camera && !listener) + SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, camera->get_camera_transform()); #endif } @@ -1076,6 +1153,11 @@ Ref<World> Viewport::find_world() const{ return Ref<World>(); } +Listener* Viewport::get_listener() const { + + return listener; +} + Camera* Viewport::get_camera() const { return camera; @@ -1358,7 +1440,6 @@ void Viewport::_vp_unhandled_input(const InputEvent& p_ev) { if (disable_input) return; - #ifdef TOOLS_ENABLED if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { return; @@ -1493,22 +1574,29 @@ void Viewport::_gui_call_input(Control *p_control,const InputEvent& p_input) { // _block(); - while(p_control) { + CanvasItem *ci=p_control; + while(ci) { - p_control->call_multilevel(SceneStringNames::get_singleton()->_input_event,p_input); - if (gui.key_event_accepted) - break; - if (!p_control->is_inside_tree()) - break; - p_control->emit_signal(SceneStringNames::get_singleton()->input_event,p_input); - if (!p_control->is_inside_tree() || p_control->is_set_as_toplevel()) { - break; + Control *control = ci->cast_to<Control>(); + if (control) { + control->call_multilevel(SceneStringNames::get_singleton()->_input_event,p_input); + if (gui.key_event_accepted) + break; + if (!control->is_inside_tree()) + break; + control->emit_signal(SceneStringNames::get_singleton()->input_event,p_input); + if (!control->is_inside_tree() || control->is_set_as_toplevel()) + break; + if (gui.key_event_accepted) + break; + if (control->data.stop_mouse && (p_input.type==InputEvent::MOUSE_BUTTON || p_input.type==InputEvent::MOUSE_MOTION)) + break; } - if (gui.key_event_accepted) - break; - if (p_control->data.stop_mouse && (p_input.type==InputEvent::MOUSE_BUTTON || p_input.type==InputEvent::MOUSE_MOTION)) + + if (ci->is_set_as_toplevel()) break; - p_control=p_control->data.parent; + + ci=ci->get_parent_item(); } //_unblock(); @@ -1842,6 +1930,8 @@ void Viewport::_gui_input_event(InputEvent p_event) { if (gui.mouse_over) gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT); + _gui_cancel_tooltip(); + if (over) over->notification(Control::NOTIFICATION_MOUSE_ENTER); @@ -1849,8 +1939,6 @@ void Viewport::_gui_input_event(InputEvent p_event) { gui.mouse_over=over; - _gui_cancel_tooltip(); - if (gui.drag_preview) { gui.drag_preview->set_pos(mpos); } @@ -2407,7 +2495,7 @@ String Viewport::get_configuration_warning() const { if (get_parent() && !get_parent()->cast_to<Control>() && !render_target) { - return TTR("This viewport is not set as render target. If you intend for it to display it's contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign it's internal texture to some node for display."); + return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display."); } return String(); @@ -2540,12 +2628,13 @@ Viewport::Viewport() { world_2d = Ref<World2D>( memnew( World2D )); viewport = VisualServer::get_singleton()->viewport_create(); - listener=SpatialSoundServer::get_singleton()->listener_create(); + internal_listener = SpatialSoundServer::get_singleton()->listener_create(); audio_listener=false; - listener_2d=SpatialSound2DServer::get_singleton()->listener_create(); + internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create(); audio_listener_2d=false; transparent_bg=false; parent=NULL; + listener=NULL; camera=NULL; size_override=false; size_override_stretch=false; @@ -2593,8 +2682,8 @@ Viewport::Viewport() { Viewport::~Viewport() { VisualServer::get_singleton()->free( viewport ); - SpatialSoundServer::get_singleton()->free(listener); - SpatialSound2DServer::get_singleton()->free(listener_2d); + SpatialSoundServer::get_singleton()->free(internal_listener); + SpatialSound2DServer::get_singleton()->free(internal_listener_2d); if (render_target_texture.is_valid()) render_target_texture->vp=NULL; //so if used, will crash } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 6ae9e421eb..545020dfc7 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -39,6 +39,7 @@ */ class Camera; +class Listener; class Control; class CanvasItem; class Panel; @@ -92,6 +93,9 @@ friend class RenderTargetTexture; Control *parent_control; Viewport *parent; + Listener *listener; + Set<Listener*> listeners; + Camera *camera; Set<Camera*> cameras; @@ -100,10 +104,10 @@ friend class RenderTargetTexture; RID current_canvas; bool audio_listener; - RID listener; + RID internal_listener; bool audio_listener_2d; - RID listener_2d; + RID internal_listener_2d; Matrix32 canvas_transform; Matrix32 global_canvas_transform; @@ -263,6 +267,13 @@ friend class Control; Control *_gui_get_focus_owner(); +friend class Listener; + void _listener_transform_changed_notify(); + void _listener_set(Listener* p_listener); + bool _listener_add(Listener* p_listener); //true if first + void _listener_remove(Listener* p_listener); + void _listener_make_next_current(Listener* p_exclude); + friend class Camera; void _camera_transform_changed_notify(); void _camera_set(Camera* p_camera); @@ -276,7 +287,7 @@ protected: static void _bind_methods(); public: - + Listener* get_listener() const; Camera* get_camera() const; void set_as_audio_listener(bool p_enable); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 8327473a60..54b4ddca9e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -133,6 +133,7 @@ #include "scene/resources/mesh_data_tool.h" #include "scene/resources/scene_preloader.h" #include "scene/resources/dynamic_font.h" +#include "scene/resources/dynamic_font_stb.h" #include "scene/main/timer.h" @@ -192,6 +193,7 @@ #ifndef _3D_DISABLED #include "scene/3d/camera.h" +#include "scene/3d/listener.h" #include "scene/3d/interpolated_camera.h" #include "scene/3d/position_3d.h" @@ -254,7 +256,6 @@ void register_scene_types() { resource_loader_wav = memnew( ResourceFormatLoaderWAV ); ResourceLoader::add_resource_format_loader( resource_loader_wav ); - resource_loader_dynamic_font = memnew( ResourceFormatLoaderDynamicFont ); ResourceLoader::add_resource_format_loader( resource_loader_dynamic_font ); @@ -293,6 +294,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init + ObjectTypeDB::register_type<ShortCut>(); ObjectTypeDB::register_type<Control>(); // ObjectTypeDB::register_type<EmptyControl>(); ObjectTypeDB::add_compatibility_type("EmptyControl","Control"); @@ -386,6 +388,7 @@ void register_scene_types() { ObjectTypeDB::register_type<BoneAttachment>(); ObjectTypeDB::register_virtual_type<VisualInstance>(); ObjectTypeDB::register_type<Camera>(); + ObjectTypeDB::register_type<Listener>(); ObjectTypeDB::register_type<InterpolatedCamera>(); ObjectTypeDB::register_type<TestCube>(); ObjectTypeDB::register_type<MeshInstance>(); @@ -578,8 +581,10 @@ void register_scene_types() { ObjectTypeDB::register_type<Animation>(); ObjectTypeDB::register_virtual_type<Font>(); ObjectTypeDB::register_type<BitmapFont>(); + ObjectTypeDB::register_type<DynamicFontData>(); ObjectTypeDB::register_type<DynamicFont>(); + ObjectTypeDB::register_type<StyleBoxEmpty>(); ObjectTypeDB::register_type<StyleBoxTexture>(); ObjectTypeDB::register_type<StyleBoxFlat>(); @@ -647,6 +652,7 @@ void unregister_scene_types() { memdelete( resource_loader_image ); memdelete( resource_loader_wav ); memdelete( resource_loader_dynamic_font ); + #ifdef TOOLS_ENABLED diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index b245ea1542..e75a2aa332 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -36,6 +36,8 @@ class BitMap : public Resource { OBJ_TYPE(BitMap,Resource); + OBJ_SAVE_TYPE(BitMap); + RES_BASE_EXTENSION("pbm"); Vector<uint8_t> bitmask; int width; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 516156c315..88ff09e961 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -544,7 +544,7 @@ void Curve2D::_bake() const { List<Vector2> pointlist; pointlist.push_back(pos); //start always from origin - + for(int i=0;i<points.size()-1;i++) { float step = 0.1; // at least 10 substeps ought to be enough? diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 0c4d8ae841..9ebb7e7561 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -28,6 +28,7 @@ typedef Map<const void*,Ref<ImageTexture> > TexCacheMap; static TexCacheMap *tex_cache; +static int scale=1; template<class T> static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, float p_right, float p_botton,float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1, bool p_draw_center=true) { @@ -40,21 +41,24 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, flo } else { texture = Ref<ImageTexture>( memnew( ImageTexture ) ); - texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER ); + Image img(p_src); + if (scale>1) + img.expand_x2_hq2x(); + texture->create_from_image( img,ImageTexture::FLAG_FILTER ); (*tex_cache)[p_src]=texture; } Ref<StyleBoxTexture> style( memnew( StyleBoxTexture ) ); style->set_texture(texture); - style->set_margin_size( MARGIN_LEFT, p_left ); - style->set_margin_size( MARGIN_RIGHT, p_right ); - style->set_margin_size( MARGIN_BOTTOM, p_botton ); - style->set_margin_size( MARGIN_TOP, p_top ); - style->set_default_margin( MARGIN_LEFT, p_margin_left ); - style->set_default_margin( MARGIN_RIGHT, p_margin_right ); - style->set_default_margin( MARGIN_BOTTOM, p_margin_botton ); - style->set_default_margin( MARGIN_TOP, p_margin_top ); + style->set_margin_size( MARGIN_LEFT, p_left * scale); + style->set_margin_size( MARGIN_RIGHT, p_right * scale); + style->set_margin_size( MARGIN_BOTTOM, p_botton * scale); + style->set_margin_size( MARGIN_TOP, p_top * scale); + style->set_default_margin( MARGIN_LEFT, p_margin_left * scale); + style->set_default_margin( MARGIN_RIGHT, p_margin_right * scale); + style->set_default_margin( MARGIN_BOTTOM, p_margin_botton * scale); + style->set_default_margin( MARGIN_TOP, p_margin_top * scale); style->set_draw_center(p_draw_center); return style; @@ -63,10 +67,10 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, flo static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox,float p_left, float p_top, float p_right, float p_botton) { - p_sbox->set_expand_margin_size(MARGIN_LEFT,p_left); - p_sbox->set_expand_margin_size(MARGIN_TOP,p_top); - p_sbox->set_expand_margin_size(MARGIN_RIGHT,p_right); - p_sbox->set_expand_margin_size(MARGIN_BOTTOM,p_botton); + p_sbox->set_expand_margin_size(MARGIN_LEFT,p_left * scale); + p_sbox->set_expand_margin_size(MARGIN_TOP,p_top * scale); + p_sbox->set_expand_margin_size(MARGIN_RIGHT,p_right * scale); + p_sbox->set_expand_margin_size(MARGIN_BOTTOM,p_botton * scale); return p_sbox; } @@ -75,7 +79,10 @@ static Ref<Texture> make_icon(T p_src) { Ref<ImageTexture> texture( memnew( ImageTexture ) ); - texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER ); + Image img = Image(p_src); + if (scale>1) + img.expand_x2_hq2x(); + texture->create_from_image( img,ImageTexture::FLAG_FILTER ); return texture; } @@ -170,27 +177,24 @@ static Ref<StyleBox> make_empty_stylebox(float p_margin_left=-1, float p_margin_ Ref<StyleBox> style( memnew( StyleBoxEmpty) ); - style->set_default_margin( MARGIN_LEFT, p_margin_left ); - style->set_default_margin( MARGIN_RIGHT, p_margin_right ); - style->set_default_margin( MARGIN_BOTTOM, p_margin_botton ); - style->set_default_margin( MARGIN_TOP, p_margin_top ); + style->set_default_margin( MARGIN_LEFT, p_margin_left * scale); + style->set_default_margin( MARGIN_RIGHT, p_margin_right * scale); + style->set_default_margin( MARGIN_BOTTOM, p_margin_botton * scale); + style->set_default_margin( MARGIN_TOP, p_margin_top * scale); return style; } -#ifndef DEFAULT_THEME_DISABLED - -void make_default_theme() { +void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<Font> & large_font,Ref<Texture>& default_icon, Ref<StyleBox>& default_style,bool p_hidpi) { + if (p_hidpi) + scale=2; + else + scale=1; tex_cache = memnew( TexCacheMap ); - Ref<Theme> t( memnew( Theme ) ); - //Ref<BitmapFont> default_font = make_font(_bi_font_normal_height,_bi_font_normal_ascent,_bi_font_normal_valign,_bi_font_normal_charcount,_bi_font_normal_characters,make_icon(font_normal_png)); - Ref<BitmapFont> default_font=make_font2(_builtin_normal_font_height,_builtin_normal_font_ascent,_builtin_normal_font_charcount,&_builtin_normal_font_charrects[0][0],_builtin_normal_font_kerning_pair_count,&_builtin_normal_font_kerning_pairs[0][0],_builtin_normal_font_img_width,_builtin_normal_font_img_height,_builtin_normal_font_img_data); - Ref<BitmapFont> source_font=make_font2(_builtin_source_font_height,_builtin_source_font_ascent,_builtin_source_font_charcount,&_builtin_source_font_charrects[0][0],_builtin_source_font_kerning_pair_count,&_builtin_source_font_kerning_pairs[0][0],_builtin_source_font_img_width,_builtin_source_font_img_height,_builtin_source_font_img_data); - Ref<BitmapFont> large_font=make_font2(_builtin_large_font_height,_builtin_large_font_ascent,_builtin_large_font_charcount,&_builtin_large_font_charrects[0][0],_builtin_large_font_kerning_pair_count,&_builtin_large_font_kerning_pairs[0][0],_builtin_large_font_img_width,_builtin_large_font_img_height,_builtin_large_font_img_data); // Font Colors @@ -213,7 +217,7 @@ void make_default_theme() { Ref<StyleBoxTexture> focus = make_stylebox( focus_png,5,5,5,5); for(int i=0;i<4;i++) { - focus->set_expand_margin_size(Margin(i),1); + focus->set_expand_margin_size(Margin(i),1 *scale); } @@ -239,7 +243,7 @@ void make_default_theme() { t->set_color("font_color_hover","Button", control_font_color_hover ); t->set_color("font_color_disabled","Button", control_font_color_disabled ); - t->set_constant("hseparation","Button", 2); + t->set_constant("hseparation","Button", 2 *scale); // LinkButton @@ -249,7 +253,7 @@ void make_default_theme() { t->set_color("font_color_pressed","LinkButton", control_font_color_pressed ); t->set_color("font_color_hover","LinkButton", control_font_color_hover ); - t->set_constant("underline_spacing","LinkButton", 2 ); + t->set_constant("underline_spacing","LinkButton", 2 *scale); // ColorPickerButton @@ -266,16 +270,16 @@ void make_default_theme() { t->set_color("font_color_hover","ColorPickerButton", Color(1,1,1,1) ); t->set_color("font_color_disabled","ColorPickerButton", Color(0.9,0.9,0.9,0.3) ); - t->set_constant("hseparation","ColorPickerButton", 2 ); + t->set_constant("hseparation","ColorPickerButton", 2 *scale); // ToolButton Ref<StyleBox> tb_empty = memnew( StyleBoxEmpty ); - tb_empty->set_default_margin(MARGIN_LEFT,6); - tb_empty->set_default_margin(MARGIN_RIGHT,6); - tb_empty->set_default_margin(MARGIN_TOP,4); - tb_empty->set_default_margin(MARGIN_BOTTOM,4); + tb_empty->set_default_margin(MARGIN_LEFT,6 *scale); + tb_empty->set_default_margin(MARGIN_RIGHT,6 *scale); + tb_empty->set_default_margin(MARGIN_TOP,4 *scale); + tb_empty->set_default_margin(MARGIN_BOTTOM,4 *scale); t->set_stylebox("normal","ToolButton", tb_empty); t->set_stylebox("pressed","ToolButton", make_stylebox( button_pressed_png,4,4,4,4) ); @@ -316,8 +320,8 @@ void make_default_theme() { t->set_color("font_color_hover","OptionButton", control_font_color_hover ); t->set_color("font_color_disabled","OptionButton", control_font_color_disabled ); - t->set_constant("hseparation","OptionButton", 2 ); - t->set_constant("arrow_margin","OptionButton", 2 ); + t->set_constant("hseparation","OptionButton", 2 *scale); + t->set_constant("arrow_margin","OptionButton", 2 *scale); @@ -336,7 +340,7 @@ void make_default_theme() { t->set_color("font_color_hover","MenuButton", control_font_color_hover ); t->set_color("font_color_disabled","MenuButton", Color(1,1,1,0.3) ); - t->set_constant("hseparation","MenuButton", 3 ); + t->set_constant("hseparation","MenuButton", 3 *scale); // ButtonGroup @@ -345,15 +349,15 @@ void make_default_theme() { // CheckBox Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty ); - cbx_empty->set_default_margin(MARGIN_LEFT,22); - cbx_empty->set_default_margin(MARGIN_RIGHT,4); - cbx_empty->set_default_margin(MARGIN_TOP,4); - cbx_empty->set_default_margin(MARGIN_BOTTOM,5); + cbx_empty->set_default_margin(MARGIN_LEFT,22 *scale); + cbx_empty->set_default_margin(MARGIN_RIGHT,4 *scale); + cbx_empty->set_default_margin(MARGIN_TOP,4 *scale); + cbx_empty->set_default_margin(MARGIN_BOTTOM,5 *scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin(MARGIN_LEFT,4); - cbx_focus->set_default_margin(MARGIN_RIGHT,22); - cbx_focus->set_default_margin(MARGIN_TOP,4); - cbx_focus->set_default_margin(MARGIN_BOTTOM,5); + cbx_focus->set_default_margin(MARGIN_LEFT,4 *scale); + cbx_focus->set_default_margin(MARGIN_RIGHT,22 *scale); + cbx_focus->set_default_margin(MARGIN_TOP,4 *scale); + cbx_focus->set_default_margin(MARGIN_BOTTOM,5 *scale); t->set_stylebox("normal","CheckBox", cbx_empty ); t->set_stylebox("pressed","CheckBox", cbx_empty ); @@ -373,18 +377,18 @@ void make_default_theme() { t->set_color("font_color_hover","CheckBox", control_font_color_hover ); t->set_color("font_color_disabled","CheckBox", control_font_color_disabled ); - t->set_constant("hseparation","CheckBox",4); - t->set_constant("check_vadjust","CheckBox",0); + t->set_constant("hseparation","CheckBox",4 *scale); + t->set_constant("check_vadjust","CheckBox",0 *scale); // CheckButton Ref<StyleBox> cb_empty = memnew( StyleBoxEmpty ); - cb_empty->set_default_margin(MARGIN_LEFT,6); - cb_empty->set_default_margin(MARGIN_RIGHT,70); - cb_empty->set_default_margin(MARGIN_TOP,4); - cb_empty->set_default_margin(MARGIN_BOTTOM,4); + cb_empty->set_default_margin(MARGIN_LEFT,6 *scale); + cb_empty->set_default_margin(MARGIN_RIGHT,70 *scale); + cb_empty->set_default_margin(MARGIN_TOP,4 *scale); + cb_empty->set_default_margin(MARGIN_BOTTOM,4 *scale); t->set_stylebox("normal","CheckButton", cb_empty ); t->set_stylebox("pressed","CheckButton", cb_empty ); @@ -402,8 +406,8 @@ void make_default_theme() { t->set_color("font_color_hover","CheckButton", control_font_color_hover ); t->set_color("font_color_disabled","CheckButton", control_font_color_disabled ); - t->set_constant("hseparation","CheckButton",4); - t->set_constant("check_vadjust","CheckButton",0); + t->set_constant("hseparation","CheckButton",4 *scale); + t->set_constant("check_vadjust","CheckButton",0 *scale); @@ -414,10 +418,10 @@ void make_default_theme() { t->set_color("font_color","Label", Color(1,1,1) ); t->set_color("font_color_shadow","Label", Color(0,0,0,0) ); - t->set_constant("shadow_offset_x","Label", 1 ); - t->set_constant("shadow_offset_y","Label", 1 ); - t->set_constant("shadow_as_outline","Label", 0 ); - t->set_constant("line_spacing","Label", 3 ); + t->set_constant("shadow_offset_x","Label", 1 *scale); + t->set_constant("shadow_offset_y","Label", 1 *scale); + t->set_constant("shadow_as_outline","Label", 0 *scale); + t->set_constant("line_spacing","Label", 3 *scale); @@ -434,7 +438,7 @@ void make_default_theme() { t->set_color("cursor_color","LineEdit", control_font_color_hover ); t->set_color("selection_color","LineEdit", font_color_selection ); - t->set_constant("minimum_spaces","LineEdit", 12 ); + t->set_constant("minimum_spaces","LineEdit", 12 *scale); @@ -468,14 +472,14 @@ void make_default_theme() { t->set_color("mark_color","TextEdit", Color(1.0,0.4,0.4,0.4) ); t->set_color("breakpoint_color","TextEdit", Color(0.8,0.8,0.4,0.2) ); t->set_color("current_line_color","TextEdit", Color(0.25,0.25,0.26,0.8) ); - t->set_color("cursor_color","TextEdit", control_font_color ); + t->set_color("caret_color","TextEdit", control_font_color ); t->set_color("symbol_color","TextEdit", control_font_color_hover ); t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) ); t->set_constant("completion_lines","TextEdit", 7 ); t->set_constant("completion_max_width","TextEdit", 50 ); t->set_constant("completion_scroll_width","TextEdit", 3 ); - t->set_constant("line_spacing","TextEdit",4 ); + t->set_constant("line_spacing","TextEdit",4 *scale); Ref<Texture> empty_icon = memnew( ImageTexture ); @@ -555,10 +559,10 @@ void make_default_theme() { t->set_color("title_color","WindowDialog", Color(0,0,0) ); - t->set_constant("close_h_ofs","WindowDialog", 22 ); - t->set_constant("close_v_ofs","WindowDialog", 20 ); - t->set_constant("titlebar_height","WindowDialog", 18 ); - t->set_constant("title_height","WindowDialog", 20 ); + t->set_constant("close_h_ofs","WindowDialog", 22 *scale); + t->set_constant("close_v_ofs","WindowDialog", 20 *scale); + t->set_constant("titlebar_height","WindowDialog", 18 *scale); + t->set_constant("title_height","WindowDialog", 20 *scale); // File Dialog @@ -572,7 +576,7 @@ void make_default_theme() { Ref<StyleBoxTexture> selected = make_stylebox( selection_png,6,6,6,6); for(int i=0;i<4;i++) { - selected->set_expand_margin_size(Margin(i),2); + selected->set_expand_margin_size(Margin(i),2 *scale); } t->set_stylebox("panel","PopupPanel", style_pp ); @@ -598,8 +602,8 @@ void make_default_theme() { t->set_color("font_color_disabled","PopupMenu", Color(0.4,0.4,0.4,0.8) ); t->set_color("font_color_hover","PopupMenu", control_font_color ); - t->set_constant("hseparation","PopupMenu",4); - t->set_constant("vseparation","PopupMenu",4); + t->set_constant("hseparation","PopupMenu",4 *scale); + t->set_constant("vseparation","PopupMenu",4 *scale); // GraphNode @@ -614,14 +618,14 @@ void make_default_theme() { t->set_stylebox("selectedframe","GraphNode", graphsbselected ); t->set_stylebox("defaultframe", "GraphNode", graphsbdefault ); t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus ); - t->set_constant("separation","GraphNode", 1 ); + t->set_constant("separation","GraphNode", 1 *scale); t->set_icon("port","GraphNode", make_icon( graph_port_png ) ); t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) ); t->set_font("title_font","GraphNode", default_font ); t->set_color("title_color","GraphNode", Color(0,0,0,1)); - t->set_constant("title_offset","GraphNode", 18); - t->set_constant("close_offset","GraphNode", 18); - t->set_constant("port_offset","GraphNode", 3); + t->set_constant("title_offset","GraphNode", 18 *scale); + t->set_constant("close_offset","GraphNode", 18 *scale); + t->set_constant("port_offset","GraphNode", 3 *scale); // Tree @@ -658,11 +662,11 @@ void make_default_theme() { t->set_color("guide_color","Tree", Color(0,0,0,0.1) ); t->set_color("drop_position_color","Tree", Color(1,0.3,0.2) ); - t->set_constant("hseparation","Tree",4); - t->set_constant("vseparation","Tree",4); - t->set_constant("guide_width","Tree",2); - t->set_constant("item_margin","Tree",12); - t->set_constant("button_margin","Tree",4); + t->set_constant("hseparation","Tree",4 *scale); + t->set_constant("vseparation","Tree",4 *scale); + t->set_constant("guide_width","Tree",2 *scale); + t->set_constant("item_margin","Tree",12 *scale); + t->set_constant("button_margin","Tree",4 *scale); // ItemList @@ -674,7 +678,7 @@ void make_default_theme() { t->set_constant("hseparation","ItemList",4); t->set_constant("vseparation","ItemList",2); t->set_constant("icon_margin","ItemList",4); - t->set_constant("line_separation","ItemList",2); + t->set_constant("line_separation","ItemList",2 *scale); t->set_font("font","ItemList", default_font ); t->set_color("font_color","ItemList", control_font_color_lower ); t->set_color("font_color_selected","ItemList", control_font_color_pressed ); @@ -695,8 +699,8 @@ void make_default_theme() { Ref<StyleBoxTexture> tc_sb = sb_expand( make_stylebox( tab_container_bg_png,4,4,4,4,4,4,4,4),3,3,3,3); - tc_sb->set_expand_margin_size(MARGIN_TOP,2); - tc_sb->set_default_margin(MARGIN_TOP,8); + tc_sb->set_expand_margin_size(MARGIN_TOP,2 *scale); + tc_sb->set_default_margin(MARGIN_TOP,8 *scale); t->set_stylebox("tab_fg","TabContainer", sb_expand( make_stylebox( tab_current_png,4,4,4,1,16,4,16,4),2,2,2,2) ); t->set_stylebox("tab_bg","TabContainer", sb_expand( make_stylebox( tab_behind_png,5,5,5,1,16,6,16,4),3,0,3,3) ); @@ -714,11 +718,11 @@ void make_default_theme() { t->set_color("font_color_fg","TabContainer", control_font_color_hover ); t->set_color("font_color_bg","TabContainer", control_font_color_low ); - t->set_constant("side_margin","TabContainer", 8 ); - t->set_constant("top_margin","TabContainer", 24); - t->set_constant("label_valign_fg","TabContainer", 0); - t->set_constant("label_valign_bg","TabContainer", 2); - t->set_constant("hseparation","TabContainer", 4); + t->set_constant("side_margin","TabContainer", 8 *scale); + t->set_constant("top_margin","TabContainer", 24 *scale); + t->set_constant("label_valign_fg","TabContainer", 0 *scale); + t->set_constant("label_valign_bg","TabContainer", 2 *scale); + t->set_constant("hseparation","TabContainer", 4 *scale); @@ -741,10 +745,10 @@ void make_default_theme() { t->set_color("font_color_fg","Tabs", control_font_color_hover ); t->set_color("font_color_bg","Tabs", control_font_color_low ); - t->set_constant("top_margin","Tabs", 24); - t->set_constant("label_valign_fg","Tabs", 0); - t->set_constant("label_valign_bg","Tabs", 2); - t->set_constant("hseparation","Tabs", 4); + t->set_constant("top_margin","Tabs", 24 *scale); + t->set_constant("label_valign_fg","Tabs", 0 *scale); + t->set_constant("label_valign_bg","Tabs", 2 *scale); + t->set_constant("hseparation","Tabs", 4 *scale); @@ -754,18 +758,17 @@ void make_default_theme() { t->set_stylebox("separator","VSeparator", make_stylebox( hseparator_png,3,3,3,3) ); t->set_icon("close","Icons", make_icon(icon_close_png)); - t->set_font("source","Fonts", source_font); t->set_font("normal","Fonts", default_font ); t->set_font("large","Fonts", large_font ); - t->set_constant("separation","HSeparator", 4); - t->set_constant("separation","VSeparator", 4); + t->set_constant("separation","HSeparator", 4 *scale); + t->set_constant("separation","VSeparator", 4 *scale); // Dialogs - t->set_constant("margin","Dialogs",8); - t->set_constant("button_margin","Dialogs",32); + t->set_constant("margin","Dialogs",8 *scale); + t->set_constant("button_margin","Dialogs",32 *scale); @@ -778,11 +781,11 @@ void make_default_theme() { // colorPicker - t->set_constant("value_height","ColorPicker", 23 ); - t->set_constant("value_width","ColorPicker", 50); - t->set_constant("color_width","ColorPicker", 100); - t->set_constant("label_width","ColorPicker", 20); - t->set_constant("hseparator","ColorPicker", 4); + t->set_constant("value_height","ColorPicker", 23 *scale); + t->set_constant("value_width","ColorPicker", 50 *scale); + t->set_constant("color_width","ColorPicker", 100 *scale); + t->set_constant("label_width","ColorPicker", 20 *scale); + t->set_constant("hseparator","ColorPicker", 4 *scale); t->set_icon("screen_picker","ColorPicker", make_icon( icon_color_pick_png ) ); t->set_icon("add_preset","ColorPicker", make_icon( icon_add_png ) ); @@ -794,7 +797,7 @@ void make_default_theme() { Ref<StyleBoxTexture> style_tt = make_stylebox( tooltip_bg_png,4,4,4,4); for(int i=0;i<4;i++) - style_tt->set_expand_margin_size((Margin)i,4); + style_tt->set_expand_margin_size((Margin)i,4 *scale); t->set_stylebox("panel","TooltipPanel", style_tt ); @@ -822,9 +825,9 @@ void make_default_theme() { t->set_color("font_color_selected","RichTextLabel", font_color_selection ); t->set_color("selection_color","RichTextLabel", Color(0.1,0.1,1,0.8) ); - t->set_constant("line_separation","RichTextLabel", 1 ); - t->set_constant("table_hseparation","RichTextLabel", 3 ); - t->set_constant("table_vseparation","RichTextLabel", 3 ); + t->set_constant("line_separation","RichTextLabel", 1 *scale); + t->set_constant("table_hseparation","RichTextLabel", 3 *scale); + t->set_constant("table_vseparation","RichTextLabel", 3 *scale); @@ -836,18 +839,18 @@ void make_default_theme() { t->set_icon("grabber","VSplitContainer",make_icon(vsplitter_png)); t->set_icon("grabber","HSplitContainer",make_icon(hsplitter_png)); - t->set_constant("separation","HBoxContainer",4); - t->set_constant("separation","VBoxContainer",4); - t->set_constant("margin_left","MarginContainer",8); - t->set_constant("margin_top","MarginContainer",0); - t->set_constant("margin_right","MarginContainer",0); - t->set_constant("margin_bottom","MarginContainer",0); - t->set_constant("hseparation","GridContainer",4); - t->set_constant("vseparation","GridContainer",4); - t->set_constant("separation","HSplitContainer",12); - t->set_constant("separation","VSplitContainer",12); - t->set_constant("autohide","HSplitContainer",1); - t->set_constant("autohide","VSplitContainer",1); + t->set_constant("separation","HBoxContainer",4 *scale); + t->set_constant("separation","VBoxContainer",4 *scale); + t->set_constant("margin_left","MarginContainer",8 *scale); + t->set_constant("margin_top","MarginContainer",0 *scale); + t->set_constant("margin_right","MarginContainer",0 *scale); + t->set_constant("margin_bottom","MarginContainer",0 *scale); + t->set_constant("hseparation","GridContainer",4 *scale); + t->set_constant("vseparation","GridContainer",4 *scale); + t->set_constant("separation","HSplitContainer",12 *scale); + t->set_constant("separation","VSplitContainer",12 *scale); + t->set_constant("autohide","HSplitContainer",1 *scale); + t->set_constant("autohide","VSplitContainer",1 *scale); @@ -863,8 +866,8 @@ void make_default_theme() { t->set_color("font_color","HButtonArray", control_font_color_low ); t->set_color("font_color_selected","HButtonArray", control_font_color_hover ); - t->set_constant("icon_separator","HButtonArray", 4 ); - t->set_constant("button_separator","HButtonArray", 8 ); + t->set_constant("icon_separator","HButtonArray", 4 *scale ); + t->set_constant("button_separator","HButtonArray", 8 *scale ); t->set_stylebox("focus","HButtonArray", focus ); @@ -881,8 +884,8 @@ void make_default_theme() { t->set_color("font_color","VButtonArray", control_font_color_low ); t->set_color("font_color_selected","VButtonArray", control_font_color_hover ); - t->set_constant("icon_separator","VButtonArray", 4); - t->set_constant("button_separator","VButtonArray", 8); + t->set_constant("icon_separator","VButtonArray", 4 *scale); + t->set_constant("button_separator","VButtonArray", 8 *scale); t->set_stylebox("focus","VButtonArray", focus ); @@ -914,45 +917,31 @@ void make_default_theme() { // Theme - Theme::set_default( t ); - Theme::set_default_icon( make_icon(error_icon_png) ); - Theme::set_default_style( make_stylebox( error_icon_png,2,2,2,2) ); - Theme::set_default_font( default_font ); + default_icon= make_icon(error_icon_png) ; + default_style = make_stylebox( error_icon_png,2,2,2,2) ; memdelete( tex_cache ); } -#else - -#include "error_icon.xpm" - void make_default_theme() { - Ref<Theme> t( memnew( Theme ) ); - + Ref<Theme> t; + t.instance(); - Image error_img(error_icon_xpm); - Ref<Texture> texture( memnew( Texture ) ); - texture->create_from_image( error_img ); - - Ref<StyleBoxTexture> style( memnew( StyleBoxTexture ) ); - style->set_texture(texture); - - for(int i=0;i<4;i++) { - style->set_margin_size( Margin(),8); - style->set_default_margin( Margin(),8); - } + Ref<StyleBox> default_style; + Ref<Texture> default_icon; + Ref<BitmapFont> default_font=make_font2(_builtin_normal_font_height,_builtin_normal_font_ascent,_builtin_normal_font_charcount,&_builtin_normal_font_charrects[0][0],_builtin_normal_font_kerning_pair_count,&_builtin_normal_font_kerning_pairs[0][0],_builtin_normal_font_img_width,_builtin_normal_font_img_height,_builtin_normal_font_img_data); + Ref<BitmapFont> large_font=make_font2(_builtin_large_font_height,_builtin_large_font_ascent,_builtin_large_font_charcount,&_builtin_large_font_charrects[0][0],_builtin_large_font_kerning_pair_count,&_builtin_large_font_kerning_pairs[0][0],_builtin_large_font_img_width,_builtin_large_font_img_height,_builtin_large_font_img_data); + fill_default_theme(t,default_font,large_font,default_icon,default_style,false); - Ref<BitmapFont> f = make_default_font(); Theme::set_default( t ); - Theme::set_default_icon( texture ); - Theme::set_default_style( style ); - Theme::set_default_font( f ); + Theme::set_default_icon( default_icon ); + Theme::set_default_style( default_style ); + Theme::set_default_font( default_font ); } -#endif void clear_default_theme() { Theme::set_default( Ref<Theme>() ); diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 44569ba192..1e3b4b4081 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -12,10 +12,12 @@ #ifndef DEFAULT_THEME_H #define DEFAULT_THEME_H +#include "scene/resources/theme.h" /** @author Juan Linietsky <reduzio@gmail.com> */ +void fill_default_theme(Ref<Theme>& theme,const Ref<Font> & default_font,const Ref<Font> & large_font,Ref<Texture>& default_icon, Ref<StyleBox>& default_style,bool p_hidpi); void make_default_theme(); void clear_default_theme(); diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 19aa0e79cc..78a5571bf0 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -1,65 +1,11 @@ +#ifdef FREETYPE_ENABLED #include "dynamic_font.h" -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" #include "os/file_access.h" -void DynamicFontData::lock() { - fr=font_data.read(); - - if (fr.ptr()!=last_data_ptr) { - - last_data_ptr=fr.ptr(); - - if (!stbtt_InitFont(&info, last_data_ptr, 0)) { - valid=false; - } else { - valid=true; - } - - last_data_ptr=fr.ptr(); - } -} - -void DynamicFontData::unlock() { - - fr = DVector<uint8_t>::Read(); -} - -void DynamicFontData::set_font_data(const DVector<uint8_t>& p_font) { - //clear caches and stuff - ERR_FAIL_COND(font_data.size()) ; - font_data=p_font; - - lock(); - - if (valid) { - stbtt_GetFontVMetrics(&info, &ascent, &descent, &linegap); - descent=-descent + linegap; - - for(int i=32;i<1024;i++) { - for(int j=32;j<1024;j++) { - - int kern = stbtt_GetCodepointKernAdvance(&info, i,j); - if (kern!=0) { - KerningPairKey kpk; - kpk.A=i; - kpk.B=j; - kerning_map[kpk]=kern; - } - } - } - } - - unlock(); - //clear existing stuff - - ERR_FAIL_COND(!valid); -} Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { - ERR_FAIL_COND_V(!valid,Ref<DynamicFontAtSize>()); if (size_cache.has(p_size)) { return Ref<DynamicFontAtSize>( size_cache[p_size] ); @@ -67,6 +13,7 @@ Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { Ref<DynamicFontAtSize> dfas; + dfas.instance(); dfas->font=Ref<DynamicFontData>( this ); @@ -74,21 +21,34 @@ Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { size_cache[p_size]=dfas.ptr(); dfas->size=p_size; + dfas->_load(); - lock(); + return dfas; - dfas->scale = stbtt_ScaleForPixelHeight(&info, p_size); +} - unlock(); +void DynamicFontData::set_font_ptr(const uint8_t* p_font_mem,int p_font_mem_size) { - return dfas; + font_mem=p_font_mem; + font_mem_size=p_font_mem_size; +} +void DynamicFontData::set_font_path(const String& p_path) { + + font_path=p_path; +} + +void DynamicFontData::set_force_autohinter(bool p_force) { + + force_autohinter=p_force; } DynamicFontData::DynamicFontData() { - last_data_ptr=NULL; - valid=false; + + force_autohinter=false; + font_mem=NULL; + font_mem_size=0; } DynamicFontData::~DynamicFontData() @@ -100,79 +60,291 @@ DynamicFontData::~DynamicFontData() //////////////////// +Error DynamicFontAtSize::_load() { + + + int error = FT_Init_FreeType( &library ); + + ERR_EXPLAIN(TTR("Error initializing FreeType.")); + ERR_FAIL_COND_V( error !=0, ERR_CANT_CREATE ); + + if (font->font_path!=String()) { + + FileAccess *f=FileAccess::open(font->font_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + + memset(&stream,0,sizeof(FT_StreamRec)); + stream.base=NULL; + stream.size=f->get_len(); + stream.pos=0; + stream.descriptor.pointer=f; + stream.read=_ft_stream_io; + stream.close=_ft_stream_close; + + FT_Open_Args fargs; + memset(&fargs,0,sizeof(FT_Open_Args)); + fargs.flags=FT_OPEN_STREAM; + fargs.stream=&stream; + error = FT_Open_Face( library,&fargs,0,&face); + } else if (font->font_mem) { + + memset(&stream,0,sizeof(FT_StreamRec)); + stream.base=(unsigned char*)font->font_mem; + stream.size=font->font_mem_size; + stream.pos=0; + + FT_Open_Args fargs; + memset(&fargs,0,sizeof(FT_Open_Args)); + fargs.memory_base=(unsigned char*)font->font_mem; + fargs.memory_size=font->font_mem_size; + fargs.flags= FT_OPEN_MEMORY; + fargs.stream=&stream; + error = FT_Open_Face( library,&fargs,0,&face); + + } else { + ERR_EXPLAIN("DynamicFont uninitialized"); + ERR_FAIL_V(ERR_UNCONFIGURED); + } + + //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); + + if ( error == FT_Err_Unknown_File_Format ) { + ERR_EXPLAIN(TTR("Unknown font format.")); + FT_Done_FreeType( library ); + + } else if ( error ) { + + ERR_EXPLAIN(TTR("Error loading font.")); + FT_Done_FreeType( library ); + + } + + ERR_FAIL_COND_V(error,ERR_FILE_CANT_OPEN); + + + /*error = FT_Set_Char_Size(face,0,64*size,512,512); + + if ( error ) { + FT_Done_FreeType( library ); + ERR_EXPLAIN(TTR("Invalid font size.")); + ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); + }*/ + + error = FT_Set_Pixel_Sizes(face,0,size); + + ascent=face->size->metrics.ascender>>6; + descent=-face->size->metrics.descender>>6; + linegap=0; + + //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); + + valid=true; + return OK; +} + float DynamicFontAtSize::get_height() const { - return (font->ascent+font->descent)*scale; + return ascent+descent; } float DynamicFontAtSize::get_ascent() const { - return font->ascent*scale; + return ascent; } float DynamicFontAtSize::get_descent() const { - return font->descent*scale; + return descent; } -Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next) const { +Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const { + if (!valid) + return Size2(1,1); const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); const Character *c = char_map.getptr(p_char); ERR_FAIL_COND_V(!c,Size2()); - Size2 ret( c->advance, get_height()); + Size2 ret(0,get_height()); + + if (!c->found) { + + //not found, try in fallbacks + for(int i=0;i<p_fallbacks.size();i++) { + + DynamicFontAtSize *fb = const_cast<DynamicFontAtSize*>(p_fallbacks[i].ptr()); + if (!fb->valid) + continue; + + fb->_update_char(p_char); + const Character *ch = fb->char_map.getptr(p_char); + ERR_CONTINUE(!ch); + + if (!ch->found) + continue; + + c=ch; + break; + } + //not found, try 0xFFFD to display 'not found'. + + if (!c->found) { + + const_cast<DynamicFontAtSize*>(this)->_update_char(0xFFFD); + c = char_map.getptr(0xFFFD); + ERR_FAIL_COND_V(!c,Size2()); + + } + } + + if (c->found) { + ret.x=c->advance; + } + if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A=p_char; - kpk.B=p_next; + FT_Vector delta; + FT_Get_Kerning( face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + + if (delta.x==0) { + for(int i=0;i<p_fallbacks.size();i++) { + + DynamicFontAtSize *fb = const_cast<DynamicFontAtSize*>(p_fallbacks[i].ptr()); + if (!fb->valid) + continue; - const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); - if (K) { - ret.x+=K->get()*scale; + FT_Get_Kerning( fb->face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + + if (delta.x==0) + continue; + + ret.x+=delta.x>>6; + break; + } + } else { + ret.x+=delta.x>>6; } + } return ret; } -float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate) const { +float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const { + + if (!valid) + return 0; const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); const Character * c = char_map.getptr(p_char); - if (!c) { - return 0; + float advance=0; + + if (!c->found) { + + //not found, try in fallbacks + bool used_fallback=false; + + for(int i=0;i<p_fallbacks.size();i++) { + + DynamicFontAtSize *fb = const_cast<DynamicFontAtSize*>(p_fallbacks[i].ptr()); + if (!fb->valid) + continue; + + fb->_update_char(p_char); + const Character *ch = fb->char_map.getptr(p_char); + ERR_CONTINUE(!ch); + + if (!ch->found) + continue; + + Point2 cpos=p_pos; + cpos.x+=ch->h_align; + cpos.y-=get_ascent(); + cpos.y+=ch->v_align; + ERR_FAIL_COND_V( ch->texture_idx<-1 || ch->texture_idx>=fb->textures.size(),0); + if (ch->texture_idx!=-1) + VisualServer::get_singleton()->canvas_item_add_texture_rect_region( p_canvas_item, Rect2( cpos, ch->rect.size ), fb->textures[ch->texture_idx].texture->get_rid(),ch->rect, p_modulate ); + advance=ch->advance; + used_fallback=true; + break; + } + //not found, try 0xFFFD to display 'not found'. + + if (!used_fallback) { + + const_cast<DynamicFontAtSize*>(this)->_update_char(0xFFFD); + c = char_map.getptr(0xFFFD); + + } } - Point2 cpos=p_pos; - cpos.x+=c->h_align; - cpos.y-=get_ascent(); - cpos.y+=c->v_align; - ERR_FAIL_COND_V( c->texture_idx<-1 || c->texture_idx>=textures.size(),0); - if (c->texture_idx!=-1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region( p_canvas_item, Rect2( cpos, c->rect.size ), textures[c->texture_idx].texture->get_rid(),c->rect, p_modulate ); + if (c->found) { + + + Point2 cpos=p_pos; + cpos.x+=c->h_align; + cpos.y-=get_ascent(); + cpos.y+=c->v_align; + ERR_FAIL_COND_V( c->texture_idx<-1 || c->texture_idx>=textures.size(),0); + if (c->texture_idx!=-1) + VisualServer::get_singleton()->canvas_item_add_texture_rect_region( p_canvas_item, Rect2( cpos, c->rect.size ), textures[c->texture_idx].texture->get_rid(),c->rect, p_modulate ); + advance=c->advance; + //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); + } - //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); - float ret = c->advance; if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A=p_char; - kpk.B=p_next; - const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); - if (K) { - ret+=K->get()*scale; + FT_Vector delta; + FT_Get_Kerning( face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + + if (delta.x==0) { + for(int i=0;i<p_fallbacks.size();i++) { + + DynamicFontAtSize *fb = const_cast<DynamicFontAtSize*>(p_fallbacks[i].ptr()); + if (!fb->valid) + continue; + + FT_Get_Kerning( fb->face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + + if (delta.x==0) + continue; + + advance+=delta.x>>6; + break; + } + } else { + advance+=delta.x>>6; } + } + + return advance; +} + +unsigned long DynamicFontAtSize::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count ) { + + + FileAccess *f=(FileAccess*)stream->descriptor.pointer; + + if (f->get_pos()!=offset) { + f->seek(offset); } - return ret; + if (count==0) + return 0; + + return f->get_buffer(buffer,count); +} +void DynamicFontAtSize::_ft_stream_close(FT_Stream stream) { + + FileAccess *f=(FileAccess*)stream->descriptor.pointer; + f->close(); + memdelete(f); } @@ -181,38 +353,59 @@ void DynamicFontAtSize::_update_char(CharType p_char) { if (char_map.has(p_char)) return; - font->lock(); + _THREAD_SAFE_METHOD_ + FT_GlyphSlot slot = face->glyph; - int w,h,xofs,yofs; - unsigned char * cpbitmap = stbtt_GetCodepointBitmap(&font->info, scale, scale, p_char, &w, &h, &xofs, &yofs ); + if (FT_Get_Char_Index( face, p_char)==0) { + //not found + Character ch; + ch.texture_idx=-1; + ch.advance=0; + ch.h_align=0; + ch.v_align=0; + ch.found=false; - if (!cpbitmap) { - //no glyph + char_map[p_char]=ch; + return; + } + int error = FT_Load_Char( face, p_char, FT_LOAD_RENDER|(font->force_autohinter?FT_LOAD_FORCE_AUTOHINT:0) ); + if (!error) { + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + } + if (error) { - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); + int advance=0; + //stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale)); Character ch; ch.texture_idx=-1; - ch.advance=advance*scale; + ch.advance=advance; ch.h_align=0; ch.v_align=0; + ch.found=false; char_map[p_char]=ch; - font->unlock(); return; } + + + int w = slot->bitmap.width; + int h = slot->bitmap.rows; + int p = slot->bitmap.pitch; + int yofs=slot->bitmap_top; + int xofs=slot->bitmap_left; + int advance=slot->advance.x>>6; + + int mw=w+rect_margin*2; int mh=h+rect_margin*2; if (mw>4096 || mh>4096) { - stbtt_FreeBitmap(cpbitmap,NULL); - font->unlock(); ERR_FAIL_COND(mw>4096); ERR_FAIL_COND(mh>4096); } @@ -304,13 +497,14 @@ void DynamicFontAtSize::_update_char(CharType p_char) { { DVector<uint8_t>::Write wr = tex.imgdata.write(); + for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { int ofs = ( (i+tex_y+rect_margin)*tex.texture_size+j+tex_x+rect_margin)*2; ERR_FAIL_COND(ofs >= tex.imgdata.size()); wr[ofs+0]=255; //grayscale as 1 - wr[ofs+1]=cpbitmap[i*w+j]; //alpha as 0 + wr[ofs+1]=slot->bitmap.buffer[i*slot->bitmap.width+j]; } } } @@ -322,7 +516,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) { if (tex.texture.is_null()) { tex.texture.instance(); - tex.texture->create_from_image(img,Texture::FLAG_FILTER); + tex.texture->create_from_image(img,0/*Texture::FLAG_FILTER*/); } else { tex.texture->set_data(img); //update } @@ -337,14 +531,13 @@ void DynamicFontAtSize::_update_char(CharType p_char) { tex.offsets[k]=tex_y+mh; } - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); Character chr; chr.h_align=xofs; - chr.v_align=yofs + get_ascent(); - chr.advance=advance*scale; + chr.v_align=ascent-yofs;// + ascent - descent; + chr.advance=advance; chr.texture_idx=tex_index; + chr.found=true; chr.rect=Rect2(tex_x+rect_margin,tex_y+rect_margin,w,h); @@ -353,45 +546,38 @@ void DynamicFontAtSize::_update_char(CharType p_char) { char_map[p_char]=chr; - stbtt_FreeBitmap(cpbitmap,NULL); - - font->unlock(); } DynamicFontAtSize::DynamicFontAtSize() { + valid=false; rect_margin=1; + ascent=1; + descent=1; + linegap=1; } DynamicFontAtSize::~DynamicFontAtSize(){ - ERR_FAIL_COND(!font.ptr()); - font->size_cache.erase(size); + if (valid) { + FT_Done_FreeType( library ); + font->size_cache.erase(size); + } } ///////////////////////// -void DynamicFont::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_font_data","data:DynamicFontData"),&DynamicFont::set_font_data); - ObjectTypeDB::bind_method(_MD("get_font_data:DynamicFontData"),&DynamicFont::get_font_data); - - ObjectTypeDB::bind_method(_MD("set_size","data"),&DynamicFont::set_size); - ObjectTypeDB::bind_method(_MD("get_size"),&DynamicFont::get_size); - - ADD_PROPERTY(PropertyInfo(Variant::INT,"size"),_SCS("set_size"),_SCS("get_size")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"font",PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData"),_SCS("set_font_data"),_SCS("get_font_data")); -} - void DynamicFont::set_font_data(const Ref<DynamicFontData>& p_data) { data=p_data; data_at_size=data->_get_dynamic_font_at_size(size); + emit_changed(); } + Ref<DynamicFontData> DynamicFont::get_font_data() const{ return data; @@ -406,7 +592,12 @@ void DynamicFont::set_size(int p_size){ if (!data.is_valid()) return; data_at_size=data->_get_dynamic_font_at_size(size); + for(int i=0;i<fallbacks.size();i++) { + fallback_data_at_size[i]=fallbacks[i]->_get_dynamic_font_at_size(size); + } + emit_changed(); + _change_notify(); } int DynamicFont::get_size() const{ @@ -443,7 +634,7 @@ Size2 DynamicFont::get_char_size(CharType p_char,CharType p_next) const{ if (!data_at_size.is_valid()) return Size2(1,1); - return data_at_size->get_char_size(p_char,p_next); + return data_at_size->get_char_size(p_char,p_next,fallback_data_at_size); } @@ -457,10 +648,120 @@ float DynamicFont::draw_char(RID p_canvas_item, const Point2& p_pos, const CharT if (!data_at_size.is_valid()) return 0; - return data_at_size->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate); + return data_at_size->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate,fallback_data_at_size); + +} +void DynamicFont::set_fallback(int p_idx,const Ref<DynamicFontData>& p_data) { + + ERR_FAIL_COND(p_data.is_null()); + ERR_FAIL_INDEX(p_idx,fallbacks.size()); + fallbacks[p_idx]=p_data; + fallback_data_at_size[p_idx]=fallbacks[p_idx]->_get_dynamic_font_at_size(size); } +void DynamicFont::add_fallback(const Ref<DynamicFontData>& p_data) { + + ERR_FAIL_COND(p_data.is_null()); + fallbacks.push_back(p_data); + fallback_data_at_size.push_back(fallbacks[fallbacks.size()-1]->_get_dynamic_font_at_size(size)); //const.. + + _change_notify(); + emit_changed(); + _change_notify(); + +} + +int DynamicFont::get_fallback_count() const { + return fallbacks.size(); +} +Ref<DynamicFontData> DynamicFont::get_fallback(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,fallbacks.size(),Ref<DynamicFontData>()); + + return fallbacks[p_idx]; +} +void DynamicFont::remove_fallback(int p_idx) { + + ERR_FAIL_INDEX(p_idx,fallbacks.size()); + fallbacks.remove(p_idx); + fallback_data_at_size.remove(p_idx); + emit_changed(); + _change_notify(); +} + +bool DynamicFont::_set(const StringName& p_name, const Variant& p_value) { + + String str = p_name; + if (str.begins_with("fallback/")) { + int idx = str.get_slicec('/',1).to_int(); + Ref<DynamicFontData> fd = p_value; + + if (fd.is_valid()) { + if (idx==fallbacks.size()) { + add_fallback(fd); + return true; + } else if (idx>=0 && idx<fallbacks.size()) { + set_fallback(idx,fd); + return true; + } else { + return false; + } + } else if (idx>=0 && idx<fallbacks.size()) { + remove_fallback(idx); + return true; + } + } + + return false; +} + +bool DynamicFont::_get(const StringName& p_name,Variant &r_ret) const{ + + String str = p_name; + if (str.begins_with("fallback/")) { + int idx = str.get_slicec('/',1).to_int(); + + if (idx==fallbacks.size()) { + r_ret=Ref<DynamicFontData>(); + return true; + } else if (idx>=0 && idx<fallbacks.size()) { + r_ret=get_fallback(idx); + return true; + } + } + + return false; +} +void DynamicFont::_get_property_list( List<PropertyInfo> *p_list) const{ + + for(int i=0;i<fallbacks.size();i++) { + p_list->push_back(PropertyInfo(Variant::OBJECT,"fallback/"+itos(i),PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData")); + } + + p_list->push_back(PropertyInfo(Variant::OBJECT,"fallback/"+itos(fallbacks.size()),PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData")); +} + + +void DynamicFont::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_font_data","data:DynamicFontData"),&DynamicFont::set_font_data); + ObjectTypeDB::bind_method(_MD("get_font_data:DynamicFontData"),&DynamicFont::get_font_data); + + ObjectTypeDB::bind_method(_MD("set_size","data"),&DynamicFont::set_size); + ObjectTypeDB::bind_method(_MD("get_size"),&DynamicFont::get_size); + + ObjectTypeDB::bind_method(_MD("add_fallback","data:DynamicFontData"),&DynamicFont::add_fallback); + ObjectTypeDB::bind_method(_MD("set_fallback","idx","data:DynamicFontData"),&DynamicFont::set_fallback); + ObjectTypeDB::bind_method(_MD("get_fallback:DynamicFontData","idx"),&DynamicFont::get_fallback); + ObjectTypeDB::bind_method(_MD("remove_fallback","idx"),&DynamicFont::remove_fallback); + ObjectTypeDB::bind_method(_MD("get_fallback_count"),&DynamicFont::get_fallback_count); + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"font/size"),_SCS("set_size"),_SCS("get_size")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"font/font",PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData"),_SCS("set_font_data"),_SCS("get_font_data")); +} + DynamicFont::DynamicFont() { size=16; @@ -478,34 +779,21 @@ RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String& p_ if (r_error) *r_error=ERR_FILE_CANT_OPEN; + Ref<DynamicFontData> dfont; + dfont.instance();; + dfont->set_font_path(p_path); - FileAccess *f = FileAccess::open(p_path,FileAccess::READ); - ERR_FAIL_COND_V(!f,RES()); - - DVector<uint8_t> data; - - data.resize(f->get_len()); - - ERR_FAIL_COND_V(data.size()==0,RES()); - - { - DVector<uint8_t>::Write w = data.write(); - f->get_buffer(w.ptr(),data.size()); - } - - Ref<DynamicFontData> dfd; - dfd.instance(); - dfd->set_font_data(data); if (r_error) *r_error=OK; - return dfd; + return dfont; } void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("ttf"); + p_extensions->push_back("otf"); } bool ResourceFormatLoaderDynamicFont::handles_type(const String& p_type) const { @@ -516,8 +804,10 @@ bool ResourceFormatLoaderDynamicFont::handles_type(const String& p_type) const { String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const { String el = p_path.extension().to_lower(); - if (el=="ttf") + if (el=="ttf" || el=="otf") return "DynamicFontData"; return ""; } + +#endif diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index ba7249a7b7..1a46e1e468 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -1,10 +1,14 @@ -#ifndef DYNAMICFONT_H -#define DYNAMICFONT_H +#ifndef DYNAMIC_FONT_H +#define DYNAMIC_FONT_H -#include "font.h" -#include "stb_truetype.h" +#ifdef FREETYPE_ENABLED +#include "scene/resources/font.h" +#include "os/thread_safe.h" #include "io/resource_loader.h" +#include <ft2build.h> +#include FT_FREETYPE_H + class DynamicFontAtSize; class DynamicFont; @@ -13,39 +17,16 @@ class DynamicFontData : public Resource { OBJ_TYPE(DynamicFontData,Resource); - bool valid; - - DVector<uint8_t> font_data; - DVector<uint8_t>::Read fr; - const uint8_t* last_data_ptr; - struct KerningPairKey { - - union { - struct { - uint32_t A,B; - }; - - uint64_t pair; - }; - - _FORCE_INLINE_ bool operator<(const KerningPairKey& p_r) const { return pair<p_r.pair; } - }; - - Map<KerningPairKey,int> kerning_map; + const uint8_t *font_mem; + int font_mem_size; + bool force_autohinter; + String font_path; Map<int,DynamicFontAtSize*> size_cache; -friend class DynamicFontAtSize; - - stbtt_fontinfo info; - int ascent; - int descent; - int linegap; - - void lock(); - void unlock(); + friend class DynamicFontAtSize; friend class DynamicFont; @@ -53,7 +34,10 @@ friend class DynamicFont; Ref<DynamicFontAtSize> _get_dynamic_font_at_size(int p_size); public: - void set_font_data(const DVector<uint8_t>& p_font); + void set_font_ptr(const uint8_t* p_font_mem,int p_font_mem_size); + void set_font_path(const String& p_path); + void set_force_autohinter(bool p_force); + DynamicFontData(); ~DynamicFontData(); }; @@ -61,11 +45,21 @@ public: class DynamicFontAtSize : public Reference { - OBJ_TYPE(DynamicFontAtSize,Reference); + OBJ_TYPE(DynamicFontAtSize,Reference) + + _THREAD_SAFE_CLASS_ + FT_Library library; /* handle to library */ + FT_Face face; /* handle to face object */ + FT_StreamRec stream; + int ascent; + int descent; + int linegap; int rect_margin; + bool valid; + struct CharTexture { DVector<uint8_t> imgdata; @@ -78,6 +72,7 @@ class DynamicFontAtSize : public Reference { struct Character { + bool found; int texture_idx; Rect2 rect; float v_align; @@ -88,6 +83,8 @@ class DynamicFontAtSize : public Reference { }; + static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count ); + static void _ft_stream_close(FT_Stream stream); HashMap< CharType, Character > char_map; @@ -95,21 +92,26 @@ class DynamicFontAtSize : public Reference { friend class DynamicFontData; Ref<DynamicFontData> font; - float scale; int size; + + + Error _load(); protected: + + public: + float get_height() const; float get_ascent() const; float get_descent() const; - Size2 get_char_size(CharType p_char,CharType p_next=0) const; + Size2 get_char_size(CharType p_char,CharType p_next,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const; - float draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next=0,const Color& p_modulate=Color(1,1,1)) const; + float draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate,const Vector<Ref<DynamicFontAtSize> >& p_fallbacks) const; @@ -123,13 +125,22 @@ class DynamicFont : public Font { OBJ_TYPE( DynamicFont, Font ); - Ref<DynamicFontData> data; + Ref<DynamicFontData> data; Ref<DynamicFontAtSize> data_at_size; - int size; + Vector< Ref<DynamicFontData> > fallbacks; + Vector< Ref<DynamicFontAtSize> > fallback_data_at_size; + + + int size; + bool valid; protected: + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + static void _bind_methods(); public: @@ -140,6 +151,13 @@ public: void set_size(int p_size); int get_size() const; + + void add_fallback(const Ref<DynamicFontData>& p_data); + void set_fallback(int p_idx,const Ref<DynamicFontData>& p_data); + int get_fallback_count() const; + Ref<DynamicFontData> get_fallback(int p_idx) const; + void remove_fallback(int p_idx); + virtual float get_height() const; virtual float get_ascent() const; @@ -171,5 +189,6 @@ public: }; +#endif -#endif // DYNAMICFONT_H +#endif diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp new file mode 100644 index 0000000000..0b9f95da4f --- /dev/null +++ b/scene/resources/dynamic_font_stb.cpp @@ -0,0 +1,527 @@ +#include "dynamic_font_stb.h" + +#ifndef FREETYPE_ENABLED + +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" +#include "os/file_access.h" + +void DynamicFontData::lock() { + + fr=font_data.read(); + + if (fr.ptr()!=last_data_ptr) { + + last_data_ptr=fr.ptr(); + + if (!stbtt_InitFont(&info, last_data_ptr, 0)) { + valid=false; + } else { + valid=true; + } + + last_data_ptr=fr.ptr(); + } +} + +void DynamicFontData::unlock() { + + fr = DVector<uint8_t>::Read(); +} + +void DynamicFontData::set_font_data(const DVector<uint8_t>& p_font) { + //clear caches and stuff + ERR_FAIL_COND(font_data.size()) ; + font_data=p_font; + + lock(); + + if (valid) { + stbtt_GetFontVMetrics(&info, &ascent, &descent, &linegap); + descent=-descent + linegap; + + for(int i=32;i<1024;i++) { + for(int j=32;j<1024;j++) { + + int kern = stbtt_GetCodepointKernAdvance(&info, i,j); + if (kern!=0) { + KerningPairKey kpk; + kpk.A=i; + kpk.B=j; + kerning_map[kpk]=kern; + } + } + } + } + + unlock(); + //clear existing stuff + + ERR_FAIL_COND(!valid); +} + +Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { + + ERR_FAIL_COND_V(!valid,Ref<DynamicFontAtSize>()); + + if (size_cache.has(p_size)) { + return Ref<DynamicFontAtSize>( size_cache[p_size] ); + } + + + Ref<DynamicFontAtSize> dfas; + dfas.instance(); + + dfas->font=Ref<DynamicFontData>( this ); + + size_cache[p_size]=dfas.ptr(); + + dfas->size=p_size; + + lock(); + + dfas->scale = stbtt_ScaleForPixelHeight(&info, p_size); + + unlock(); + + return dfas; + +} + +DynamicFontData::DynamicFontData() +{ + last_data_ptr=NULL; + valid=false; +} + +DynamicFontData::~DynamicFontData() +{ + +} + + + +//////////////////// + +float DynamicFontAtSize::get_height() const { + + return (font->ascent+font->descent)*scale; +} + +float DynamicFontAtSize::get_ascent() const { + + return font->ascent*scale; +} +float DynamicFontAtSize::get_descent() const { + + return font->descent*scale; +} + +Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next) const { + + const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); + + const Character *c = char_map.getptr(p_char); + ERR_FAIL_COND_V(!c,Size2()); + + Size2 ret( c->advance, get_height()); + + if (p_next) { + DynamicFontData::KerningPairKey kpk; + kpk.A=p_char; + kpk.B=p_next; + + const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); + if (K) { + ret.x+=K->get()*scale; + } + + } + + return ret; +} + + +float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate) const { + + const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); + + const Character * c = char_map.getptr(p_char); + + if (!c) { + return 0; + } + + Point2 cpos=p_pos; + cpos.x+=c->h_align; + cpos.y-=get_ascent(); + cpos.y+=c->v_align; + ERR_FAIL_COND_V( c->texture_idx<-1 || c->texture_idx>=textures.size(),0); + if (c->texture_idx!=-1) + VisualServer::get_singleton()->canvas_item_add_texture_rect_region( p_canvas_item, Rect2( cpos, c->rect.size ), textures[c->texture_idx].texture->get_rid(),c->rect, p_modulate ); + + //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); + + float ret = c->advance; + if (p_next) { + DynamicFontData::KerningPairKey kpk; + kpk.A=p_char; + kpk.B=p_next; + + const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); + if (K) { + ret+=K->get()*scale; + } + + } + + return ret; +} + + +void DynamicFontAtSize::_update_char(CharType p_char) { + + if (char_map.has(p_char)) + return; + + font->lock(); + + + int w,h,xofs,yofs; + unsigned char * cpbitmap = stbtt_GetCodepointBitmap(&font->info, scale, scale, p_char, &w, &h, &xofs, &yofs ); + + if (!cpbitmap) { + //no glyph + + int advance; + stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); + //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale)); + Character ch; + ch.texture_idx=-1; + ch.advance=advance*scale; + ch.h_align=0; + ch.v_align=0; + + char_map[p_char]=ch; + + font->unlock(); + + return; + } + + int mw=w+rect_margin*2; + int mh=h+rect_margin*2; + + if (mw>4096 || mh>4096) { + + stbtt_FreeBitmap(cpbitmap,NULL); + font->unlock(); + ERR_FAIL_COND(mw>4096); + ERR_FAIL_COND(mh>4096); + } + + //find a texture to fit this... + + int tex_index=-1; + int tex_x=0; + int tex_y=0; + + for(int i=0;i<textures.size();i++) { + + CharTexture &ct=textures[i]; + + if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture + continue; + + tex_y=0x7FFFFFFF; + tex_x=0; + + for(int j=0;j<ct.texture_size-mw;j++) { + + int max_y=0; + + for(int k=j;k<j+mw;k++) { + + int y = ct.offsets[k]; + if (y>max_y) + max_y=y; + } + + if (max_y<tex_y) { + tex_y=max_y; + tex_x=j; + } + } + + if (tex_y==0x7FFFFFFF || tex_y+mh > ct.texture_size) + continue; //fail, could not fit it here + + tex_index=i; + break; + } + +// print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y)); + + if (tex_index==-1) { + //could not find texture to fit, create one + tex_x = 0; + tex_y = 0; + + int texsize = MAX(size*8,256); + if (mw>texsize) + texsize=mw; //special case, adapt to it? + if (mh>texsize) + texsize=mh; //special case, adapt to it? + + texsize=nearest_power_of_2(texsize); + + texsize=MIN(texsize,4096); + + + CharTexture tex; + tex.texture_size=texsize; + tex.imgdata.resize(texsize*texsize*2); //grayscale alpha + + { + //zero texture + DVector<uint8_t>::Write w = tex.imgdata.write(); + ERR_FAIL_COND(texsize*texsize*2 > tex.imgdata.size()); + for(int i=0;i<texsize*texsize*2;i++) { + w[i]=0; + } + } + tex.offsets.resize(texsize); + for(int i=0;i<texsize;i++) //zero offsets + tex.offsets[i]=0; + + textures.push_back(tex); + tex_index=textures.size()-1; + + } + + + //fit character in char texture + + CharTexture &tex=textures[tex_index]; + + { + DVector<uint8_t>::Write wr = tex.imgdata.write(); + + for(int i=0;i<h;i++) { + for(int j=0;j<w;j++) { + + int ofs = ( (i+tex_y+rect_margin)*tex.texture_size+j+tex_x+rect_margin)*2; + ERR_FAIL_COND(ofs >= tex.imgdata.size()); + wr[ofs+0]=255; //grayscale as 1 + wr[ofs+1]=cpbitmap[i*w+j]; //alpha as 0 + } + } + } + + //blit to image and texture + { + + Image img(tex.texture_size,tex.texture_size,0,Image::FORMAT_GRAYSCALE_ALPHA,tex.imgdata); + + if (tex.texture.is_null()) { + tex.texture.instance(); + tex.texture->create_from_image(img,Texture::FLAG_FILTER); + } else { + tex.texture->set_data(img); //update + } + + } + + + // update height array + + for(int k=tex_x;k<tex_x+mw;k++) { + + tex.offsets[k]=tex_y+mh; + } + + int advance; + stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); + + Character chr; + chr.h_align=xofs; + chr.v_align=yofs + get_ascent(); + chr.advance=advance*scale; + chr.texture_idx=tex_index; + + + chr.rect=Rect2(tex_x+rect_margin,tex_y+rect_margin,w,h); + + //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs)); + + char_map[p_char]=chr; + + stbtt_FreeBitmap(cpbitmap,NULL); + + font->unlock(); + +} + +DynamicFontAtSize::DynamicFontAtSize() { + + rect_margin=1; +} + +DynamicFontAtSize::~DynamicFontAtSize(){ + + ERR_FAIL_COND(!font.ptr()); + font->size_cache.erase(size); +} + +///////////////////////// + + +void DynamicFont::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_font_data","data:DynamicFontData"),&DynamicFont::set_font_data); + ObjectTypeDB::bind_method(_MD("get_font_data:DynamicFontData"),&DynamicFont::get_font_data); + + ObjectTypeDB::bind_method(_MD("set_size","data"),&DynamicFont::set_size); + ObjectTypeDB::bind_method(_MD("get_size"),&DynamicFont::get_size); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"font/size"),_SCS("set_size"),_SCS("get_size")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"font/font",PROPERTY_HINT_RESOURCE_TYPE,"DynamicFontData"),_SCS("set_font_data"),_SCS("get_font_data")); +} + + +void DynamicFont::set_font_data(const Ref<DynamicFontData>& p_data) { + + data=p_data; + data_at_size=data->_get_dynamic_font_at_size(size); +} + +Ref<DynamicFontData> DynamicFont::get_font_data() const{ + + return data; +} + +void DynamicFont::set_size(int p_size){ + + if (size==p_size) + return; + size=p_size; + ERR_FAIL_COND(p_size<1); + if (!data.is_valid()) + return; + data_at_size=data->_get_dynamic_font_at_size(size); + +} +int DynamicFont::get_size() const{ + + return size; +} + +float DynamicFont::get_height() const{ + + if (!data_at_size.is_valid()) + return 1; + + return data_at_size->get_height(); +} + +float DynamicFont::get_ascent() const{ + + if (!data_at_size.is_valid()) + return 1; + + return data_at_size->get_ascent(); +} + +float DynamicFont::get_descent() const{ + + if (!data_at_size.is_valid()) + return 1; + + return data_at_size->get_descent(); + +} + +Size2 DynamicFont::get_char_size(CharType p_char,CharType p_next) const{ + + if (!data_at_size.is_valid()) + return Size2(1,1); + + return data_at_size->get_char_size(p_char,p_next); + +} + +bool DynamicFont::is_distance_field_hint() const{ + + return false; +} + +float DynamicFont::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate) const { + + if (!data_at_size.is_valid()) + return 0; + + return data_at_size->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate); + +} + +DynamicFont::DynamicFont() { + + size=16; +} + +DynamicFont::~DynamicFont() { + +} + +///////////////////////// + + +RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; + + + FileAccess *f = FileAccess::open(p_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,RES()); + + DVector<uint8_t> data; + + data.resize(f->get_len()); + + ERR_FAIL_COND_V(data.size()==0,RES()); + + { + DVector<uint8_t>::Write w = data.write(); + f->get_buffer(w.ptr(),data.size()); + } + + Ref<DynamicFontData> dfd; + dfd.instance(); + dfd->set_font_data(data); + + if (r_error) + *r_error=OK; + + return dfd; +} + +void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("ttf"); +} + +bool ResourceFormatLoaderDynamicFont::handles_type(const String& p_type) const { + + return (p_type=="DynamicFontData"); +} + +String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const { + + String el = p_path.extension().to_lower(); + if (el=="ttf") + return "DynamicFontData"; + return ""; +} + +#endif diff --git a/scene/resources/dynamic_font_stb.h b/scene/resources/dynamic_font_stb.h new file mode 100644 index 0000000000..6b72fb3703 --- /dev/null +++ b/scene/resources/dynamic_font_stb.h @@ -0,0 +1,178 @@ +#ifndef DYNAMICFONT_STB_H +#define DYNAMICFONT_STB_H + +#ifndef FREETYPE_ENABLED + +#include "font.h" +#include "stb_truetype.h" +#include "io/resource_loader.h" + + + +class DynamicFontAtSize; +class DynamicFont; + +class DynamicFontData : public Resource { + + OBJ_TYPE(DynamicFontData,Resource); + + bool valid; + + DVector<uint8_t> font_data; + DVector<uint8_t>::Read fr; + const uint8_t* last_data_ptr; + + struct KerningPairKey { + + union { + struct { + uint32_t A,B; + }; + + uint64_t pair; + }; + + _FORCE_INLINE_ bool operator<(const KerningPairKey& p_r) const { return pair<p_r.pair; } + }; + + Map<KerningPairKey,int> kerning_map; + + + Map<int,DynamicFontAtSize*> size_cache; + +friend class DynamicFontAtSize; + + stbtt_fontinfo info; + int ascent; + int descent; + int linegap; + + void lock(); + void unlock(); + +friend class DynamicFont; + + + Ref<DynamicFontAtSize> _get_dynamic_font_at_size(int p_size); +public: + + void set_font_data(const DVector<uint8_t>& p_font); + DynamicFontData(); + ~DynamicFontData(); +}; + + +class DynamicFontAtSize : public Reference { + + OBJ_TYPE(DynamicFontAtSize,Reference); + + + int rect_margin; + + struct CharTexture { + + DVector<uint8_t> imgdata; + int texture_size; + Vector<int> offsets; + Ref<ImageTexture> texture; + }; + + Vector<CharTexture> textures; + + struct Character { + + int texture_idx; + Rect2 rect; + float v_align; + float h_align; + float advance; + + Character() { texture_idx=0; v_align=0; } + }; + + + + HashMap< CharType, Character > char_map; + + _FORCE_INLINE_ void _update_char(CharType p_char); + +friend class DynamicFontData; + Ref<DynamicFontData> font; + float scale; + int size; + +protected: + +public: + + float get_height() const; + + float get_ascent() const; + float get_descent() const; + + Size2 get_char_size(CharType p_char,CharType p_next=0) const; + + float draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next=0,const Color& p_modulate=Color(1,1,1)) const; + + + + DynamicFontAtSize(); + ~DynamicFontAtSize(); +}; + +/////////////// + +class DynamicFont : public Font { + + OBJ_TYPE( DynamicFont, Font ); + + Ref<DynamicFontData> data; + Ref<DynamicFontAtSize> data_at_size; + int size; + + +protected: + + static void _bind_methods(); + +public: + + void set_font_data(const Ref<DynamicFontData>& p_data); + Ref<DynamicFontData> get_font_data() const; + + void set_size(int p_size); + int get_size() const; + + virtual float get_height() const; + + virtual float get_ascent() const; + virtual float get_descent() const; + + virtual Size2 get_char_size(CharType p_char,CharType p_next=0) const; + + virtual bool is_distance_field_hint() const; + + virtual float draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next=0,const Color& p_modulate=Color(1,1,1)) const; + + DynamicFont(); + ~DynamicFont(); + +}; + + + +///////////// + +class ResourceFormatLoaderDynamicFont : public ResourceFormatLoader { +public: + + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String& p_type) const; + virtual String get_resource_type(const String &p_path) const; + +}; + + +#endif +#endif // DYNAMICFONT_H diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 09c0a21f53..e6356d3366 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -30,7 +30,6 @@ #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" #include "surface_tool.h" - static const char*_array_name[]={ "vertex_array", "normal_array", @@ -288,6 +287,7 @@ void Mesh::add_surface(PrimitiveType p_primitive,const Array& p_arrays,const Arr triangle_mesh=Ref<TriangleMesh>(); _change_notify(); + emit_changed(); } @@ -387,6 +387,7 @@ void Mesh::surface_remove(int p_idx) { triangle_mesh=Ref<TriangleMesh>(); _recompute_aabb(); _change_notify(); + emit_changed(); } @@ -491,6 +492,8 @@ void Mesh::add_surface_from_mesh_data(const Geometry::MeshData& p_mesh_data) { surfaces.push_back(s); _change_notify(); + + emit_changed(); } RID Mesh::get_rid() const { diff --git a/scene/resources/stb_truetype.h b/scene/resources/stb_truetype.h index d360d60920..016972785a 100644 --- a/scene/resources/stb_truetype.h +++ b/scene/resources/stb_truetype.h @@ -29,7 +29,7 @@ // "Zer" on mollyrocket (with fix) // Cass Everitt // stoiko (Haemimont Games) -// Brian Hook +// Brian Hook // Walter van Niftrik // David Gow // David Given @@ -218,7 +218,7 @@ // Curve tesselation 120 LOC \__ 550 LOC Bitmap creation // Bitmap management 100 LOC / // Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 +// Font name matching & access 150 LOC ---- 150 // C runtime library abstraction 60 LOC ---- 60 // // @@ -311,7 +311,7 @@ int main(int argc, char **argv) } return 0; } -#endif +#endif // // Output: // @@ -325,9 +325,9 @@ int main(int argc, char **argv) // :@@. M@M // @@@o@@@@ // :M@@V:@@. -// +// ////////////////////////////////////////////////////////////////////////////// -// +// // Complete program: print "Hello World!" banner, with bugs // #if 0 @@ -599,7 +599,7 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbt // Calling these functions in sequence is roughly equivalent to calling // stbtt_PackFontRanges(). If you more control over the packing of multiple // fonts, or if you want to pack custom data into a font texture, take a look -// at the source to of stbtt_PackFontRanges() and create a custom version +// at the source to of stbtt_PackFontRanges() and create a custom version // using these functions, e.g. call GatherRects multiple times, // building up a single array of rects, then call PackRects once, // then call RenderIntoRects repeatedly. This may result in a @@ -1350,7 +1350,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s if (i != 0) num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - // now start the new one + // now start the new one start_off = !(flags & 1); if (start_off) { // if we start off with an off-curve point, then when we need to find a point on the curve @@ -1403,7 +1403,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s int comp_num_verts = 0, i; stbtt_vertex *comp_verts = 0, *tmp = 0; float mtx[6] = {1,0,0,1,0,0}, m, n; - + flags = ttSHORT(comp); comp+=2; gidx = ttSHORT(comp); comp+=2; @@ -1433,7 +1433,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; } - + // Find transformation scales. m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); @@ -1691,7 +1691,7 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); STBTT_assert(z != NULL); if (!z) return z; - + // round dx down to avoid overshooting if (dxdy < 0) z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); @@ -1769,7 +1769,7 @@ static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__ac } } } - + e = e->next; } } @@ -2441,7 +2441,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info { int ix0,iy0,ix1,iy1; stbtt__bitmap gbm; - stbtt_vertex *vertices; + stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); if (scale_x == 0) scale_x = scale_y; @@ -2464,7 +2464,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info if (height) *height = gbm.h; if (xoff ) *xoff = ix0; if (yoff ) *yoff = iy0; - + if (gbm.w && gbm.h) { gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); if (gbm.pixels) { @@ -2475,7 +2475,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info } STBTT_free(vertices, info->userdata); return gbm.pixels; -} +} STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) { @@ -2487,7 +2487,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigne int ix0,iy0; stbtt_vertex *vertices; int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; + stbtt__bitmap gbm; stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); gbm.pixels = output; @@ -2509,7 +2509,7 @@ STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char * STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) { @@ -2519,7 +2519,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) { return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} +} STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) { @@ -2644,7 +2644,7 @@ static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *no con->y = 0; con->bottom_y = 0; STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); + STBTT__NOTUSED(num_nodes); } static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) @@ -2996,7 +2996,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd n = 0; for (i=0; i < num_ranges; ++i) n += ranges[i].num_chars; - + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); if (rects == NULL) return 0; @@ -3007,7 +3007,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); stbtt_PackFontRangesPackRects(spc, rects, n); - + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); STBTT_free(rects, spc->user_allocator_context); @@ -3060,7 +3060,7 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i // // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) { stbtt_int32 i=0; @@ -3099,7 +3099,7 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 return i; } -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) { return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2); } diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 75e38f9701..a61ffe8e97 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -138,7 +138,7 @@ void StyleBoxTexture::draw(RID p_canvas_item,const Rect2& p_rect) const { r.pos.y-=expand_margin[MARGIN_TOP]; r.size.x+=expand_margin[MARGIN_LEFT]+expand_margin[MARGIN_RIGHT]; r.size.y+=expand_margin[MARGIN_TOP]+expand_margin[MARGIN_BOTTOM]; - VisualServer::get_singleton()->canvas_item_add_style_box( p_canvas_item,r,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center); + VisualServer::get_singleton()->canvas_item_add_style_box( p_canvas_item,r,region_rect,texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center); } void StyleBoxTexture::set_draw_center(bool p_draw) { @@ -175,6 +175,20 @@ float StyleBoxTexture::get_expand_margin_size(Margin p_expand_margin) const { return expand_margin[p_expand_margin]; } +void StyleBoxTexture::set_region_rect(const Rect2& p_region_rect) { + + if (region_rect==p_region_rect) + return; + + region_rect=p_region_rect; + emit_changed(); +} + +Rect2 StyleBoxTexture::get_region_rect() const { + + return region_rect; +} + void StyleBoxTexture::_bind_methods() { @@ -187,10 +201,14 @@ void StyleBoxTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_expand_margin_size","margin","size"),&StyleBoxTexture::set_expand_margin_size); ObjectTypeDB::bind_method(_MD("get_expand_margin_size","margin"),&StyleBoxTexture::get_expand_margin_size); + ObjectTypeDB::bind_method(_MD("set_region_rect","region"),&StyleBoxTexture::set_region_rect); + ObjectTypeDB::bind_method(_MD("get_region_rect"),&StyleBoxTexture::get_region_rect); + ObjectTypeDB::bind_method(_MD("set_draw_center","enable"),&StyleBoxTexture::set_draw_center); ObjectTypeDB::bind_method(_MD("get_draw_center"),&StyleBoxTexture::get_draw_center); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_texture"),_SCS("get_texture") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "margin/left", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_margin_size"),_SCS("get_margin_size"), MARGIN_LEFT ); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "margin/right", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_margin_size"),_SCS("get_margin_size"), MARGIN_RIGHT ); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "margin/top", PROPERTY_HINT_RANGE,"0,2048,1" ), _SCS("set_margin_size"),_SCS("get_margin_size"), MARGIN_TOP); @@ -505,4 +523,3 @@ StyleBoxImageMask::StyleBoxImageMask() { } expand=true; } - diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 02d79bc2ac..98aaee754b 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -81,6 +81,7 @@ class StyleBoxTexture : public StyleBox { float expand_margin[4]; float margin[4]; + Rect2 region_rect; Ref<Texture> texture; bool draw_center; @@ -98,6 +99,9 @@ public: void set_margin_size(Margin p_margin,float p_size); float get_margin_size(Margin p_margin) const; + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + void set_texture(RES p_texture); RES get_texture() const; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 20405a57b2..8d0aedbf93 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -374,7 +374,7 @@ void Theme::get_stylebox_types(List<StringName> *p_list) const { const StringName *key=NULL; while((key=style_map.next(key))) { p_list->push_back(*key); - } + } } void Theme::set_font(const StringName& p_name,const StringName& p_type,const Ref<Font>& p_font) { diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 8cacc0fce7..e96cac170b 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -373,7 +373,15 @@ World2D::World2D() { Physics2DServer::get_singleton()->space_set_active(space,true); Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,GLOBAL_DEF("physics_2d/default_gravity",98)); Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,GLOBAL_DEF("physics_2d/default_gravity_vector",Vector2(0,1))); - Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_density",0.1)); + // TODO: Remove this deprecation warning and compatibility code for 2.2 or 3.0 + if (Globals::get_singleton()->get("physics_2d/default_density") && !Globals::get_singleton()->get("physics_2d/default_linear_damp)")) { + WARN_PRINT("Deprecated parameter 'physics_2d/default_density'. It was renamed to 'physics_2d/default_linear_damp', adjusting your project settings accordingly (make sure to adjust scripts that potentially rely on 'physics_2d/default_density'."); + Globals::get_singleton()->set("physics_2d/default_linear_damp", Globals::get_singleton()->get("physics_2d/default_density")); + Globals::get_singleton()->set_persisting("physics_2d/default_linear_damp", true); + Globals::get_singleton()->set_persisting("physics_2d/default_density", false); + Globals::get_singleton()->save(); + } + Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_linear_damp",0.1)); Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_angular_damp",1)); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS,1.0); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION,1.5); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 7e8dd41ed9..164ae55c9f 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -176,4 +176,11 @@ SceneStringNames::SceneStringNames() { path_pp=NodePath(".."); _default=StaticCString::create("default"); + + for(int i=0;i<MAX_MATERIALS;i++) { + + mesh_materials[i]="material/"+itos(i); + } + + _mesh_changed=StaticCString::create("_mesh_changed"); } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 7143bd539f..32e51ce8f4 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -186,6 +186,12 @@ public: StringName node_configuration_warning_changed; + enum { + MAX_MATERIALS=32 + }; + StringName mesh_materials[MAX_MATERIALS]; + StringName _mesh_changed; + }; |