summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/area_2d.cpp6
-rw-r--r--scene/2d/canvas_item.cpp18
-rw-r--r--scene/2d/canvas_modulate.cpp2
-rw-r--r--scene/2d/light_2d.cpp6
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/2d/polygon_2d.cpp27
-rw-r--r--scene/2d/polygon_2d.h4
-rw-r--r--scene/2d/sprite.cpp2
-rw-r--r--scene/3d/listener.cpp167
-rw-r--r--scene/3d/listener.h53
-rw-r--r--scene/3d/mesh_instance.cpp87
-rw-r--r--scene/3d/mesh_instance.h5
-rw-r--r--scene/3d/vehicle_body.cpp8
-rw-r--r--scene/3d/vehicle_body.h1
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/gui/base_button.cpp53
-rw-r--r--scene/gui/base_button.h11
-rw-r--r--scene/gui/box_container.cpp1
-rw-r--r--scene/gui/button.cpp1
-rw-r--r--scene/gui/button.h4
-rw-r--r--scene/gui/control.cpp118
-rw-r--r--scene/gui/control.h9
-rw-r--r--scene/gui/dialogs.cpp87
-rw-r--r--scene/gui/dialogs.h7
-rw-r--r--scene/gui/input_action.cpp125
-rw-r--r--scene/gui/input_action.h26
-rw-r--r--scene/gui/item_list.cpp64
-rw-r--r--scene/gui/item_list.h14
-rw-r--r--scene/gui/line_edit.cpp7
-rw-r--r--scene/gui/link_button.cpp2
-rw-r--r--scene/gui/menu_button.cpp21
-rw-r--r--scene/gui/patch_9_frame.cpp38
-rw-r--r--scene/gui/patch_9_frame.h4
-rw-r--r--scene/gui/popup_menu.cpp176
-rw-r--r--scene/gui/popup_menu.h19
-rw-r--r--scene/gui/slider.cpp1
-rw-r--r--scene/gui/tab_container.cpp4
-rw-r--r--scene/gui/text_edit.cpp176
-rw-r--r--scene/gui/text_edit.h22
-rw-r--r--scene/gui/texture_frame.cpp46
-rw-r--r--scene/gui/texture_frame.h15
-rw-r--r--scene/gui/video_player.cpp2
-rw-r--r--scene/io/resource_format_image.cpp4
-rw-r--r--scene/main/http_request.cpp5
-rw-r--r--scene/main/node.cpp12
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/main/scene_main_loop.cpp11
-rw-r--r--scene/main/scene_main_loop.h1
-rw-r--r--scene/main/viewport.cpp155
-rw-r--r--scene/main/viewport.h17
-rw-r--r--scene/register_scene_types.cpp8
-rw-r--r--scene/resources/bit_mask.h2
-rw-r--r--scene/resources/curve.cpp2
-rw-r--r--scene/resources/default_theme/default_theme.cpp277
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/dynamic_font.cpp582
-rw-r--r--scene/resources/dynamic_font.h99
-rw-r--r--scene/resources/dynamic_font_stb.cpp527
-rw-r--r--scene/resources/dynamic_font_stb.h178
-rw-r--r--scene/resources/mesh.cpp5
-rw-r--r--scene/resources/stb_truetype.h44
-rw-r--r--scene/resources/style_box.cpp21
-rw-r--r--scene/resources/style_box.h4
-rw-r--r--scene/resources/theme.cpp2
-rw-r--r--scene/resources/world_2d.cpp10
-rw-r--r--scene/scene_string_names.cpp7
-rw-r--r--scene/scene_string_names.h6
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;
+
};