summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp32
-rw-r--r--scene/2d/animated_sprite.h6
-rw-r--r--scene/2d/area_2d.cpp4
-rw-r--r--scene/2d/canvas_item.cpp35
-rw-r--r--scene/2d/canvas_item.h3
-rw-r--r--scene/2d/cpu_particles_2d.cpp162
-rw-r--r--scene/2d/cpu_particles_2d.h1
-rw-r--r--scene/2d/joints_2d.cpp8
-rw-r--r--scene/2d/line_builder.cpp2
-rw-r--r--scene/2d/navigation_2d.cpp12
-rw-r--r--scene/2d/navigation_polygon.cpp2
-rw-r--r--scene/2d/node_2d.cpp2
-rw-r--r--scene/2d/particles_2d.cpp4
-rw-r--r--scene/2d/physics_body_2d.cpp8
-rw-r--r--scene/2d/polygon_2d.cpp2
-rw-r--r--scene/2d/position_2d.cpp5
-rw-r--r--scene/2d/sprite.cpp24
-rw-r--r--scene/2d/sprite.h4
-rw-r--r--scene/2d/tile_map.cpp18
-rw-r--r--scene/2d/touch_screen_button.cpp8
-rw-r--r--scene/3d/audio_stream_player_3d.cpp1
-rw-r--r--scene/3d/baked_lightmap.cpp5
-rw-r--r--scene/3d/camera.cpp6
-rw-r--r--scene/3d/cpu_particles.cpp188
-rw-r--r--scene/3d/cpu_particles.h1
-rw-r--r--scene/3d/gi_probe.cpp1
-rw-r--r--scene/3d/mesh_instance.cpp37
-rw-r--r--scene/3d/mesh_instance.h7
-rw-r--r--scene/3d/navigation.cpp2
-rw-r--r--scene/3d/navigation_mesh.cpp35
-rw-r--r--scene/3d/navigation_mesh.h16
-rw-r--r--scene/3d/particles.cpp4
-rw-r--r--scene/3d/physics_body.cpp17
-rw-r--r--scene/3d/skeleton.cpp291
-rw-r--r--scene/3d/skeleton.h57
-rw-r--r--scene/3d/soft_body.cpp11
-rw-r--r--scene/3d/spatial.cpp5
-rw-r--r--scene/3d/sprite_3d.cpp11
-rw-r--r--scene/animation/animation_blend_space_1d.cpp1
-rw-r--r--scene/animation/animation_blend_space_2d.cpp1
-rw-r--r--scene/animation/animation_blend_tree.cpp4
-rw-r--r--scene/animation/animation_cache.cpp10
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/animation/animation_tree_player.cpp6
-rw-r--r--scene/animation/skeleton_ik.cpp2
-rw-r--r--scene/animation/tween.cpp46
-rw-r--r--scene/animation/tween.h3
-rw-r--r--scene/gui/color_picker.cpp22
-rw-r--r--scene/gui/control.cpp59
-rw-r--r--scene/gui/dialogs.cpp33
-rw-r--r--scene/gui/dialogs.h6
-rw-r--r--scene/gui/file_dialog.cpp59
-rw-r--r--scene/gui/file_dialog.h3
-rw-r--r--scene/gui/grid_container.cpp39
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/label.cpp18
-rw-r--r--scene/gui/line_edit.cpp228
-rw-r--r--scene/gui/line_edit.h16
-rw-r--r--scene/gui/option_button.cpp6
-rw-r--r--scene/gui/popup_menu.cpp166
-rw-r--r--scene/gui/popup_menu.h14
-rw-r--r--scene/gui/rich_text_effect.cpp5
-rw-r--r--scene/gui/rich_text_effect.h2
-rw-r--r--scene/gui/rich_text_label.cpp207
-rw-r--r--scene/gui/rich_text_label.h67
-rw-r--r--scene/gui/slider.cpp1
-rw-r--r--scene/gui/spin_box.cpp6
-rw-r--r--scene/gui/tab_container.cpp112
-rw-r--r--scene/gui/tab_container.h4
-rw-r--r--scene/gui/tabs.cpp33
-rw-r--r--scene/gui/tabs.h5
-rw-r--r--scene/gui/text_edit.cpp331
-rw-r--r--scene/gui/text_edit.h28
-rw-r--r--scene/gui/texture_progress.cpp11
-rw-r--r--scene/gui/texture_rect.cpp20
-rw-r--r--scene/gui/texture_rect.h2
-rw-r--r--scene/gui/tree.cpp77
-rw-r--r--scene/gui/tree.h7
-rw-r--r--scene/gui/video_player.cpp23
-rw-r--r--scene/gui/video_player.h7
-rw-r--r--scene/main/node.cpp6
-rw-r--r--scene/main/node.h4
-rw-r--r--scene/main/scene_tree.cpp54
-rw-r--r--scene/main/scene_tree.h2
-rw-r--r--scene/main/viewport.cpp28
-rw-r--r--scene/register_scene_types.cpp4
-rw-r--r--scene/resources/animation.cpp120
-rw-r--r--scene/resources/bit_map.cpp56
-rw-r--r--scene/resources/bit_map.h1
-rw-r--r--scene/resources/box_shape.cpp2
-rw-r--r--scene/resources/box_shape.h3
-rw-r--r--scene/resources/capsule_shape.cpp2
-rw-r--r--scene/resources/capsule_shape.h4
-rw-r--r--scene/resources/concave_polygon_shape.cpp2
-rw-r--r--scene/resources/concave_polygon_shape.h3
-rw-r--r--scene/resources/convex_polygon_shape.cpp2
-rw-r--r--scene/resources/convex_polygon_shape.h4
-rw-r--r--scene/resources/cylinder_shape.cpp2
-rw-r--r--scene/resources/cylinder_shape.h4
-rw-r--r--scene/resources/default_theme/button_hover.pngbin344 -> 342 bytes
-rw-r--r--scene/resources/default_theme/button_normal.pngbin338 -> 336 bytes
-rw-r--r--scene/resources/default_theme/color_picker_hue.pngbin146 -> 141 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp13
-rw-r--r--scene/resources/default_theme/error_icon.pngbin125 -> 106 bytes
-rw-r--r--scene/resources/default_theme/graph_node_selected.pngbin836 -> 827 bytes
-rw-r--r--scene/resources/default_theme/graph_port.pngbin171 -> 167 bytes
-rw-r--r--scene/resources/default_theme/icon_visibility.pngbin488 -> 448 bytes
-rw-r--r--scene/resources/default_theme/option_button_normal.pngbin669 -> 668 bytes
-rw-r--r--scene/resources/default_theme/overbright_indicator.pngbin0 -> 593 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber_hl.pngbin278 -> 275 bytes
-rw-r--r--scene/resources/default_theme/space.pngbin122 -> 99 bytes
-rw-r--r--scene/resources/default_theme/tab_container_bg.pngbin338 -> 336 bytes
-rw-r--r--scene/resources/default_theme/tab_current.pngbin347 -> 346 bytes
-rw-r--r--scene/resources/default_theme/tab_disabled.pngbin1233 -> 258 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h30
-rw-r--r--scene/resources/dynamic_font.cpp13
-rw-r--r--scene/resources/dynamic_font_stb.cpp524
-rw-r--r--scene/resources/dynamic_font_stb.h191
-rw-r--r--scene/resources/environment.cpp4
-rw-r--r--scene/resources/font.cpp4
-rw-r--r--scene/resources/height_map_shape.cpp2
-rw-r--r--scene/resources/height_map_shape.h4
-rw-r--r--scene/resources/material.cpp53
-rw-r--r--scene/resources/mesh_library.cpp32
-rw-r--r--scene/resources/particles_material.cpp4
-rw-r--r--scene/resources/plane_shape.cpp2
-rw-r--r--scene/resources/plane_shape.h4
-rw-r--r--scene/resources/polygon_path_finder.cpp6
-rw-r--r--scene/resources/ray_shape.cpp12
-rw-r--r--scene/resources/ray_shape.h3
-rw-r--r--scene/resources/resource_format_text.cpp7
-rw-r--r--scene/resources/shader.cpp5
-rw-r--r--scene/resources/shape.cpp4
-rw-r--r--scene/resources/shape.h2
-rw-r--r--scene/resources/skin.cpp132
-rw-r--r--scene/resources/skin.h84
-rw-r--r--scene/resources/sphere_shape.cpp2
-rw-r--r--scene/resources/sphere_shape.h3
-rw-r--r--scene/resources/style_box.cpp32
-rw-r--r--scene/resources/text_file.cpp5
-rw-r--r--scene/resources/texture.cpp19
-rw-r--r--scene/resources/theme.cpp115
-rw-r--r--scene/resources/theme.h72
-rw-r--r--scene/resources/video_stream.h2
-rw-r--r--scene/resources/visual_shader.cpp68
-rw-r--r--scene/resources/visual_shader.h7
-rw-r--r--scene/resources/visual_shader_nodes.cpp424
-rw-r--r--scene/resources/visual_shader_nodes.h27
-rw-r--r--scene/resources/world.cpp2
-rw-r--r--scene/resources/world_2d.cpp4
151 files changed, 3027 insertions, 1930 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 0b20b781f0..9d02408641 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -102,7 +102,7 @@ Rect2 AnimatedSprite::_get_rect() const {
void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
if (p_at_pos >= 0 && p_at_pos < E->get().frames.size())
E->get().frames.insert(p_at_pos, p_frame);
@@ -114,7 +114,7 @@ void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_fra
int SpriteFrames::get_frame_count(const StringName &p_anim) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, 0);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
return E->get().frames.size();
}
@@ -122,7 +122,7 @@ int SpriteFrames::get_frame_count(const StringName &p_anim) const {
void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->get().frames.remove(p_idx);
emit_changed();
@@ -130,7 +130,7 @@ void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
void SpriteFrames::clear(const StringName &p_anim) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->get().frames.clear();
emit_changed();
@@ -144,7 +144,7 @@ void SpriteFrames::clear_all() {
void SpriteFrames::add_animation(const StringName &p_anim) {
- ERR_FAIL_COND(animations.has(p_anim));
+ ERR_FAIL_COND_MSG(animations.has(p_anim), "SpriteFrames already has animation '" + p_anim + "'.");
animations[p_anim] = Anim();
animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
@@ -161,8 +161,8 @@ void SpriteFrames::remove_animation(const StringName &p_anim) {
void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
- ERR_FAIL_COND(!animations.has(p_prev));
- ERR_FAIL_COND(animations.has(p_next));
+ ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'.");
+ ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists.");
Anim anim = animations[p_prev];
animations.erase(p_prev);
@@ -202,26 +202,26 @@ Vector<String> SpriteFrames::get_animation_names() const {
void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
- ERR_FAIL_COND(p_fps < 0);
+ ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ").");
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->get().speed = p_fps;
}
float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, 0);
+ ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
return E->get().speed;
}
void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->get().loop = p_loop;
}
bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, false);
+ ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist.");
return E->get().loop;
}
@@ -604,10 +604,14 @@ bool AnimatedSprite::_is_playing() const {
void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) {
- if (p_animation)
+ backwards = p_backwards;
+
+ if (p_animation) {
set_animation(p_animation);
+ if (backwards && get_frame() == 0)
+ set_frame(frames->get_frame_count(p_animation) - 1);
+ }
- backwards = p_backwards;
_set_playing(true);
}
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index 2cc372bd93..3192d44678 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -85,7 +85,7 @@ public:
_FORCE_INLINE_ Ref<Texture> get_frame(const StringName &p_anim, int p_idx) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, Ref<Texture>());
+ ERR_FAIL_COND_V_MSG(!E, Ref<Texture>(), "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture>());
if (p_idx >= E->get().frames.size())
return Ref<Texture>();
@@ -96,7 +96,7 @@ public:
_FORCE_INLINE_ Ref<Texture> get_normal_frame(const StringName &p_anim, int p_idx) const {
const Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND_V(!E, Ref<Texture>());
+ ERR_FAIL_COND_V_MSG(!E, Ref<Texture>(), "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture>());
const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
@@ -109,7 +109,7 @@ public:
void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture> &p_frame) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
- ERR_FAIL_COND(!E);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND(p_idx < 0);
if (p_idx >= E->get().frames.size())
return;
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index a636eea285..66a1318cb7 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -438,7 +438,7 @@ bool Area2D::is_monitorable() const {
Array Area2D::get_overlapping_bodies() const {
- ERR_FAIL_COND_V(!monitoring, Array());
+ ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off.");
Array ret;
ret.resize(body_map.size());
int idx = 0;
@@ -456,7 +456,7 @@ Array Area2D::get_overlapping_bodies() const {
Array Area2D::get_overlapping_areas() const {
- ERR_FAIL_COND_V(!monitoring, Array());
+ ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off.");
Array ret;
ret.resize(area_map.size());
int idx = 0;
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index fc5e5cbba2..fa23e3fd39 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -360,6 +360,10 @@ bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tole
}
}
+Transform2D CanvasItem::_edit_get_transform() const {
+ return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
+}
+
bool CanvasItem::is_visible_in_tree() const {
if (!is_inside_tree())
@@ -602,9 +606,7 @@ void CanvasItem::_notification(int p_what) {
}
global_invalid = true;
} break;
- case NOTIFICATION_DRAW: {
-
- } break;
+ case NOTIFICATION_DRAW:
case NOTIFICATION_TRANSFORM_CHANGED: {
} break;
@@ -737,6 +739,19 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect
VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
+void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
+
+ Vector<Point2> points;
+ points.resize(p_point_count);
+ const float delta_angle = p_end_angle - p_start_angle;
+ for (int i = 0; i < p_point_count; i++) {
+ float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
+ }
+
+ draw_polyline(points, p_color, p_width, p_antialiased);
+}
+
void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -779,29 +794,29 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(-offset, 0),
+ p_rect.position + Size2(-offset, 0),
p_rect.position + Size2(p_rect.size.width + offset, 0),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(0, offset),
- p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(p_rect.size.width, offset),
+ p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(-offset, p_rect.size.height),
p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
+ p_rect.position + Size2(-offset, p_rect.size.height),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(p_rect.size.width, offset),
- p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
+ p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(0, offset),
p_color,
p_width,
p_antialiased);
@@ -1122,6 +1137,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
+ ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
@@ -1154,6 +1170,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width", "antialiased"), &CanvasItem::draw_multiline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width", "antialiased"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0), DEFVAL(false));
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 9c6799a441..e51ee601e2 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -281,6 +281,8 @@ public:
virtual void _edit_set_pivot(const Point2 &p_pivot){};
virtual Point2 _edit_get_pivot() const { return Point2(); };
+ virtual Transform2D _edit_get_transform() const;
+
/* VISIBILITY */
void set_visible(bool p_visible);
@@ -305,6 +307,7 @@ public:
void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
+ void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0, bool p_antialiased = false);
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index f9f273d494..372d8f614b 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -37,6 +37,9 @@
void CPUParticles2D::set_emitting(bool p_emitting) {
+ if (emitting == p_emitting)
+ return;
+
emitting = p_emitting;
if (emitting)
set_process_internal(true);
@@ -44,7 +47,7 @@ void CPUParticles2D::set_emitting(bool p_emitting) {
void CPUParticles2D::set_amount(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");
particles.resize(p_amount);
{
@@ -62,7 +65,7 @@ void CPUParticles2D::set_amount(int p_amount) {
}
void CPUParticles2D::set_lifetime(float p_lifetime) {
- ERR_FAIL_COND(p_lifetime <= 0);
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
}
@@ -257,8 +260,7 @@ void CPUParticles2D::restart() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
-
- set_emitting(true);
+ emitting = false;
{
int pc = particles.size();
@@ -268,6 +270,8 @@ void CPUParticles2D::restart() {
w[i].active = false;
}
}
+
+ set_emitting(true);
}
void CPUParticles2D::set_direction(Vector2 p_direction) {
@@ -535,6 +539,74 @@ static float rand_from_seed(uint32_t &seed) {
return float(seed % uint32_t(65536)) / 65535.0;
}
+void CPUParticles2D::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ }
+
+ _update_particle_data_buffer();
+}
+
void CPUParticles2D::_particles_process(float p_delta) {
p_delta *= speed_scale;
@@ -866,8 +938,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
//scale by scale
- float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale == 0.0) base_scale = 0.000001;
+ float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ if (base_scale < 0.000001) base_scale = 0.000001;
p.transform.elements[0] *= base_scale;
p.transform.elements[1] *= base_scale;
@@ -965,7 +1037,9 @@ void CPUParticles2D::_set_redraw(bool p_redraw) {
VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ }
VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
@@ -1000,6 +1074,10 @@ void CPUParticles2D::_notification(int p_what) {
}
if (p_what == NOTIFICATION_DRAW) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+
if (!redraw)
return; // don't add to render list
@@ -1017,71 +1095,7 @@ void CPUParticles2D::_notification(int p_what) {
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- }
-
- _update_particle_data_buffer();
+ _update_internal();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
@@ -1122,8 +1136,9 @@ void CPUParticles2D::_notification(int p_what) {
}
void CPUParticles2D::convert_from_particles(Node *p_particles) {
+
Particles2D *particles = Object::cast_to<Particles2D>(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND_MSG(!particles, "Only Particles2D nodes can be converted to CPUParticles2D.");
set_emitting(particles->is_emitting());
set_amount(particles->get_amount());
@@ -1410,6 +1425,7 @@ CPUParticles2D::CPUParticles2D() {
frame_remainder = 0;
cycle = 0;
redraw = false;
+ emitting = false;
mesh = VisualServer::get_singleton()->mesh_create();
multimesh = VisualServer::get_singleton()->multimesh_create();
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index da668664b9..47b4568dd4 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -174,6 +174,7 @@ private:
Vector2 gravity;
+ void _update_internal();
void _particles_process(float p_delta);
void _update_particle_data_buffer();
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index d8156a0afe..847d08b025 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -37,8 +37,8 @@
void Joint2D::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid())
- Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb);
+ if (ba.is_valid() && bb.is_valid() && exclude_from_collision)
+ Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
Physics2DServer::get_singleton()->free(joint);
joint = RID();
@@ -61,8 +61,6 @@ void Joint2D::_update_joint(bool p_only_free) {
if (!body_a || !body_b)
return;
- SWAP(body_a, body_b);
-
joint = _configure_joint(body_a, body_b);
if (!joint.is_valid())
@@ -133,6 +131,8 @@ void Joint2D::set_exclude_nodes_from_collision(bool p_enable) {
if (exclude_from_collision == p_enable)
return;
+
+ _update_joint(true);
exclude_from_collision = p_enable;
_update_joint();
}
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 9fe5fb98b6..6436b3878f 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -155,7 +155,7 @@ void LineBuilder::build() {
texture_mode == Line2D::LINE_TEXTURE_STRETCH;
if (distance_required) {
total_distance = calculate_total_distance(points);
- //Ajust totalDistance.
+ //Adjust totalDistance.
// The line's outer length will be a little higher due to begin and end caps
if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) {
if (retrieve_curve)
diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp
index 5cf28d6c89..c7d2dabbae 100644
--- a/scene/2d/navigation_2d.cpp
+++ b/scene/2d/navigation_2d.cpp
@@ -541,7 +541,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) {
//process
- if (Math::is_zero_approx(portal_left.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
+ if (portal_left.is_equal_approx(apex_point) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
left_poly = p;
portal_left = left;
} else {
@@ -551,7 +551,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
left_poly = p;
portal_left = apex_point;
portal_right = apex_point;
- if (!path.size() || path[path.size() - 1] != apex_point)
+ if (!path.size() || !path[path.size() - 1].is_equal_approx(apex_point))
path.push_back(apex_point);
skip = true;
}
@@ -559,7 +559,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) {
//process
- if (Math::is_zero_approx(portal_right.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
+ if (portal_right.is_equal_approx(apex_point) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
right_poly = p;
portal_right = right;
} else {
@@ -569,7 +569,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
right_poly = p;
portal_right = apex_point;
portal_left = apex_point;
- if (!path.size() || path[path.size() - 1] != apex_point)
+ if (!path.size() || !path[path.size() - 1].is_equal_approx(apex_point))
path.push_back(apex_point);
}
}
@@ -595,7 +595,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
}
}
- if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(begin_point))) {
+ if (!path.size() || !path[path.size() - 1].is_equal_approx(begin_point)) {
path.push_back(begin_point); // Add the begin point
} else {
path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
@@ -603,7 +603,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
path.invert();
- if (path.size() <= 1 || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(end_point))) {
+ if (path.size() <= 1 || !path[path.size() - 1].is_equal_approx(end_point)) {
path.push_back(end_point); // Add the end point
} else {
path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index e389d5f98f..678db85ff0 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -271,7 +271,7 @@ void NavigationPolygon::make_polygons_from_outlines() {
struct Polygon p;
- for (int i = 0; i < tp.GetNumPoints(); i++) {
+ for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
Map<Vector2, int>::Element *E = points.find(tp[i]);
if (!E) {
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index f4430d93f6..336c8aa78e 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -437,7 +437,7 @@ void Node2D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 93c12f0103..0bf8237d37 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -51,13 +51,13 @@ void Particles2D::set_emitting(bool p_emitting) {
void Particles2D::set_amount(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
amount = p_amount;
VS::get_singleton()->particles_set_amount(particles, amount);
}
void Particles2D::set_lifetime(float p_lifetime) {
- ERR_FAIL_COND(p_lifetime <= 0);
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
VS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 9b6020e0fd..3a4f397fe0 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -199,7 +199,7 @@ void StaticBody2D::set_friction(real_t p_friction) {
WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead.");
- ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+ ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1.");
if (physics_material_override.is_null()) {
physics_material_override.instance();
@@ -227,7 +227,7 @@ void StaticBody2D::set_bounce(real_t p_bounce) {
WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.");
- ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
+ ERR_FAIL_COND_MSG(p_bounce < 0 || p_bounce > 1, "Bounce must be between 0 and 1.");
if (physics_material_override.is_null()) {
physics_material_override.instance();
@@ -622,7 +622,7 @@ void RigidBody2D::set_friction(real_t p_friction) {
WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead.");
- ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+ ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1.");
if (physics_material_override.is_null()) {
physics_material_override.instance();
@@ -1209,7 +1209,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
return colliding;
}
-//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 32a0b732c0..5e14959e9d 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -842,7 +842,7 @@ void Polygon2D::_bind_methods() {
ADD_GROUP("Texture", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
ADD_GROUP("Skeleton", "");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index f0c46a5fb7..e37407ceb3 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -38,8 +38,9 @@ const float DEFAULT_GIZMO_EXTENTS = 10.0;
void Position2D::_draw_cross() {
float extents = get_gizmo_extents();
- draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(1, 0.5, 0.5));
- draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.5, 1, 0.5));
+ // Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`)
+ draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32));
+ draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01));
}
Rect2 Position2D::_edit_get_rect() const {
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index d7a8005187..8cdfceea52 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -135,12 +135,12 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) {
return;
if (texture.is_valid())
- texture->remove_change_receptor(this);
+ texture->disconnect(CoreStringNames::get_singleton()->changed, this, "_texture_changed");
texture = p_texture;
if (texture.is_valid())
- texture->add_change_receptor(this);
+ texture->connect(CoreStringNames::get_singleton()->changed, this, "_texture_changed");
update();
emit_signal("texture_changed");
@@ -269,8 +269,8 @@ int Sprite::get_frame() const {
}
void Sprite::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), vframes);
- ERR_FAIL_INDEX(int(p_coord.y), hframes);
+ ERR_FAIL_INDEX(int(p_coord.x), hframes);
+ ERR_FAIL_INDEX(int(p_coord.y), vframes);
set_frame(int(p_coord.y) * hframes + int(p_coord.x));
}
@@ -281,7 +281,7 @@ Vector2 Sprite::get_frame_coords() const {
void Sprite::set_vframes(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1.");
vframes = p_amount;
update();
item_rect_changed();
@@ -294,7 +294,7 @@ int Sprite::get_vframes() const {
void Sprite::set_hframes(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1.");
hframes = p_amount;
update();
item_rect_changed();
@@ -387,13 +387,17 @@ void Sprite::_validate_property(PropertyInfo &property) const {
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
}
-void Sprite::_changed_callback(Object *p_changed, const char *p_prop) {
+void Sprite::_texture_changed() {
// Changes to the texture need to trigger an update to make
// the editor redraw the sprite with the updated texture.
- if (texture.is_valid() && texture.ptr() == p_changed) {
+ if (texture.is_valid()) {
update();
}
}
@@ -443,6 +447,8 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rect"), &Sprite::get_rect);
+ ClassDB::bind_method(D_METHOD("_texture_changed"), &Sprite::_texture_changed);
+
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("texture_changed"));
@@ -480,6 +486,4 @@ Sprite::Sprite() {
}
Sprite::~Sprite() {
- if (texture.is_valid())
- texture->remove_change_receptor(this);
}
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index 5e6717a3f5..d3c0112e62 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -57,6 +57,8 @@ class Sprite : public Node2D {
void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+ void _texture_changed();
+
protected:
void _notification(int p_what);
@@ -64,8 +66,6 @@ protected:
virtual void _validate_property(PropertyInfo &property) const;
- virtual void _changed_callback(Object *p_changed, const char *p_prop);
-
public:
virtual Dictionary _edit_get_state() const;
virtual void _edit_set_state(const Dictionary &p_state);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 15423f8c5e..173214dfe4 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -216,7 +216,7 @@ Size2 TileMap::get_cell_size() const {
void TileMap::set_quadrant_size(int p_size) {
- ERR_FAIL_COND(p_size < 1);
+ ERR_FAIL_COND_MSG(p_size < 1, "Quadrant size cannot be smaller than 1.");
_clear_quadrants();
quadrant_size = p_size;
@@ -955,6 +955,7 @@ void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end
void TileMap::update_cell_bitmask(int p_x, int p_y) {
+ ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot update cell bitmask if Tileset is not open.");
PosKey p(p_x, p_y);
Map<PosKey, Cell>::Element *E = tile_map.find(p);
if (E != NULL) {
@@ -1050,6 +1051,7 @@ void TileMap::update_dirty_bitmask() {
void TileMap::fix_invalid_tiles() {
+ ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) {
@@ -1549,7 +1551,8 @@ Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const {
ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5);
}
} break;
- default: {
+ case HALF_OFFSET_DISABLED: {
+ // Nothing to do.
}
}
}
@@ -1612,26 +1615,27 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
switch (half_offset) {
case HALF_OFFSET_X: {
- if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) {
+ if (int(floor(ret.y)) & 1) {
ret.x -= 0.5;
}
} break;
case HALF_OFFSET_NEGATIVE_X: {
- if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) {
+ if (int(floor(ret.y)) & 1) {
ret.x += 0.5;
}
} break;
case HALF_OFFSET_Y: {
- if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
+ if (int(floor(ret.x)) & 1) {
ret.y -= 0.5;
}
} break;
case HALF_OFFSET_NEGATIVE_Y: {
- if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
+ if (int(floor(ret.x)) & 1) {
ret.y += 0.5;
}
} break;
- default: {
+ case HALF_OFFSET_DISABLED: {
+ // Nothing to do.
}
}
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 9a1a759e72..cf68528388 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -325,8 +325,12 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
}
Rect2 TouchScreenButton::_edit_get_rect() const {
- if (texture.is_null())
- return CanvasItem::_edit_get_rect();
+ if (texture.is_null()) {
+ if (shape.is_valid())
+ return shape->get_rect();
+ else
+ return CanvasItem::_edit_get_rect();
+ }
return Rect2(Size2(), texture->get_size());
}
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 27f16f7601..05ae281cc1 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -836,6 +836,7 @@ void AudioStreamPlayer3D::set_emission_angle(float p_angle) {
ERR_FAIL_COND(p_angle < 0 || p_angle > 90);
emission_angle = p_angle;
update_gizmo();
+ _change_notify("emission_angle");
}
float AudioStreamPlayer3D::get_emission_angle() const {
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index c5ff4dadbc..4b1eccb40d 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -88,7 +88,7 @@ float BakedLightmapData::get_energy() const {
void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) {
- ERR_FAIL_COND(p_lightmap.is_null());
+ ERR_FAIL_COND_MSG(p_lightmap.is_null(), "It's not a reference to a valid Texture object.");
User user;
user.path = p_path;
user.lightmap = p_lightmap;
@@ -215,6 +215,7 @@ float BakedLightmap::get_capture_cell_size() const {
void BakedLightmap::set_extents(const Vector3 &p_extents) {
extents = p_extents;
update_gizmo();
+ _change_notify("bake_extents");
}
Vector3 BakedLightmap::get_extents() const {
@@ -359,7 +360,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
//check for valid save path
DirAccessRef d = DirAccess::open(save_path);
if (!d) {
- ERR_PRINTS("Invalid Save Path: " + save_path);
+ ERR_PRINTS("Invalid Save Path '" + save_path + "'.");
return BAKE_ERROR_NO_SAVE_PATH;
}
}
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 9f8510248c..9797b5f3ab 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -548,9 +548,9 @@ void Camera::_bind_methods() {
BIND_ENUM_CONSTANT(KEEP_WIDTH);
BIND_ENUM_CONSTANT(KEEP_HEIGHT);
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED)
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP)
- BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP)
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP);
+ BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP);
}
float Camera::get_fov() const {
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index fc16bc36cb..86daabefd2 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -46,14 +46,22 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
void CPUParticles::set_emitting(bool p_emitting) {
+ if (emitting == p_emitting)
+ return;
+
emitting = p_emitting;
- if (emitting)
+ if (emitting) {
set_process_internal(true);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (time == 0)
+ _update_internal();
+ }
}
void CPUParticles::set_amount(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles must be greater than 0.");
particles.resize(p_amount);
{
@@ -71,7 +79,7 @@ void CPUParticles::set_amount(int p_amount) {
}
void CPUParticles::set_lifetime(float p_lifetime) {
- ERR_FAIL_COND(p_lifetime <= 0);
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
}
@@ -232,8 +240,7 @@ void CPUParticles::restart() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
-
- set_emitting(true);
+ emitting = false;
{
int pc = particles.size();
@@ -243,6 +250,8 @@ void CPUParticles::restart() {
w[i].active = false;
}
}
+
+ set_emitting(true);
}
void CPUParticles::set_direction(Vector3 p_direction) {
@@ -508,6 +517,81 @@ static float rand_from_seed(uint32_t &seed) {
return float(seed % uint32_t(65536)) / 65535.0;
}
+void CPUParticles::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ bool processed = false;
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ processed = true;
+ }
+
+ if (processed) {
+ _update_particle_data_buffer();
+ }
+}
+
void CPUParticles::_particles_process(float p_delta) {
p_delta *= speed_scale;
@@ -915,8 +999,8 @@ void CPUParticles::_particles_process(float p_delta) {
}
//scale by scale
- float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale == 0.0) base_scale = 0.000001;
+ float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ if (base_scale < 0.000001) base_scale = 0.000001;
p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
@@ -1040,7 +1124,9 @@ void CPUParticles::_set_redraw(bool p_redraw) {
VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ }
VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
}
@@ -1068,85 +1154,24 @@ void CPUParticles::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
set_process_internal(emitting);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
}
if (p_what == NOTIFICATION_EXIT_TREE) {
_set_redraw(false);
}
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- bool processed = false;
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- processed = true;
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- processed = true;
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- processed = true;
- }
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+ }
- if (processed) {
- _update_particle_data_buffer();
- }
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ _update_internal();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
@@ -1193,7 +1218,7 @@ void CPUParticles::_notification(int p_what) {
void CPUParticles::convert_from_particles(Node *p_particles) {
Particles *particles = Object::cast_to<Particles>(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND_MSG(!particles, "Only Particles nodes can be converted to CPUParticles.");
set_emitting(particles->is_emitting());
set_amount(particles->get_amount());
@@ -1472,6 +1497,7 @@ CPUParticles::CPUParticles() {
frame_remainder = 0;
cycle = 0;
redraw = false;
+ emitting = false;
set_notify_transform(true);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 66b37f359a..635265be7f 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -173,6 +173,7 @@ private:
Vector3 gravity;
+ void _update_internal();
void _particles_process(float p_delta);
void _update_particle_data_buffer();
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index a04f156d80..ccc87b924c 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -243,6 +243,7 @@ void GIProbe::set_extents(const Vector3 &p_extents) {
extents = p_extents;
update_gizmo();
+ _change_notify("extents");
}
Vector3 GIProbe::get_extents() const {
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 89072519d5..50ca466df3 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -149,12 +149,38 @@ Ref<Mesh> MeshInstance::get_mesh() const {
void MeshInstance::_resolve_skeleton_path() {
- if (skeleton_path.is_empty())
+ Ref<SkinReference> new_skin_reference;
+
+ if (!skeleton_path.is_empty()) {
+ Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path));
+ if (skeleton) {
+ new_skin_reference = skeleton->register_skin(skin);
+ if (skin.is_null()) {
+ //a skin was created for us
+ skin = new_skin_reference->get_skin();
+ _change_notify();
+ }
+ }
+ }
+
+ skin_ref = new_skin_reference;
+
+ if (skin_ref.is_valid()) {
+ VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton());
+ } else {
+ VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), RID());
+ }
+}
+
+void MeshInstance::set_skin(const Ref<Skin> &p_skin) {
+ skin = p_skin;
+ if (!is_inside_tree())
return;
+ _resolve_skeleton_path();
+}
- Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path));
- if (skeleton)
- VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skeleton->get_skeleton());
+Ref<Skin> MeshInstance::get_skin() const {
+ return skin;
}
void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) {
@@ -365,6 +391,8 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh);
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance::get_skin);
ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
@@ -380,6 +408,7 @@ void MeshInstance::_bind_methods() {
ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
}
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 8b690b0c21..77ead75dd3 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -31,8 +31,10 @@
#ifndef MESH_INSTANCE_H
#define MESH_INSTANCE_H
+#include "scene/3d/skeleton.h"
#include "scene/3d/visual_instance.h"
#include "scene/resources/mesh.h"
+#include "scene/resources/skin.h"
class MeshInstance : public GeometryInstance {
@@ -40,6 +42,8 @@ class MeshInstance : public GeometryInstance {
protected:
Ref<Mesh> mesh;
+ Ref<Skin> skin;
+ Ref<SkinReference> skin_ref;
NodePath skeleton_path;
struct BlendShapeTrack {
@@ -70,6 +74,9 @@ public:
void set_mesh(const Ref<Mesh> &p_mesh);
Ref<Mesh> get_mesh() const;
+ void set_skin(const Ref<Skin> &p_skin);
+ Ref<Skin> get_skin() const;
+
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 12d562c0c6..ba0460d47c 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -230,7 +230,7 @@ void Navigation::navmesh_set_transform(int p_id, const Transform &p_xform) {
}
void Navigation::navmesh_remove(int p_id) {
- ERR_FAIL_COND(!navmesh_map.has(p_id));
+ ERR_FAIL_COND_MSG(!navmesh_map.has(p_id), "Trying to remove nonexisting navmesh with id: " + itos(p_id));
_navmesh_unlink(p_id);
navmesh_map.erase(p_id);
}
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index f82543b789..496dc4b411 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -108,6 +108,24 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
+void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) {
+ ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
+ source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode);
+ _change_notify();
+}
+
+int NavigationMesh::get_source_geometry_mode() const {
+ return source_geometry_mode;
+}
+
+void NavigationMesh::set_source_group_name(StringName p_group_name) {
+ source_group_name = p_group_name;
+}
+
+StringName NavigationMesh::get_source_group_name() const {
+ return source_group_name;
+}
+
void NavigationMesh::set_cell_size(float p_value) {
cell_size = p_value;
}
@@ -387,6 +405,12 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode);
+ ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode);
+
+ ClassDB::bind_method(D_METHOD("set_source_group_name", "mask"), &NavigationMesh::set_source_group_name);
+ ClassDB::bind_method(D_METHOD("get_source_group_name"), &NavigationMesh::get_source_group_name);
+
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
@@ -462,6 +486,8 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
@@ -489,6 +515,13 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
return;
}
}
+
+ if (property.name == "geometry/source_group_name") {
+ if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
+ property.usage = 0;
+ return;
+ }
+ }
}
NavigationMesh::NavigationMesh() {
@@ -509,6 +542,8 @@ NavigationMesh::NavigationMesh() {
partition_type = SAMPLE_PARTITION_WATERSHED;
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
collision_mask = 0xFFFFFFFF;
+ source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
+ source_group_name = "navmesh";
filter_low_hanging_obstacles = false;
filter_ledge_spans = false;
filter_walkable_low_height_spans = false;
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index 5fbf3998ff..d5de653e40 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -77,6 +77,13 @@ public:
PARSED_GEOMETRY_MAX
};
+ enum SourceGeometryMode {
+ SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
+ SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
+ SOURCE_GEOMETRY_GROUPS_EXPLICIT,
+ SOURCE_GEOMETRY_MAX
+ };
+
protected:
float cell_size;
float cell_height;
@@ -96,6 +103,9 @@ protected:
ParsedGeometryType parsed_geometry_type;
uint32_t collision_mask;
+ SourceGeometryMode source_geometry_mode;
+ StringName source_group_name;
+
bool filter_low_hanging_obstacles;
bool filter_ledge_spans;
bool filter_walkable_low_height_spans;
@@ -114,6 +124,12 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+ void set_source_geometry_mode(int p_geometry_mode);
+ int get_source_geometry_mode() const;
+
+ void set_source_group_name(StringName p_group_name);
+ StringName get_source_group_name() const;
+
void set_cell_size(float p_value);
float get_cell_size() const;
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index a6ccdb5791..241eb7d1ca 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -57,13 +57,13 @@ void Particles::set_emitting(bool p_emitting) {
void Particles::set_amount(int p_amount) {
- ERR_FAIL_COND(p_amount < 1);
+ ERR_FAIL_COND_MSG(p_amount < 1, "Amount of particles cannot be smaller than 1.");
amount = p_amount;
VS::get_singleton()->particles_set_amount(particles, amount);
}
void Particles::set_lifetime(float p_lifetime) {
- ERR_FAIL_COND(p_lifetime <= 0);
+ ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
VS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 0756be5fc8..a107c3bf7a 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -188,7 +188,7 @@ void StaticBody::set_friction(real_t p_friction) {
WARN_DEPRECATED_MSG("The method set_friction has been deprecated and will be removed in the future, use physics material instead.");
- ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+ ERR_FAIL_COND_MSG(p_friction < 0 || p_friction > 1, "Friction must be between 0 and 1.");
if (physics_material_override.is_null()) {
physics_material_override.instance();
@@ -216,7 +216,7 @@ void StaticBody::set_bounce(real_t p_bounce) {
WARN_DEPRECATED_MSG("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.");
- ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
+ ERR_FAIL_COND_MSG(p_bounce < 0 || p_bounce > 1, "Bounce must be between 0 and 1.");
if (physics_material_override.is_null()) {
physics_material_override.instance();
@@ -1137,7 +1137,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
return colliding;
}
-//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
+//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
@@ -1201,7 +1201,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
if (p_stop_on_slope) {
if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) {
Transform gt = get_global_transform();
- gt.origin -= collision.travel;
+ gt.origin -= collision.travel.slide(p_floor_direction);
set_global_transform(gt);
return Vector3();
}
@@ -1265,7 +1265,7 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity
if (p_stop_on_slope) {
// move and collide may stray the object a bit because of pre un-stucking,
// so only ensure that motion happens on floor direction in this case.
- col.travel = p_floor_direction * p_floor_direction.dot(col.travel);
+ col.travel = col.travel.project(p_floor_direction);
}
} else {
apply = false; //snapped with floor direction, but did not snap to a floor, do not snap.
@@ -2182,7 +2182,7 @@ void PhysicalBone::_notification(int p_what) {
void PhysicalBone::_direct_state_changed(Object *p_state) {
- if (!simulate_physics) {
+ if (!simulate_physics || !_internal_simulate_physics) {
return;
}
@@ -2205,7 +2205,7 @@ void PhysicalBone::_direct_state_changed(Object *p_state) {
// Update skeleton
if (parent_skeleton) {
if (-1 != bone_id) {
- parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse));
+ parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true);
}
}
}
@@ -2716,7 +2716,6 @@ void PhysicalBone::_start_physics_simulation() {
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
- parent_skeleton->set_bone_ignore_animation(bone_id, true);
_internal_simulate_physics = true;
}
@@ -2728,6 +2727,6 @@ void PhysicalBone::_stop_physics_simulation() {
PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
- parent_skeleton->set_bone_ignore_animation(bone_id, false);
+ parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
_internal_simulate_physics = false;
}
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index e192e040f2..ae79b4eebf 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -36,6 +36,34 @@
#include "scene/3d/physics_body.h"
#include "scene/resources/surface_tool.h"
+void SkinReference::_skin_changed() {
+ if (skeleton_node) {
+ skeleton_node->_make_dirty();
+ }
+}
+
+void SkinReference::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton);
+ ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin);
+}
+
+RID SkinReference::get_skeleton() const {
+ return skeleton;
+}
+
+Ref<Skin> SkinReference::get_skin() const {
+ return skin;
+}
+
+SkinReference::~SkinReference() {
+ if (skeleton_node) {
+ skeleton_node->skin_bindings.erase(this);
+ }
+
+ VS::get_singleton()->free(skeleton);
+}
+
bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
String path = p_path;
@@ -196,110 +224,82 @@ void Skeleton::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_WORLD: {
-
- VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
-
- } break;
- case NOTIFICATION_EXIT_WORLD: {
-
- } break;
- case NOTIFICATION_TRANSFORM_CHANGED: {
-
- VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
- } break;
case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton();
Bone *bonesptr = bones.ptrw();
int len = bones.size();
- vs->skeleton_allocate(skeleton, len); // if same size, nothing really happens
-
_update_process_order();
const int *order = process_order.ptr();
- // pose changed, rebuild cache of inverses
- if (rest_global_inverse_dirty) {
-
- // calculate global rests and invert them
- for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[order[i]];
- if (b.parent >= 0)
- b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
- else
- b.rest_global_inverse = b.rest;
- }
- for (int i = 0; i < len; i++) {
- Bone &b = bonesptr[order[i]];
- b.rest_global_inverse.affine_invert();
- }
-
- rest_global_inverse_dirty = false;
- }
-
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[order[i]];
- if (b.disable_rest) {
- if (b.enabled) {
-
- Transform pose = b.pose;
- if (b.custom_pose_enable) {
+ if (b.global_pose_override_amount >= 0.999) {
+ b.pose_global = b.global_pose_override;
+ } else {
+ if (b.disable_rest) {
+ if (b.enabled) {
- pose = b.custom_pose * pose;
- }
+ Transform pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
- if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * pose;
+ } else {
- b.pose_global = bonesptr[b.parent].pose_global * pose;
+ b.pose_global = pose;
+ }
} else {
- b.pose_global = pose;
- }
- } else {
-
- if (b.parent >= 0) {
+ if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global;
- } else {
+ b.pose_global = bonesptr[b.parent].pose_global;
+ } else {
- b.pose_global = Transform();
+ b.pose_global = Transform();
+ }
}
- }
-
- } else {
- if (b.enabled) {
- Transform pose = b.pose;
- if (b.custom_pose_enable) {
+ } else {
+ if (b.enabled) {
- pose = b.custom_pose * pose;
- }
+ Transform pose = b.pose;
+ if (b.custom_pose_enable) {
+ pose = b.custom_pose * pose;
+ }
+ if (b.parent >= 0) {
- if (b.parent >= 0) {
+ b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
+ } else {
- b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
+ b.pose_global = b.rest * pose;
+ }
} else {
- b.pose_global = b.rest * pose;
- }
- } else {
-
- if (b.parent >= 0) {
+ if (b.parent >= 0) {
- b.pose_global = bonesptr[b.parent].pose_global * b.rest;
- } else {
+ b.pose_global = bonesptr[b.parent].pose_global * b.rest;
+ } else {
- b.pose_global = b.rest;
+ b.pose_global = b.rest;
+ }
}
}
+
+ if (b.global_pose_override_amount >= CMP_EPSILON) {
+ b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
+ }
}
- b.transform_final = b.pose_global * b.rest_global_inverse;
- vs->skeleton_bone_set_transform(skeleton, order[i], b.transform_final);
+ if (b.global_pose_override_reset) {
+ b.global_pose_override_amount = 0.0;
+ }
for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
@@ -311,28 +311,37 @@ void Skeleton::_notification(int p_what) {
}
}
+ //update skins
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+
+ const Skin *skin = E->get()->skin.operator->();
+ RID skeleton = E->get()->skeleton;
+ uint32_t bind_count = skin->get_bind_count();
+
+ if (E->get()->bind_count != bind_count) {
+ VS::get_singleton()->skeleton_allocate(skeleton, bind_count);
+ E->get()->bind_count = bind_count;
+ }
+
+ for (uint32_t i = 0; i < bind_count; i++) {
+ uint32_t bone_index = skin->get_bind_bone(i);
+ ERR_CONTINUE(bone_index >= (uint32_t)len);
+ vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i));
+ }
+ }
+
dirty = false;
} break;
}
}
-Transform Skeleton::get_bone_transform(int p_bone) const {
- ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform());
- if (dirty)
- const_cast<Skeleton *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
- return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
-}
-
-void Skeleton::set_bone_global_pose(int p_bone, const Transform &p_pose) {
+void Skeleton::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) {
ERR_FAIL_INDEX(p_bone, bones.size());
- if (bones[p_bone].parent == -1) {
-
- set_bone_pose(p_bone, bones[p_bone].rest_global_inverse * p_pose); //fast
- } else {
-
- set_bone_pose(p_bone, bones[p_bone].rest.affine_inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose)); //slow
- }
+ bones.write[p_bone].global_pose_override_amount = p_amount;
+ bones.write[p_bone].global_pose_override = p_pose;
+ bones.write[p_bone].global_pose_override_reset = !p_persistent;
+ _make_dirty();
}
Transform Skeleton::get_bone_global_pose(int p_bone) const {
@@ -343,11 +352,6 @@ Transform Skeleton::get_bone_global_pose(int p_bone) const {
return bones[p_bone].pose_global;
}
-RID Skeleton::get_skeleton() const {
-
- return skeleton;
-}
-
// skeleton creation api
void Skeleton::add_bone(const String &p_name) {
@@ -362,8 +366,6 @@ void Skeleton::add_bone(const String &p_name) {
b.name = p_name;
bones.push_back(b);
process_order_dirty = true;
-
- rest_global_inverse_dirty = true;
_make_dirty();
update_gizmo();
}
@@ -408,7 +410,6 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) {
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
bones.write[p_bone].parent = p_parent;
- rest_global_inverse_dirty = true;
process_order_dirty = true;
_make_dirty();
}
@@ -426,23 +427,11 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
}
bones.write[p_bone].parent = -1;
- bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing
process_order_dirty = true;
_make_dirty();
}
-void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
- ERR_FAIL_INDEX(p_bone, bones.size());
- bones.write[p_bone].ignore_animation = p_ignore;
-}
-
-bool Skeleton::is_bone_ignore_animation(int p_bone) const {
-
- ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
- return bones[p_bone].ignore_animation;
-}
-
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size());
@@ -467,7 +456,6 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].rest = p_rest;
- rest_global_inverse_dirty = true;
_make_dirty();
}
Transform Skeleton::get_bone_rest(int p_bone) const {
@@ -482,7 +470,6 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bones.size());
bones.write[p_bone].enabled = p_enabled;
- rest_global_inverse_dirty = true;
_make_dirty();
}
bool Skeleton::is_bone_enabled(int p_bone) const {
@@ -529,7 +516,6 @@ void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound)
void Skeleton::clear_bones() {
bones.clear();
- rest_global_inverse_dirty = true;
process_order_dirty = true;
_make_dirty();
@@ -747,14 +733,67 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
#endif // _3D_DISABLED
-void Skeleton::set_use_bones_in_world_transform(bool p_enable) {
- use_bones_in_world_transform = p_enable;
- if (is_inside_tree()) {
- VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform());
- }
+void Skeleton::_skin_changed() {
+ _make_dirty();
}
-bool Skeleton::is_using_bones_in_world_transform() const {
- return use_bones_in_world_transform;
+
+Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
+
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+ if (E->get()->skin == p_skin) {
+ return Ref<SkinReference>(E->get());
+ }
+ }
+
+ Ref<Skin> skin = p_skin;
+
+ if (skin.is_null()) {
+ //need to create one from existing code, this is for compatibility only
+ //when skeletons did not support skins. It is also used by gizmo
+ //to display the skeleton.
+
+ skin.instance();
+ skin->set_bind_count(bones.size());
+ _update_process_order(); //just in case
+
+ // pose changed, rebuild cache of inverses
+ const Bone *bonesptr = bones.ptr();
+ int len = bones.size();
+ const int *order = process_order.ptr();
+
+ // calculate global rests and invert them
+ for (int i = 0; i < len; i++) {
+ const Bone &b = bonesptr[order[i]];
+ if (b.parent >= 0) {
+ skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest);
+ } else {
+ skin->set_bind_pose(order[i], b.rest);
+ }
+ }
+
+ for (int i = 0; i < len; i++) {
+ //the inverse is what is actually required
+ skin->set_bind_bone(i, i);
+ skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
+ }
+ }
+
+ ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>());
+
+ Ref<SkinReference> skin_ref;
+ skin_ref.instance();
+
+ skin_ref->skeleton_node = this;
+ skin_ref->bind_count = 0;
+ skin_ref->skeleton = VisualServer::get_singleton()->skeleton_create();
+ skin_ref->skeleton_node = this;
+ skin_ref->skin = skin;
+
+ skin_bindings.insert(skin_ref.operator->());
+
+ skin->connect("changed", skin_ref.operator->(), "_skin_changed");
+ _make_dirty();
+ return skin_ref;
}
void Skeleton::_bind_methods() {
@@ -773,6 +812,8 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest);
+ ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton::register_skin);
+
ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests);
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest);
@@ -787,17 +828,12 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose);
- ClassDB::bind_method(D_METHOD("set_bone_global_pose", "bone_idx", "pose"), &Skeleton::set_bone_global_pose);
+ ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose);
ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose);
ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose);
- ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
-
- ClassDB::bind_method(D_METHOD("set_use_bones_in_world_transform", "enable"), &Skeleton::set_use_bones_in_world_transform);
- ClassDB::bind_method(D_METHOD("is_using_bones_in_world_transform"), &Skeleton::is_using_bones_in_world_transform);
-
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
@@ -807,22 +843,19 @@ void Skeleton::_bind_methods() {
#endif // _3D_DISABLED
- ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones_in_world_transform"), "set_use_bones_in_world_transform", "is_using_bones_in_world_transform");
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
Skeleton::Skeleton() {
- rest_global_inverse_dirty = true;
dirty = false;
process_order_dirty = true;
- skeleton = VisualServer::get_singleton()->skeleton_create();
- set_notify_transform(true);
- use_bones_in_world_transform = false;
}
Skeleton::~Skeleton() {
- VisualServer::get_singleton()->free(skeleton);
+
+ //some skins may remain bound
+ for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
+ E->get()->skeleton_node = nullptr;
+ }
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index 5b55dffbc8..824d9567fa 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -33,6 +33,7 @@
#include "core/rid.h"
#include "scene/3d/spatial.h"
+#include "scene/resources/skin.h"
#ifndef _3D_DISABLED
typedef int BoneId;
@@ -40,10 +41,38 @@ typedef int BoneId;
class PhysicalBone;
#endif // _3D_DISABLED
+class Skeleton;
+
+class SkinReference : public Reference {
+ GDCLASS(SkinReference, Reference)
+ friend class Skeleton;
+
+ Skeleton *skeleton_node;
+ RID skeleton;
+ Ref<Skin> skin;
+ uint32_t bind_count = 0;
+ void _skin_changed();
+
+protected:
+ static void _bind_methods();
+
+public:
+ RID get_skeleton() const;
+ Ref<Skin> get_skin() const;
+ ~SkinReference();
+};
+
class Skeleton : public Spatial {
GDCLASS(Skeleton, Spatial);
+private:
+ friend class SkinReference;
+
+ Set<SkinReference *> skin_bindings;
+
+ void _skin_changed();
+
struct Bone {
String name;
@@ -52,11 +81,8 @@ class Skeleton : public Spatial {
int parent;
int sort_index; //used for re-sorting process order
- bool ignore_animation;
-
bool disable_rest;
Transform rest;
- Transform rest_global_inverse;
Transform pose;
Transform pose_global;
@@ -64,7 +90,9 @@ class Skeleton : public Spatial {
bool custom_pose_enable;
Transform custom_pose;
- Transform transform_final;
+ float global_pose_override_amount;
+ bool global_pose_override_reset;
+ Transform global_pose_override;
#ifndef _3D_DISABLED
PhysicalBone *physical_bone;
@@ -76,9 +104,10 @@ class Skeleton : public Spatial {
Bone() {
parent = -1;
enabled = true;
- ignore_animation = false;
- custom_pose_enable = false;
disable_rest = false;
+ custom_pose_enable = false;
+ global_pose_override_amount = 0;
+ global_pose_override_reset = false;
#ifndef _3D_DISABLED
physical_bone = NULL;
cache_parent_physical_bone = NULL;
@@ -86,17 +115,12 @@ class Skeleton : public Spatial {
}
};
- bool rest_global_inverse_dirty;
-
Vector<Bone> bones;
Vector<int> process_order;
bool process_order_dirty;
- RID skeleton;
-
void _make_dirty();
bool dirty;
- bool use_bones_in_world_transform;
// bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {
@@ -127,8 +151,6 @@ public:
NOTIFICATION_UPDATE_SKELETON = 50
};
- RID get_skeleton() const;
-
// skeleton creation api
void add_bone(const String &p_name);
int find_bone(const String &p_name) const;
@@ -141,9 +163,6 @@ public:
void unparent_bone_and_rest(int p_bone);
- void set_bone_ignore_animation(int p_bone, bool p_ignore);
- bool is_bone_ignore_animation(int p_bone) const;
-
void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const;
@@ -151,10 +170,9 @@ public:
void set_bone_rest(int p_bone, const Transform &p_rest);
Transform get_bone_rest(int p_bone) const;
- Transform get_bone_transform(int p_bone) const;
Transform get_bone_global_pose(int p_bone) const;
- void set_bone_global_pose(int p_bone, const Transform &p_pose);
+ void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false);
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
@@ -176,8 +194,7 @@ public:
void localize_rests(); // used for loaders and tools
int get_process_order(int p_idx);
- void set_use_bones_in_world_transform(bool p_enable);
- bool is_using_bones_in_world_transform() const;
+ Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
#ifndef _3D_DISABLED
// Physical bone API
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index 6c3949a0a8..6883da7f6d 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -115,7 +115,7 @@ SoftBody::PinnedPoint SoftBody::PinnedPoint::operator=(const PinnedPoint &obj) {
void SoftBody::_update_pickable() {
if (!is_inside_tree())
return;
- bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree();
+ bool pickable = ray_pickable && is_visible_in_tree();
PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
@@ -395,6 +395,8 @@ void SoftBody::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
}
String SoftBody::get_configuration_warning() const {
@@ -460,7 +462,9 @@ void SoftBody::update_physics_server() {
} else {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_draw_soft_mesh")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ }
}
}
@@ -698,7 +702,8 @@ SoftBody::SoftBody() :
collision_mask(1),
collision_layer(1),
simulation_started(false),
- pinned_points_cache_dirty(true) {
+ pinned_points_cache_dirty(true),
+ ray_pickable(true) {
PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
//set_notify_transform(true);
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index df831f92ef..9a659ef4af 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -690,11 +690,10 @@ void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_targe
Transform lookat;
lookat.origin = p_pos;
- Vector3 original_scale(get_global_transform().basis.get_scale());
+ Vector3 original_scale(get_scale());
lookat = lookat.looking_at(p_target, p_up);
- // as basis was normalized, we just need to apply original scale back
- lookat.basis.scale(original_scale);
set_global_transform(lookat);
+ set_scale(original_scale);
}
Vector3 Spatial::to_local(Vector3 p_global) const {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index a9dacc442c..adcd80b0ab 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -577,9 +577,8 @@ void Sprite3D::set_frame(int p_frame) {
ERR_FAIL_INDEX(p_frame, int64_t(vframes) * hframes);
- if (frame != p_frame)
+ frame = p_frame;
- frame = p_frame;
_queue_update();
_change_notify("frame");
@@ -593,8 +592,8 @@ int Sprite3D::get_frame() const {
}
void Sprite3D::set_frame_coords(const Vector2 &p_coord) {
- ERR_FAIL_INDEX(int(p_coord.x), vframes);
- ERR_FAIL_INDEX(int(p_coord.y), hframes);
+ ERR_FAIL_INDEX(int(p_coord.x), hframes);
+ ERR_FAIL_INDEX(int(p_coord.y), vframes);
set_frame(int(p_coord.y) * hframes + int(p_coord.x));
}
@@ -663,6 +662,10 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
}
void Sprite3D::_bind_methods() {
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index 416a291da1..7fe544eaab 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -157,6 +157,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
+ ERR_FAIL_COND(blend_points[p_point].node.is_null());
blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = p_point; i < blend_points_used - 1; i++) {
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 75031f0149..b04eefbe31 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -113,6 +113,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
+ ERR_FAIL_COND(blend_points[p_point].node.is_null());
blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = 0; i < triangles.size(); i++) {
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 20a09696e1..6f67d01a1c 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -350,8 +350,8 @@ void AnimationNodeOneShot::_bind_methods() {
ADD_GROUP("", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
- BIND_ENUM_CONSTANT(MIX_MODE_BLEND)
- BIND_ENUM_CONSTANT(MIX_MODE_ADD)
+ BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
+ BIND_ENUM_CONSTANT(MIX_MODE_ADD);
}
AnimationNodeOneShot::AnimationNodeOneShot() {
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index e26bd5b5a1..5956609244 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -80,7 +80,7 @@ void AnimationCache::_update_cache() {
if (!node) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!node, "Invalid track path in animation: " + np + ".");
+ ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'.");
}
Path path;
@@ -91,7 +91,7 @@ void AnimationCache::_update_cache() {
if (np.get_subname_count() > 1) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath: " + np + ".");
+ ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'.");
}
Spatial *sp = Object::cast_to<Spatial>(node);
@@ -99,7 +99,7 @@ void AnimationCache::_update_cache() {
if (!sp) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial: " + np + ".");
+ ERR_CONTINUE_MSG(!sp, "Transform track not of type Spatial '" + np + "'.");
}
if (np.get_subname_count() == 1) {
@@ -110,13 +110,13 @@ void AnimationCache::_update_cache() {
if (!sk) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton!: " + np + ".");
+ ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'.");
}
int idx = sk->find_bone(ps);
if (idx == -1) {
path_cache.push_back(Path());
- ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone!: " + np + ".");
+ ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'.");
}
path.bone_idx = idx;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 051f832882..f9bf129b59 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -256,7 +256,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
Skeleton *sk = Object::cast_to<Skeleton>(child);
bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
- if (bone_idx == -1 || sk->is_bone_ignore_animation(bone_idx)) {
+ if (bone_idx == -1) {
continue;
}
@@ -1098,7 +1098,7 @@ void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const {
void AnimationPlayer::set_blend_time(const StringName &p_animation1, const StringName &p_animation2, float p_time) {
- ERR_FAIL_COND(p_time < 0);
+ ERR_FAIL_COND_MSG(p_time < 0, "Blend time cannot be smaller than 0.");
BlendKey bk;
bk.from = p_animation1;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index bb7c400cfe..eb152bc41e 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -622,7 +622,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
Skeleton *sk = Object::cast_to<Skeleton>(spatial);
int bone_idx = sk->find_bone(path.get_subname(0));
- if (bone_idx != -1 && !sk->is_bone_ignore_animation(bone_idx)) {
+ if (bone_idx != -1) {
track_xform->skeleton = sk;
track_xform->bone_idx = bone_idx;
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 8f6d53c21c..ba5936562a 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -820,11 +820,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
t.value = t.object->get_indexed(t.subpath);
t.value.zero();
- if (t.skeleton) {
- t.skip = t.skeleton->is_bone_ignore_animation(t.bone_idx);
- } else {
- t.skip = false;
- }
+ t.skip = false;
}
/* STEP 2 PROCESS ANIMATIONS */
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
index 7a1b10792b..4ec22cf3df 100644
--- a/scene/animation/skeleton_ik.cpp
+++ b/scene/animation/skeleton_ik.cpp
@@ -320,7 +320,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
}
- p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose);
+ p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0);
if (!ci->children.empty())
ci = &ci->children.write[0];
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 0f7d4466c8..a7d936fcd3 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -191,7 +191,7 @@ void Tween::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
// Are we processing during 'regular' time?
if (tween_process_mode == TWEEN_PROCESS_IDLE)
- // Do nothing since we whould only process during idle time
+ // Do nothing since we would only process during idle time
break;
// Should we update?
@@ -281,7 +281,7 @@ void Tween::_bind_methods() {
BIND_ENUM_CONSTANT(EASE_OUT_IN);
}
-Variant &Tween::_get_initial_val(InterpolateData &p_data) {
+Variant Tween::_get_initial_val(const InterpolateData &p_data) const {
// What type of data are we interpolating?
switch (p_data.type) {
@@ -299,7 +299,7 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) {
ERR_FAIL_COND_V(object == NULL, p_data.initial_val);
// Are we targeting a property or a method?
- static Variant initial_val;
+ Variant initial_val;
if (p_data.type == TARGETING_PROPERTY) {
// Get the property from the target object
bool valid = false;
@@ -322,6 +322,41 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) {
return p_data.delta_val;
}
+Variant Tween::_get_final_val(const InterpolateData &p_data) const {
+ switch (p_data.type) {
+ case FOLLOW_PROPERTY:
+ case FOLLOW_METHOD: {
+ // Get the object that is being followed
+ Object *target = ObjectDB::get_instance(p_data.target_id);
+ ERR_FAIL_COND_V(target == NULL, p_data.initial_val);
+
+ // We want to figure out the final value
+ Variant final_val;
+ if (p_data.type == FOLLOW_PROPERTY) {
+ // Read the property as-is
+ bool valid = false;
+ final_val = target->get_indexed(p_data.target_key, &valid);
+ ERR_FAIL_COND_V(!valid, p_data.initial_val);
+ } else {
+ // We're looking at a method. Call the method on the target object
+ Variant::CallError error;
+ final_val = target->call(p_data.target_key[0], NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val);
+ }
+
+ // If we're looking at an INT value, instead convert it to a REAL
+ // This is better for interpolation
+ if (final_val.get_type() == Variant::INT) final_val = final_val.operator real_t();
+
+ return final_val;
+ }
+ default: {
+ // If we're not following a final value/method, use the final value from the data
+ return p_data.final_val;
+ }
+ }
+}
+
Variant &Tween::_get_delta_val(InterpolateData &p_data) {
// What kind of data are we interpolating?
@@ -384,7 +419,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) {
Variant Tween::_run_equation(InterpolateData &p_data) {
// Get the initial and delta values from the data
- Variant &initial_val = _get_initial_val(p_data);
+ Variant initial_val = _get_initial_val(p_data);
Variant &delta_val = _get_delta_val(p_data);
Variant result;
@@ -718,7 +753,8 @@ void Tween::_tween_process(float p_delta) {
// Is the tween now finished?
if (data.finish) {
// Set it to the final value directly
- _apply_tween_value(data, data.final_val);
+ Variant final_val = _get_final_val(data);
+ _apply_tween_value(data, final_val);
// Mark the tween as completed and emit the signal
data.elapsed = 0;
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 64ce099ecd..574238f5c9 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -127,7 +127,8 @@ private:
real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
Variant &_get_delta_val(InterpolateData &p_data);
- Variant &_get_initial_val(InterpolateData &p_data);
+ Variant _get_initial_val(const InterpolateData &p_data) const;
+ Variant _get_final_val(const InterpolateData &p_data) const;
Variant _run_equation(InterpolateData &p_data);
bool _calc_delta_val(const Variant &p_initial_val, const Variant &p_final_val, Variant &p_delta_val);
bool _apply_tween_value(InterpolateData &p_data, Variant &value);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 6dd9e401f6..96b62b97f9 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -35,8 +35,8 @@
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
-#include "editor_scale.h"
-#include "editor_settings.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
#endif
#include "scene/main/viewport.h"
@@ -396,11 +396,18 @@ void ColorPicker::_update_text_value() {
}
void ColorPicker::_sample_draw() {
- Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
+ const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
+
if (color.a < 1.0) {
sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), r, true);
}
+
sample->draw_rect(r, color);
+
+ if (color.r > 1 || color.g > 1 || color.b > 1) {
+ // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
+ sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2());
+ }
}
void ColorPicker::_hsv_draw(int p_which, Control *c) {
@@ -894,10 +901,15 @@ void ColorPickerButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
- Ref<StyleBox> normal = get_stylebox("normal");
- Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
+ const Ref<StyleBox> normal = get_stylebox("normal");
+ const Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
draw_rect(r, color);
+
+ if (color.r > 1 || color.g > 1 || color.b > 1) {
+ // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
+ draw_texture(Control::get_icon("overbright_indicator", "ColorPicker"), normal->get_offset());
+ }
} break;
case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 174c2fce7d..8b4d5d4980 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -645,6 +645,7 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_THEME_CHANGED: {
+ minimum_size_changed();
update();
} break;
case NOTIFICATION_MODAL_CLOSE: {
@@ -818,7 +819,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() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const Ref<Texture> *tex = data.icon_override.getptr(p_name);
if (tex)
@@ -860,7 +861,7 @@ Ref<Texture> Control::get_icon(const StringName &p_name, const StringName &p_typ
}
Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const Ref<Shader> *sdr = data.shader_override.getptr(p_name);
if (sdr)
@@ -903,7 +904,7 @@ Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_ty
Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const Ref<StyleBox> *style = data.style_override.getptr(p_name);
if (style)
return *style;
@@ -949,7 +950,7 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &
}
Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const Ref<Font> *font = data.font_override.getptr(p_name);
if (font)
return *font;
@@ -986,7 +987,7 @@ Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type)
}
Color Control::get_color(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const Color *color = data.color_override.getptr(p_name);
if (color)
return *color;
@@ -1026,7 +1027,7 @@ Color Control::get_color(const StringName &p_name, const StringName &p_type) con
int Control::get_constant(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
const int *constant = data.constant_override.getptr(p_name);
if (constant)
return *constant;
@@ -1102,7 +1103,7 @@ bool Control::has_constant_override(const StringName &p_name) const {
bool Control::has_icon(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_icon_override(p_name))
return true;
}
@@ -1141,7 +1142,7 @@ 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() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_shader_override(p_name))
return true;
}
@@ -1179,7 +1180,7 @@ 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() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_stylebox_override(p_name))
return true;
}
@@ -1217,7 +1218,7 @@ bool Control::has_stylebox(const StringName &p_name, const StringName &p_type) c
}
bool Control::has_font(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_font_override(p_name))
return true;
}
@@ -1256,7 +1257,7 @@ bool Control::has_font(const StringName &p_name, const StringName &p_type) const
bool Control::has_color(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_color_override(p_name))
return true;
}
@@ -1295,7 +1296,7 @@ bool Control::has_color(const StringName &p_name, const StringName &p_type) cons
bool Control::has_constant(const StringName &p_name, const StringName &p_type) const {
- if (p_type == StringName() || p_type == "") {
+ if (p_type == StringName() || p_type == get_class_name()) {
if (has_constant_override(p_name))
return true;
}
@@ -1411,6 +1412,9 @@ void Control::_size_changed() {
}
void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
+
+ ERR_FAIL_INDEX((int)p_margin, 4);
+
Rect2 parent_rect = get_parent_anchorable_rect();
float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range;
@@ -1455,6 +1459,9 @@ void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos
}
void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) {
+
+ ERR_FAIL_INDEX((int)p_preset, 16);
+
//Left
switch (p_preset) {
case PRESET_TOP_LEFT:
@@ -1569,6 +1576,10 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) {
}
void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) {
+
+ ERR_FAIL_INDEX((int)p_preset, 16);
+ ERR_FAIL_INDEX((int)p_resize_mode, 4);
+
// Calculate the size if the node is not resized
Size2 min_size = get_minimum_size();
Size2 new_size = get_size();
@@ -1703,6 +1714,8 @@ void Control::set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPreset
float Control::get_anchor(Margin p_margin) const {
+ ERR_FAIL_INDEX_V(int(p_margin), 4, 0.0);
+
return data.anchor[p_margin];
}
@@ -1719,6 +1732,8 @@ void Control::_change_notify_margins() {
void Control::set_margin(Margin p_margin, float p_value) {
+ ERR_FAIL_INDEX((int)p_margin, 4);
+
data.margin[p_margin] = p_value;
_size_changed();
}
@@ -1739,6 +1754,8 @@ void Control::set_end(const Size2 &p_point) {
float Control::get_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0);
+
return data.margin[p_margin];
}
@@ -1950,6 +1967,8 @@ void Control::add_constant_override(const StringName &p_name, int p_constant) {
void Control::set_focus_mode(FocusMode p_focus_mode) {
+ ERR_FAIL_INDEX((int)p_focus_mode, 3);
+
if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode != FOCUS_NONE && has_focus())
release_focus();
@@ -2202,9 +2221,11 @@ void Control::_modal_stack_remove() {
if (!data.MI)
return;
- get_viewport()->_gui_remove_from_modal_stack(data.MI, data.modal_prev_focus_owner);
-
+ List<Control *>::Element *element = data.MI;
data.MI = NULL;
+
+ get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner);
+
data.modal_prev_focus_owner = 0;
}
@@ -2297,6 +2318,8 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
void Control::set_default_cursor_shape(CursorShape p_shape) {
+ ERR_FAIL_INDEX(int(p_shape), CURSOR_MAX);
+
data.default_cursor = p_shape;
}
@@ -2357,6 +2380,8 @@ NodePath Control::get_focus_previous() const {
Control *Control::_get_focus_neighbour(Margin p_margin, int p_count) {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, NULL);
+
if (p_count >= MAX_NEIGHBOUR_SEARCH_COUNT)
return NULL;
if (!data.focus_neighbour[p_margin].is_empty()) {
@@ -2759,6 +2784,8 @@ bool Control::is_clipping_contents() {
void Control::set_h_grow_direction(GrowDirection p_direction) {
+ ERR_FAIL_INDEX((int)p_direction, 3);
+
data.h_grow = p_direction;
_size_changed();
}
@@ -2770,6 +2797,8 @@ Control::GrowDirection Control::get_h_grow_direction() const {
void Control::set_v_grow_direction(GrowDirection p_direction) {
+ ERR_FAIL_INDEX((int)p_direction, 3);
+
data.v_grow = p_direction;
_size_changed();
}
@@ -2947,7 +2976,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "_set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 59bbdad97a..a1b584bad6 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -35,6 +35,7 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
+#include "scene/main/viewport.h" // Only used to check for more modals when dimming the editor.
#endif
// WindowDialog
@@ -59,7 +60,7 @@ void WindowDialog::_fix_size() {
float left = 0;
float bottom = 0;
float right = 0;
- // Check validity, because the theme could contain a different type of StyleBox
+ // Check validity, because the theme could contain a different type of StyleBox.
if (panel->get_class() == "StyleBoxTexture") {
Ref<StyleBoxTexture> panel_texture = Object::cast_to<StyleBoxTexture>(*panel);
top = panel_texture->get_expand_margin_size(MARGIN_TOP);
@@ -205,9 +206,9 @@ void WindowDialog::_notification(int p_what) {
Color title_color = get_color("title_color", "WindowDialog");
int title_height = get_constant("title_height", "WindowDialog");
int font_height = title_font->get_height() - title_font->get_descent() * 2;
- int x = (size.x - title_font->get_string_size(title).x) / 2;
+ int x = (size.x - title_font->get_string_size(xl_title).x) / 2;
int y = (-title_height + font_height) / 2;
- title_font->draw(canvas, Point2(x, y), title, title_color, size.x - panel->get_minimum_size().x);
+ title_font->draw(canvas, Point2(x, y), xl_title, title_color, size.x - panel->get_minimum_size().x);
} break;
case NOTIFICATION_THEME_CHANGED:
@@ -221,8 +222,9 @@ void WindowDialog::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
String new_title = tr(title);
- if (title != new_title) {
- title = new_title;
+ if (new_title != xl_title) {
+ xl_title = new_title;
+ minimum_size_changed();
update();
}
} break;
@@ -237,12 +239,14 @@ void WindowDialog::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_POST_POPUP: {
- if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton())
+ if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) {
+ was_editor_dimmed = EditorNode::get_singleton()->is_editor_dimmed();
EditorNode::get_singleton()->dim_editor(true);
+ }
} break;
case NOTIFICATION_POPUP_HIDE: {
- if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton())
+ if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton() && !was_editor_dimmed)
EditorNode::get_singleton()->dim_editor(false);
} break;
#endif
@@ -282,9 +286,10 @@ int WindowDialog::_drag_hit_test(const Point2 &pos) const {
void WindowDialog::set_title(const String &p_title) {
- String new_title = tr(p_title);
- if (title != new_title) {
- title = new_title;
+ if (title != p_title) {
+ title = p_title;
+ xl_title = tr(p_title);
+ minimum_size_changed();
update();
}
}
@@ -305,7 +310,7 @@ Size2 WindowDialog::get_minimum_size() const {
Ref<Font> font = get_font("title_font", "WindowDialog");
const int button_width = close_button->get_combined_minimum_size().x;
- const int title_width = font->get_string_size(title).x;
+ const int title_width = font->get_string_size(xl_title).x;
const int padding = button_width / 2;
const int button_area = button_width + padding;
@@ -342,6 +347,10 @@ WindowDialog::WindowDialog() {
close_button = memnew(TextureButton);
add_child(close_button);
close_button->connect("pressed", this, "_closed");
+
+#ifdef TOOLS_ENABLED
+ was_editor_dimmed = false;
+#endif
}
WindowDialog::~WindowDialog() {
@@ -353,7 +362,7 @@ void PopupDialog::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size()));
+ get_stylebox("panel")->draw(ci, Rect2(Point2(), get_size()));
}
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 1a0350ba18..2eb0978e9b 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -53,11 +53,16 @@ class WindowDialog : public Popup {
TextureButton *close_button;
String title;
+ String xl_title;
int drag_type;
Point2 drag_offset;
Point2 drag_offset_far;
bool resizable;
+#ifdef TOOLS_ENABLED
+ bool was_editor_dimmed;
+#endif
+
void _gui_input(const Ref<InputEvent> &p_event);
void _closed();
int _drag_hit_test(const Point2 &pos) const;
@@ -105,7 +110,6 @@ class AcceptDialog : public WindowDialog {
HBoxContainer *hbc;
Label *label;
Button *ok;
- //Button *cancel; no more cancel (there is X on that titlebar)
bool hide_on_ok;
void _custom_action(const String &p_action);
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 9bc593ea3b..6400061309 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -46,14 +46,31 @@ VBoxContainer *FileDialog::get_vbox() {
void FileDialog::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
- dir_up->set_icon(get_icon("parent_folder"));
- refresh->set_icon(get_icon("reload"));
- show_hidden->set_icon(get_icon("toggle_hidden"));
- }
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ dir_up->set_icon(get_icon("parent_folder"));
+ refresh->set_icon(get_icon("reload"));
+ show_hidden->set_icon(get_icon("toggle_hidden"));
+ }
+
+ Color font_color = get_color("font_color", "ToolButton");
+ Color font_color_hover = get_color("font_color_hover", "ToolButton");
+ Color font_color_pressed = get_color("font_color_pressed", "ToolButton");
+
+ dir_up->add_color_override("icon_color_normal", font_color);
+ dir_up->add_color_override("icon_color_hover", font_color_hover);
+ dir_up->add_color_override("icon_color_pressed", font_color_pressed);
+
+ refresh->add_color_override("icon_color_normal", font_color);
+ refresh->add_color_override("icon_color_hover", font_color_hover);
+ refresh->add_color_override("icon_color_pressed", font_color_pressed);
- if (p_what == NOTIFICATION_POPUP_HIDE) {
+ show_hidden->add_color_override("icon_color_normal", font_color);
+ show_hidden->add_color_override("icon_color_hover", font_color_hover);
+ show_hidden->add_color_override("icon_color_pressed", font_color_pressed);
+
+ } else if (p_what == NOTIFICATION_POPUP_HIDE) {
set_process_unhandled_input(false);
}
@@ -161,8 +178,12 @@ void FileDialog::_post_popup() {
set_process_unhandled_input(true);
// For open dir mode, deselect all items on file dialog open.
- if (mode == MODE_OPEN_DIR)
+ if (mode == MODE_OPEN_DIR) {
deselect_items();
+ file_box->set_visible(false);
+ } else {
+ file_box->set_visible(true);
+ }
}
void FileDialog::_action_pressed() {
@@ -396,6 +417,10 @@ void FileDialog::update_file_name() {
void FileDialog::update_file_list() {
tree->clear();
+
+ // Scroll back to the top after opening a directory
+ tree->get_vscroll_bar()->set_value(0);
+
dir_access->list_dir_begin();
TreeItem *root = tree->create_item();
@@ -637,6 +662,8 @@ bool FileDialog::is_mode_overriding_title() const {
void FileDialog::set_mode(Mode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 5);
+
mode = p_mode;
switch (mode) {
@@ -875,6 +902,10 @@ FileDialog::FileDialog() {
hbc->add_child(dir_up);
dir_up->connect("pressed", this, "_go_up");
+ drives = memnew(OptionButton);
+ hbc->add_child(drives);
+ drives->connect("item_selected", this, "_select_drive");
+
hbc->add_child(memnew(Label(RTR("Path:"))));
dir = memnew(LineEdit);
hbc->add_child(dir);
@@ -892,10 +923,6 @@ FileDialog::FileDialog() {
show_hidden->connect("toggled", this, "set_show_hidden_files");
hbc->add_child(show_hidden);
- drives = memnew(OptionButton);
- hbc->add_child(drives);
- drives->connect("item_selected", this, "_select_drive");
-
makedir = memnew(Button);
makedir->set_text(RTR("Create Folder"));
makedir->connect("pressed", this, "_make_dir");
@@ -906,18 +933,18 @@ FileDialog::FileDialog() {
tree->set_hide_root(true);
vbc->add_margin_child(RTR("Directories & Files:"), tree, true);
- hbc = memnew(HBoxContainer);
- hbc->add_child(memnew(Label(RTR("File:"))));
+ file_box = memnew(HBoxContainer);
+ file_box->add_child(memnew(Label(RTR("File:"))));
file = memnew(LineEdit);
file->set_stretch_ratio(4);
file->set_h_size_flags(SIZE_EXPAND_FILL);
- hbc->add_child(file);
+ file_box->add_child(file);
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
filter->set_h_size_flags(SIZE_EXPAND_FILL);
filter->set_clip_text(true); // too many extensions overflows it
- hbc->add_child(filter);
- vbc->add_child(hbc);
+ file_box->add_child(filter);
+ vbc->add_child(file_box);
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
access = ACCESS_RESOURCES;
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 4fd6d0d13c..687ebc8036 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -78,10 +78,11 @@ private:
LineEdit *dir;
OptionButton *drives;
Tree *tree;
+ HBoxContainer *file_box;
LineEdit *file;
+ OptionButton *filter;
AcceptDialog *mkdirerr;
AcceptDialog *exterr;
- OptionButton *filter;
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index d0e2edc7b5..154e67b6f3 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -36,20 +36,18 @@ void GridContainer::_notification(int p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- int valid_controls_index;
-
- Map<int, int> col_minw; // max of min_width of all controls in each col (indexed by col)
- Map<int, int> row_minh; // max of min_height of all controls in each row (indexed by row)
- Set<int> col_expanded; // columns which have the SIZE_EXPAND flag set
- Set<int> row_expanded; // rows which have the SIZE_EXPAND flag set
+ Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col).
+ Map<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row).
+ Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set.
+ Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set.
int hsep = get_constant("hseparation");
int vsep = get_constant("vseparation");
int max_col = MIN(get_child_count(), columns);
- int max_row = get_child_count() / columns;
+ int max_row = ceil((float)get_child_count() / (float)columns);
- // Compute the per-column/per-row data
- valid_controls_index = 0;
+ // Compute the per-column/per-row data.
+ int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c || !c->is_visible_in_tree())
@@ -77,7 +75,12 @@ void GridContainer::_notification(int p_what) {
}
}
- // Evaluate the remaining space for expanded columns/rows
+ // Consider all empty columns expanded.
+ for (int i = valid_controls_index; i < columns; i++) {
+ col_expanded.insert(i);
+ }
+
+ // Evaluate the remaining space for expanded columns/rows.
Size2 remaining_space = get_size();
for (Map<int, int>::Element *E = col_minw.front(); E; E = E->next()) {
if (!col_expanded.has(E->key()))
@@ -93,7 +96,7 @@ void GridContainer::_notification(int p_what) {
bool can_fit = false;
while (!can_fit && col_expanded.size() > 0) {
- // Check if all minwidth constraints are ok if we use the remaining space
+ // Check if all minwidth constraints are OK if we use the remaining space.
can_fit = true;
int max_index = col_expanded.front()->get();
for (Set<int>::Element *E = col_expanded.front(); E; E = E->next()) {
@@ -105,7 +108,7 @@ void GridContainer::_notification(int p_what) {
}
}
- // If not, the column with maximum minwidth is not expanded
+ // If not, the column with maximum minwidth is not expanded.
if (!can_fit) {
col_expanded.erase(max_index);
remaining_space.width -= col_minw[max_index];
@@ -114,7 +117,7 @@ void GridContainer::_notification(int p_what) {
can_fit = false;
while (!can_fit && row_expanded.size() > 0) {
- // Check if all minwidth constraints are ok if we use the remaining space
+ // Check if all minheight constraints are OK if we use the remaining space.
can_fit = true;
int max_index = row_expanded.front()->get();
for (Set<int>::Element *E = row_expanded.front(); E; E = E->next()) {
@@ -126,14 +129,14 @@ void GridContainer::_notification(int p_what) {
}
}
- // If not, the row with maximum minwidth is not expanded
+ // If not, the row with maximum minheight is not expanded.
if (!can_fit) {
row_expanded.erase(max_index);
remaining_space.height -= row_minh[max_index];
}
}
- // Finally, fit the nodes
+ // Finally, fit the nodes.
int col_expand = col_expanded.size() > 0 ? remaining_space.width / col_expanded.size() : 0;
int row_expand = row_expanded.size() > 0 ? remaining_space.height / row_expanded.size() : 0;
@@ -152,11 +155,11 @@ void GridContainer::_notification(int p_what) {
if (col == 0) {
col_ofs = 0;
if (row > 0)
- row_ofs += ((row_expanded.has(row - 1)) ? row_expand : row_minh[row - 1]) + vsep;
+ row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep;
}
Point2 p(col_ofs, row_ofs);
- Size2 s((col_expanded.has(col)) ? col_expand : col_minw[col], (row_expanded.has(row)) ? row_expand : row_minh[row]);
+ Size2 s(col_expanded.has(col) ? col_expand : col_minw[col], row_expanded.has(row) ? row_expand : row_minh[row]);
fit_child_in_rect(c, Rect2(p, s));
@@ -207,7 +210,7 @@ Size2 GridContainer::get_minimum_size() const {
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree())
+ if (!c || !c->is_visible())
continue;
int row = valid_controls_index / columns;
int col = valid_controls_index % columns;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index a3bc68ffcd..1406586361 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -411,6 +411,7 @@ void ItemList::set_max_columns(int p_amount) {
ERR_FAIL_COND(p_amount < 0);
max_columns = p_amount;
update();
+ shape_changed = true;
}
int ItemList::get_max_columns() const {
@@ -430,6 +431,7 @@ ItemList::SelectMode ItemList::get_select_mode() const {
void ItemList::set_icon_mode(IconMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 2);
icon_mode = p_mode;
update();
shape_changed = true;
@@ -925,7 +927,7 @@ void ItemList::_notification(int p_what) {
current_columns = max_columns;
while (true) {
- //repeat util all fits
+ //repeat until all fits
bool all_fit = true;
Vector2 ofs;
int col = 0;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 510f1b18ad..9e2cd9e941 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -296,8 +296,9 @@ Size2 Label::get_minimum_size() const {
Size2 min_style = get_stylebox("normal")->get_minimum_size();
// don't want to mutable everything
- if (word_cache_dirty)
+ if (word_cache_dirty) {
const_cast<Label *>(this)->regenerate_word_cache();
+ }
if (autowrap)
return Size2(1, clip ? 1 : minsize.height) + min_style;
@@ -377,8 +378,14 @@ void Label::regenerate_word_cache() {
memdelete(current);
}
- Ref<StyleBox> style = get_stylebox("normal");
- int width = autowrap ? (get_size().width - style->get_minimum_size().width) : get_longest_line_width();
+ int width;
+ if (autowrap) {
+ Ref<StyleBox> style = get_stylebox("normal");
+ width = MAX(get_size().width, get_custom_minimum_size().width) - style->get_minimum_size().width;
+ } else {
+ width = get_longest_line_width();
+ }
+
Ref<Font> font = get_font("font");
int current_word_size = 0;
@@ -452,6 +459,11 @@ void Label::regenerate_word_cache() {
current_word_size += char_width;
line_width += char_width;
total_char_cache++;
+
+ // allow autowrap to cut words when they exceed line width
+ if (autowrap && (current_word_size > width)) {
+ separatable = true;
+ }
}
if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 6893c38733..ab6f80bfa9 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -87,7 +87,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} else {
- if (b->is_doubleclick()) {
+ if (b->is_doubleclick() && selecting_enabled) {
selection.enabled = true;
selection.begin = 0;
@@ -195,13 +195,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
unsigned int code = k->get_scancode();
- if (k->get_command()) {
+ if (k->get_command() && is_shortcut_keys_enabled()) {
bool handled = true;
switch (code) {
- case (KEY_X): { // CUT
+ case (KEY_X): { // CUT.
if (editable) {
cut_text();
@@ -209,13 +209,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
- case (KEY_C): { // COPY
+ case (KEY_C): { // COPY.
copy_text();
} break;
- case (KEY_V): { // PASTE
+ case (KEY_V): { // PASTE.
if (editable) {
@@ -224,7 +224,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
- case (KEY_Z): { // undo / redo
+ case (KEY_Z): { // Undo/redo.
if (editable) {
if (k->get_shift()) {
redo();
@@ -234,7 +234,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case (KEY_U): { // Delete from start to cursor
+ case (KEY_U): { // Delete from start to cursor.
if (editable) {
@@ -255,7 +255,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} break;
- case (KEY_Y): { // PASTE (Yank for unix users)
+ case (KEY_Y): { // PASTE (Yank for unix users).
if (editable) {
@@ -263,7 +263,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case (KEY_K): { // Delete from cursor_pos to end
+ case (KEY_K): { // Delete from cursor_pos to end.
if (editable) {
@@ -273,14 +273,15 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case (KEY_A): { //Select All
+ case (KEY_A): { // Select all.
select();
+
} break;
#ifdef APPLE_STYLE_KEYS
- case (KEY_LEFT): { // Go to start of text - like HOME key
+ case (KEY_LEFT): { // Go to start of text - like HOME key.
set_cursor_position(0);
} break;
- case (KEY_RIGHT): { // Go to end of text - like END key
+ case (KEY_RIGHT): { // Go to end of text - like END key.
set_cursor_position(text.length());
} break;
#endif
@@ -473,7 +474,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
int text_len = text.length();
if (cursor_pos == text_len)
- break; // nothing to do
+ break; // Nothing to do.
#ifdef APPLE_STYLE_KEYS
if (k->get_alt()) {
@@ -531,6 +532,16 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
set_cursor_position(text.length());
shift_selection_check_post(k->get_shift());
} break;
+ case KEY_MENU: {
+ if (context_menu_enabled) {
+ Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_font("font")->get_height()) / 2);
+ menu->set_position(get_global_transform().xform(pos));
+ menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
+ menu->popup();
+ menu->grab_focus();
+ }
+ } break;
default: {
@@ -730,7 +741,7 @@ void LineEdit::_notification(int p_what) {
Color cursor_color = get_color("cursor_color");
const String &t = using_placeholder ? placeholder_translated : text;
- // draw placeholder color
+ // Draw placeholder color.
if (using_placeholder)
font_color.a *= placeholder_alpha;
@@ -745,6 +756,7 @@ void LineEdit::_notification(int p_what) {
color_icon = get_color("clear_button_color");
}
}
+
r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
if (align == ALIGN_CENTER) {
@@ -762,7 +774,7 @@ void LineEdit::_notification(int p_what) {
FontDrawer drawer(font, Color(1, 1, 1));
while (true) {
- //end of string, break!
+ // End of string, break.
if (char_ofs >= t.length())
break;
@@ -799,7 +811,7 @@ void LineEdit::_notification(int p_what) {
CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1];
int char_width = font->get_char_size(cchar, next).width;
- // end of widget, break!
+ // End of widget, break.
if ((x_ofs + char_width) > ofs_max)
break;
@@ -854,7 +866,7 @@ void LineEdit::_notification(int p_what) {
}
}
- if (char_ofs == cursor_pos && draw_caret) { //may be at the end
+ if (char_ofs == cursor_pos && draw_caret) { // May be at the end.
if (ime_text.length() == 0) {
#ifdef TOOLS_ENABLED
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color);
@@ -1043,7 +1055,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
}
pixel_ofs += char_w;
- if (pixel_ofs > p_x) { //found what we look for
+ if (pixel_ofs > p_x) { // Found what we look for.
break;
}
@@ -1053,6 +1065,52 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
set_cursor_position(ofs);
}
+int LineEdit::get_cursor_pixel_pos() {
+
+ Ref<Font> font = get_font("font");
+ int ofs = window_pos;
+ Ref<StyleBox> style = get_stylebox("normal");
+ int pixel_ofs = 0;
+ Size2 size = get_size();
+ bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
+ int r_icon_width = Control::get_icon("clear")->get_width();
+
+ switch (align) {
+
+ case ALIGN_FILL:
+ case ALIGN_LEFT: {
+
+ pixel_ofs = int(style->get_offset().x);
+ } break;
+ case ALIGN_CENTER: {
+
+ if (window_pos != 0)
+ pixel_ofs = int(style->get_offset().x);
+ else
+ pixel_ofs = int(size.width - (cached_width)) / 2;
+
+ if (display_clear_icon)
+ pixel_ofs -= int(r_icon_width / 2 + style->get_margin(MARGIN_RIGHT));
+ } break;
+ case ALIGN_RIGHT: {
+
+ pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width));
+
+ if (display_clear_icon)
+ pixel_ofs -= int(r_icon_width + style->get_margin(MARGIN_RIGHT));
+ } break;
+ }
+
+ while (ofs < cursor_pos) {
+ if (font != NULL) {
+ pixel_ofs += font->get_char_size(text[ofs]).width;
+ }
+ ofs++;
+ }
+
+ return pixel_ofs;
+}
+
bool LineEdit::cursor_get_blink_enabled() const {
return caret_blink_enabled;
}
@@ -1210,10 +1268,10 @@ void LineEdit::set_cursor_position(int p_pos) {
Ref<Font> font = get_font("font");
if (cursor_pos <= window_pos) {
- /* Adjust window if cursor goes too much to the left */
+ // Adjust window if cursor goes too much to the left.
set_window_pos(MAX(0, cursor_pos - 1));
} else {
- /* Adjust window if cursor goes too much to the right */
+ // Adjust window if cursor goes too much to the right.
int window_width = get_size().width - style->get_minimum_size().width;
bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
@@ -1232,10 +1290,10 @@ void LineEdit::set_cursor_position(int p_pos) {
for (int i = cursor_pos; i >= window_pos; i--) {
if (i >= text.length()) {
- //do not do this, because if the cursor is at the end, its just fine that it takes no space
- //accum_width = font->get_char_size(' ').width; //anything should do
+ // Do not do this, because if the cursor is at the end, its just fine that it takes no space.
+ // accum_width = font->get_char_size(' ').width;
} else {
- accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; //anything should do
+ accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; // Anything should do.
}
if (accum_width > window_width)
break;
@@ -1297,23 +1355,31 @@ Size2 LineEdit::get_minimum_size() const {
Ref<StyleBox> style = get_stylebox("normal");
Ref<Font> font = get_font("font");
- Size2 min = style->get_minimum_size();
- min.height += font->get_height();
+ Size2 min_size;
- //minimum size of text
+ // Minimum size of text.
int space_size = font->get_char_size(' ').x;
- int mstext = get_constant("minimum_spaces") * space_size;
+ min_size.width = get_constant("minimum_spaces") * space_size;
if (expand_to_text_length) {
- mstext = MAX(mstext, font->get_string_size(text).x + space_size); //add a spce because some fonts are too exact, and because cursor needs a bit more when at the end
+ // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end.
+ min_size.width = MAX(min_size.width, font->get_string_size(text).x + space_size);
}
- min.width += mstext;
+ min_size.height = font->get_height();
- return min;
-}
+ // Take icons into account.
+ if (!text.empty() && is_editable() && clear_button_enabled) {
+ min_size.width = MAX(min_size.width, Control::get_icon("clear")->get_width());
+ min_size.height = MAX(min_size.height, Control::get_icon("clear")->get_height());
+ }
+ if (right_icon.is_valid()) {
+ min_size.width = MAX(min_size.width, right_icon->get_width());
+ min_size.height = MAX(min_size.height, right_icon->get_height());
+ }
-/* selection */
+ return style->get_minimum_size() + min_size;
+}
void LineEdit::deselect() {
@@ -1347,6 +1413,8 @@ int LineEdit::get_max_length() const {
}
void LineEdit::selection_fill_at_cursor() {
+ if (!selecting_enabled)
+ return;
selection.begin = cursor_pos;
selection.end = selection.cursor_start;
@@ -1361,6 +1429,8 @@ void LineEdit::selection_fill_at_cursor() {
}
void LineEdit::select_all() {
+ if (!selecting_enabled)
+ return;
if (!text.length())
return;
@@ -1377,32 +1447,7 @@ void LineEdit::set_editable(bool p_editable) {
return;
editable = p_editable;
-
- // Reorganize context menu.
- menu->clear();
-
- if (editable) {
- menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
- }
-
- if (editable) {
- menu->add_separator();
- menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- }
-
- menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
-
- if (editable) {
- menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
- }
-
- menu->add_separator();
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
-
- if (editable) {
- menu->add_item(RTR("Clear"), MENU_CLEAR);
- }
+ _generate_context_menu();
update();
}
@@ -1425,8 +1470,8 @@ bool LineEdit::is_secret() const {
void LineEdit::set_secret_character(const String &p_string) {
- // An empty string as the secret character would crash the engine
- // It also wouldn't make sense to use multiple characters as the secret character
+ // An empty string as the secret character would crash the engine.
+ // It also wouldn't make sense to use multiple characters as the secret character.
ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given).");
secret_character = p_string;
@@ -1438,6 +1483,8 @@ String LineEdit::get_secret_character() const {
}
void LineEdit::select(int p_from, int p_to) {
+ if (!selecting_enabled)
+ return;
if (p_from == 0 && p_to == 0) {
deselect();
@@ -1545,6 +1592,29 @@ bool LineEdit::is_clear_button_enabled() const {
return clear_button_enabled;
}
+void LineEdit::set_shortcut_keys_enabled(bool p_enabled) {
+ shortcut_keys_enabled = p_enabled;
+
+ _generate_context_menu();
+}
+
+bool LineEdit::is_shortcut_keys_enabled() const {
+ return shortcut_keys_enabled;
+}
+
+void LineEdit::set_selecting_enabled(bool p_enabled) {
+ selecting_enabled = p_enabled;
+
+ if (!selecting_enabled)
+ deselect();
+
+ _generate_context_menu();
+}
+
+bool LineEdit::is_selecting_enabled() const {
+ return selecting_enabled;
+}
+
void LineEdit::set_right_icon(const Ref<Texture> &p_icon) {
if (right_icon == p_icon) {
return;
@@ -1553,8 +1623,11 @@ void LineEdit::set_right_icon(const Ref<Texture> &p_icon) {
update();
}
-void LineEdit::_text_changed() {
+Ref<Texture> LineEdit::get_right_icon() {
+ return right_icon;
+}
+void LineEdit::_text_changed() {
if (expand_to_text_length)
minimum_size_changed();
@@ -1608,6 +1681,25 @@ void LineEdit::_create_undo_state() {
undo_stack.push_back(op);
}
+void LineEdit::_generate_context_menu() {
+ // Reorganize context menu.
+ menu->clear();
+ if (editable)
+ menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0);
+ menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0);
+ if (editable)
+ menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0);
+ menu->add_separator();
+ if (is_selecting_enabled())
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0);
+ if (editable) {
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
+ menu->add_separator();
+ menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0);
+ menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0);
+ }
+}
+
void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed);
@@ -1652,6 +1744,12 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled);
ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled);
+ ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &LineEdit::set_shortcut_keys_enabled);
+ ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &LineEdit::is_shortcut_keys_enabled);
+ ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &LineEdit::set_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &LineEdit::is_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("set_right_icon", "icon"), &LineEdit::set_right_icon);
+ ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon);
ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text")));
@@ -1677,9 +1775,11 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
ADD_GROUP("Placeholder", "placeholder_");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
@@ -1707,6 +1807,8 @@ LineEdit::LineEdit() {
clear_button_enabled = false;
clear_button_status.press_attempt = false;
clear_button_status.pressing_inside = false;
+ shortcut_keys_enabled = true;
+ selecting_enabled = true;
deselect();
set_focus_mode(FOCUS_ALL);
@@ -1724,7 +1826,7 @@ LineEdit::LineEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- editable = false; // initialise to opposite first, so we get past the early-out in set_editable
+ editable = false; // Initialise to opposite first, so we get past the early-out in set_editable.
set_editable(true);
menu->connect("id_pressed", this, "menu_option");
expand_to_text_length = false;
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 1d33f7d4ce..3424131dad 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -75,18 +75,22 @@ private:
String ime_text;
Point2 ime_selection;
+ bool selecting_enabled;
+
bool context_menu_enabled;
PopupMenu *menu;
int cursor_pos;
int window_pos;
- int max_length; // 0 for no maximum
+ int max_length; // 0 for no maximum.
int cached_width;
int cached_placeholder_width;
bool clear_button_enabled;
+ bool shortcut_keys_enabled;
+
Ref<Texture> right_icon;
struct Selection {
@@ -118,6 +122,8 @@ private:
void _clear_redo();
void _create_undo_state();
+ void _generate_context_menu();
+
Timer *caret_blink_timer;
void _text_changed();
@@ -137,6 +143,7 @@ private:
void set_window_pos(int p_pos);
void set_cursor_at_pixel_pos(int p_x);
+ int get_cursor_pixel_pos();
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -216,7 +223,14 @@ public:
void set_clear_button_enabled(bool p_enabled);
bool is_clear_button_enabled() const;
+ void set_shortcut_keys_enabled(bool p_enabled);
+ bool is_shortcut_keys_enabled() const;
+
+ void set_selecting_enabled(bool p_enabled);
+ bool is_selecting_enabled() const;
+
void set_right_icon(const Ref<Texture> &p_icon);
+ Ref<Texture> get_right_icon();
virtual bool is_text_field() const;
LineEdit();
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index d1840e43a3..de8df4215d 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -116,10 +116,16 @@ void OptionButton::add_item(const String &p_label, int p_id) {
void OptionButton::set_item_text(int p_idx, const String &p_text) {
popup->set_item_text(p_idx, p_text);
+
+ if (current == p_idx)
+ set_text(p_text);
}
void OptionButton::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
popup->set_item_icon(p_idx, p_icon);
+
+ if (current == p_idx)
+ set_icon(p_icon);
}
void OptionButton::set_item_id(int p_idx, int p_id) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index a7c6c5ccab..08faaf7d45 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -79,7 +79,7 @@ Size2 PopupMenu::get_minimum_size() const {
if (items[i].checkable_type)
has_check = true;
- String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
+ String text = items[i].xl_text;
size.width += font->get_string_size(text).width;
if (i > 0)
size.height += vseparation;
@@ -519,7 +519,7 @@ void PopupMenu::_notification(int p_what) {
hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
}
- String text = items[i].shortcut.is_valid() ? String(tr(items[i].shortcut->get_name())) : items[i].xl_text;
+ String text = items[i].xl_text;
item_ofs.x += items[i].h_ofs;
if (items[i].separator) {
@@ -627,63 +627,50 @@ void PopupMenu::_notification(int p_what) {
}
}
-void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
+/* Methods to add items with or without icon, checkbox, shortcut.
+ * Be sure to keep them in sync when adding new properties in the Item struct.
+ */
- Item item;
- item.icon = p_icon;
- item.text = p_label;
- item.xl_text = tr(p_label);
+#define ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel) \
+ item.text = p_label; \
+ item.xl_text = tr(p_label); \
+ item.id = p_id == -1 ? items.size() : p_id; \
item.accel = p_accel;
- item.id = p_id;
- items.push_back(item);
- update();
- minimum_size_changed();
-}
+
void PopupMenu::add_item(const String &p_label, int p_id, uint32_t p_accel) {
Item item;
- item.text = p_label;
- item.xl_text = tr(p_label);
- item.accel = p_accel;
- item.id = p_id == -1 ? items.size() : p_id;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
+void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
Item item;
- item.text = p_label;
- item.xl_text = tr(p_label);
- item.id = p_id;
- item.submenu = p_submenu;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
+ item.icon = p_icon;
items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
+void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) {
Item item;
- item.icon = p_icon;
- item.text = p_label;
- item.xl_text = tr(p_label);
- item.accel = p_accel;
- item.id = p_id;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel) {
+void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
Item item;
- item.text = p_label;
- item.xl_text = tr(p_label);
- item.accel = p_accel;
- item.id = p_id == -1 ? items.size() : p_id;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
+ item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
@@ -692,63 +679,59 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, uint32_t p_accel
void PopupMenu::add_radio_check_item(const String &p_label, int p_id, uint32_t p_accel) {
- add_check_item(p_label, p_id, p_accel);
- items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ Item item;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
+ item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ items.push_back(item);
update();
minimum_size_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id, uint32_t p_accel) {
- add_icon_check_item(p_icon, p_label, p_id, p_accel);
- items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ Item item;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
+ item.icon = p_icon;
+ item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
-
- ERR_FAIL_COND(p_shortcut.is_null());
-
- _ref_shortcut(p_shortcut);
+void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) {
Item item;
- item.id = p_id;
- item.icon = p_icon;
- item.shortcut = p_shortcut;
- item.shortcut_is_global = p_global;
+ ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel);
+ item.max_states = p_max_states;
+ item.state = p_default_state;
items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
-
- ERR_FAIL_COND(p_shortcut.is_null());
+#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
+ ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add item with invalid ShortCut."); \
+ _ref_shortcut(p_shortcut); \
+ item.text = p_shortcut->get_name(); \
+ item.xl_text = tr(item.text); \
+ item.id = p_id == -1 ? items.size() : p_id; \
+ item.shortcut = p_shortcut; \
+ item.shortcut_is_global = p_global;
- _ref_shortcut(p_shortcut);
+void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
Item item;
- item.id = p_id;
- item.shortcut = p_shortcut;
- item.shortcut_is_global = p_global;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
-
- ERR_FAIL_COND(p_shortcut.is_null());
-
- _ref_shortcut(p_shortcut);
+void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
Item item;
- item.id = p_id;
- item.shortcut = p_shortcut;
- item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
item.icon = p_icon;
- item.shortcut_is_global = p_global;
items.push_back(item);
update();
minimum_size_changed();
@@ -756,14 +739,19 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh
void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
- ERR_FAIL_COND(p_shortcut.is_null());
+ Item item;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
+ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
+ items.push_back(item);
+ update();
+ minimum_size_changed();
+}
- _ref_shortcut(p_shortcut);
+void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
Item item;
- item.id = p_id;
- item.shortcut = p_shortcut;
- item.shortcut_is_global = p_global;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
+ item.icon = p_icon;
item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
@@ -772,26 +760,42 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bo
void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
- add_check_shortcut(p_shortcut, p_id, p_global);
- items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ Item item;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
+ item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ items.push_back(item);
update();
minimum_size_changed();
}
-void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, uint32_t p_accel) {
+void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id, bool p_global) {
+
+ Item item;
+ ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global);
+ item.icon = p_icon;
+ item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ items.push_back(item);
+ update();
+ minimum_size_changed();
+}
+
+void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
Item item;
item.text = p_label;
item.xl_text = tr(p_label);
- item.accel = p_accel;
- item.id = p_id;
- item.max_states = p_max_states;
- item.state = p_default_state;
+ item.id = p_id == -1 ? items.size() : p_id;
+ item.submenu = p_submenu;
items.push_back(item);
update();
minimum_size_changed();
}
+#undef ITEM_SETUP_WITH_ACCEL
+#undef ITEM_SETUP_WITH_SHORTCUT
+
+/* Methods to modify existing items. */
+
void PopupMenu::set_item_text(int p_idx, const String &p_text) {
ERR_FAIL_INDEX(p_idx, items.size());
@@ -1380,18 +1384,24 @@ void PopupMenu::clear_autohide_areas() {
void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input);
- ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
+
ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_radio_check_item", "label", "id", "accel"), &PopupMenu::add_radio_check_item, DEFVAL(-1), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_icon_radio_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_radio_check_item, DEFVAL(-1), DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("add_multistate_item", "label", "max_states", "default_state", "id", "accel"), &PopupMenu::add_multistate_item, DEFVAL(0), DEFVAL(-1), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_shortcut", "shortcut", "id", "global"), &PopupMenu::add_shortcut, DEFVAL(-1), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_check_shortcut, DEFVAL(-1), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_radio_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_radio_check_shortcut, DEFVAL(-1), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_icon_radio_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_radio_check_shortcut, DEFVAL(-1), DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &PopupMenu::set_item_text);
ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &PopupMenu::set_item_icon);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 8bfe8fc607..8c33178b09 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -120,21 +120,23 @@ protected:
static void _bind_methods();
public:
- void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0);
void add_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0);
- void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0);
+ void add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0);
void add_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0);
+ void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_id = -1, uint32_t p_accel = 0);
void add_radio_check_item(const String &p_label, int p_id = -1, uint32_t p_accel = 0);
void add_icon_radio_check_item(const Ref<Texture> &p_icon, 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, bool p_global = false);
+ void add_multistate_item(const String &p_label, int p_max_states, int p_default_state = 0, int p_id = -1, uint32_t p_accel = 0);
+
void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
+ void add_icon_radio_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_id = -1, bool p_global = false);
- void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, 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 set_item_text(int p_idx, const String &p_text);
void set_item_icon(int p_idx, const Ref<Texture> &p_icon);
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index 67fa85b832..f9e0be5b31 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -119,4 +119,9 @@ CharFXTransform::CharFXTransform() {
offset = Point2();
color = Color();
character = 0;
+ elapsed_time = 0.0f;
+}
+
+CharFXTransform::~CharFXTransform() {
+ environment.clear();
}
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index f9c3e15399..4330cebfe6 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -64,6 +64,8 @@ public:
Dictionary environment;
CharFXTransform();
+ ~CharFXTransform();
+
uint64_t get_relative_index() { return relative_index; }
void set_relative_index(uint64_t p_index) { relative_index = p_index; }
uint64_t get_absolute_index() { return absolute_index; }
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 77d5c8e91f..0331046492 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -143,6 +143,8 @@ Rect2 RichTextLabel::_get_text_rect() {
int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
+ ERR_FAIL_INDEX_V((int)p_mode, 3, 0);
+
RID ci;
if (r_outside)
*r_outside = false;
@@ -348,6 +350,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int it_char_start = p_char_count;
Vector<ItemFX *> fx_stack = Vector<ItemFX *>();
+ _fetch_item_fx_stack(text, fx_stack);
bool custom_fx_ok = true;
if (p_mode == PROCESS_DRAW) {
@@ -359,8 +362,14 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
strikethrough = true;
}
- fade = _fetch_by_type<ItemFade>(text, ITEM_FADE);
- _fetch_item_stack<ItemFX>(text, fx_stack);
+ Item *fade_item = it;
+ while (fade_item) {
+ if (fade_item->type == ITEM_FADE) {
+ fade = static_cast<ItemFade *>(fade_item);
+ break;
+ }
+ fade_item = fade_item->parent;
+ }
} else if (p_mode == PROCESS_CACHE) {
l.char_count += text->text.length();
@@ -467,18 +476,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
faded_visibility > 0.0f);
for (int j = 0; j < fx_stack.size(); j++) {
- ItemCustomFX *item_custom = Object::cast_to<ItemCustomFX>(fx_stack[j]);
- ItemShake *item_shake = Object::cast_to<ItemShake>(fx_stack[j]);
- ItemWave *item_wave = Object::cast_to<ItemWave>(fx_stack[j]);
- ItemTornado *item_tornado = Object::cast_to<ItemTornado>(fx_stack[j]);
- ItemRainbow *item_rainbow = Object::cast_to<ItemRainbow>(fx_stack[j]);
-
- if (item_custom && custom_fx_ok) {
- Ref<CharFXTransform> charfx = Ref<CharFXTransform>(memnew(CharFXTransform));
- Ref<RichTextEffect> custom_effect = _get_custom_effect_by_code(item_custom->identifier);
+ ItemFX *item_fx = fx_stack[j];
+
+ if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) {
+ ItemCustomFX *item_custom = static_cast<ItemCustomFX *>(item_fx);
+
+ Ref<CharFXTransform> charfx = item_custom->char_fx_transform;
+ Ref<RichTextEffect> custom_effect = item_custom->custom_effect;
+
if (!custom_effect.is_null()) {
charfx->elapsed_time = item_custom->elapsed_time;
- charfx->environment = item_custom->environment;
charfx->relative_index = c_item_offset;
charfx->absolute_index = p_char_count;
charfx->visibility = visible;
@@ -494,7 +501,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
visible &= charfx->visibility;
fx_char = charfx->character;
}
- } else if (item_shake) {
+ } else if (item_fx->type == ITEM_SHAKE) {
+ ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
+
uint64_t char_current_rand = item_shake->offset_random(c_item_offset);
uint64_t char_previous_rand = item_shake->offset_previous_random(c_item_offset);
uint64_t max_rand = 2147483647;
@@ -509,14 +518,20 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
Math::cos(current_offset),
n_time)) *
(float)item_shake->strength / 10.0f;
- } else if (item_wave) {
+ } else if (item_fx->type == ITEM_WAVE) {
+ ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
+
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_wave->amplitude / 10.0f);
fx_offset += Point2(0, 1) * value;
- } else if (item_tornado) {
+ } else if (item_fx->type == ITEM_TORNADO) {
+ ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
+
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + pofs) / 50)) * (item_tornado->radius);
fx_offset += Point2(torn_x, torn_y);
- } else if (item_rainbow) {
+ } else if (item_fx->type == ITEM_RAINBOW) {
+ ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
+
fx_color = fx_color.from_hsv(item_rainbow->frequency * (item_rainbow->elapsed_time + ((p_ofs.x + pofs) / 50)),
item_rainbow->saturation,
item_rainbow->value,
@@ -540,12 +555,12 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_font_color_shadow.a > 0) {
float x_ofs_shadow = align_ofs + pofs;
float y_ofs_shadow = y + lh - line_descent;
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
if (p_shadow_as_outline) {
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
}
}
@@ -609,19 +624,19 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_mode == PROCESS_POINTER && r_click_char)
*r_click_char = 0;
- ENSURE_WIDTH(img->image->get_width());
+ ENSURE_WIDTH(img->size.width);
- bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->image->get_height(), img->image->get_height()));
+ bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height));
if (visible)
line_is_blank = false;
if (p_mode == PROCESS_DRAW && visible) {
- img->image->draw(ci, p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->image->get_height()));
+ img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size));
}
p_char_count++;
- ADVANCE(img->image->get_width());
- CHECK_HEIGHT((img->image->get_height() + font->get_descent()));
+ ADVANCE(img->size.width);
+ CHECK_HEIGHT((img->size.height + font->get_descent()));
} break;
case ITEM_NEWLINE: {
@@ -844,7 +859,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
void RichTextLabel::_scroll_changed(double) {
- if (updating_scroll)
+ if (updating_scroll || !scroll_active)
return;
if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - vscroll->get_page()))
@@ -884,7 +899,11 @@ void RichTextLabel::_update_scroll() {
void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_time) {
Item *it = p_frame;
while (it) {
- ItemFX *ifx = Object::cast_to<ItemFX>(it);
+ ItemFX *ifx = NULL;
+
+ if (it->type == ITEM_CUSTOMFX || it->type == ITEM_SHAKE || it->type == ITEM_WAVE || it->type == ITEM_TORNADO || it->type == ITEM_RAINBOW) {
+ ifx = static_cast<ItemFX *>(it);
+ }
if (!ifx) {
it = _get_next_item(it, true);
@@ -893,7 +912,12 @@ void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_
ifx->elapsed_time += p_delta_time;
- ItemShake *shake = Object::cast_to<ItemShake>(it);
+ ItemShake *shake = NULL;
+
+ if (it->type == ITEM_SHAKE) {
+ shake = static_cast<ItemShake *>(it);
+ }
+
if (shake) {
bool cycle = (shake->elapsed_time > (1.0f / shake->rate));
if (cycle) {
@@ -983,9 +1007,6 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
float dt = get_process_delta_time();
- for (int i = 0; i < custom_effects.size(); i++) {
- }
-
_update_fx(main, dt);
update();
}
@@ -1397,6 +1418,9 @@ bool RichTextLabel::_find_strikethrough(Item *p_item) {
}
bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) {
+
+ ERR_FAIL_INDEX_V((int)p_type, 19, false);
+
Item *item = p_item;
while (item) {
@@ -1408,6 +1432,17 @@ bool RichTextLabel::_find_by_type(Item *p_item, ItemType p_type) {
return false;
}
+void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack) {
+ Item *item = p_item;
+ while (item) {
+ if (item->type == ITEM_CUSTOMFX || item->type == ITEM_SHAKE || item->type == ITEM_WAVE || item->type == ITEM_TORNADO || item->type == ITEM_RAINBOW) {
+ r_stack.push_back(static_cast<ItemFX *>(item));
+ }
+
+ item = item->parent;
+ }
+}
+
bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) {
Item *item = p_item;
@@ -1599,7 +1634,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
}
}
-void RichTextLabel::add_image(const Ref<Texture> &p_image) {
+void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, const int p_height) {
if (current->type == ITEM_TABLE)
return;
@@ -1608,6 +1643,30 @@ void RichTextLabel::add_image(const Ref<Texture> &p_image) {
ItemImage *item = memnew(ItemImage);
item->image = p_image;
+
+ if (p_width > 0) {
+ // custom width
+ item->size.width = p_width;
+ if (p_height > 0) {
+ // custom height
+ item->size.height = p_height;
+ } else {
+ // calculate height to keep aspect ratio
+ item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ }
+ } else {
+ if (p_height > 0) {
+ // custom height
+ item->size.height = p_height;
+ // calculate width to keep aspect ratio
+ item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ } else {
+ // keep original width and height
+ item->size.height = p_image->get_height();
+ item->size.width = p_image->get_width();
+ }
+ }
+
_add_item(item, false);
}
@@ -1662,6 +1721,41 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) {
_add_item(item, true);
}
+void RichTextLabel::push_normal() {
+ Ref<Font> normal_font = get_font("normal_font");
+ ERR_FAIL_COND(normal_font.is_null());
+
+ push_font(normal_font);
+}
+
+void RichTextLabel::push_bold() {
+ Ref<Font> bold_font = get_font("bold_font");
+ ERR_FAIL_COND(bold_font.is_null());
+
+ push_font(bold_font);
+}
+
+void RichTextLabel::push_bold_italics() {
+ Ref<Font> bold_italics_font = get_font("bold_italics_font");
+ ERR_FAIL_COND(bold_italics_font.is_null());
+
+ push_font(bold_italics_font);
+}
+
+void RichTextLabel::push_italics() {
+ Ref<Font> italics_font = get_font("italics_font");
+ ERR_FAIL_COND(italics_font.is_null());
+
+ push_font(italics_font);
+}
+
+void RichTextLabel::push_mono() {
+ Ref<Font> mono_font = get_font("mono_font");
+ ERR_FAIL_COND(mono_font.is_null());
+
+ push_font(mono_font);
+}
+
void RichTextLabel::push_color(const Color &p_color) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
@@ -1776,10 +1870,10 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq
_add_item(item, true);
}
-void RichTextLabel::push_customfx(String p_identifier, Dictionary p_environment) {
+void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment) {
ItemCustomFX *item = memnew(ItemCustomFX);
- item->identifier = p_identifier;
- item->environment = p_environment;
+ item->custom_effect = p_custom_effect;
+ item->char_fx_transform->environment = p_environment;
_add_item(item, true);
}
@@ -2090,6 +2184,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
int end = p_bbcode.find("[", brk_end);
if (end == -1)
end = p_bbcode.length();
+
String image = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
Ref<Texture> texture = ResourceLoader::load(image, "Texture");
@@ -2098,6 +2193,32 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = end;
tag_stack.push_front(tag);
+ } else if (tag.begins_with("img=")) {
+
+ int width = 0;
+ int height = 0;
+
+ String params = tag.substr(4, tag.length());
+ int sep = params.find("x");
+ if (sep == -1) {
+ width = params.to_int();
+ } else {
+ width = params.substr(0, sep).to_int();
+ height = params.substr(sep + 1, params.length()).to_int();
+ }
+
+ int end = p_bbcode.find("[", brk_end);
+ if (end == -1)
+ end = p_bbcode.length();
+
+ String image = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
+
+ Ref<Texture> texture = ResourceLoader::load(image, "Texture");
+ if (texture.is_valid())
+ add_image(texture, width, height);
+
+ pos = end;
+ tag_stack.push_front("img");
} else if (tag.begins_with("color=")) {
String col = tag.substr(6, tag.length());
@@ -2287,7 +2408,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
Ref<RichTextEffect> effect = _get_custom_effect_by_code(identifier);
if (!effect.is_null()) {
- push_customfx(identifier, properties);
+ push_customfx(effect, properties);
pos = brk_end + 1;
tag_stack.push_front(identifier);
set_process_internal(true);
@@ -2546,10 +2667,15 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
- ClassDB::bind_method(D_METHOD("add_image", "image"), &RichTextLabel::add_image);
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
+ ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
+ ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold);
+ ClassDB::bind_method(D_METHOD("push_bold_italics"), &RichTextLabel::push_bold_italics);
+ ClassDB::bind_method(D_METHOD("push_italics"), &RichTextLabel::push_italics);
+ ClassDB::bind_method(D_METHOD("push_mono"), &RichTextLabel::push_mono);
ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color);
ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align);
ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent);
@@ -2631,7 +2757,7 @@ void RichTextLabel::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", (PropertyHint)(PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE), "17/17:RichTextEffect", PROPERTY_USAGE_DEFAULT, "RichTextEffect"), "set_effects", "get_effects");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_RESOURCE_TYPE, "17/17:RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE), "RichTextEffect"), "set_effects", "get_effects");
ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
@@ -2700,17 +2826,16 @@ Size2 RichTextLabel::get_minimum_size() const {
}
Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_identifier) {
- Ref<RichTextEffect> r;
for (int i = 0; i < custom_effects.size(); i++) {
if (!custom_effects[i].is_valid())
continue;
if (custom_effects[i]->get_bbcode() == p_bbcode_identifier) {
- r = custom_effects[i];
+ return custom_effects[i];
}
}
- return r;
+ return Ref<RichTextEffect>();
}
Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressions) {
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 6755f9ef2a..b9837fdfcc 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -103,8 +103,7 @@ private:
}
};
- struct Item : public Object {
-
+ struct Item {
int index;
Item *parent;
ItemType type;
@@ -128,7 +127,6 @@ private:
};
struct ItemFrame : public Item {
-
int parent_line;
bool cell;
Vector<Line> lines;
@@ -144,70 +142,59 @@ private:
};
struct ItemText : public Item {
-
String text;
ItemText() { type = ITEM_TEXT; }
};
struct ItemImage : public Item {
-
Ref<Texture> image;
+ Size2 size;
ItemImage() { type = ITEM_IMAGE; }
};
struct ItemFont : public Item {
-
Ref<Font> font;
ItemFont() { type = ITEM_FONT; }
};
struct ItemColor : public Item {
-
Color color;
ItemColor() { type = ITEM_COLOR; }
};
struct ItemUnderline : public Item {
-
ItemUnderline() { type = ITEM_UNDERLINE; }
};
struct ItemStrikethrough : public Item {
-
ItemStrikethrough() { type = ITEM_STRIKETHROUGH; }
};
struct ItemMeta : public Item {
-
Variant meta;
ItemMeta() { type = ITEM_META; }
};
struct ItemAlign : public Item {
-
Align align;
ItemAlign() { type = ITEM_ALIGN; }
};
struct ItemIndent : public Item {
-
int level;
ItemIndent() { type = ITEM_INDENT; }
};
struct ItemList : public Item {
-
ListType list_type;
ItemList() { type = ITEM_LIST; }
};
struct ItemNewline : public Item {
-
ItemNewline() { type = ITEM_NEWLINE; }
};
struct ItemTable : public Item {
-
struct Column {
bool expand;
int expand_ratio;
@@ -301,18 +288,20 @@ private:
};
struct ItemCustomFX : public ItemFX {
- String identifier;
- Dictionary environment;
+ Ref<CharFXTransform> char_fx_transform;
+ Ref<RichTextEffect> custom_effect;
ItemCustomFX() {
- identifier = "";
- environment = Dictionary();
type = ITEM_CUSTOMFX;
+
+ char_fx_transform.instance();
}
virtual ~ItemCustomFX() {
_clear_children();
- environment.clear();
+
+ char_fx_transform.unref();
+ custom_effect.unref();
}
};
@@ -391,32 +380,7 @@ private:
bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = NULL);
bool _find_layout_subitem(Item *from, Item *to);
bool _find_by_type(Item *p_item, ItemType p_type);
- template <typename T>
- T *_fetch_by_type(Item *p_item, ItemType p_type) {
- Item *item = p_item;
- T *result = NULL;
- while (item) {
- if (item->type == p_type) {
- result = Object::cast_to<T>(item);
- if (result)
- return result;
- }
- item = item->parent;
- }
-
- return result;
- };
- template <typename T>
- void _fetch_item_stack(Item *p_item, Vector<T *> &r_stack) {
- Item *item = p_item;
- while (item) {
- T *found = Object::cast_to<T>(item);
- if (found) {
- r_stack.push_back(found);
- }
- item = item->parent;
- }
- }
+ void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
void _update_scroll();
void _update_fx(ItemFrame *p_frame, float p_delta_time);
@@ -443,10 +407,15 @@ protected:
public:
String get_text();
void add_text(const String &p_text);
- void add_image(const Ref<Texture> &p_image);
+ void add_image(const Ref<Texture> &p_image, const int p_width = 0, const int p_height = 0);
void add_newline();
bool remove_line(const int p_line);
void push_font(const Ref<Font> &p_font);
+ void push_normal();
+ void push_bold();
+ void push_bold_italics();
+ void push_italics();
+ void push_mono();
void push_color(const Color &p_color);
void push_underline();
void push_strikethrough();
@@ -456,11 +425,11 @@ public:
void push_meta(const Variant &p_meta);
void push_table(int p_columns);
void push_fade(int p_start_index, int p_length);
- void push_shake(int p_level, float p_rate);
+ void push_shake(int p_strength, float p_rate);
void push_wave(float p_frequency, float p_amplitude);
void push_tornado(float p_frequency, float p_radius);
void push_rainbow(float p_saturation, float p_value, float p_frequency);
- void push_customfx(String p_identifier, Dictionary p_environment);
+ void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment);
void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1);
int get_current_table_column() const;
void push_cell();
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index b777e77bc3..9f853cf0c8 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -287,7 +287,6 @@ void Slider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrollable"), "set_scrollable", "is_scrollable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tick_count", PROPERTY_HINT_RANGE, "0,4096,1"), "set_ticks", "get_ticks");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ticks_on_borders"), "set_ticks_on_borders", "get_ticks_on_borders");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
}
Slider::Slider(Orientation p_orientation) {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 172c366c41..bf067898e6 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -108,21 +108,21 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_LEFT: {
+ line_edit->grab_focus();
+
set_value(get_value() + (up ? get_step() : -get_step()));
range_click_timer->set_wait_time(0.6);
range_click_timer->set_one_shot(true);
range_click_timer->start();
- line_edit->grab_focus();
-
drag.allowed = true;
drag.capture_pos = mb->get_position();
} break;
case BUTTON_RIGHT: {
- set_value((up ? get_max() : get_min()));
line_edit->grab_focus();
+ set_value((up ? get_max() : get_min()));
} break;
case BUTTON_WHEEL_UP: {
if (line_edit->has_focus()) {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 292d80be9d..a29ba36bad 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -94,7 +94,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- // Do not activate tabs when tabs is empty
+ // Do not activate tabs when tabs is empty.
if (get_tab_count() == 0)
return;
@@ -140,6 +140,76 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
pos.x -= tab_width;
}
}
+
+ Ref<InputEventMouseMotion> mm = p_event;
+
+ if (mm.is_valid()) {
+
+ Point2 pos(mm->get_position().x, mm->get_position().y);
+ Size2 size = get_size();
+
+ // Mouse must be on tabs in the tab header area.
+ if (pos.x < tabs_ofs_cache || pos.y > _get_top_margin()) {
+
+ if (menu_hovered || highlight_arrow > -1) {
+ menu_hovered = false;
+ highlight_arrow = -1;
+ update();
+ }
+ return;
+ }
+
+ Ref<Texture> menu = get_icon("menu");
+ if (popup) {
+
+ if (pos.x >= size.width - menu->get_width()) {
+ if (!menu_hovered) {
+ menu_hovered = true;
+ highlight_arrow = -1;
+ update();
+ return;
+ }
+ } else if (menu_hovered) {
+ menu_hovered = false;
+ update();
+ }
+
+ if (menu_hovered) {
+ return;
+ }
+ }
+
+ // Do not activate tabs when tabs is empty.
+ if ((get_tab_count() == 0 || !buttons_visible_cache) && menu_hovered) {
+ highlight_arrow = -1;
+ update();
+ return;
+ }
+
+ int popup_ofs = 0;
+ if (popup) {
+ popup_ofs = menu->get_width();
+ }
+
+ Ref<Texture> increment = get_icon("increment");
+ Ref<Texture> decrement = get_icon("decrement");
+ if (pos.x >= size.width - increment->get_width() - popup_ofs) {
+
+ if (highlight_arrow != 1) {
+ highlight_arrow = 1;
+ update();
+ }
+ } else if (pos.x >= size.width - increment->get_width() - decrement->get_width() - popup_ofs) {
+
+ if (highlight_arrow != 0) {
+ highlight_arrow = 0;
+ update();
+ }
+ } else if (highlight_arrow > -1) {
+ highlight_arrow = -1;
+ update();
+ }
+ }
}
void TabContainer::_notification(int p_what) {
@@ -203,9 +273,11 @@ void TabContainer::_notification(int p_what) {
Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
Ref<Texture> increment = get_icon("increment");
+ Ref<Texture> increment_hl = get_icon("increment_highlight");
Ref<Texture> decrement = get_icon("decrement");
+ Ref<Texture> decrement_hl = get_icon("decrement_highlight");
Ref<Texture> menu = get_icon("menu");
- Ref<Texture> menu_hl = get_icon("menu_hl");
+ Ref<Texture> menu_hl = get_icon("menu_highlight");
Ref<Font> font = get_font("font");
Color font_color_fg = get_color("font_color_fg");
Color font_color_bg = get_color("font_color_bg");
@@ -332,7 +404,7 @@ void TabContainer::_notification(int p_what) {
x = get_size().width;
if (popup) {
x -= menu->get_width();
- if (mouse_x_cache > x)
+ if (menu_hovered)
menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2));
else
menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2));
@@ -340,23 +412,26 @@ void TabContainer::_notification(int p_what) {
// Draw the navigation buttons.
if (buttons_visible_cache) {
- int y_center = header_height / 2;
x -= increment->get_width();
- increment->draw(canvas,
- Point2(x, y_center - (increment->get_height() / 2)),
- Color(1, 1, 1, last_tab_cache < tabs.size() - 1 ? 1.0 : 0.5));
+ if (last_tab_cache < tabs.size() - 1) {
+ draw_texture(highlight_arrow == 1 ? increment_hl : increment, Point2(x, (header_height - increment->get_height()) / 2));
+ } else {
+ draw_texture(increment, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5));
+ }
x -= decrement->get_width();
- decrement->draw(canvas,
- Point2(x, y_center - (decrement->get_height() / 2)),
- Color(1, 1, 1, first_tab_cache > 0 ? 1.0 : 0.5));
+ if (first_tab_cache > 0) {
+ draw_texture(highlight_arrow == 0 ? decrement_hl : decrement, Point2(x, (header_height - decrement->get_height()) / 2));
+ } else {
+ draw_texture(decrement, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5));
+ }
}
} break;
case NOTIFICATION_THEME_CHANGED: {
minimum_size_changed();
- call_deferred("_on_theme_changed"); //wait until all changed theme
+ call_deferred("_on_theme_changed"); // Wait until all changed theme.
} break;
}
}
@@ -367,6 +442,14 @@ void TabContainer::_on_theme_changed() {
}
}
+void TabContainer::_on_mouse_exited() {
+ if (menu_hovered || highlight_arrow > -1) {
+ menu_hovered = false;
+ highlight_arrow = -1;
+ update();
+ }
+}
+
int TabContainer::_get_tab_width(int p_index) const {
ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0);
@@ -894,6 +977,7 @@ void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) {
bool TabContainer::get_use_hidden_tabs_for_min_size() const {
return use_hidden_tabs_for_min_size;
}
+
void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input);
@@ -925,6 +1009,7 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
+ ClassDB::bind_method(D_METHOD("_on_mouse_exited"), &TabContainer::_on_mouse_exited);
ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
@@ -947,14 +1032,17 @@ TabContainer::TabContainer() {
first_tab_cache = 0;
last_tab_cache = 0;
buttons_visible_cache = false;
+ menu_hovered = false;
+ highlight_arrow = -1;
tabs_ofs_cache = 0;
current = 0;
previous = 0;
- mouse_x_cache = 0;
align = ALIGN_CENTER;
tabs_visible = true;
popup = NULL;
drag_to_rearrange_enabled = false;
tabs_rearrange_group = -1;
use_hidden_tabs_for_min_size = false;
+
+ connect("mouse_exited", this, "_on_mouse_exited");
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 0314f86837..0c17ebc3ae 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -46,7 +46,6 @@ public:
};
private:
- int mouse_x_cache;
int first_tab_cache;
int tabs_ofs_cache;
int last_tab_cache;
@@ -54,6 +53,8 @@ private:
int previous;
bool tabs_visible;
bool buttons_visible_cache;
+ bool menu_hovered;
+ int highlight_arrow;
TabAlign align;
Control *_get_tab(int p_idx) const;
int _get_top_margin() const;
@@ -65,6 +66,7 @@ private:
Vector<Control *> _get_tabs() const;
int _get_tab_width(int p_index) const;
void _on_theme_changed();
+ void _on_mouse_exited();
void _update_current_tab();
protected:
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 7b0836cd28..c24f15384b 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -53,7 +53,7 @@ Size2 Tabs::get_minimum_size() const {
ms.width += get_constant("hseparation");
}
- ms.width += Math::ceil(font->get_string_size(tabs[i].text).width);
+ ms.width += Math::ceil(font->get_string_size(tabs[i].xl_text).width);
if (tabs[i].disabled)
ms.width += tab_disabled->get_minimum_size().width;
@@ -223,15 +223,12 @@ void Tabs::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
+ for (int i = 0; i < tabs.size(); ++i) {
+ tabs.write[i].xl_text = tr(tabs[i].text);
+ }
minimum_size_changed();
update();
} break;
- case NOTIFICATION_MOUSE_EXIT: {
- rb_hover = -1;
- cb_hover = -1;
- hover = -1;
- update();
- } break;
case NOTIFICATION_RESIZED: {
_update_cache();
_ensure_no_over_offset();
@@ -324,7 +321,7 @@ void Tabs::_notification(int p_what) {
w += icon->get_width() + get_constant("hseparation");
}
- font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].text, col, tabs[i].size_text);
+ font->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - font->get_height()) / 2 + font->get_ascent()), tabs[i].xl_text, col, tabs[i].size_text);
w += tabs[i].size_text;
@@ -441,6 +438,7 @@ void Tabs::set_tab_title(int p_tab, const String &p_title) {
ERR_FAIL_INDEX(p_tab, tabs.size());
tabs.write[p_tab].text = p_title;
+ tabs.write[p_tab].xl_text = tr(p_title);
update();
minimum_size_changed();
}
@@ -549,7 +547,7 @@ void Tabs::_update_cache() {
for (int i = 0; i < tabs.size(); i++) {
tabs.write[i].ofs_cache = mw;
tabs.write[i].size_cache = get_tab_width(i);
- tabs.write[i].size_text = Math::ceil(font->get_string_size(tabs[i].text).width);
+ tabs.write[i].size_text = Math::ceil(font->get_string_size(tabs[i].xl_text).width);
mw += tabs[i].size_cache;
if (tabs[i].size_cache <= min_width || i == current) {
size_fixed += tabs[i].size_cache;
@@ -597,10 +595,20 @@ void Tabs::_update_cache() {
}
}
+void Tabs::_on_mouse_exited() {
+
+ rb_hover = -1;
+ cb_hover = -1;
+ hover = -1;
+ highlight_arrow = -1;
+ update();
+}
+
void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) {
Tab t;
t.text = p_str;
+ t.xl_text = tr(p_str);
t.icon = p_icon;
t.disabled = false;
t.ofs_cache = 0;
@@ -656,7 +664,7 @@ Variant Tabs::get_drag_data(const Point2 &p_point) {
tf->set_texture(tabs[tab_over].icon);
drag_preview->add_child(tf);
}
- Label *label = memnew(Label(tabs[tab_over].text));
+ Label *label = memnew(Label(tabs[tab_over].xl_text));
drag_preview->add_child(label);
if (!tabs[tab_over].right_button.is_null()) {
TextureRect *tf = memnew(TextureRect);
@@ -805,7 +813,7 @@ int Tabs::get_tab_width(int p_idx) const {
x += get_constant("hseparation");
}
- x += Math::ceil(font->get_string_size(tabs[p_idx].text).width);
+ x += Math::ceil(font->get_string_size(tabs[p_idx].xl_text).width);
if (tabs[p_idx].disabled)
x += tab_disabled->get_minimum_size().width;
@@ -948,6 +956,7 @@ void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover);
+ ClassDB::bind_method(D_METHOD("_on_mouse_exited"), &Tabs::_on_mouse_exited);
ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab);
ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab);
@@ -1024,4 +1033,6 @@ Tabs::Tabs() {
hover = -1;
drag_to_rearrange_enabled = false;
tabs_rearrange_group = -1;
+
+ connect("mouse_exited", this, "_on_mouse_exited");
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 7c54f1acf2..0edf2fedc1 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -58,6 +58,7 @@ private:
struct Tab {
String text;
+ String xl_text;
Ref<Texture> icon;
int ofs_cache;
bool disabled;
@@ -89,7 +90,7 @@ private:
bool cb_pressing;
CloseButtonDisplayPolicy cb_displaypolicy;
- int hover; // hovered tab
+ int hover; // Hovered tab.
int min_width;
bool scrolling_enabled;
bool drag_to_rearrange_enabled;
@@ -101,6 +102,8 @@ private:
void _update_hover();
void _update_cache();
+ void _on_mouse_exited();
+
protected:
void _gui_input(const Ref<InputEvent> &p_event);
void _notification(int p_what);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 7bcef5f9ab..c818633f48 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -161,57 +161,58 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
/* BEGIN */
int lr = cr.begin_key.length();
- if (lr == 0 || lr > left)
- continue;
+ const CharType *kc;
+ bool match;
- const CharType *kc = cr.begin_key.c_str();
+ if (lr != 0 && lr <= left) {
+ kc = cr.begin_key.c_str();
- bool match = true;
+ match = true;
- for (int k = 0; k < lr; k++) {
- if (kc[k] != str[i + k]) {
- match = false;
- break;
+ for (int k = 0; k < lr; k++) {
+ if (kc[k] != str[i + k]) {
+ match = false;
+ break;
+ }
}
- }
- if (match) {
+ if (match) {
- ColorRegionInfo cri;
- cri.end = false;
- cri.region = j;
- text.write[p_line].region_info[i] = cri;
- i += lr - 1;
+ ColorRegionInfo cri;
+ cri.end = false;
+ cri.region = j;
+ text.write[p_line].region_info[i] = cri;
+ i += lr - 1;
- break;
+ break;
+ }
}
/* END */
lr = cr.end_key.length();
- if (lr == 0 || lr > left)
- continue;
-
- kc = cr.end_key.c_str();
+ if (lr != 0 && lr <= left) {
+ kc = cr.end_key.c_str();
- match = true;
+ match = true;
- for (int k = 0; k < lr; k++) {
- if (kc[k] != str[i + k]) {
- match = false;
- break;
+ for (int k = 0; k < lr; k++) {
+ if (kc[k] != str[i + k]) {
+ match = false;
+ break;
+ }
}
- }
- if (match) {
+ if (match) {
- ColorRegionInfo cri;
- cri.end = true;
- cri.region = j;
- text.write[p_line].region_info[i] = cri;
- i += lr - 1;
+ ColorRegionInfo cri;
+ cri.end = true;
+ cri.region = j;
+ text.write[p_line].region_info[i] = cri;
+ i += lr - 1;
- break;
+ break;
+ }
}
}
}
@@ -268,6 +269,12 @@ void TextEdit::Text::clear_wrap_cache() {
}
}
+void TextEdit::Text::clear_info_icons() {
+ for (int i = 0; i < text.size(); i++) {
+ text.write[i].has_info = false;
+ }
+}
+
void TextEdit::Text::clear() {
text.clear();
@@ -302,6 +309,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) {
line.breakpoint = false;
line.bookmark = false;
line.hidden = false;
+ line.has_info = false;
line.width_cache = -1;
line.wrap_amount_cache = -1;
line.data = p_text;
@@ -647,7 +655,7 @@ void TextEdit::_notification(int p_what) {
if (scrolling && get_v_scroll() != target_v_scroll) {
double target_y = target_v_scroll - get_v_scroll();
double dist = sqrt(target_y * target_y);
- // To ensure minimap is responsive overide the speed setting.
+ // To ensure minimap is responsive override the speed setting.
double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
@@ -935,7 +943,7 @@ void TextEdit::_notification(int p_what) {
int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
if (minimap_line >= 0) {
minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
- minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
}
int minimap_draw_amount = minimap_visible_lines + times_line_wraps(minimap_line + 1);
@@ -957,6 +965,10 @@ void TextEdit::_notification(int p_what) {
}
}
+ if (minimap_line < 0 || minimap_line >= (int)text.size()) {
+ break;
+ }
+
Map<int, HighlighterInfo> color_map;
if (syntax_coloring) {
color_map = _get_line_syntax_highlighting(minimap_line);
@@ -1271,7 +1283,8 @@ void TextEdit::_notification(int p_what) {
}
// Loop through characters in one line.
- for (int j = 0; j < str.length(); j++) {
+ int j = 0;
+ for (; j < str.length(); j++) {
if (syntax_coloring) {
if (color_map.has(last_wrap_column + j)) {
@@ -1501,7 +1514,7 @@ void TextEdit::_notification(int p_what) {
}
}
- if (cursor.column == last_wrap_column + str.length() && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) {
+ if (cursor.column == (last_wrap_column + j) && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) {
cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
cursor_pos.y += (get_row_height() - cache.font->get_height()) / 2;
@@ -1722,7 +1735,9 @@ void TextEdit::_notification(int p_what) {
end = font->get_string_size(l.substr(0, l.rfind(String::chr(0xFFFF)))).x;
}
- draw_string(font, hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font->get_height() * i + spacing), l.replace(String::chr(0xFFFF), ""), font_color);
+ Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font->get_height() * i + spacing);
+ round_ofs = round_ofs.round();
+ draw_string(font, round_ofs, l.replace(String::chr(0xFFFF), ""), font_color);
if (end > 0) {
Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font->get_height() + font->get_height() * i + spacing - 1);
draw_line(b, b + Vector2(end - begin, 0), font_color);
@@ -2081,6 +2096,44 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
r_col = col;
}
+Vector2i TextEdit::_get_cursor_pixel_pos() {
+ adjust_viewport_to_cursor();
+ int row = (cursor.line - get_first_visible_line() - cursor.wrap_ofs);
+ // Correct for hidden and wrapped lines
+ for (int i = get_first_visible_line(); i < cursor.line; i++) {
+ if (is_line_hidden(i)) {
+ row -= 1;
+ continue;
+ }
+ row += times_line_wraps(i);
+ }
+ // Row might be wrapped. Adjust row and r_column
+ Vector<String> rows2 = get_wrap_rows_text(cursor.line);
+ while (rows2.size() > 1) {
+ if (cursor.column >= rows2[0].length()) {
+ cursor.column -= rows2[0].length();
+ rows2.remove(0);
+ row++;
+ } else {
+ break;
+ }
+ }
+
+ // Calculate final pixel position
+ int y = (row - get_v_scroll_offset() + 1 /*Bottom of line*/) * get_row_height();
+ int x = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs;
+ int ix = 0;
+ while (ix < rows2[0].size() && ix < cursor.column) {
+ if (cache.font != NULL) {
+ x += cache.font->get_char_size(rows2[0].get(ix)).width;
+ }
+ ix++;
+ }
+ x += get_indent_level(cursor.line) * cache.font->get_char_size(' ').width;
+
+ return Vector2i(x, y);
+}
+
void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const {
float rows = p_mouse.y;
@@ -2107,7 +2160,7 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
if (first_visible_line > 0 && minimap_line >= 0) {
minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
- minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
} else {
minimap_line = 0;
}
@@ -2417,7 +2470,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mm.is_valid()) {
if (select_identifiers_enabled) {
- if (mm->get_command() && mm->get_button_mask() == 0) {
+ if (!dragging_minimap && !dragging_selection && mm->get_command() && mm->get_button_mask() == 0) {
String new_word = get_word_at_pos(mm->get_position());
if (new_word != highlighted_word) {
@@ -2475,7 +2528,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
#endif
if (select_identifiers_enabled) {
- if (k->is_pressed()) {
+ if (k->is_pressed() && !dragging_minimap && !dragging_selection) {
highlighted_word = get_word_at_pos(get_local_mouse_position());
update();
@@ -2804,19 +2857,51 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// No need to indent if we are going upwards.
if (auto_indent && !(k->get_command() && k->get_shift())) {
- // Indent once again if previous line will end with ':' or '{' and the line is not a comment
+ // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment
// (i.e. colon/brace precedes current cursor position).
- if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{') && !is_line_comment(cursor.line)) {
- if (indent_using_spaces) {
- ins += space_indent;
- } else {
- ins += "\t";
+ if (cursor.column > 0) {
+ const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(cursor.line);
+ bool indent_char_found = false;
+ bool should_indent = false;
+ char indent_char = ':';
+ char c = text[cursor.line][cursor.column];
+
+ for (int i = 0; i < cursor.column; i++) {
+ c = text[cursor.line][i];
+ switch (c) {
+ case ':':
+ case '{':
+ case '[':
+ case '(':
+ indent_char_found = true;
+ should_indent = true;
+ indent_char = c;
+ continue;
+ }
+
+ if (indent_char_found && cri_map.has(i) && (color_regions[cri_map[i].region].begin_key == "#" || color_regions[cri_map[i].region].begin_key == "//")) {
+
+ should_indent = true;
+ break;
+ } else if (indent_char_found && !_is_whitespace(c)) {
+ should_indent = false;
+ indent_char_found = false;
+ }
}
- // No need to move the brace below if we are not taking the text with us.
- if (text[cursor.line][cursor.column] == '}' && !k->get_command()) {
- brace_indent = true;
- ins += "\n" + ins.substr(1, ins.length() - 2);
+ if (!is_line_comment(cursor.line) && should_indent) {
+ if (indent_using_spaces) {
+ ins += space_indent;
+ } else {
+ ins += "\t";
+ }
+
+ // No need to move the brace below if we are not taking the text with us.
+ char closing_char = _get_right_pair_symbol(indent_char);
+ if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column]) && !k->get_command()) {
+ brace_indent = true;
+ ins += "\n" + ins.substr(1, ins.length() - 2);
+ }
}
}
}
@@ -3222,7 +3307,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (readonly)
break;
- if (k->get_shift() && !k->get_command() && !k->get_alt()) {
+ if (k->get_shift() && !k->get_command() && !k->get_alt() && is_shortcut_keys_enabled()) {
cut();
break;
}
@@ -3453,13 +3538,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
scancode_handled = false;
break;
}
- select_all();
+ if (is_shortcut_keys_enabled()) {
+ select_all();
+ }
#else
if ((!k->get_command() && !k->get_control())) {
scancode_handled = false;
break;
}
- if (!k->get_shift() && k->get_command())
+ if (!k->get_shift() && k->get_command() && is_shortcut_keys_enabled())
select_all();
else if (k->get_control()) {
if (k->get_shift())
@@ -3515,8 +3602,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
scancode_handled = false;
break;
}
-
- cut();
+ if (is_shortcut_keys_enabled()) {
+ cut();
+ }
} break;
case KEY_C: {
@@ -3526,7 +3614,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- copy();
+ if (is_shortcut_keys_enabled()) {
+ copy();
+ }
} break;
case KEY_Z: {
@@ -3540,10 +3630,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- if (k->get_shift())
- redo();
- else
- undo();
+ if (is_shortcut_keys_enabled()) {
+ if (k->get_shift())
+ redo();
+ else
+ undo();
+ }
} break;
case KEY_Y: {
@@ -3556,7 +3648,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- redo();
+ if (is_shortcut_keys_enabled()) {
+ redo();
+ }
} break;
case KEY_V: {
if (readonly) {
@@ -3567,7 +3661,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- paste();
+ if (is_shortcut_keys_enabled()) {
+ paste();
+ }
} break;
case KEY_SPACE: {
@@ -3585,6 +3681,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
+ case KEY_MENU: {
+ if (context_menu_enabled) {
+ menu->set_position(get_global_transform().xform(_get_cursor_pixel_pos()));
+ menu->set_size(Vector2(1, 1));
+ menu->set_scale(get_global_transform().get_scale());
+ menu->popup();
+ menu->grab_focus();
+ }
+ } break;
+
default: {
scancode_handled = false;
@@ -3822,7 +3928,9 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
if (shift_first_line) {
text.set_breakpoint(p_line + 1, text.is_breakpoint(p_line));
text.set_hidden(p_line + 1, text.is_hidden(p_line));
- text.set_info_icon(p_line + 1, text.get_info_icon(p_line), text.get_info(p_line));
+ if (text.has_info_icon(p_line)) {
+ text.set_info_icon(p_line + 1, text.get_info_icon(p_line), text.get_info(p_line));
+ }
text.set_breakpoint(p_line, false);
text.set_hidden(p_line, false);
@@ -3906,7 +4014,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) {
- if (!setting_text)
+ if (!setting_text && idle_detect->is_inside_tree())
idle_detect->start();
if (undo_enabled) {
@@ -3960,7 +4068,7 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r
void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
- if (!setting_text)
+ if (!setting_text && idle_detect->is_inside_tree())
idle_detect->start();
String text;
@@ -4011,6 +4119,7 @@ void TextEdit::_insert_text_at_cursor(const String &p_text) {
int new_column, new_line;
_insert_text(cursor.line, cursor.column, p_text, &new_line, &new_column);
+ _update_scrollbars();
cursor_set_line(new_line);
cursor_set_column(new_column);
@@ -4061,6 +4170,25 @@ int TextEdit::_get_control_height() const {
return control_height;
}
+void TextEdit::_generate_context_menu() {
+ // Reorganize context menu.
+ menu->clear();
+ if (!readonly)
+ menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0);
+ menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0);
+ if (!readonly)
+ menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0);
+ menu->add_separator();
+ if (is_selecting_enabled())
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0);
+ if (!readonly) {
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
+ menu->add_separator();
+ menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0);
+ menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0);
+ }
+}
+
int TextEdit::get_visible_rows() const {
return _get_control_height() / get_row_height();
}
@@ -4671,6 +4799,9 @@ void TextEdit::set_text(String p_text) {
selection.active = false;
}
+ cursor_set_line(0);
+ cursor_set_column(0);
+
update();
setting_text = false;
};
@@ -4769,6 +4900,7 @@ void TextEdit::set_readonly(bool p_readonly) {
return;
readonly = p_readonly;
+ _generate_context_menu();
// Reorganize context menu.
menu->clear();
@@ -4971,15 +5103,18 @@ Map<int, TextEdit::Text::ColorRegionInfo> TextEdit::_get_line_color_region_info(
void TextEdit::clear_colors() {
keywords.clear();
+ member_keywords.clear();
color_regions.clear();
color_region_cache.clear();
syntax_highlighting_cache.clear();
text.clear_width_cache();
+ update();
}
void TextEdit::add_keyword_color(const String &p_keyword, const Color &p_color) {
keywords[p_keyword] = p_color;
+ syntax_highlighting_cache.clear();
update();
}
@@ -4996,12 +5131,14 @@ Color TextEdit::get_keyword_color(String p_keyword) const {
void TextEdit::add_color_region(const String &p_begin_key, const String &p_end_key, const Color &p_color, bool p_line_only) {
color_regions.push_back(ColorRegion(p_begin_key, p_end_key, p_color, p_line_only));
+ syntax_highlighting_cache.clear();
text.clear_width_cache();
update();
}
void TextEdit::add_member_keyword(const String &p_keyword, const Color &p_color) {
member_keywords[p_keyword] = p_color;
+ syntax_highlighting_cache.clear();
update();
}
@@ -5015,6 +5152,7 @@ Color TextEdit::get_member_color(String p_member) const {
void TextEdit::clear_member_keywords() {
member_keywords.clear();
+ syntax_highlighting_cache.clear();
update();
}
@@ -5108,6 +5246,8 @@ void TextEdit::paste() {
}
void TextEdit::select_all() {
+ if (!selecting_enabled)
+ return;
if (text.size() == 1 && text[0].length() == 0)
return;
@@ -5132,6 +5272,8 @@ void TextEdit::deselect() {
}
void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
+ if (!selecting_enabled)
+ return;
if (p_from_line < 0)
p_from_line = 0;
@@ -5303,11 +5445,11 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc
PoolVector<int> TextEdit::_search_bind(const String &p_key, uint32_t p_search_flags, int p_from_line, int p_from_column) const {
int col, line;
- if (search(p_key, p_search_flags, p_from_line, p_from_column, col, line)) {
+ if (search(p_key, p_search_flags, p_from_line, p_from_column, line, col)) {
PoolVector<int> result;
result.resize(2);
- result.set(0, line);
- result.set(1, col);
+ result.set(SEARCH_RESULT_COLUMN, col);
+ result.set(SEARCH_RESULT_LINE, line);
return result;
} else {
@@ -5551,9 +5693,7 @@ void TextEdit::set_line_info_icon(int p_line, Ref<Texture> p_icon, String p_info
}
void TextEdit::clear_info_icons() {
- for (int i = 0; i < text.size(); i++) {
- text.set_info_icon(i, NULL, "");
- }
+ text.clear_info_icons();
update();
}
@@ -5830,7 +5970,7 @@ void TextEdit::unfold_line(int p_line) {
if (!is_folded(p_line) && !is_line_hidden(p_line))
return;
- int fold_start = p_line;
+ int fold_start;
for (fold_start = p_line; fold_start > 0; fold_start--) {
if (is_folded(fold_start))
break;
@@ -5935,6 +6075,7 @@ void TextEdit::undo() {
}
}
+ _update_scrollbars();
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
cursor_set_line(undo_stack_pos->get().to_line);
cursor_set_column(undo_stack_pos->get().to_column);
@@ -5970,6 +6111,8 @@ void TextEdit::redo() {
break;
}
}
+
+ _update_scrollbars();
cursor_set_line(undo_stack_pos->get().to_line);
cursor_set_column(undo_stack_pos->get().to_column);
undo_stack_pos = undo_stack_pos->next();
@@ -6027,7 +6170,7 @@ bool TextEdit::is_indent_using_spaces() const {
}
void TextEdit::set_indent_size(const int p_size) {
- ERR_FAIL_COND(p_size <= 0);
+ ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0.");
indent_size = p_size;
text.set_indent_size(p_size);
@@ -6245,9 +6388,10 @@ void TextEdit::_confirm_completion() {
String line = text[cursor.line];
CharType next_char = line[cursor.column];
CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1];
+ CharType last_completion_char_display = completion_current.display[completion_current.display.length() - 1];
- if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) {
- _base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
+ if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) {
+ _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
if (last_completion_char == '(') {
@@ -6393,6 +6537,7 @@ void TextEdit::_update_completion_candidates() {
if (inquote && restore_quotes == 1 && !option.display.is_quoted()) {
String quote = single_quote ? "'" : "\"";
option.display = option.display.quote(quote);
+ option.insert_text = option.insert_text.quote(quote);
}
if (option.display.begins_with(s)) {
@@ -6775,6 +6920,29 @@ bool TextEdit::is_context_menu_enabled() {
return context_menu_enabled;
}
+void TextEdit::set_shortcut_keys_enabled(bool p_enabled) {
+ shortcut_keys_enabled = p_enabled;
+
+ _generate_context_menu();
+}
+
+void TextEdit::set_selecting_enabled(bool p_enabled) {
+ selecting_enabled = p_enabled;
+
+ if (!selecting_enabled)
+ deselect();
+
+ _generate_context_menu();
+}
+
+bool TextEdit::is_selecting_enabled() const {
+ return selecting_enabled;
+}
+
+bool TextEdit::is_shortcut_keys_enabled() const {
+ return shortcut_keys_enabled;
+}
+
PopupMenu *TextEdit::get_menu() const {
return menu;
}
@@ -6795,6 +6963,9 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(SEARCH_WHOLE_WORDS);
BIND_ENUM_CONSTANT(SEARCH_BACKWARDS);
+ BIND_ENUM_CONSTANT(SEARCH_RESULT_COLUMN);
+ BIND_ENUM_CONSTANT(SEARCH_RESULT_LINE);
+
/*
ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char);
ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line);
@@ -6830,6 +7001,10 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_wrap_enabled"), &TextEdit::is_wrap_enabled);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled);
+ ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &TextEdit::set_shortcut_keys_enabled);
+ ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled);
+ ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
+ ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut);
ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
@@ -6920,6 +7095,8 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled");
@@ -7078,7 +7255,9 @@ TextEdit::TextEdit() {
minimap_char_size = Point2(1, 2);
minimap_line_spacing = 1;
+ selecting_enabled = true;
context_menu_enabled = true;
+ shortcut_keys_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly.
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 9c568acd93..594366de7d 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -78,6 +78,7 @@ public:
bool bookmark : 1;
bool hidden : 1;
bool safe : 1;
+ bool has_info : 1;
int wrap_amount_cache : 24;
Map<int, ColorRegionInfo> region_info;
Ref<Texture> info_icon;
@@ -115,10 +116,15 @@ public:
void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; }
bool is_safe(int p_line) const { return text[p_line].safe; }
void set_info_icon(int p_line, Ref<Texture> p_icon, String p_info) {
+ if (p_icon.is_null()) {
+ text.write[p_line].has_info = false;
+ return;
+ }
text.write[p_line].info_icon = p_icon;
text.write[p_line].info = p_info;
+ text.write[p_line].has_info = true;
}
- bool has_info_icon(int p_line) const { return text[p_line].info_icon.is_valid(); }
+ bool has_info_icon(int p_line) const { return text[p_line].has_info; }
const Ref<Texture> &get_info_icon(int p_line) const { return text[p_line].info_icon; }
const String &get_info(int p_line) const { return text[p_line].info; }
void insert(int p_at, const String &p_text);
@@ -127,6 +133,7 @@ public:
void clear();
void clear_width_cache();
void clear_wrap_cache();
+ void clear_info_icons();
_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
Text() { indent_size = 4; }
};
@@ -365,10 +372,15 @@ private:
int search_result_line;
int search_result_col;
+ bool selecting_enabled;
+
bool context_menu_enabled;
+ bool shortcut_keys_enabled;
int executing_line;
+ void _generate_context_menu();
+
int get_visible_rows() const;
int get_total_visible_rows() const;
@@ -492,12 +504,16 @@ public:
};
enum SearchFlags {
-
SEARCH_MATCH_CASE = 1,
SEARCH_WHOLE_WORDS = 2,
SEARCH_BACKWARDS = 4
};
+ enum SearchResult {
+ SEARCH_RESULT_COLUMN,
+ SEARCH_RESULT_LINE,
+ };
+
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const;
void _get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const;
@@ -582,6 +598,7 @@ public:
int cursor_get_column() const;
int cursor_get_line() const;
+ Vector2i _get_cursor_pixel_pos();
bool cursor_get_blink_enabled() const;
void cursor_set_blink_enabled(const bool p_enabled);
@@ -737,6 +754,12 @@ public:
void set_context_menu_enabled(bool p_enable);
bool is_context_menu_enabled();
+ void set_selecting_enabled(bool p_enabled);
+ bool is_selecting_enabled() const;
+
+ void set_shortcut_keys_enabled(bool p_enabled);
+ bool is_shortcut_keys_enabled() const;
+
PopupMenu *get_menu() const;
String get_text_for_completion();
@@ -749,6 +772,7 @@ public:
VARIANT_ENUM_CAST(TextEdit::MenuItems);
VARIANT_ENUM_CAST(TextEdit::SearchFlags);
+VARIANT_ENUM_CAST(TextEdit::SearchResult);
class SyntaxHighlighter {
protected:
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index c534df5cbe..9b60a9d1c3 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -344,6 +344,9 @@ void TextureProgress::_notification(int p_what) {
case FILL_CLOCKWISE:
case FILL_COUNTER_CLOCKWISE:
case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: {
+ if (nine_patch_stretch)
+ s = get_size();
+
float val = get_as_ratio() * rad_max_degrees / 360;
if (val == 1) {
Rect2 region = Rect2(Point2(), s);
@@ -384,7 +387,13 @@ void TextureProgress::_notification(int p_what) {
draw_polygon(points, colors, uvs, progress);
}
if (Engine::get_singleton()->is_editor_hint()) {
- Point2 p = progress->get_size();
+ Point2 p;
+
+ if (nine_patch_stretch)
+ p = get_size();
+ else
+ p = progress->get_size();
+
p.x *= get_relative_center().x;
p.y *= get_relative_center().y;
p = p.floor();
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 423794d8ba..473cee5ca1 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "texture_rect.h"
+#include "core/core_string_names.h"
#include "servers/visual_server.h"
void TextureRect::_notification(int p_what) {
@@ -123,6 +124,7 @@ void TextureRect::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_flipped_v"), &TextureRect::is_flipped_v);
ClassDB::bind_method(D_METHOD("set_stretch_mode", "stretch_mode"), &TextureRect::set_stretch_mode);
ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureRect::get_stretch_mode);
+ ClassDB::bind_method(D_METHOD("_texture_changed"), &TextureRect::_texture_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
@@ -140,9 +142,27 @@ void TextureRect::_bind_methods() {
BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED);
}
+void TextureRect::_texture_changed() {
+
+ if (texture.is_valid()) {
+ update();
+ minimum_size_changed();
+ }
+}
+
void TextureRect::set_texture(const Ref<Texture> &p_tex) {
+ if (p_tex == texture)
+ return;
+
+ if (texture.is_valid())
+ texture->disconnect(CoreStringNames::get_singleton()->changed, this, "_texture_changed");
+
texture = p_tex;
+
+ if (texture.is_valid())
+ texture->connect(CoreStringNames::get_singleton()->changed, this, "_texture_changed");
+
update();
/*
if (texture.is_valid())
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 1c5bd9d99c..d144020562 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -56,6 +56,8 @@ private:
Ref<Texture> texture;
StretchMode stretch_mode;
+ void _texture_changed();
+
protected:
void _notification(int p_what);
virtual Size2 get_minimum_size() const;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 2a18436a5e..2c38676c83 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -328,7 +328,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
ci = ci->parent;
}
- if (ci) { // collapsing cursor/selectd, move it!
+ if (ci) { // collapsing cursor/selected, move it!
if (tree->select_mode == Tree::SELECT_MULTI) {
@@ -547,6 +547,11 @@ Ref<Texture> TreeItem::get_button(int p_column, int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), Ref<Texture>());
return cells[p_column].buttons[p_idx].texture;
}
+String TreeItem::get_button_tooltip(int p_column, int p_idx) const {
+ ERR_FAIL_INDEX_V(p_column, cells.size(), String());
+ ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String());
+ return cells[p_column].buttons[p_idx].tooltip;
+}
int TreeItem::get_button_id(int p_column, int p_idx) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), -1);
ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1);
@@ -724,6 +729,43 @@ bool TreeItem::is_folding_disabled() const {
return disable_folding;
}
+Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+
+ if (p_argcount < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return Variant();
+ }
+
+ if (p_args[0]->get_type() != Variant::STRING) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::STRING;
+ return Variant();
+ }
+
+ StringName method = *p_args[0];
+
+ call_recursive(method, &p_args[1], p_argcount - 1, r_error);
+ return Variant();
+}
+
+void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ if (!p_item) {
+ return;
+ }
+ p_item->call(p_method, p_args, p_argcount, r_error);
+ TreeItem *c = p_item->get_children();
+ while (c) {
+ recursive_call_aux(c, p_method, p_args, p_argcount, r_error);
+ c = c->get_next();
+ }
+}
+
+void TreeItem::call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+ recursive_call_aux(this, p_method, p_args, p_argcount, r_error);
+}
+
void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_mode", "column", "mode"), &TreeItem::set_cell_mode);
@@ -785,6 +827,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_color", "column", "color"), &TreeItem::set_custom_color);
ClassDB::bind_method(D_METHOD("clear_custom_color", "column"), &TreeItem::clear_custom_color);
+ ClassDB::bind_method(D_METHOD("get_custom_color", "column"), &TreeItem::get_custom_color);
ClassDB::bind_method(D_METHOD("set_custom_bg_color", "column", "color", "just_outline"), &TreeItem::set_custom_bg_color, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_custom_bg_color", "column"), &TreeItem::clear_custom_bg_color);
@@ -795,6 +838,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_button", "column", "button", "button_idx", "disabled", "tooltip"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count);
+ ClassDB::bind_method(D_METHOD("get_button_tooltip", "column", "button_idx"), &TreeItem::get_button_tooltip);
ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button);
ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button);
ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button);
@@ -814,6 +858,14 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
+ {
+ MethodInfo mi;
+ mi.name = "call_recursive";
+ mi.arguments.push_back(PropertyInfo(Variant::STRING, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_recursive", &TreeItem::_call_recursive_bind, mi);
+ }
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height");
@@ -914,7 +966,6 @@ void Tree::update_cache() {
cache.arrow_collapsed = get_icon("arrow_collapsed");
cache.arrow = get_icon("arrow");
cache.select_arrow = get_icon("select_arrow");
- cache.select_option = get_icon("select_option");
cache.updown = get_icon("updown");
cache.custom_button = get_stylebox("custom_button");
@@ -930,7 +981,6 @@ void Tree::update_cache() {
cache.vseparation = get_constant("vseparation");
cache.item_margin = get_constant("item_margin");
cache.button_margin = get_constant("button_margin");
- cache.guide_width = get_constant("guide_width");
cache.draw_guides = get_constant("draw_guides");
cache.draw_relationship_lines = get_constant("draw_relationship_lines");
cache.relationship_line_color = get_color("relationship_line_color");
@@ -1184,7 +1234,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if (select_mode != SELECT_ROW && (p_item->cells[i].selected || selected_item == p_item)) {
+ if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected) {
Rect2i r(cell_rect.position, cell_rect.size);
if (p_item->cells[i].text.size() > 0) {
@@ -2548,7 +2598,9 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
} else {
Rect2 rect = get_selected()->get_meta("__focus_rect");
if (rect.has_point(Point2(b->get_position().x, b->get_position().y))) {
- edit_selected();
+ if (!edit_selected()) {
+ emit_signal("item_double_clicked");
+ }
} else {
emit_signal("item_double_clicked");
}
@@ -2671,11 +2723,21 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
} break;
case BUTTON_WHEEL_UP: {
+ double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
+ if (v_scroll->get_value() != prev_value) {
+ accept_event();
+ }
+
} break;
case BUTTON_WHEEL_DOWN: {
+ double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
+ if (v_scroll->get_value() != prev_value) {
+ accept_event();
+ }
+
} break;
}
}
@@ -2683,7 +2745,11 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
+ double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
+ if (v_scroll->get_value() != prev_value) {
+ accept_event();
+ }
}
}
@@ -2699,7 +2765,6 @@ bool Tree::edit_selected() {
return false;
Rect2 rect = s->get_meta("__focus_rect");
-
popup_edited_item = s;
popup_edited_item_col = col;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index fdc6da5055..361830173b 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -172,6 +172,8 @@ protected:
remove_child(Object::cast_to<TreeItem>(p_child));
}
+ Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
public:
/* cell mode */
void set_cell_mode(int p_column, TreeCellMode p_mode);
@@ -201,6 +203,7 @@ public:
void add_button(int p_column, const Ref<Texture> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = "");
int get_button_count(int p_column) const;
+ String get_button_tooltip(int p_column, int p_idx) const;
Ref<Texture> get_button(int p_column, int p_idx) const;
int get_button_id(int p_column, int p_idx) const;
void erase_button(int p_column, int p_idx);
@@ -279,6 +282,8 @@ public:
void set_disable_folding(bool p_disable);
bool is_folding_disabled() const;
+ void call_recursive(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+
~TreeItem();
};
@@ -416,7 +421,6 @@ private:
Ref<Texture> arrow_collapsed;
Ref<Texture> arrow;
Ref<Texture> select_arrow;
- Ref<Texture> select_option;
Ref<Texture> updown;
Color font_color;
@@ -429,7 +433,6 @@ private:
int hseparation;
int vseparation;
int item_margin;
- int guide_width;
int button_margin;
Point2 offset;
int draw_relationship_lines;
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 5768f58977..fd2d4a1a11 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -36,6 +36,10 @@
int VideoPlayer::sp_get_channel_count() const {
+ if (playback.is_null()) {
+ return 0;
+ }
+
return playback->get_channels();
}
@@ -56,6 +60,9 @@ bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) {
// Called from main thread (eg VideoStreamPlaybackWebm::update)
int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_frames) {
+ ERR_FAIL_NULL_V(p_udata, 0);
+ ERR_FAIL_NULL_V(p_data, 0);
+
VideoPlayer *vp = (VideoPlayer *)p_udata;
int todo = MIN(vp->resampler.get_writer_space(), p_frames);
@@ -71,6 +78,12 @@ int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_f
return todo;
}
+void VideoPlayer::_mix_audios(void *p_self) {
+
+ ERR_FAIL_NULL(p_self);
+ reinterpret_cast<VideoPlayer *>(p_self)->_mix_audio();
+}
+
// Called from audio thread
void VideoPlayer::_mix_audio() {
@@ -143,7 +156,7 @@ void VideoPlayer::_notification(int p_notification) {
bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
- if (stream.is_null() || paused || !playback->is_playing())
+ if (stream.is_null() || paused || playback.is_null() || !playback->is_playing())
return;
double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec());
@@ -358,7 +371,7 @@ void VideoPlayer::set_stream_position(float p_position) {
playback->seek(p_position);
}
-Ref<Texture> VideoPlayer::get_video_texture() {
+Ref<Texture> VideoPlayer::get_video_texture() const {
if (playback.is_valid())
return playback->get_texture();
@@ -394,9 +407,9 @@ StringName VideoPlayer::get_bus() const {
return "Master";
}
-void VideoPlayer::_validate_property(PropertyInfo &property) const {
+void VideoPlayer::_validate_property(PropertyInfo &p_property) const {
- if (property.name == "bus") {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
@@ -406,7 +419,7 @@ void VideoPlayer::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
}
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 62fb7838b6..7d2821427e 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -55,7 +55,6 @@ class VideoPlayer : public Control {
RID stream_rid;
Ref<ImageTexture> texture;
- Ref<Image> last_frame;
AudioRBResampler resampler;
Vector<AudioFrame> mix_buffer;
@@ -75,19 +74,19 @@ class VideoPlayer : public Control {
void _mix_audio();
static int _audio_mix_callback(void *p_udata, const float *p_data, int p_frames);
- static void _mix_audios(void *self) { reinterpret_cast<VideoPlayer *>(self)->_mix_audio(); }
+ static void _mix_audios(void *p_self);
protected:
static void _bind_methods();
void _notification(int p_notification);
- void _validate_property(PropertyInfo &property) const;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Size2 get_minimum_size() const;
void set_expand(bool p_expand);
bool has_expand() const;
- Ref<Texture> get_video_texture();
+ Ref<Texture> get_video_texture() const;
void set_stream(const Ref<VideoStream> &p_stream);
Ref<VideoStream> get_stream() const;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index bd01ca2886..217dacfbfe 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2171,7 +2171,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
if (get_filename() != "") {
Ref<PackedScene> res = ResourceLoader::load(get_filename());
- ERR_FAIL_COND(res.is_null());
+ ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename());
node = res->instance();
ERR_FAIL_COND(!node);
} else {
@@ -2832,6 +2832,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
+ ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning);
+
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_TREE);
BIND_CONSTANT(NOTIFICATION_MOVED_IN_PARENT);
@@ -2861,6 +2863,8 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_WM_ABOUT);
BIND_CONSTANT(NOTIFICATION_CRASH);
BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE);
+ BIND_CONSTANT(NOTIFICATION_APP_RESUMED);
+ BIND_CONSTANT(NOTIFICATION_APP_PAUSED);
BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT);
BIND_ENUM_CONSTANT(PAUSE_MODE_STOP);
diff --git a/scene/main/node.h b/scene/main/node.h
index 51a1436014..a8bcd2f273 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -250,7 +250,9 @@ public:
NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED,
NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT,
NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH,
- NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE
+ NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE,
+ NOTIFICATION_APP_RESUMED = MainLoop::NOTIFICATION_APP_RESUMED,
+ NOTIFICATION_APP_PAUSED = MainLoop::NOTIFICATION_APP_PAUSED
};
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 5483fe1d6f..38ad6886b1 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -70,15 +70,25 @@ float SceneTreeTimer::get_time_left() const {
}
void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) {
- if (process_pause != p_pause_mode_process) {
- process_pause = p_pause_mode_process;
- }
+
+ process_pause = p_pause_mode_process;
}
bool SceneTreeTimer::is_pause_mode_process() {
return process_pause;
}
+void SceneTreeTimer::release_connections() {
+
+ List<Connection> connections;
+ get_all_signal_connections(&connections);
+
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+ Connection const &connection = E->get();
+ disconnect(connection.signal, connection.target, connection.method);
+ }
+}
+
SceneTreeTimer::SceneTreeTimer() {
time_left = 0;
process_pause = true;
@@ -561,6 +571,8 @@ bool SceneTree::idle(float p_time) {
E = N;
}
+ flush_transform_notifications(); //additional transforms after timers update
+
_call_idle_callbacks();
#ifdef TOOLS_ENABLED
@@ -610,6 +622,12 @@ void SceneTree::finish() {
memdelete(root); //delete root
root = NULL;
}
+
+ // cleanup timers
+ for (List<Ref<SceneTreeTimer> >::Element *E = timers.front(); E; E = E->next()) {
+ E->get()->release_connections();
+ }
+ timers.clear();
}
void SceneTree::quit() {
@@ -630,6 +648,7 @@ void SceneTree::_notification(int p_notification) {
break;
}
} break;
+
case NOTIFICATION_WM_GO_BACK_REQUEST: {
get_root()->propagate_notification(p_notification);
@@ -639,28 +658,23 @@ void SceneTree::_notification(int p_notification) {
break;
}
} break;
- case NOTIFICATION_OS_MEMORY_WARNING:
- case NOTIFICATION_OS_IME_UPDATE:
- case NOTIFICATION_WM_MOUSE_ENTER:
- case NOTIFICATION_WM_MOUSE_EXIT:
- case NOTIFICATION_WM_FOCUS_IN:
- case NOTIFICATION_WM_FOCUS_OUT:
- case NOTIFICATION_WM_ABOUT: {
- if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
- InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
- if (id) {
- id->ensure_touch_mouse_raised();
- }
+ case NOTIFICATION_WM_FOCUS_IN: {
+
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ if (id) {
+ id->ensure_touch_mouse_raised();
}
get_root()->propagate_notification(p_notification);
} break;
+
case NOTIFICATION_TRANSLATION_CHANGED: {
if (!Engine::get_singleton()->is_editor_hint()) {
get_root()->propagate_notification(p_notification);
}
} break;
+
case NOTIFICATION_WM_UNFOCUS_REQUEST: {
notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST);
@@ -669,7 +683,15 @@ void SceneTree::_notification(int p_notification) {
} break;
- case NOTIFICATION_CRASH: {
+ case NOTIFICATION_OS_MEMORY_WARNING:
+ case NOTIFICATION_OS_IME_UPDATE:
+ case NOTIFICATION_WM_MOUSE_ENTER:
+ case NOTIFICATION_WM_MOUSE_EXIT:
+ case NOTIFICATION_WM_FOCUS_OUT:
+ case NOTIFICATION_WM_ABOUT:
+ case NOTIFICATION_CRASH:
+ case NOTIFICATION_APP_RESUMED:
+ case NOTIFICATION_APP_PAUSED: {
get_root()->propagate_notification(p_notification);
} break;
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index d387886d61..ef847ebb5b 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -61,6 +61,8 @@ public:
void set_pause_mode_process(bool p_pause_mode_process);
bool is_pause_mode_process();
+ void release_connections();
+
SceneTreeTimer();
};
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 0b26602b68..d060ac273d 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -98,22 +98,22 @@ NodePath ViewportTexture::get_viewport_path_in_scene() const {
int ViewportTexture::get_width() const {
- ERR_FAIL_COND_V(!vp, 0);
+ ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
return vp->size.width;
}
int ViewportTexture::get_height() const {
- ERR_FAIL_COND_V(!vp, 0);
+ ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
return vp->size.height;
}
Size2 ViewportTexture::get_size() const {
- ERR_FAIL_COND_V(!vp, Size2());
+ ERR_FAIL_COND_V_MSG(!vp, Size2(), "Viewport Texture must be set to use it.");
return vp->size;
}
RID ViewportTexture::get_rid() const {
- //ERR_FAIL_COND_V(!vp, RID());
+ //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
return proxy;
}
@@ -123,7 +123,7 @@ bool ViewportTexture::has_alpha() const {
}
Ref<Image> ViewportTexture::get_data() const {
- ERR_FAIL_COND_V(!vp, Ref<Image>());
+ ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
return VS::get_singleton()->texture_get_data(vp->texture_rid);
}
void ViewportTexture::set_flags(uint32_t p_flags) {
@@ -1465,18 +1465,19 @@ void Viewport::_gui_show_tooltip() {
rp->add_child(gui.tooltip_popup);
gui.tooltip_popup->force_parent_owned();
gui.tooltip_popup->set_as_toplevel(true);
- //gui.tooltip_popup->hide();
+ if (gui.tooltip) // Avoids crash when rapidly switching controls.
+ gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
Rect2 vr = gui.tooltip_popup->get_viewport_rect();
- if (r.size.x + r.position.x > vr.size.x)
- r.position.x = vr.size.x - r.size.x;
+ if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x)
+ r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x;
else if (r.position.x < 0)
r.position.x = 0;
- if (r.size.y + r.position.y > vr.size.y)
- r.position.y = vr.size.y - r.size.y;
+ if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y)
+ r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y;
else if (r.position.y < 0)
r.position.y = 0;
@@ -1742,6 +1743,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
return; // no one gets the event if exclusive NO ONE
}
+ if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
+ //cancel scroll wheel events, only clicks should trigger focus changes.
+ set_input_as_handled();
+ return;
+ }
+
top->notification(Control::NOTIFICATION_MODAL_CLOSE);
top->_modal_stack_remove();
top->hide();
@@ -2367,7 +2374,6 @@ void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, Object
List<Control *>::Element *next = MI->next();
gui.modal_stack.erase(MI);
- MI = NULL;
if (p_prev_focus_owner) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index e3af521e8c..314fc721fc 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -139,7 +139,6 @@
#include "scene/resources/cylinder_shape.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/dynamic_font.h"
-#include "scene/resources/dynamic_font_stb.h"
#include "scene/resources/gradient.h"
#include "scene/resources/height_map_shape.h"
#include "scene/resources/line_shape_2d.h"
@@ -364,6 +363,9 @@ void register_scene_types() {
/* REGISTER 3D */
+ ClassDB::register_class<Skin>();
+ ClassDB::register_virtual_class<SkinReference>();
+
ClassDB::register_class<Spatial>();
ClassDB::register_virtual_class<SpatialGizmo>();
ClassDB::register_class<Skeleton>();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 985b38f913..f4ac277d00 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2741,77 +2741,77 @@ void Animation::copy_track(int p_track, Ref<Animation> p_to_animation) {
void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_track", "type", "at_position"), &Animation::add_track, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("remove_track", "idx"), &Animation::remove_track);
+ ClassDB::bind_method(D_METHOD("remove_track", "track_idx"), &Animation::remove_track);
ClassDB::bind_method(D_METHOD("get_track_count"), &Animation::get_track_count);
- ClassDB::bind_method(D_METHOD("track_get_type", "idx"), &Animation::track_get_type);
- ClassDB::bind_method(D_METHOD("track_get_path", "idx"), &Animation::track_get_path);
- ClassDB::bind_method(D_METHOD("track_set_path", "idx", "path"), &Animation::track_set_path);
+ ClassDB::bind_method(D_METHOD("track_get_type", "track_idx"), &Animation::track_get_type);
+ ClassDB::bind_method(D_METHOD("track_get_path", "track_idx"), &Animation::track_get_path);
+ ClassDB::bind_method(D_METHOD("track_set_path", "track_idx", "path"), &Animation::track_set_path);
ClassDB::bind_method(D_METHOD("find_track", "path"), &Animation::find_track);
- ClassDB::bind_method(D_METHOD("track_move_up", "idx"), &Animation::track_move_up);
- ClassDB::bind_method(D_METHOD("track_move_down", "idx"), &Animation::track_move_down);
- ClassDB::bind_method(D_METHOD("track_move_to", "idx", "to_idx"), &Animation::track_move_to);
- ClassDB::bind_method(D_METHOD("track_swap", "idx", "with_idx"), &Animation::track_swap);
+ ClassDB::bind_method(D_METHOD("track_move_up", "track_idx"), &Animation::track_move_up);
+ ClassDB::bind_method(D_METHOD("track_move_down", "track_idx"), &Animation::track_move_down);
+ ClassDB::bind_method(D_METHOD("track_move_to", "track_idx", "to_idx"), &Animation::track_move_to);
+ ClassDB::bind_method(D_METHOD("track_swap", "track_idx", "with_idx"), &Animation::track_swap);
- ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported);
- ClassDB::bind_method(D_METHOD("track_is_imported", "idx"), &Animation::track_is_imported);
+ ClassDB::bind_method(D_METHOD("track_set_imported", "track_idx", "imported"), &Animation::track_set_imported);
+ ClassDB::bind_method(D_METHOD("track_is_imported", "track_idx"), &Animation::track_is_imported);
- ClassDB::bind_method(D_METHOD("track_set_enabled", "idx", "enabled"), &Animation::track_set_enabled);
- ClassDB::bind_method(D_METHOD("track_is_enabled", "idx"), &Animation::track_is_enabled);
+ ClassDB::bind_method(D_METHOD("track_set_enabled", "track_idx", "enabled"), &Animation::track_set_enabled);
+ ClassDB::bind_method(D_METHOD("track_is_enabled", "track_idx"), &Animation::track_is_enabled);
- ClassDB::bind_method(D_METHOD("transform_track_insert_key", "idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
- ClassDB::bind_method(D_METHOD("track_insert_key", "idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
- ClassDB::bind_method(D_METHOD("track_remove_key", "idx", "key_idx"), &Animation::track_remove_key);
- ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "idx", "position"), &Animation::track_remove_key_at_position);
- ClassDB::bind_method(D_METHOD("track_set_key_value", "idx", "key", "value"), &Animation::track_set_key_value);
- ClassDB::bind_method(D_METHOD("track_set_key_transition", "idx", "key_idx", "transition"), &Animation::track_set_key_transition);
- ClassDB::bind_method(D_METHOD("track_set_key_time", "idx", "key_idx", "time"), &Animation::track_set_key_time);
- ClassDB::bind_method(D_METHOD("track_get_key_transition", "idx", "key_idx"), &Animation::track_get_key_transition);
+ ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
+ ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key);
+ ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "track_idx", "position"), &Animation::track_remove_key_at_position);
+ ClassDB::bind_method(D_METHOD("track_set_key_value", "track_idx", "key", "value"), &Animation::track_set_key_value);
+ ClassDB::bind_method(D_METHOD("track_set_key_transition", "track_idx", "key_idx", "transition"), &Animation::track_set_key_transition);
+ ClassDB::bind_method(D_METHOD("track_set_key_time", "track_idx", "key_idx", "time"), &Animation::track_set_key_time);
+ ClassDB::bind_method(D_METHOD("track_get_key_transition", "track_idx", "key_idx"), &Animation::track_get_key_transition);
- ClassDB::bind_method(D_METHOD("track_get_key_count", "idx"), &Animation::track_get_key_count);
- ClassDB::bind_method(D_METHOD("track_get_key_value", "idx", "key_idx"), &Animation::track_get_key_value);
- ClassDB::bind_method(D_METHOD("track_get_key_time", "idx", "key_idx"), &Animation::track_get_key_time);
- ClassDB::bind_method(D_METHOD("track_find_key", "idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
+ ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
+ ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
+ ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "idx", "interpolation"), &Animation::track_set_interpolation_type);
- ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "idx"), &Animation::track_get_interpolation_type);
+ ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
+ ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);
- ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap);
- ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "idx"), &Animation::track_get_interpolation_loop_wrap);
+ ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "track_idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap);
+ ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "track_idx"), &Animation::track_get_interpolation_loop_wrap);
- ClassDB::bind_method(D_METHOD("transform_track_interpolate", "idx", "time_sec"), &Animation::_transform_track_interpolate);
- ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "idx", "mode"), &Animation::value_track_set_update_mode);
- ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "idx"), &Animation::value_track_get_update_mode);
+ ClassDB::bind_method(D_METHOD("transform_track_interpolate", "track_idx", "time_sec"), &Animation::_transform_track_interpolate);
+ ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode);
+ ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode);
- ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices);
+ ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices);
- ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices);
- ClassDB::bind_method(D_METHOD("method_track_get_name", "idx", "key_idx"), &Animation::method_track_get_name);
- ClassDB::bind_method(D_METHOD("method_track_get_params", "idx", "key_idx"), &Animation::method_track_get_params);
+ ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices);
+ ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
+ ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
- ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "track_idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "idx", "key_idx"), &Animation::bezier_track_get_key_value);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_in_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_out_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_out_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "track_idx", "key_idx"), &Animation::bezier_track_get_key_value);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "track_idx", "key_idx"), &Animation::bezier_track_get_key_in_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_out_handle", "track_idx", "key_idx"), &Animation::bezier_track_get_key_out_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_interpolate", "track", "time"), &Animation::bezier_track_interpolate);
+ ClassDB::bind_method(D_METHOD("bezier_track_interpolate", "track_idx", "time"), &Animation::bezier_track_interpolate);
- ClassDB::bind_method(D_METHOD("audio_track_insert_key", "track", "time", "stream", "start_offset", "end_offset"), &Animation::audio_track_insert_key, DEFVAL(0), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("audio_track_set_key_stream", "idx", "key_idx", "stream"), &Animation::audio_track_set_key_stream);
- ClassDB::bind_method(D_METHOD("audio_track_set_key_start_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_start_offset);
- ClassDB::bind_method(D_METHOD("audio_track_set_key_end_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_end_offset);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "idx", "key_idx"), &Animation::audio_track_get_key_stream);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_insert_key", "track_idx", "time", "stream", "start_offset", "end_offset"), &Animation::audio_track_insert_key, DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_stream", "track_idx", "key_idx", "stream"), &Animation::audio_track_set_key_stream);
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_start_offset", "track_idx", "key_idx", "offset"), &Animation::audio_track_set_key_start_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_end_offset", "track_idx", "key_idx", "offset"), &Animation::audio_track_set_key_end_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "track_idx", "key_idx"), &Animation::audio_track_get_key_stream);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
- ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track", "time", "animation"), &Animation::animation_track_insert_key);
- ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
- ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "idx", "key_idx"), &Animation::animation_track_get_key_animation);
+ ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
+ ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
+ ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
ClassDB::bind_method(D_METHOD("set_length", "time_sec"), &Animation::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &Animation::get_length);
@@ -2823,7 +2823,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_step"), &Animation::get_step);
ClassDB::bind_method(D_METHOD("clear"), &Animation::clear);
- ClassDB::bind_method(D_METHOD("copy_track", "track", "to_animation"), &Animation::copy_track);
+ ClassDB::bind_method(D_METHOD("copy_track", "track_idx", "to_animation"), &Animation::copy_track);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
@@ -2870,9 +2870,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.loc;
const Vector3 &v2 = t2.value.loc;
- if (v0 == v2) {
+ if (v0.is_equal_approx(v2)) {
//0 and 2 are close, let's see if 1 is close
- if (v0 != v1) {
+ if (!v0.is_equal_approx(v1)) {
//not close, not optimizable
return false;
}
@@ -2909,9 +2909,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
//localize both to rotation from q0
- if (Math::is_zero_approx((q0 - q2).length())) {
+ if (q0.is_equal_approx(q2)) {
- if (!Math::is_zero_approx((q0 - q1).length()))
+ if (!q0.is_equal_approx(q1))
return false;
} else {
@@ -2959,9 +2959,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.scale;
const Vector3 &v2 = t2.value.scale;
- if (v0 == v2) {
+ if (v0.is_equal_approx(v2)) {
//0 and 2 are close, let's see if 1 is close
- if (v0 != v1) {
+ if (!v0.is_equal_approx(v1)) {
//not close, not optimizable
return false;
}
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index e4a64a1de1..e6139dd707 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -197,16 +197,14 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
| 4 | 8 | <- current pixel (curx,cury)
+---+---+
*/
- //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel
- Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2));
Point2i tl = Point2i(curx - 1, cury - 1);
- sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
Point2i tr = Point2i(curx, cury - 1);
- sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
Point2i bl = Point2i(curx - 1, cury);
- sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
Point2i br = Point2i(curx, cury);
- sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0;
ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
}
@@ -300,15 +298,15 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start)
+---+---+
| 4 | |
+---+---+
- this normally go RIGHT, but if its coming from UP, it should go LEFT
+ this normally go RIGHT, but if its coming from RIGHT, it should go LEFT
*/
if (case6s.has(Point2i(curx, cury))) {
- //found, so we go down, and delete from case6s;
+ //found, so we go left, and delete from case6s;
stepx = -1;
stepy = 0;
case6s.erase(Point2i(curx, cury));
} else {
- //not found, we go up, and add to case6s;
+ //not found, we go right, and add to case6s;
stepx = 1;
stepy = 0;
case6s.insert(Point2i(curx, cury));
@@ -510,12 +508,19 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+ fill_bits(this, fill, Point2i(j, i), r);
+
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
print_verbose("BitMap: Pre reduce: " + itos(polygon.size()));
polygon = reduce(polygon, r, p_epsilon);
print_verbose("BitMap: Post reduce: " + itos(polygon.size()));
+
+ if (polygon.size() < 3) {
+ print_verbose("Invalid polygon, skipped");
+ continue;
+ }
+
polygons.push_back(polygon);
- fill_bits(this, fill, Point2i(j, i), r);
}
}
}
@@ -525,6 +530,13 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+ if (p_pixels == 0) {
+ return;
+ }
+
+ bool bit_value = p_pixels > 0;
+ p_pixels = Math::abs(p_pixels);
+
Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
Ref<BitMap> copy;
@@ -534,7 +546,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
- if (copy->get_bit(Point2(j, i)))
+ if (bit_value == get_bit(Point2(j, i)))
continue;
bool found = false;
@@ -542,16 +554,21 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
for (int y = i - p_pixels; y <= i + p_pixels; y++) {
for (int x = j - p_pixels; x <= j + p_pixels; x++) {
- if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x)
- continue;
- if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y)
- continue;
+ bool outside = false;
+
+ if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) {
+ // outside of rectangle counts as bit not set
+ if (!bit_value)
+ outside = true;
+ else
+ continue;
+ }
float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON;
if (d > p_pixels)
continue;
- if (copy->get_bit(Point2(x, y))) {
+ if (outside || (bit_value == copy->get_bit(Point2(x, y)))) {
found = true;
break;
}
@@ -561,12 +578,17 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
}
if (found) {
- set_bit(Point2(j, i), true);
+ set_bit(Point2(j, i), bit_value);
}
}
}
}
+void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
+
+ grow_mask(-p_pixels, p_rect);
+}
+
Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon);
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index daf24affb1..b062dd7376 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -67,6 +67,7 @@ public:
void resize(const Size2 &p_new_size);
void grow_mask(int p_pixels, const Rect2 &p_rect);
+ void shrink_mask(int p_pixels, const Rect2 &p_rect);
void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap);
Ref<Image> convert_to_image() const;
diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp
index d819e9f776..c6fe14e55e 100644
--- a/scene/resources/box_shape.cpp
+++ b/scene/resources/box_shape.cpp
@@ -31,7 +31,7 @@
#include "box_shape.h"
#include "servers/physics_server.h"
-Vector<Vector3> BoxShape::_gen_debug_mesh_lines() {
+Vector<Vector3> BoxShape::get_debug_mesh_lines() {
Vector<Vector3> lines;
AABB aabb;
diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h
index 42d54310a8..0bce929aee 100644
--- a/scene/resources/box_shape.h
+++ b/scene/resources/box_shape.h
@@ -42,12 +42,13 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
BoxShape();
};
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
index 669b261bfe..1ec3bd7158 100644
--- a/scene/resources/capsule_shape.cpp
+++ b/scene/resources/capsule_shape.cpp
@@ -31,7 +31,7 @@
#include "capsule_shape.h"
#include "servers/physics_server.h"
-Vector<Vector3> CapsuleShape::_gen_debug_mesh_lines() {
+Vector<Vector3> CapsuleShape::get_debug_mesh_lines() {
float radius = get_radius();
float height = get_height();
diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h
index 6bca53f783..befbc1dcd5 100644
--- a/scene/resources/capsule_shape.h
+++ b/scene/resources/capsule_shape.h
@@ -44,14 +44,14 @@ protected:
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
-
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
CapsuleShape();
};
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
index b4cc38c8c0..dbc07ef591 100644
--- a/scene/resources/concave_polygon_shape.cpp
+++ b/scene/resources/concave_polygon_shape.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server.h"
-Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() {
+Vector<Vector3> ConcavePolygonShape::get_debug_mesh_lines() {
Set<DrawEdge> edges;
diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h
index 1b8ddfc308..57362a29be 100644
--- a/scene/resources/concave_polygon_shape.h
+++ b/scene/resources/concave_polygon_shape.h
@@ -61,12 +61,13 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_faces(const PoolVector<Vector3> &p_faces);
PoolVector<Vector3> get_faces() const;
+ Vector<Vector3> get_debug_mesh_lines();
+
ConcavePolygonShape();
};
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 499688a185..af459ec311 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -32,7 +32,7 @@
#include "core/math/quick_hull.h"
#include "servers/physics_server.h"
-Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() {
+Vector<Vector3> ConvexPolygonShape::get_debug_mesh_lines() {
PoolVector<Vector3> points = get_points();
diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h
index 5c192476d3..e6daf1bef4 100644
--- a/scene/resources/convex_polygon_shape.h
+++ b/scene/resources/convex_polygon_shape.h
@@ -43,12 +43,12 @@ protected:
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
-
public:
void set_points(const PoolVector<Vector3> &p_points);
PoolVector<Vector3> get_points() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
ConvexPolygonShape();
};
diff --git a/scene/resources/cylinder_shape.cpp b/scene/resources/cylinder_shape.cpp
index f60f7ab376..c1a0a0ac5d 100644
--- a/scene/resources/cylinder_shape.cpp
+++ b/scene/resources/cylinder_shape.cpp
@@ -31,7 +31,7 @@
#include "cylinder_shape.h"
#include "servers/physics_server.h"
-Vector<Vector3> CylinderShape::_gen_debug_mesh_lines() {
+Vector<Vector3> CylinderShape::get_debug_mesh_lines() {
float radius = get_radius();
float height = get_height();
diff --git a/scene/resources/cylinder_shape.h b/scene/resources/cylinder_shape.h
index 58a4f5a817..411c1515ed 100644
--- a/scene/resources/cylinder_shape.h
+++ b/scene/resources/cylinder_shape.h
@@ -43,14 +43,14 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
-
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
CylinderShape();
};
diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png
index ef226e3caf..ff2258281e 100644
--- a/scene/resources/default_theme/button_hover.png
+++ b/scene/resources/default_theme/button_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png
index 7d0bd16221..c189b61b89 100644
--- a/scene/resources/default_theme/button_normal.png
+++ b/scene/resources/default_theme/button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/color_picker_hue.png b/scene/resources/default_theme/color_picker_hue.png
index de2cd0c2bf..7b46f03cb4 100644
--- a/scene/resources/default_theme/color_picker_hue.png
+++ b/scene/resources/default_theme/color_picker_hue.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index d761eb01fe..e82819f270 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -432,7 +432,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("font", "TextEdit", default_font);
- theme->set_color("background_color", "TextEdit", Color(0, 0, 0));
+ theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2));
theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27));
theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13));
@@ -558,9 +558,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel", "PopupPanel", style_pp);
+ // PopupDialog
+
+ Ref<StyleBoxTexture> style_pd = make_stylebox(popup_bg_png, 4, 4, 4, 4, 10, 10, 10, 10);
+ theme->set_stylebox("panel", "PopupDialog", style_pd);
+
// PopupMenu
- theme->set_stylebox("panel", "PopupMenu", make_stylebox(popup_bg_png, 4, 4, 4, 4, 10, 10, 10, 10));
+ theme->set_stylebox("panel", "PopupMenu", style_pd);
theme->set_stylebox("panel_disabled", "PopupMenu", make_stylebox(popup_bg_disabled_png, 4, 4, 4, 4));
theme->set_stylebox("hover", "PopupMenu", selected);
theme->set_stylebox("separator", "PopupMenu", make_stylebox(vseparator_png, 3, 3, 3, 3));
@@ -657,7 +662,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("hseparation", "Tree", 4 * scale);
theme->set_constant("vseparation", "Tree", 4 * scale);
- theme->set_constant("guide_width", "Tree", 2 * scale);
theme->set_constant("item_margin", "Tree", 12 * scale);
theme->set_constant("button_margin", "Tree", 4 * scale);
theme->set_constant("draw_relationship_lines", "Tree", 0);
@@ -764,7 +768,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1));
theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7));
- // colorPicker
+ // ColorPicker
theme->set_constant("margin", "ColorPicker", 4 * scale);
theme->set_constant("sv_width", "ColorPicker", 256 * scale);
@@ -777,6 +781,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("color_hue", "ColorPicker", make_icon(color_picker_hue_png));
theme->set_icon("color_sample", "ColorPicker", make_icon(color_picker_sample_png));
theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png));
+ theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png));
theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png));
diff --git a/scene/resources/default_theme/error_icon.png b/scene/resources/default_theme/error_icon.png
index 00680db5df..30336b91a4 100644
--- a/scene/resources/default_theme/error_icon.png
+++ b/scene/resources/default_theme/error_icon.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png
index cc4eb7f753..c52d88586b 100644
--- a/scene/resources/default_theme/graph_node_selected.png
+++ b/scene/resources/default_theme/graph_node_selected.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png
index f33ae3baf3..358934f4d8 100644
--- a/scene/resources/default_theme/graph_port.png
+++ b/scene/resources/default_theme/graph_port.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_visibility.png b/scene/resources/default_theme/icon_visibility.png
index 6402571f3e..b2df8cbdb8 100644
--- a/scene/resources/default_theme/icon_visibility.png
+++ b/scene/resources/default_theme/icon_visibility.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png
index 2dadb40338..43fc29e958 100644
--- a/scene/resources/default_theme/option_button_normal.png
+++ b/scene/resources/default_theme/option_button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/overbright_indicator.png b/scene/resources/default_theme/overbright_indicator.png
new file mode 100644
index 0000000000..89f800c230
--- /dev/null
+++ b/scene/resources/default_theme/overbright_indicator.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png
index 006cfa3361..21ee486e0b 100644
--- a/scene/resources/default_theme/scroll_grabber_hl.png
+++ b/scene/resources/default_theme/scroll_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png
index 7e458a6c45..3c66316074 100644
--- a/scene/resources/default_theme/space.png
+++ b/scene/resources/default_theme/space.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png
index 7d0bd16221..c189b61b89 100644
--- a/scene/resources/default_theme/tab_container_bg.png
+++ b/scene/resources/default_theme/tab_container_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png
index 520d147217..d5641e917a 100644
--- a/scene/resources/default_theme/tab_current.png
+++ b/scene/resources/default_theme/tab_current.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_disabled.png b/scene/resources/default_theme/tab_disabled.png
index 97157a58dd..a7c04effa3 100644
--- a/scene/resources/default_theme/tab_disabled.png
+++ b/scene/resources/default_theme/tab_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 11904b7aff..0a4e557451 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -19,11 +19,11 @@ static const unsigned char button_focus_png[] = {
};
static const unsigned char button_hover_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x40, 0xdc, 0xe6, 0x80, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcf, 0x47, 0x2, 0x83, 0x30, 0x10, 0x43, 0x51, 0x69, 0x98, 0xf4, 0xe4, 0xfe, 0x87, 0x24, 0xfb, 0xf4, 0x8, 0xd1, 0xb1, 0x3f, 0xb8, 0xbd, 0xdd, 0x24, 0x38, 0x4, 0x40, 0x43, 0xc9, 0xfd, 0x24, 0x1a, 0x7a, 0x27, 0x2d, 0x7, 0xc2, 0x41, 0x2f, 0xbd, 0x69, 0x88, 0x23, 0x27, 0x38, 0x3d, 0xfd, 0x22, 0x2f, 0xd3, 0x1b, 0xc3, 0x35, 0xe9, 0x85, 0x39, 0xd, 0x10, 0x2c, 0x0, 0x25, 0x20, 0x81, 0x2d, 0xc0, 0xa0, 0x2d, 0x8, 0xa9, 0x12, 0x64, 0x0, 0x66, 0x91, 0xa5, 0x61, 0xf3, 0xbe, 0xc5, 0x18, 0xd9, 0x7e, 0x7e, 0x21, 0x45, 0x1b, 0x53, 0x77, 0x4a, 0xac, 0x87, 0x63, 0x3d, 0x7e, 0x7, 0x87, 0x7b, 0x3b, 0x5b, 0x7a, 0xd3, 0xea, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x40, 0xdc, 0xe6, 0x80, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0xcf, 0xc5, 0x1, 0x84, 0x40, 0x14, 0x4, 0xd1, 0x2e, 0x5c, 0xf3, 0xf, 0x92, 0xbd, 0xaf, 0xd3, 0xb8, 0x53, 0x30, 0xf6, 0x6e, 0x1f, 0x31, 0x26, 0xc9, 0x63, 0x90, 0xcc, 0xe2, 0xb1, 0x4f, 0x34, 0x48, 0x8a, 0x86, 0xfc, 0xf6, 0x87, 0x1e, 0x82, 0x8c, 0x19, 0xf2, 0x17, 0x4, 0x50, 0xce, 0x6f, 0x8d, 0xd7, 0x88, 0x7e, 0x69, 0xc9, 0x23, 0x4, 0x1c, 0x40, 0x47, 0x50, 0x24, 0xed, 0x41, 0x3d, 0x78, 0xf, 0x56, 0xe4, 0x23, 0xb8, 0x7, 0x69, 0x11, 0xf7, 0x12, 0x12, 0x7e, 0xea, 0x60, 0xa, 0x9a, 0xef, 0x3f, 0xb0, 0x83, 0x26, 0x98, 0x7b, 0x70, 0x33, 0xdc, 0x65, 0xfc, 0xe, 0x81, 0x4e, 0x3b, 0x55, 0xea, 0xaa, 0xb0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_normal_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x0, 0x4, 0xc1, 0x69, 0x1c, 0xfe, 0xff, 0xca, 0xd5, 0xeb, 0x2a, 0x83, 0x6b, 0xd2, 0xb7, 0x54, 0x1c, 0x31, 0x26, 0xc9, 0x63, 0x50, 0xcc, 0x32, 0x8d, 0x3f, 0xd9, 0x20, 0x5, 0x1a, 0xf2, 0xc7, 0x1f, 0x7a, 0x48, 0x4a, 0x66, 0xa8, 0xde, 0xc, 0xd0, 0x38, 0xd1, 0x54, 0xdb, 0x4c, 0x2b, 0xd0, 0x5c, 0x62, 0x8e, 0xa0, 0x1, 0x74, 0x4, 0x65, 0xd2, 0x1e, 0xd4, 0x83, 0xf7, 0x60, 0x65, 0x3e, 0x82, 0x3, 0x48, 0x49, 0xdf, 0x55, 0xca, 0xd4, 0xef, 0xfa, 0xfb, 0x27, 0x36, 0xf, 0x92, 0x31, 0x9e, 0x44, 0x3e, 0x17, 0x7c, 0xbf, 0x3, 0xef, 0x34, 0x3f, 0x3e, 0xe0, 0x24, 0x67, 0xb9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char button_pressed_png[] = {
@@ -47,7 +47,7 @@ static const unsigned char close_hl_png[] = {
};
static const unsigned char color_picker_hue_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x8, 0x2, 0x0, 0x0, 0x0, 0xfd, 0x5c, 0x8b, 0xcf, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xcd, 0xd0, 0x31, 0xa, 0x3, 0x31, 0x10, 0x43, 0xd1, 0x87, 0xc0, 0xf6, 0xfd, 0x8f, 0x1b, 0xdb, 0x30, 0x69, 0x76, 0x21, 0x65, 0xd8, 0x14, 0x71, 0xf1, 0xf9, 0x8c, 0x84, 0x9a, 0x51, 0x44, 0x13, 0xfd, 0x21, 0xe3, 0x87, 0xed, 0xf7, 0xa8, 0xcd, 0x2a, 0x99, 0x8e, 0x46, 0x2b, 0x94, 0xd0, 0x43, 0xb, 0xe3, 0x64, 0xb3, 0x2a, 0xa6, 0x93, 0xb9, 0x9f, 0x9a, 0x4e, 0x3a, 0x69, 0x97, 0xc7, 0xe5, 0x3b, 0x1b, 0xff, 0xef, 0x6d, 0xa5, 0xec, 0x30, 0xc3, 0xeb, 0xf2, 0xc, 0xeb, 0xe3, 0x5e, 0x27, 0xf4, 0x8a, 0x37, 0x75, 0x7b, 0x8a, 0xe5, 0x90, 0x9a, 0xab, 0x81, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x8, 0x2, 0x0, 0x0, 0x0, 0xfd, 0x5c, 0x8b, 0xcf, 0x0, 0x0, 0x0, 0x54, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xcd, 0xc9, 0x1, 0x6, 0x43, 0x31, 0x10, 0x45, 0xd1, 0x63, 0xc8, 0xcf, 0xfe, 0x97, 0xdb, 0x9f, 0xf0, 0x1a, 0x15, 0xb4, 0x0, 0xa5, 0x1a, 0x1c, 0xd7, 0xcc, 0x13, 0x4a, 0x5b, 0xae, 0x2f, 0xf5, 0xdd, 0xdf, 0x92, 0xc9, 0x88, 0xba, 0x1d, 0x4d, 0xb, 0xa2, 0xb8, 0x96, 0xb6, 0xf4, 0x93, 0xcb, 0x48, 0xb9, 0x9d, 0x8c, 0x16, 0xa4, 0x2e, 0x5e, 0xda, 0x6e, 0xe7, 0xe3, 0xd7, 0xff, 0xbf, 0x9b, 0x22, 0x66, 0x71, 0x2f, 0x8f, 0xdd, 0xc5, 0x78, 0xbb, 0xc7, 0x9, 0xbb, 0xf0, 0x4, 0x75, 0x7b, 0x8a, 0xe5, 0x7c, 0x23, 0x8a, 0xd3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char color_picker_sample_png[] = {
@@ -59,7 +59,7 @@ static const unsigned char dropdown_png[] = {
};
static const unsigned char error_icon_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe2, 0xb, 0xf, 0x0, 0x22, 0x18, 0xc, 0x35, 0xef, 0x18, 0x0, 0x0, 0x0, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x0, 0x1, 0x0, 0x2, 0x10, 0x0, 0x1, 0x14, 0xc2, 0xc0, 0x92, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x0, 0x1, 0x0, 0x2, 0x10, 0x0, 0x1, 0x14, 0xc2, 0xc0, 0x92, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char focus_png[] = {
@@ -99,11 +99,11 @@ static const unsigned char graph_node_position_png[] = {
};
static const unsigned char graph_node_selected_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x1, 0x5f, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, 0xb2, 0xcc, 0xae, 0xa0, 0xbb, 0x9c, 0x92, 0xa6, 0x9a, 0x91, 0xa4, 0x95, 0x8c, 0x9e, 0xaf, 0x9f, 0xaf, 0xa0, 0x94, 0xa5, 0x8e, 0x84, 0x95, 0x7f, 0x75, 0x84, 0x73, 0x6a, 0x78, 0x6d, 0x64, 0x72, 0xa2, 0xa2, 0xb9, 0x9c, 0x90, 0xa2, 0x8b, 0x81, 0x90, 0xdc, 0xda, 0xce, 0xe2, 0xe1, 0xd2, 0x9d, 0x91, 0xa9, 0x85, 0x7c, 0x8c, 0xdb, 0xd9, 0xce, 0xdb, 0xd9, 0xcd, 0xda, 0xce, 0xe0, 0xde, 0xd5, 0xe3, 0xdf, 0xd6, 0xe4, 0x97, 0x8d, 0xa0, 0x7a, 0x70, 0x7f, 0xdb, 0xd0, 0xdf, 0xdb, 0xd0, 0xe1, 0xda, 0xd0, 0xe1, 0x70, 0x67, 0x75, 0xd8, 0xcb, 0xde, 0xda, 0xcf, 0xdf, 0xdb, 0xce, 0xe1, 0xdb, 0xcf, 0xe1, 0xdb, 0xd0, 0xe0, 0xda, 0xcf, 0xe0, 0xd8, 0xcc, 0xde, 0x90, 0x87, 0x99, 0x6d, 0x67, 0x72, 0xd7, 0xcc, 0xdf, 0xda, 0xce, 0xdf, 0xd8, 0xcb, 0xdf, 0xd7, 0xca, 0xde, 0xd9, 0xcc, 0xdf, 0xd9, 0xcd, 0xdf, 0xd6, 0xc9, 0xdd, 0xd9, 0xcd, 0xde, 0xd6, 0xc8, 0xdc, 0xd5, 0xc8, 0xdc, 0xd7, 0xcb, 0xdd, 0xd7, 0xca, 0xdd, 0xd5, 0xc7, 0xdc, 0xd3, 0xc6, 0xdb, 0xd5, 0xc9, 0xdc, 0xd5, 0xc9, 0xdd, 0xd6, 0xc9, 0xdc, 0xd4, 0xc6, 0xdb, 0xd3, 0xc5, 0xdb, 0xd5, 0xc8, 0xdb, 0xd4, 0xc8, 0xdc, 0xd3, 0xc4, 0xd9, 0xd4, 0xc6, 0xda, 0xd2, 0xc3, 0xd9, 0xd3, 0xc5, 0xda, 0xd2, 0xc5, 0xd9, 0xd3, 0xc5, 0xd9, 0xd2, 0xc5, 0xda, 0xd1, 0xc2, 0xd9, 0xd2, 0xc4, 0xd8, 0xd2, 0xc4, 0xd9, 0xd0, 0xc2, 0xd9, 0xd0, 0xc1, 0xd7, 0xd0, 0xc2, 0xd7, 0xd0, 0xc2, 0xd8, 0xd1, 0xc2, 0xd7, 0xcf, 0xc1, 0xd7, 0xd0, 0xc2, 0xd6, 0xcf, 0xc1, 0xd6, 0xcf, 0xc2, 0xd7, 0xcf, 0xc0, 0xd7, 0xce, 0xbf, 0xd6, 0xce, 0xc0, 0xd5, 0xce, 0xc0, 0xd6, 0xce, 0xbf, 0xd5, 0xcd, 0xbf, 0xd5, 0xcd, 0xbe, 0xd5, 0xcd, 0xbe, 0xd4, 0xcc, 0xbd, 0xd5, 0xcc, 0xbd, 0xd4, 0xcc, 0xbc, 0xd4, 0x47, 0x40, 0x4a, 0x1d, 0x1a, 0x1f, 0x69, 0x5f, 0x6f, 0x4a, 0x42, 0x4f, 0x5e, 0x54, 0x63, 0x3b, 0x34, 0x3f, 0x5e, 0x55, 0x63, 0x63, 0x59, 0x67, 0x77, 0x6d, 0x7b, 0x6d, 0x62, 0x73, 0x7f, 0x76, 0x85, 0xdb, 0xd9, 0xcd, 0xdb, 0xd8, 0xcd, 0x6d, 0x62, 0x74, 0x8f, 0x84, 0x94, 0x7f, 0x76, 0x83, 0xdb, 0xd8, 0xcd, 0xa4, 0x95, 0xa4, 0x7e, 0x74, 0x84, 0x74, 0x6b, 0x79, 0x6f, 0x66, 0x74, 0x96, 0x8a, 0xa2, 0x91, 0x88, 0x9b, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xbf, 0xf0, 0xc9, 0xec, 0x71, 0x0, 0x0, 0x0, 0x75, 0x74, 0x52, 0x4e, 0x53, 0x1, 0x3, 0xa, 0x13, 0x1a, 0x1c, 0x1d, 0x10, 0x2b, 0x4d, 0x64, 0x6e, 0x72, 0xb, 0x2c, 0x6a, 0xfc, 0xff, 0x15, 0x52, 0xfd, 0xff, 0xe2, 0xe2, 0xe2, 0x1b, 0x68, 0xe2, 0xe2, 0xe2, 0x71, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0x1e, 0x72, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0x6b, 0xc7, 0x56, 0xfe, 0xff, 0xc7, 0x30, 0x74, 0xfe, 0x11, 0x57, 0x6d, 0x72, 0x16, 0x1c, 0x0, 0x3, 0x4, 0x35, 0xf5, 0x4, 0x26, 0x0, 0x0, 0x1, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0xd0, 0x35, 0x82, 0x1c, 0x31, 0x14, 0x84, 0xe1, 0xbf, 0xa4, 0xd7, 0x32, 0x33, 0xb3, 0xf, 0x63, 0x8e, 0xcd, 0x10, 0xcd, 0x99, 0x1c, 0x3a, 0x75, 0xe8, 0xcc, 0xbe, 0x8e, 0x99, 0x79, 0xb9, 0x49, 0x6f, 0x49, 0xd3, 0xcb, 0x7b, 0x82, 0xa9, 0xac, 0x3e, 0xb1, 0xc, 0xad, 0x4, 0xf0, 0x95, 0x98, 0xd2, 0x6, 0x68, 0xec, 0x60, 0xa9, 0xac, 0x52, 0xb2, 0x6a, 0xf3, 0x92, 0x3d, 0x9a, 0xdf, 0x2f, 0x39, 0x20, 0xf7, 0xb9, 0x7d, 0x6e, 0xbf, 0xcf, 0x62, 0xea, 0xaa, 0x96, 0x24, 0x69, 0xce, 0xbe, 0xd9, 0x55, 0x4d, 0xef, 0x5b, 0xd8, 0xbb, 0x90, 0x9a, 0xa6, 0x39, 0x21, 0xf6, 0x5d, 0xb5, 0x77, 0xa9, 0x8a, 0x7, 0x35, 0xd5, 0xc0, 0x19, 0x32, 0x9f, 0xcf, 0x1b, 0x10, 0x3d, 0x9c, 0x1, 0x20, 0x2, 0x6, 0x84, 0xbf, 0x24, 0x9a, 0x44, 0x73, 0xac, 0x80, 0x4e, 0x80, 0x5c, 0x4e, 0x28, 0x60, 0x2, 0xc9, 0x3d, 0xa8, 0x40, 0x25, 0xe6, 0x0, 0xe, 0xe4, 0x2, 0x51, 0x1c, 0x2, 0x40, 0x5, 0x82, 0xa4, 0x2c, 0x3c, 0x76, 0xc3, 0x12, 0x51, 0xfb, 0x9e, 0xba, 0xdb, 0x3b, 0x6c, 0x2a, 0x45, 0xd8, 0xaf, 0x3c, 0x86, 0x3e, 0x57, 0x31, 0xc7, 0x7e, 0x98, 0x51, 0x25, 0x39, 0xca, 0x15, 0x1a, 0x3, 0x2, 0x8f, 0xc0, 0x70, 0xa, 0x20, 0x1c, 0x2f, 0x10, 0x87, 0x2f, 0x1c, 0x66, 0xec, 0xe, 0x1b, 0x33, 0x81, 0xd, 0x99, 0xc0, 0x55, 0xfd, 0x8, 0x5e, 0x4a, 0xe0, 0x82, 0x1b, 0xf3, 0x68, 0xc, 0x62, 0x7e, 0xaf, 0x4d, 0xdf, 0x79, 0x15, 0xf2, 0x30, 0xe3, 0xfa, 0x1b, 0xab, 0xc3, 0x3d, 0x59, 0xe3, 0x99, 0xa0, 0xe4, 0xf7, 0xbc, 0xb6, 0xd6, 0xa4, 0x97, 0x65, 0xc6, 0x63, 0xf7, 0xd6, 0x66, 0x62, 0x1f, 0x9f, 0xe9, 0x5, 0x30, 0x72, 0xef, 0xe2, 0x8c, 0xf9, 0xf3, 0x83, 0x23, 0xbd, 0x3e, 0xf, 0x2c, 0x6e, 0xbb, 0xf7, 0xff, 0x5, 0x5f, 0xfe, 0xb3, 0x14, 0x31, 0xf4, 0x31, 0x33, 0xfa, 0x41, 0xd3, 0xe9, 0xe7, 0x22, 0x6, 0x0, 0xb4, 0xb3, 0x74, 0xef, 0x4f, 0xde, 0x59, 0x95, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x1, 0x5f, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, 0xb2, 0xcc, 0xae, 0xa0, 0xbb, 0x9c, 0x92, 0xa6, 0x9a, 0x91, 0xa4, 0x95, 0x8c, 0x9e, 0xaf, 0x9f, 0xaf, 0xa0, 0x94, 0xa5, 0x8e, 0x84, 0x95, 0x7f, 0x75, 0x84, 0x73, 0x6a, 0x78, 0x6d, 0x64, 0x72, 0xa2, 0xa2, 0xb9, 0x9c, 0x90, 0xa2, 0x8b, 0x81, 0x90, 0xdc, 0xda, 0xce, 0xe2, 0xe1, 0xd2, 0x9d, 0x91, 0xa9, 0x85, 0x7c, 0x8c, 0xdb, 0xd9, 0xce, 0xdb, 0xd9, 0xcd, 0xda, 0xce, 0xe0, 0xde, 0xd5, 0xe3, 0xdf, 0xd6, 0xe4, 0x97, 0x8d, 0xa0, 0x7a, 0x70, 0x7f, 0xdb, 0xd0, 0xdf, 0xdb, 0xd0, 0xe1, 0xda, 0xd0, 0xe1, 0x70, 0x67, 0x75, 0xd8, 0xcb, 0xde, 0xda, 0xcf, 0xdf, 0xdb, 0xce, 0xe1, 0xdb, 0xcf, 0xe1, 0xdb, 0xd0, 0xe0, 0xda, 0xcf, 0xe0, 0xd8, 0xcc, 0xde, 0x90, 0x87, 0x99, 0x6d, 0x67, 0x72, 0xd7, 0xcc, 0xdf, 0xda, 0xce, 0xdf, 0xd8, 0xcb, 0xdf, 0xd7, 0xca, 0xde, 0xd9, 0xcc, 0xdf, 0xd9, 0xcd, 0xdf, 0xd6, 0xc9, 0xdd, 0xd9, 0xcd, 0xde, 0xd6, 0xc8, 0xdc, 0xd5, 0xc8, 0xdc, 0xd7, 0xcb, 0xdd, 0xd7, 0xca, 0xdd, 0xd5, 0xc7, 0xdc, 0xd3, 0xc6, 0xdb, 0xd5, 0xc9, 0xdc, 0xd5, 0xc9, 0xdd, 0xd6, 0xc9, 0xdc, 0xd4, 0xc6, 0xdb, 0xd3, 0xc5, 0xdb, 0xd5, 0xc8, 0xdb, 0xd4, 0xc8, 0xdc, 0xd3, 0xc4, 0xd9, 0xd4, 0xc6, 0xda, 0xd2, 0xc3, 0xd9, 0xd3, 0xc5, 0xda, 0xd2, 0xc5, 0xd9, 0xd3, 0xc5, 0xd9, 0xd2, 0xc5, 0xda, 0xd1, 0xc2, 0xd9, 0xd2, 0xc4, 0xd8, 0xd2, 0xc4, 0xd9, 0xd0, 0xc2, 0xd9, 0xd0, 0xc1, 0xd7, 0xd0, 0xc2, 0xd7, 0xd0, 0xc2, 0xd8, 0xd1, 0xc2, 0xd7, 0xcf, 0xc1, 0xd7, 0xd0, 0xc2, 0xd6, 0xcf, 0xc1, 0xd6, 0xcf, 0xc2, 0xd7, 0xcf, 0xc0, 0xd7, 0xce, 0xbf, 0xd6, 0xce, 0xc0, 0xd5, 0xce, 0xc0, 0xd6, 0xce, 0xbf, 0xd5, 0xcd, 0xbf, 0xd5, 0xcd, 0xbe, 0xd5, 0xcd, 0xbe, 0xd4, 0xcc, 0xbd, 0xd5, 0xcc, 0xbd, 0xd4, 0xcc, 0xbc, 0xd4, 0x47, 0x40, 0x4a, 0x1d, 0x1a, 0x1f, 0x69, 0x5f, 0x6f, 0x4a, 0x42, 0x4f, 0x5e, 0x54, 0x63, 0x3b, 0x34, 0x3f, 0x5e, 0x55, 0x63, 0x63, 0x59, 0x67, 0x77, 0x6d, 0x7b, 0x6d, 0x62, 0x73, 0x7f, 0x76, 0x85, 0xdb, 0xd9, 0xcd, 0xdb, 0xd8, 0xcd, 0x6d, 0x62, 0x74, 0x8f, 0x84, 0x94, 0x7f, 0x76, 0x83, 0xdb, 0xd8, 0xcd, 0xa4, 0x95, 0xa4, 0x7e, 0x74, 0x84, 0x74, 0x6b, 0x79, 0x6f, 0x66, 0x74, 0x96, 0x8a, 0xa2, 0x91, 0x88, 0x9b, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xbf, 0xf0, 0xc9, 0xec, 0x71, 0x0, 0x0, 0x0, 0x75, 0x74, 0x52, 0x4e, 0x53, 0x1, 0x3, 0xa, 0x13, 0x1a, 0x1c, 0x1d, 0x10, 0x2b, 0x4d, 0x64, 0x6e, 0x72, 0xb, 0x2c, 0x6a, 0xfc, 0xff, 0x15, 0x52, 0xfd, 0xff, 0xe2, 0xe2, 0xe2, 0x1b, 0x68, 0xe2, 0xe2, 0xe2, 0x71, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0x1e, 0x72, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0x6b, 0xc7, 0x56, 0xfe, 0xff, 0xc7, 0x30, 0x74, 0xfe, 0x11, 0x57, 0x6d, 0x72, 0x16, 0x1c, 0x0, 0x3, 0x4, 0x35, 0xf5, 0x4, 0x26, 0x0, 0x0, 0x1, 0x16, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xcc, 0xc5, 0x61, 0x95, 0x61, 0x10, 0x85, 0xe1, 0xf7, 0x8c, 0x5c, 0xc3, 0xdd, 0x65, 0x4d, 0xea, 0xc8, 0x6, 0xdb, 0x63, 0xab, 0x74, 0x90, 0x42, 0xe8, 0x20, 0x5b, 0x3a, 0xa0, 0x12, 0xaa, 0xc0, 0x25, 0xd7, 0xe5, 0x1f, 0xec, 0xc3, 0xa5, 0x82, 0x9c, 0xdd, 0x79, 0x46, 0x84, 0xbe, 0x4, 0xa8, 0x2f, 0x91, 0x7a, 0xbf, 0xc0, 0x52, 0x47, 0x5a, 0xa5, 0x51, 0xe4, 0x6f, 0x27, 0xd1, 0xd7, 0x6c, 0x24, 0x15, 0xa0, 0xaa, 0xe9, 0xb0, 0xec, 0x75, 0x10, 0x51, 0x9, 0xbd, 0xde, 0x60, 0x44, 0xbc, 0xb6, 0xeb, 0x43, 0x86, 0xc, 0x56, 0x3d, 0x96, 0xfb, 0x99, 0xc, 0xaf, 0xfb, 0xfe, 0xd4, 0x8f, 0xf5, 0xf3, 0xc3, 0x72, 0xb3, 0x39, 0x67, 0xec, 0xbf, 0x3b, 0x12, 0x80, 0x97, 0x9d, 0x3, 0xc0, 0x81, 0x0, 0xec, 0x2d, 0x3d, 0x96, 0x3d, 0x96, 0x27, 0x1a, 0xe8, 0x14, 0xa8, 0x54, 0x58, 0x83, 0x10, 0x48, 0x55, 0xa6, 0x6, 0x29, 0xa6, 0x0, 0x87, 0xba, 0x6, 0x2e, 0x8e, 0x0, 0xa0, 0x6, 0x26, 0xa9, 0x13, 0xe5, 0x6b, 0xc0, 0x80, 0xcc, 0x8c, 0xea, 0xb2, 0xd6, 0x83, 0xef, 0x4f, 0x25, 0x87, 0x91, 0xba, 0xb6, 0x11, 0x74, 0x96, 0xde, 0xf3, 0xae, 0x6d, 0x90, 0x3d, 0x15, 0xea, 0x12, 0xd1, 0x0, 0x41, 0x39, 0xd0, 0xc0, 0x4, 0x88, 0xa2, 0x1a, 0xb8, 0x0, 0xe0, 0x3b, 0xd8, 0x7f, 0xc1, 0xf8, 0x25, 0x7, 0xf0, 0x4b, 0x3b, 0x80, 0xb8, 0xae, 0x17, 0x56, 0xad, 0x18, 0x97, 0xca, 0x98, 0xa1, 0xd6, 0x11, 0x33, 0x6c, 0x7f, 0x1b, 0xe3, 0xfb, 0xc6, 0xf6, 0xbe, 0xf7, 0xb6, 0xb6, 0x2c, 0x3b, 0xa, 0xb3, 0xbe, 0x6e, 0xe8, 0x59, 0xac, 0x42, 0x7a, 0xd2, 0x36, 0xee, 0x57, 0xad, 0x62, 0xec, 0x1b, 0x7f, 0xa4, 0x3d, 0x60, 0xa7, 0x6a, 0xed, 0x63, 0xa1, 0xc3, 0x3b, 0x7a, 0xa, 0xc0, 0xad, 0xda, 0x1b, 0x57, 0xec, 0xf2, 0xd8, 0x75, 0x17, 0x0, 0x6a, 0x7f, 0x97, 0x8f, 0x54, 0xa2, 0x67, 0xc8, 0xba, 0xb8, 0x46, 0x24, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char graph_port_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xce, 0x41, 0xa, 0x83, 0x30, 0x10, 0x85, 0xe1, 0xb9, 0x98, 0xe2, 0x9, 0x3c, 0x50, 0xe9, 0xc6, 0x83, 0x45, 0x7b, 0x8b, 0xfc, 0x7a, 0x1, 0xd7, 0x49, 0xba, 0xd, 0xd3, 0x79, 0xd0, 0x16, 0x41, 0xfe, 0x6c, 0xe6, 0x83, 0xc0, 0x33, 0x8f, 0xf2, 0xc4, 0xc6, 0x3b, 0x5a, 0x99, 0x75, 0xc7, 0xe3, 0x49, 0xc7, 0x7f, 0xe5, 0x25, 0x30, 0x4f, 0xa2, 0xd3, 0x6b, 0x74, 0x8a, 0xfb, 0x31, 0x1a, 0x2f, 0x51, 0xfb, 0x26, 0x66, 0x35, 0x1a, 0x5e, 0xff, 0x58, 0x84, 0xd5, 0xa8, 0x37, 0x2c, 0xc6, 0x76, 0xfb, 0x9e, 0x8c, 0x19, 0x17, 0x97, 0x48, 0x44, 0xdf, 0x7, 0xad, 0x5c, 0x2e, 0x93, 0x7a, 0x7e, 0x68, 0x67, 0x74, 0x8c, 0x24, 0x1a, 0x95, 0xb4, 0xf, 0xba, 0x3f, 0x56, 0x94, 0xa6, 0x72, 0xc9, 0xf9, 0xda, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8e, 0xc1, 0xd, 0xc2, 0x30, 0x10, 0x4, 0xb7, 0x31, 0x22, 0x2a, 0x48, 0x41, 0x88, 0x4f, 0xa, 0x73, 0x42, 0x17, 0x1e, 0xd2, 0x40, 0xde, 0x3e, 0xf3, 0xb5, 0x8c, 0x8f, 0x13, 0x8, 0x29, 0x3b, 0xbf, 0xd1, 0x9e, 0xf6, 0xe4, 0xc9, 0x57, 0x36, 0x5e, 0x83, 0x95, 0x59, 0x11, 0xee, 0x34, 0xfa, 0x97, 0xbc, 0x44, 0x6b, 0xa8, 0xa3, 0xdb, 0xe0, 0x70, 0xdd, 0xf6, 0x49, 0x3c, 0x5c, 0xd5, 0x20, 0xf4, 0x2a, 0x2a, 0xdd, 0x7e, 0xb2, 0xb8, 0x34, 0x61, 0x27, 0x59, 0xc4, 0x76, 0x3a, 0x4f, 0x62, 0xa6, 0xbb, 0x2e, 0x83, 0x18, 0x7a, 0x5e, 0x7c, 0x7f, 0xf9, 0x7b, 0xa9, 0xe5, 0x9b, 0x22, 0xfb, 0x44, 0xa2, 0x62, 0xa4, 0x4f, 0x4b, 0x6f, 0x69, 0x3b, 0x9a, 0x7e, 0xcd, 0xde, 0x94, 0x27, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char hseparator_png[] = {
@@ -167,7 +167,7 @@ static const unsigned char icon_snap_grid_png[] = {
};
static const unsigned char icon_visibility_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x3, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0xdb, 0xe1, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xdf, 0xdf, 0xdf, 0xe3, 0xe3, 0xe3, 0xe6, 0xe6, 0xe6, 0xd5, 0xd5, 0xd5, 0xd8, 0xd8, 0xd8, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xe1, 0xe1, 0xe1, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xb7, 0x7e, 0xd, 0xb6, 0x0, 0x0, 0x0, 0x32, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x8, 0x9, 0xa, 0xc, 0xd, 0xe, 0xf, 0x11, 0x12, 0x13, 0x2e, 0x2f, 0x32, 0x33, 0x36, 0x37, 0x38, 0x48, 0x49, 0x4b, 0x50, 0x53, 0x55, 0x56, 0x6c, 0x6d, 0x6e, 0x70, 0x77, 0x79, 0x7b, 0x7c, 0xc5, 0xd7, 0xd8, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1, 0xe2, 0xe3, 0xf0, 0xf2, 0xf3, 0xf4, 0xfe, 0x5e, 0x62, 0x1a, 0x26, 0x0, 0x0, 0x0, 0x86, 0x49, 0x44, 0x41, 0x54, 0x18, 0x19, 0x8d, 0xc1, 0xb, 0x16, 0x42, 0x40, 0x0, 0x86, 0xd1, 0x2f, 0xa2, 0x77, 0x2a, 0x85, 0xde, 0x91, 0x5e, 0x33, 0x8a, 0x7f, 0xff, 0x9b, 0xcb, 0x99, 0x63, 0x1, 0xee, 0xa5, 0x9f, 0xc1, 0x3e, 0x6f, 0xea, 0xfc, 0xe0, 0xd1, 0x99, 0xdd, 0xe5, 0x94, 0xb, 0x9c, 0xf9, 0x57, 0x26, 0x9, 0x82, 0x5d, 0xa1, 0xdf, 0x92, 0x96, 0xf7, 0x94, 0x99, 0xd0, 0x1a, 0x1b, 0x7d, 0x7c, 0xe0, 0x2c, 0x25, 0x6c, 0x2b, 0x1b, 0x93, 0x4a, 0x17, 0xa0, 0x94, 0x2, 0xac, 0x64, 0x8, 0xa5, 0x12, 0x78, 0x48, 0x1, 0x56, 0x32, 0x8c, 0xa4, 0x7, 0x70, 0x93, 0x76, 0xc4, 0xd6, 0x6c, 0xc8, 0xa4, 0x2b, 0x30, 0xac, 0x54, 0x8c, 0x69, 0x4d, 0xad, 0xcc, 0x90, 0xd6, 0xba, 0x91, 0x49, 0xc3, 0x30, 0xb3, 0x6a, 0x22, 0x9c, 0xd5, 0x5b, 0xce, 0x2b, 0xa2, 0xe3, 0x9f, 0xf2, 0xba, 0xce, 0x8f, 0x3e, 0xbd, 0xfc, 0x1, 0xdb, 0xf3, 0x10, 0xc5, 0x78, 0x85, 0x14, 0x89, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x3, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0xdb, 0xe1, 0x4f, 0xe0, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xdf, 0xdf, 0xdf, 0xe3, 0xe3, 0xe3, 0xe6, 0xe6, 0xe6, 0xd5, 0xd5, 0xd5, 0xd8, 0xd8, 0xd8, 0xdb, 0xdb, 0xdb, 0xdd, 0xdd, 0xdd, 0xe1, 0xe1, 0xe1, 0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xde, 0xde, 0xde, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xb7, 0x7e, 0xd, 0xb6, 0x0, 0x0, 0x0, 0x32, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x8, 0x9, 0xa, 0xc, 0xd, 0xe, 0xf, 0x11, 0x12, 0x13, 0x2e, 0x2f, 0x32, 0x33, 0x36, 0x37, 0x38, 0x48, 0x49, 0x4b, 0x50, 0x53, 0x55, 0x56, 0x6c, 0x6d, 0x6e, 0x70, 0x77, 0x79, 0x7b, 0x7c, 0xc5, 0xd7, 0xd8, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1, 0xe2, 0xe3, 0xf0, 0xf2, 0xf3, 0xf4, 0xfe, 0x5e, 0x62, 0x1a, 0x26, 0x0, 0x0, 0x0, 0x83, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0xc8, 0x45, 0x42, 0x3, 0x1, 0x0, 0xc0, 0xc0, 0xd4, 0x8b, 0x43, 0x1d, 0x5f, 0x77, 0xcb, 0xff, 0x1f, 0x87, 0xd3, 0xf3, 0xe6, 0x36, 0x61, 0x5c, 0x93, 0xc7, 0x70, 0xe8, 0xc3, 0xa7, 0xe9, 0xbf, 0xaf, 0x62, 0x55, 0x4d, 0x6e, 0x7e, 0x7d, 0xdd, 0x5a, 0x1d, 0x16, 0x8b, 0x7d, 0x64, 0x77, 0xfb, 0xed, 0x69, 0x66, 0x75, 0x1, 0xb0, 0xae, 0x2c, 0x67, 0xc0, 0xab, 0x1e, 0xd8, 0x35, 0xf5, 0x96, 0xa3, 0xbe, 0x1, 0x89, 0x2e, 0xa8, 0xb5, 0x62, 0xa9, 0x9, 0x90, 0x9e, 0xc7, 0x4a, 0x53, 0x20, 0xd0, 0x3d, 0xdb, 0xba, 0xda, 0x70, 0xd2, 0x77, 0x60, 0xde, 0x18, 0xad, 0x1, 0x2e, 0x6b, 0xab, 0x39, 0xc0, 0xc3, 0x60, 0x75, 0x5c, 0x2e, 0x4f, 0xb5, 0xc3, 0x1d, 0x3f, 0xdd, 0x17, 0xaa, 0x9a, 0xff, 0x19, 0x66, 0x2f, 0x61, 0xdf, 0x87, 0xcf, 0x33, 0x46, 0xf5, 0x9, 0xdb, 0xf3, 0x10, 0xc5, 0x55, 0x93, 0xc, 0xea, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char icon_zoom_less_png[] = {
@@ -211,13 +211,17 @@ static const unsigned char option_button_hover_png[] = {
};
static const unsigned char option_button_normal_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0x8, 0xd9, 0x10, 0xcb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x91, 0x53, 0x62, 0x5, 0x41, 0x14, 0x44, 0xab, 0x46, 0xb1, 0x6d, 0x67, 0x3, 0x59, 0x44, 0x16, 0x9e, 0xdf, 0xe8, 0x2f, 0xb6, 0xcd, 0xe7, 0x61, 0xe3, 0x3e, 0x4e, 0xb5, 0x2e, 0x4e, 0xdb, 0xa3, 0x11, 0x80, 0xc4, 0x51, 0xc6, 0x3f, 0x5a, 0xe5, 0xb1, 0x4f, 0x8, 0xd5, 0xff, 0x15, 0xd1, 0x26, 0xba, 0x7d, 0xbd, 0xec, 0xa3, 0x75, 0x94, 0x24, 0x11, 0xbb, 0xe1, 0x2f, 0x1f, 0xe0, 0x91, 0xde, 0x8, 0xf3, 0x1, 0xe, 0x3d, 0x42, 0x1, 0xe3, 0x49, 0xf, 0x1a, 0xc0, 0xb7, 0xb5, 0x47, 0x92, 0x52, 0xb7, 0x3b, 0x79, 0xa7, 0x80, 0x21, 0xc2, 0x2a, 0xa9, 0x15, 0x8b, 0x8e, 0x1c, 0x2e, 0x64, 0x71, 0x4, 0xd0, 0x5b, 0x34, 0x80, 0xa0, 0x34, 0x29, 0xab, 0xd5, 0x7a, 0xfb, 0x5e, 0xc2, 0x51, 0xc0, 0x3, 0x83, 0x6, 0x10, 0xa2, 0xa1, 0x62, 0x1f, 0xf0, 0xae, 0x0, 0x38, 0xd, 0xe0, 0x67, 0xfe, 0xe9, 0xb, 0x72, 0x86, 0xb7, 0x5, 0x46, 0xa, 0x48, 0xfc, 0xa6, 0x15, 0x1e, 0x96, 0xc5, 0x79, 0x99, 0xbe, 0x78, 0x59, 0x2c, 0x1, 0x5e, 0x92, 0x34, 0x6d, 0xb1, 0xf9, 0xda, 0x75, 0x66, 0x6d, 0xfa, 0xf3, 0x5, 0x7f, 0x58, 0x3, 0x8d, 0x15, 0xc8, 0x85, 0xf3, 0xd, 0x6b, 0x1f, 0xdf, 0x6e, 0x8c, 0x33, 0xd4, 0xc0, 0xce, 0xd6, 0xa8, 0x0, 0xd5, 0x20, 0xbc, 0xb5, 0xf6, 0xc2, 0x68, 0xb6, 0xf4, 0x8d, 0x6, 0x9c, 0xc3, 0x6d, 0x5a, 0x60, 0xf, 0x53, 0x7d, 0x72, 0x86, 0x6a, 0xf4, 0xf1, 0xed, 0x1, 0x74, 0x5a, 0x3f, 0xab, 0x94, 0xee, 0x3f, 0x7a, 0x64, 0x11, 0x8a, 0x6e, 0x0, 0x80, 0xdd, 0x4f, 0x5c, 0xe, 0xd7, 0x26, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0x8, 0xd9, 0x10, 0xcb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd1, 0x55, 0x5a, 0xc4, 0x30, 0x14, 0x5, 0xe0, 0x73, 0xea, 0x82, 0xbb, 0x3b, 0x6c, 0x80, 0x45, 0xb0, 0x70, 0x5e, 0xb1, 0x37, 0xdc, 0x75, 0xdc, 0x3d, 0x43, 0x2a, 0x5f, 0x3a, 0x7e, 0x6a, 0xc9, 0xbd, 0x7f, 0x9d, 0x2a, 0x0, 0xa4, 0x16, 0xd, 0xaa, 0x18, 0x8e, 0x41, 0x3f, 0x11, 0xd1, 0xbe, 0x52, 0xc7, 0x48, 0xa8, 0xfb, 0x5e, 0x68, 0xd4, 0x24, 0x96, 0x6a, 0xfc, 0xaf, 0x8b, 0x32, 0xbf, 0x61, 0x90, 0xc6, 0x3c, 0x27, 0x3, 0xce, 0xfe, 0x20, 0x2, 0x4b, 0xd2, 0x45, 0x1f, 0x14, 0xd5, 0x78, 0x5e, 0x36, 0x1c, 0x7d, 0xe5, 0x33, 0x2, 0xb3, 0x84, 0x8a, 0xec, 0xd4, 0xeb, 0x9a, 0x1a, 0x1b, 0x82, 0xf5, 0x79, 0x20, 0x2, 0x46, 0x1f, 0x58, 0x8d, 0x95, 0xe4, 0x6a, 0x1d, 0xcf, 0x4f, 0x89, 0x85, 0x10, 0x80, 0x56, 0x1f, 0x8, 0xf4, 0x53, 0xf7, 0x81, 0x6c, 0x4, 0xa0, 0xf5, 0x41, 0x69, 0xeb, 0xb7, 0xd0, 0x7b, 0x86, 0xcc, 0x36, 0xbb, 0x11, 0x90, 0x66, 0x1f, 0x88, 0xef, 0xbd, 0x64, 0x92, 0x5a, 0x7b, 0x4e, 0xed, 0x34, 0x42, 0x20, 0xa5, 0xd5, 0x7, 0x27, 0x69, 0xfb, 0x51, 0x8d, 0x69, 0x6e, 0xd5, 0xcc, 0xb9, 0x18, 0xf4, 0xaf, 0x40, 0x6e, 0x3f, 0x1d, 0xab, 0xf1, 0xdd, 0xc7, 0xf1, 0x12, 0x45, 0xc, 0xce, 0x4f, 0x17, 0x12, 0xd0, 0xb6, 0xc4, 0x87, 0x1a, 0x6f, 0x2f, 0x48, 0x8b, 0xef, 0x31, 0xd0, 0x6e, 0xce, 0xa8, 0xc0, 0x25, 0x56, 0x7d, 0x5, 0x52, 0xed, 0x6e, 0xae, 0x68, 0x0, 0xd4, 0x86, 0x7f, 0x56, 0x43, 0x62, 0x38, 0xc, 0x46, 0x28, 0xba, 0x1, 0x7a, 0xad, 0x4f, 0x59, 0x90, 0xab, 0xbf, 0xa4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char option_button_pressed_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0x10, 0x9d, 0xe0, 0x3c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xcf, 0x3, 0x62, 0x4, 0x51, 0x10, 0x4, 0xd0, 0xaa, 0x31, 0x62, 0xdb, 0xb8, 0x49, 0x2e, 0x9e, 0x3b, 0xc4, 0xb6, 0x9d, 0xc5, 0x58, 0x1f, 0xc1, 0xd6, 0xe8, 0x77, 0xf7, 0x1b, 0x59, 0x6c, 0x2, 0x20, 0x37, 0xaa, 0xc5, 0x17, 0x7e, 0xc7, 0x62, 0x28, 0x45, 0x75, 0xfe, 0x6c, 0xe1, 0x4f, 0x68, 0x86, 0x41, 0x69, 0x44, 0x51, 0x4b, 0xb1, 0xce, 0xcc, 0xe4, 0x83, 0xd7, 0xb0, 0x48, 0x6b, 0x98, 0xe8, 0x9, 0x38, 0x70, 0x8b, 0xa, 0xcc, 0x12, 0x1a, 0xf0, 0x4d, 0xac, 0x87, 0xf3, 0x96, 0x6f, 0x8e, 0x5f, 0x56, 0xc0, 0x53, 0x20, 0x8f, 0xbf, 0xdb, 0x86, 0x58, 0x5b, 0x9, 0xbf, 0x47, 0x80, 0xa, 0x58, 0x1a, 0x38, 0xad, 0x9, 0x5f, 0xac, 0xe3, 0x20, 0xbc, 0x4b, 0x46, 0x4b, 0x0, 0x3a, 0x1a, 0x24, 0xd0, 0x69, 0x85, 0xc0, 0x63, 0x5, 0x60, 0x68, 0xf0, 0x36, 0x7f, 0xf3, 0xaa, 0xbe, 0xe1, 0x61, 0x81, 0x69, 0x5, 0x72, 0x5b, 0x83, 0xe4, 0x6a, 0x59, 0x16, 0xf7, 0x53, 0x47, 0x77, 0x8b, 0xad, 0x12, 0xe4, 0xb9, 0xa3, 0xc1, 0xe6, 0x83, 0x7b, 0x20, 0xd6, 0xb4, 0xe7, 0xbf, 0xed, 0xe1, 0x1a, 0xd8, 0xfa, 0xdf, 0xb9, 0x70, 0xb8, 0x21, 0xd6, 0xbb, 0x17, 0x1b, 0xe3, 0x4c, 0x6a, 0xb0, 0xbd, 0x25, 0x5, 0x3b, 0x5e, 0x7c, 0x21, 0xc0, 0xc2, 0x68, 0xee, 0xf1, 0xbc, 0x6, 0x46, 0xb1, 0xbd, 0x5e, 0x30, 0x5, 0x27, 0x19, 0x24, 0xb8, 0x61, 0x6e, 0xf8, 0xf5, 0xf7, 0xcd, 0x47, 0x16, 0xa0, 0x18, 0x13, 0x6a, 0x64, 0x7d, 0xff, 0x8f, 0x1e, 0x59, 0x84, 0xa2, 0x1b, 0x0, 0xe5, 0xe0, 0x4e, 0x46, 0x1d, 0x98, 0x92, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char overbright_indicator_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x1, 0x85, 0x69, 0x43, 0x43, 0x50, 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x0, 0x0, 0x78, 0x9c, 0x7d, 0x91, 0x3d, 0x48, 0xc3, 0x40, 0x1c, 0xc5, 0x5f, 0x53, 0xa5, 0x2a, 0x2d, 0xe, 0x16, 0x11, 0x75, 0xc8, 0x50, 0x9d, 0x2c, 0x8a, 0x8a, 0x38, 0x6a, 0x15, 0x8a, 0x50, 0x21, 0xd4, 0xa, 0xad, 0x3a, 0x98, 0x5c, 0xfa, 0x21, 0x34, 0x69, 0x48, 0x52, 0x5c, 0x1c, 0x5, 0xd7, 0x82, 0x83, 0x1f, 0x8b, 0x55, 0x7, 0x17, 0x67, 0x5d, 0x1d, 0x5c, 0x5, 0x41, 0xf0, 0x3, 0xc4, 0xc5, 0xd5, 0x49, 0xd1, 0x45, 0x4a, 0xfc, 0x5f, 0x5a, 0x68, 0x11, 0xe3, 0xc1, 0x71, 0x3f, 0xde, 0xdd, 0x7b, 0xdc, 0xbd, 0x3, 0x84, 0x6a, 0x91, 0x69, 0x56, 0xdb, 0x18, 0xa0, 0xe9, 0xb6, 0x99, 0x8c, 0xc7, 0xc4, 0x74, 0x66, 0x45, 0xc, 0xbc, 0xa2, 0x13, 0x3, 0x8, 0xa1, 0x17, 0xa3, 0x32, 0xb3, 0x8c, 0x59, 0x49, 0x4a, 0xc0, 0x73, 0x7c, 0xdd, 0xc3, 0xc7, 0xd7, 0xbb, 0x28, 0xcf, 0xf2, 0x3e, 0xf7, 0xe7, 0x8, 0xa9, 0x59, 0x8b, 0x1, 0x3e, 0x91, 0x78, 0x86, 0x19, 0xa6, 0x4d, 0xbc, 0x4e, 0x3c, 0xb5, 0x69, 0x1b, 0x9c, 0xf7, 0x89, 0xc3, 0xac, 0x20, 0xab, 0xc4, 0xe7, 0xc4, 0x23, 0x26, 0x5d, 0x90, 0xf8, 0x91, 0xeb, 0x4a, 0x9d, 0xdf, 0x38, 0xe7, 0x5d, 0x16, 0x78, 0x66, 0xd8, 0x4c, 0x25, 0xe7, 0x88, 0xc3, 0xc4, 0x62, 0xbe, 0x85, 0x95, 0x16, 0x66, 0x5, 0x53, 0x23, 0x9e, 0x24, 0x8e, 0xa8, 0x9a, 0x4e, 0xf9, 0x42, 0xba, 0xce, 0x2a, 0xe7, 0x2d, 0xce, 0x5a, 0xb1, 0xcc, 0x1a, 0xf7, 0xe4, 0x2f, 0xc, 0x66, 0xf5, 0xe5, 0x25, 0xae, 0xd3, 0x1c, 0x44, 0x1c, 0xb, 0x58, 0x84, 0x4, 0x11, 0xa, 0xca, 0xd8, 0x40, 0x11, 0x36, 0xa2, 0xb4, 0xea, 0xa4, 0x58, 0x48, 0xd2, 0x7e, 0xcc, 0xc3, 0xdf, 0xef, 0xfa, 0x25, 0x72, 0x29, 0xe4, 0xda, 0x0, 0x23, 0xc7, 0x3c, 0x4a, 0xd0, 0x20, 0xbb, 0x7e, 0xf0, 0x3f, 0xf8, 0xdd, 0xad, 0x95, 0x9b, 0x18, 0xaf, 0x27, 0x5, 0x63, 0x40, 0xfb, 0x8b, 0xe3, 0x7c, 0xc, 0x1, 0x81, 0x5d, 0xa0, 0x56, 0x71, 0x9c, 0xef, 0x63, 0xc7, 0xa9, 0x9d, 0x0, 0xfe, 0x67, 0xe0, 0x4a, 0x6f, 0xfa, 0x4b, 0x55, 0x60, 0xfa, 0x93, 0xf4, 0x4a, 0x53, 0x8b, 0x1c, 0x1, 0xdd, 0xdb, 0xc0, 0xc5, 0x75, 0x53, 0x53, 0xf6, 0x80, 0xcb, 0x1d, 0xa0, 0xef, 0xc9, 0x90, 0x4d, 0xd9, 0x95, 0xfc, 0x34, 0x85, 0x5c, 0xe, 0x78, 0x3f, 0xa3, 0x6f, 0xca, 0x0, 0x3d, 0xb7, 0x40, 0xd7, 0x6a, 0xbd, 0xb7, 0xc6, 0x3e, 0x4e, 0x1f, 0x80, 0x14, 0x75, 0x95, 0xb8, 0x1, 0xe, 0xe, 0x81, 0xe1, 0x3c, 0x65, 0xaf, 0x79, 0xbc, 0xbb, 0xa3, 0xb5, 0xb7, 0x7f, 0xcf, 0x34, 0xfa, 0xfb, 0x1, 0x8e, 0x80, 0x72, 0xb2, 0xed, 0x78, 0xfa, 0x7b, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x15, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x63, 0x63, 0x66, 0x0, 0x0, 0x3, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4c, 0x39, 0x3a, 0xe, 0x0, 0x0, 0x0, 0x6, 0x74, 0x52, 0x4e, 0x53, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x80, 0x2c, 0x16, 0xc1, 0x6d, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6, 0x61, 0x66, 0xb8, 0x7d, 0x0, 0x0, 0x0, 0x32, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x1, 0x46, 0x65, 0x17, 0x17, 0x30, 0x43, 0xc8, 0x4, 0x50, 0x88, 0x1c, 0x52, 0x1, 0x0, 0x2, 0x40, 0x14, 0xbb, 0x70, 0x8b, 0x40, 0xff, 0x2c, 0x18, 0xbe, 0xc6, 0xed, 0x8d, 0x42, 0xa1, 0x50, 0x28, 0x14, 0xa, 0x85, 0xbd, 0xb0, 0x13, 0xfc, 0x71, 0x1, 0xca, 0xf, 0x19, 0x62, 0x24, 0xd6, 0x8, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char panel_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -275,7 +279,7 @@ static const unsigned char scroll_grabber_png[] = {
};
static const unsigned char scroll_grabber_hl_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0x17, 0x3b, 0xfc, 0x67, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0xc7, 0xa5, 0x1, 0x3, 0x1, 0x0, 0x4, 0xc1, 0xdd, 0xb, 0x9a, 0x60, 0xff, 0x3d, 0x6, 0x54, 0xe0, 0x59, 0x3d, 0x8f, 0x9b, 0xb0, 0x66, 0x3, 0x98, 0xdc, 0xff, 0x35, 0x20, 0xec, 0x3c, 0x6b, 0xf5, 0xae, 0xff, 0x6c, 0xda, 0xdc, 0x36, 0x31, 0xc7, 0x6f, 0xc9, 0x16, 0x8c, 0x40, 0x1d, 0xba, 0x64, 0x21, 0x42, 0xc0, 0x97, 0xc9, 0xe6, 0x25, 0x8, 0x5c, 0xf4, 0xf6, 0x2c, 0x5f, 0x8c, 0x39, 0x4c, 0x3, 0xfe, 0x9a, 0x10, 0x43, 0x82, 0xcf, 0x27, 0x93, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0x17, 0x3b, 0xfc, 0x67, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x46, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x7d, 0x8a, 0x25, 0x2, 0xc4, 0x40, 0x0, 0x3, 0x27, 0x39, 0x52, 0x57, 0xfa, 0xff, 0x1f, 0x17, 0x54, 0x19, 0x6d, 0x61, 0x4c, 0x90, 0x5b, 0x5e, 0x80, 0xec, 0x66, 0x58, 0x76, 0x3, 0x1f, 0x15, 0xd2, 0x9c, 0x97, 0x61, 0xf, 0xbf, 0x4a, 0xc0, 0x12, 0x3b, 0xde, 0xfb, 0xeb, 0x8, 0x66, 0xf, 0xbe, 0x8, 0x2, 0x83, 0x92, 0xec, 0x57, 0x12, 0x8, 0x28, 0xa5, 0x3a, 0x4e, 0x89, 0x7, 0x56, 0x51, 0x36, 0x11, 0x22, 0x4, 0xb, 0xcc, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char scroll_grabber_pressed_png[] = {
@@ -291,7 +295,7 @@ static const unsigned char selection_oof_png[] = {
};
static const unsigned char space_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x63, 0x60, 0xa0, 0x2a, 0xf8, 0xff, 0xff, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0x5, 0x91, 0xc5, 0x58, 0x90, 0x24, 0x85, 0x18, 0x18, 0x18, 0x14, 0xa0, 0x6c, 0x6, 0x46, 0x46, 0xc6, 0xf7, 0xc, 0xc, 0xc, 0xc, 0x4c, 0x14, 0x5b, 0x41, 0x39, 0x0, 0x0, 0x71, 0x1a, 0x13, 0x5d, 0x87, 0xfe, 0x9e, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x16, 0xfc, 0x17, 0xfc, 0x2f, 0x88, 0xcc, 0x15, 0xfa, 0x6f, 0x4, 0x84, 0x82, 0x18, 0x2, 0xe8, 0x5a, 0x88, 0x4, 0x0, 0x8c, 0xa4, 0xd, 0x47, 0x8, 0xea, 0xcc, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char spinbox_updown_png[] = {
@@ -315,15 +319,15 @@ static const unsigned char tab_close_png[] = {
};
static const unsigned char tab_container_bg_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x0, 0x4, 0xc1, 0x69, 0x1c, 0xfe, 0xff, 0xca, 0xd5, 0xeb, 0x2a, 0x83, 0x6b, 0xd2, 0xb7, 0x54, 0x1c, 0x31, 0x26, 0xc9, 0x63, 0x50, 0xcc, 0x32, 0x8d, 0x3f, 0xd9, 0x20, 0x5, 0x1a, 0xf2, 0xc7, 0x1f, 0x7a, 0x48, 0x4a, 0x66, 0xa8, 0xde, 0xc, 0xd0, 0x38, 0xd1, 0x54, 0xdb, 0x4c, 0x2b, 0xd0, 0x5c, 0x62, 0x8e, 0xa0, 0x1, 0x74, 0x4, 0x65, 0xd2, 0x1e, 0xd4, 0x83, 0xf7, 0x60, 0x65, 0x3e, 0x82, 0x3, 0x48, 0x49, 0xdf, 0x55, 0xca, 0xd4, 0xef, 0xfa, 0xfb, 0x27, 0x36, 0xf, 0x92, 0x31, 0x9e, 0x44, 0x3e, 0x17, 0x7c, 0xbf, 0x3, 0xef, 0x34, 0x3f, 0x3e, 0xe0, 0x24, 0x67, 0xb9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_current_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0xd7, 0x41, 0xa4, 0x19, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xca, 0x85, 0xd, 0xc0, 0x40, 0x14, 0xc3, 0x50, 0x27, 0xf7, 0xd5, 0xfd, 0xd7, 0x2d, 0xa6, 0x4c, 0x16, 0x3f, 0xb9, 0xd0, 0x11, 0x90, 0xa3, 0x52, 0x77, 0x49, 0x8e, 0x86, 0xd2, 0x26, 0x16, 0x7b, 0x59, 0x32, 0x68, 0x3, 0x37, 0x5d, 0xe0, 0x59, 0x3b, 0x74, 0x31, 0x67, 0x4b, 0x3b, 0xf, 0x71, 0xe5, 0xe8, 0xf, 0xec, 0xc0, 0x1f, 0x28, 0xf8, 0x2, 0x14, 0xf9, 0x42, 0xa8, 0xfc, 0x21, 0x3b, 0xe4, 0x1, 0x6f, 0x0, 0x18, 0x11, 0xac, 0x99, 0xc0, 0xe, 0x25, 0x22, 0x2d, 0x76, 0xc6, 0x13, 0x1a, 0x8, 0xac, 0x78, 0xfc, 0x1c, 0x70, 0x30, 0x2b, 0xba, 0xe9, 0x31, 0x70, 0xc1, 0x7f, 0x3b, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0xd7, 0x41, 0xa4, 0x19, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xca, 0x85, 0xd, 0xc0, 0x40, 0x14, 0xc3, 0x50, 0x27, 0xf7, 0xd5, 0xfd, 0xd7, 0x2d, 0xa6, 0x4c, 0x16, 0x3f, 0x59, 0xe8, 0x8, 0xc8, 0x91, 0xd4, 0x5d, 0x92, 0xa3, 0xa1, 0x76, 0xb1, 0xd8, 0xcb, 0x92, 0x41, 0x1b, 0xb8, 0xe9, 0x2, 0xcf, 0xd2, 0x7e, 0xc4, 0x9c, 0x2d, 0xed, 0x3c, 0xc4, 0x95, 0xa3, 0x3f, 0xb0, 0x3, 0x7f, 0xa0, 0xe0, 0xb, 0x50, 0xe4, 0xb, 0xa1, 0xf2, 0x87, 0x38, 0x31, 0x4f, 0x4e, 0xa, 0x30, 0x22, 0x58, 0x33, 0x81, 0x1d, 0x4a, 0x44, 0x5a, 0xec, 0x8c, 0x27, 0x34, 0x10, 0x58, 0xf1, 0xf8, 0x39, 0xe0, 0x60, 0x56, 0x63, 0x63, 0x30, 0x69, 0xf8, 0x3c, 0xb4, 0xd1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_disabled_png[] = {
- 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x3, 0xa7, 0x7a, 0x54, 0x58, 0x74, 0x52, 0x61, 0x77, 0x20, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x65, 0x78, 0x69, 0x66, 0x0, 0x0, 0x78, 0xda, 0xcd, 0x96, 0x59, 0x92, 0xe3, 0x2a, 0x10, 0x45, 0xff, 0x59, 0x45, 0x2f, 0x81, 0xcc, 0x24, 0x19, 0x96, 0x83, 0x18, 0x22, 0x7a, 0x7, 0x6f, 0xf9, 0x7d, 0xc1, 0x48, 0x1e, 0xab, 0x5c, 0x65, 0xfb, 0xe3, 0x89, 0xb0, 0x40, 0x29, 0x48, 0xae, 0xee, 0x41, 0xc8, 0xa6, 0xfd, 0xf7, 0xb7, 0x9b, 0x3f, 0x38, 0x28, 0x45, 0x6f, 0x9c, 0x86, 0xe8, 0x93, 0xf7, 0x16, 0x87, 0x4b, 0x2e, 0x71, 0x46, 0x23, 0xda, 0xd3, 0x71, 0xaa, 0xc9, 0xba, 0x79, 0x5e, 0x17, 0x76, 0x6f, 0x5c, 0xc5, 0xcd, 0x71, 0x83, 0x11, 0x12, 0xd4, 0x72, 0xba, 0xf4, 0x6d, 0xf5, 0xcf, 0x88, 0xeb, 0x79, 0x40, 0x70, 0x2b, 0xbe, 0x5d, 0xc7, 0x4d, 0x28, 0x2b, 0x4f, 0x5c, 0x89, 0xe8, 0x48, 0x3c, 0xf, 0x19, 0x33, 0x8f, 0xf6, 0xea, 0x17, 0x57, 0x22, 0xe1, 0x53, 0x9c, 0xd6, 0xb5, 0x49, 0x6b, 0x5c, 0x76, 0x17, 0x8f, 0xb3, 0x7e, 0x5c, 0x56, 0xda, 0x95, 0xfc, 0xf6, 0xda, 0x5, 0x98, 0x51, 0x15, 0xf9, 0x84, 0xd, 0x37, 0x21, 0xb1, 0x38, 0xc7, 0x31, 0x8b, 0x40, 0x81, 0x24, 0xc9, 0x32, 0xda, 0x79, 0xde, 0x19, 0x91, 0x80, 0xb6, 0x43, 0x9d, 0x45, 0x84, 0x1e, 0x7b, 0x67, 0x8e, 0xe6, 0x8d, 0x79, 0x47, 0xeb, 0xc6, 0x3b, 0x9b, 0x57, 0x5c, 0xae, 0xad, 0x30, 0xd6, 0xaf, 0xe, 0xfe, 0xc6, 0xa3, 0x15, 0x27, 0xbd, 0x89, 0xcb, 0x31, 0xd, 0xdf, 0x52, 0xdb, 0x67, 0xbe, 0xba, 0x91, 0xcb, 0x31, 0xc5, 0x9d, 0x77, 0xbd, 0xd7, 0xd8, 0x7b, 0x3b, 0x3d, 0x5d, 0x76, 0x1e, 0x4e, 0x79, 0xb3, 0x1e, 0x6a, 0x7f, 0x94, 0xd9, 0x42, 0xc7, 0xd, 0x56, 0xca, 0x1c, 0xe6, 0x51, 0x2, 0x7e, 0x8a, 0x76, 0x98, 0x25, 0xa1, 0x44, 0x3c, 0x62, 0x1, 0xb1, 0xa, 0x9a, 0x1b, 0x4a, 0x31, 0x94, 0x88, 0xe1, 0x69, 0x27, 0x47, 0x95, 0x32, 0x75, 0x6a, 0xb3, 0x2e, 0x54, 0x20, 0xd1, 0x71, 0xe3, 0x80, 0x9a, 0xb9, 0xb0, 0xcc, 0x58, 0x94, 0xc0, 0x89, 0xcb, 0x84, 0xe2, 0x46, 0xa1, 0xce, 0x1, 0x78, 0xaa, 0x91, 0x8, 0x3e, 0x5, 0xd4, 0x4, 0x61, 0x3e, 0xb4, 0xd0, 0x9c, 0x37, 0xcd, 0xf9, 0xa, 0x45, 0xcc, 0x5c, 0x9, 0x3d, 0x99, 0x90, 0x8c, 0x30, 0xe2, 0xae, 0x98, 0x47, 0xc1, 0x57, 0xca, 0x91, 0xa8, 0xf7, 0xb1, 0x74, 0x89, 0x6c, 0x3c, 0xbc, 0x82, 0x2e, 0x1e, 0x6b, 0x1a, 0x32, 0x6, 0xb9, 0x71, 0x46, 0x2f, 0x0, 0xa1, 0xbe, 0x3c, 0xd5, 0xe9, 0xef, 0x2c, 0xe6, 0x62, 0xdd, 0xd8, 0xb, 0xb0, 0x2, 0x82, 0x3a, 0x6d, 0x8e, 0x78, 0xc0, 0x6c, 0xb7, 0x53, 0x8a, 0x4d, 0xe9, 0xbc, 0xb6, 0x64, 0x72, 0x16, 0xf4, 0x53, 0xeb, 0x8c, 0x3d, 0xbd, 0x1a, 0x14, 0xea, 0x4a, 0x0, 0x8b, 0x30, 0xb7, 0x42, 0xc, 0x9, 0x8, 0x58, 0x4f, 0xa2, 0xe4, 0xc9, 0x6, 0xe6, 0x40, 0x4, 0x1f, 0x23, 0xf8, 0x64, 0x28, 0x67, 0x71, 0xbc, 0x81, 0x0, 0xa9, 0x72, 0x25, 0xd3, 0xc1, 0x46, 0xc4, 0x3, 0x4e, 0xe4, 0x31, 0x37, 0xc6, 0x4, 0x9a, 0x7d, 0x59, 0xf9, 0x14, 0xc6, 0xd6, 0x2, 0x10, 0x2a, 0x1e, 0xaf, 0x4a, 0x1c, 0x2f, 0x10, 0x60, 0x39, 0xa7, 0x58, 0x3f, 0xc1, 0x45, 0xac, 0xa1, 0xac, 0xa2, 0xce, 0xa8, 0xaa, 0xd7, 0xa0, 0x51, 0x93, 0x66, 0x2f, 0xde, 0x79, 0xf5, 0xde, 0x7, 0x3f, 0xf6, 0xa8, 0x1c, 0x24, 0xb8, 0xa0, 0xc1, 0x87, 0x10, 0x62, 0x48, 0x21, 0x47, 0x89, 0x2e, 0x6a, 0xf4, 0x31, 0xc4, 0x18, 0x53, 0xcc, 0x89, 0x93, 0x60, 0xb, 0xd3, 0xe4, 0x53, 0x30, 0x29, 0xa6, 0x94, 0x72, 0xc6, 0xa4, 0x19, 0xa9, 0x33, 0x46, 0x67, 0xf4, 0xc8, 0x79, 0xe3, 0x4d, 0x36, 0xb7, 0xe9, 0xe6, 0xb7, 0xb0, 0xc5, 0x2d, 0x6d, 0xb9, 0x60, 0xf9, 0x14, 0x57, 0xb4, 0xf8, 0x12, 0x4a, 0x2c, 0xa9, 0xe4, 0xca, 0x55, 0x2a, 0x5e, 0xff, 0xea, 0x6b, 0x30, 0x35, 0xd6, 0x54, 0x73, 0xa3, 0x86, 0xa5, 0xd4, 0x5c, 0xd3, 0xe6, 0x5b, 0x68, 0xb1, 0xa5, 0x96, 0x3b, 0xd6, 0x5a, 0x97, 0xee, 0xba, 0x76, 0xdf, 0x43, 0x8f, 0x3d, 0xf5, 0x7c, 0x50, 0x5b, 0x54, 0xaf, 0xa9, 0xd1, 0xd, 0xb9, 0xef, 0xa9, 0xd1, 0xa2, 0x36, 0x88, 0xb9, 0xd9, 0x2f, 0x9c, 0xa9, 0x21, 0x1c, 0xc2, 0x9e, 0x82, 0xc6, 0x76, 0xa2, 0x83, 0x19, 0x88, 0xb1, 0x23, 0x10, 0xf, 0x83, 0x0, 0x16, 0x34, 0xf, 0x66, 0x36, 0x92, 0x73, 0x3c, 0xc8, 0xd, 0x66, 0x36, 0x31, 0x5e, 0xa, 0x65, 0x50, 0x23, 0x1d, 0x70, 0x2a, 0xd, 0x62, 0x20, 0xe8, 0x1a, 0xb1, 0x76, 0x3a, 0xd8, 0x9d, 0xc9, 0x7d, 0xcb, 0xcd, 0xa8, 0xfb, 0x15, 0x37, 0xfe, 0x8a, 0x9c, 0x19, 0xe8, 0x3e, 0x41, 0xce, 0xc, 0x74, 0x8b, 0xdc, 0x3d, 0xb7, 0x7, 0xd4, 0x6a, 0x9e, 0x5f, 0x14, 0x99, 0x80, 0xc6, 0x5b, 0x38, 0x3c, 0xb5, 0xd2, 0xb1, 0xb1, 0xa1, 0x43, 0x8b, 0x99, 0x63, 0x1e, 0xdf, 0xa4, 0x97, 0x6b, 0xf3, 0x6e, 0x82, 0xff, 0x59, 0xa2, 0x76, 0x98, 0x52, 0xcd, 0x96, 0x67, 0xd4, 0xe2, 0x7b, 0x78, 0x6a, 0xd8, 0xd7, 0x6a, 0x83, 0x5d, 0x64, 0x45, 0x84, 0x8e, 0x89, 0x9e, 0x4a, 0xe9, 0x9a, 0xf6, 0x51, 0x92, 0x67, 0xc, 0xd4, 0xe2, 0x2e, 0xcf, 0xfd, 0x52, 0xb, 0xf9, 0x35, 0x30, 0x1d, 0x1e, 0xe1, 0x3, 0xb4, 0xf2, 0x97, 0x94, 0x9f, 0x8a, 0x71, 0x37, 0x62, 0x3e, 0x48, 0xd, 0x42, 0xcc, 0xae, 0x24, 0xb7, 0xa7, 0x4a, 0xf8, 0x50, 0xd2, 0x3e, 0x8d, 0xbf, 0xda, 0xc3, 0x12, 0xb3, 0xf9, 0xa7, 0x4a, 0xe8, 0x91, 0x27, 0x9f, 0x51, 0x74, 0x1, 0x67, 0x5b, 0xc9, 0xcd, 0xd7, 0x4a, 0x5c, 0xff, 0xce, 0x93, 0xf7, 0x14, 0x5d, 0x78, 0x52, 0x6e, 0xee, 0x99, 0x7, 0x4a, 0xea, 0xfe, 0xd6, 0x44, 0x25, 0xa7, 0xe3, 0x6f, 0xeb, 0xf, 0x6a, 0xf3, 0x93, 0x8e, 0x14, 0xf6, 0x67, 0xeb, 0xc2, 0x5f, 0x2c, 0x73, 0x73, 0x88, 0xad, 0xb2, 0x6b, 0xca, 0x73, 0xb8, 0x8e, 0xff, 0xd0, 0x3f, 0xaf, 0xcd, 0x77, 0x1d, 0xb4, 0x9f, 0x2d, 0x79, 0xe6, 0xb7, 0xe9, 0x2e, 0xbf, 0x62, 0xc9, 0x5d, 0x6d, 0x9e, 0x58, 0xa2, 0x4f, 0x76, 0x0, 0xa9, 0xec, 0xf7, 0x6d, 0xe4, 0x25, 0x4b, 0xee, 0x6a, 0xf3, 0xd8, 0x92, 0xfa, 0x74, 0x33, 0x71, 0xe9, 0x7a, 0xb9, 0x9a, 0xcf, 0x6c, 0xfd, 0xa7, 0x44, 0x17, 0xeb, 0xf5, 0xf7, 0x4a, 0x2e, 0x13, 0xbd, 0xbd, 0xad, 0xd9, 0x99, 0xe8, 0x4d, 0x25, 0x9f, 0x50, 0x74, 0x65, 0x89, 0x79, 0x57, 0xc9, 0x3b, 0x8a, 0x1e, 0xc2, 0xd9, 0x15, 0x75, 0xfc, 0x61, 0x49, 0xe6, 0x1f, 0xbf, 0x1c, 0xa8, 0x52, 0x2b, 0xb1, 0xc9, 0xd4, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x2e, 0x23, 0x0, 0x0, 0x2e, 0x23, 0x1, 0x78, 0xa5, 0x3f, 0x76, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe3, 0x2, 0xa, 0x13, 0x29, 0x21, 0x5f, 0x36, 0xe2, 0x14, 0x0, 0x0, 0x0, 0xaf, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x7d, 0x91, 0x41, 0xa, 0xc2, 0x40, 0x10, 0x4, 0x6b, 0x92, 0x61, 0x37, 0xb0, 0x87, 0xec, 0x39, 0x3e, 0xc6, 0x3f, 0xf8, 0x9a, 0x3c, 0xc1, 0xd7, 0xf8, 0x3, 0xf, 0x3e, 0xc6, 0xab, 0x44, 0x50, 0x30, 0x26, 0x66, 0x3c, 0x2c, 0x6, 0x3, 0xd9, 0xf4, 0x69, 0xa0, 0xab, 0x9b, 0x86, 0x11, 0x14, 0x87, 0xa7, 0xc2, 0x51, 0x52, 0x90, 0x34, 0xf1, 0xe1, 0xcd, 0x8b, 0x9e, 0xb7, 0xe2, 0x8, 0x44, 0x6a, 0x2, 0x1e, 0x41, 0x0, 0xc3, 0xe8, 0x79, 0x72, 0xa7, 0x3, 0xc5, 0x13, 0xf7, 0x87, 0x5d, 0x3b, 0x46, 0x16, 0xd2, 0xee, 0x7a, 0xbc, 0x9c, 0x18, 0x95, 0x8a, 0xba, 0x69, 0x6f, 0x71, 0xc4, 0xfe, 0x6c, 0x41, 0x63, 0xd3, 0x72, 0xe6, 0xa1, 0x38, 0xc2, 0x10, 0x87, 0x65, 0x1c, 0x63, 0x60, 0x88, 0x4, 0x9c, 0x52, 0xe2, 0xa7, 0x45, 0x9a, 0x79, 0x29, 0x9e, 0x52, 0x29, 0x10, 0x63, 0x5a, 0x1, 0xc, 0x84, 0x42, 0x1, 0xc9, 0x36, 0x8, 0x68, 0x3a, 0x33, 0x0, 0x9, 0x30, 0x5b, 0x5, 0xc, 0x6c, 0x6e, 0x98, 0x36, 0x1b, 0x24, 0xdb, 0xf0, 0xdb, 0xc0, 0x2a, 0x90, 0x54, 0x6c, 0xba, 0x96, 0x0, 0xc9, 0x2, 0xc2, 0xfc, 0xe0, 0xac, 0xbe, 0xe, 0x38, 0x38, 0x83, 0xbf, 0x35, 0x30, 0x94, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x2e, 0x23, 0x0, 0x0, 0x2e, 0x23, 0x1, 0x78, 0xa5, 0x3f, 0x76, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0xa6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x7c, 0xcd, 0xc5, 0x41, 0x4, 0x41, 0x10, 0x0, 0xc0, 0xea, 0xbd, 0xc1, 0x6d, 0xde, 0x47, 0x30, 0xe4, 0x40, 0x34, 0x1b, 0x2, 0xd1, 0x10, 0x1, 0x1a, 0xc, 0x4f, 0xdc, 0x6d, 0x1b, 0x77, 0xe6, 0xea, 0xd5, 0xde, 0xa1, 0x98, 0x36, 0x63, 0xd6, 0xb4, 0x91, 0xe, 0x30, 0x78, 0x74, 0xe7, 0xc6, 0xad, 0xbb, 0x97, 0xf6, 0x82, 0x6a, 0xc5, 0x82, 0x19, 0x21, 0x90, 0xd2, 0xad, 0x4b, 0xa7, 0x4e, 0x28, 0x66, 0xd4, 0xb5, 0xf5, 0xd5, 0xfe, 0xa1, 0xfa, 0xa1, 0x9c, 0x1c, 0x6c, 0xec, 0x6f, 0x7a, 0x28, 0x66, 0xad, 0x8c, 0xfb, 0xa3, 0xfa, 0x20, 0x7d, 0x9, 0xa5, 0x8e, 0x7b, 0xdb, 0x2e, 0x5e, 0x5f, 0xdc, 0xd7, 0x7b, 0x3f, 0xa5, 0x7b, 0xf7, 0xd5, 0x82, 0xe9, 0x62, 0x64, 0x66, 0x90, 0xfe, 0x1a, 0x98, 0x31, 0x2a, 0x3a, 0x91, 0x6, 0x7f, 0x25, 0xa1, 0x2b, 0x88, 0xe6, 0x85, 0xa0, 0x40, 0x73, 0x0, 0x5, 0x99, 0xf2, 0xff, 0x17, 0xf9, 0x79, 0x61, 0x98, 0x78, 0x21, 0x9a, 0x17, 0x82, 0xf2, 0x99, 0x34, 0x74, 0x13, 0xbb, 0x49, 0x87, 0xd0, 0x12, 0x4f, 0x3, 0x29, 0x20, 0x0, 0x0, 0xe, 0x38, 0x38, 0x83, 0xd2, 0xe8, 0x36, 0x36, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned char tab_menu_png[] = {
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 2364a4a8a3..99a2881d58 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -130,7 +130,7 @@ Error DynamicFontAtSize::_load() {
} else {
FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ);
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'.");
size_t len = f->get_len();
_fontdata[font->font_path] = Vector<uint8_t>();
@@ -145,7 +145,7 @@ Error DynamicFontAtSize::_load() {
if (font->font_mem == NULL && font->font_path != String()) {
FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ);
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open font file '" + font->font_path + "'.");
memset(&stream, 0, sizeof(FT_StreamRec));
stream.base = NULL;
@@ -182,18 +182,17 @@ Error DynamicFontAtSize::_load() {
//error = FT_New_Face( library, src_path.utf8().get_data(),0,&face );
if (error == FT_Err_Unknown_File_Format) {
- ERR_EXPLAIN("Unknown font format.");
+
FT_Done_FreeType(library);
+ ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Unknown font format.");
} else if (error) {
- ERR_EXPLAIN("Error loading font.");
FT_Done_FreeType(library);
+ ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, "Error loading font.");
}
- ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN);
-
- if (FT_HAS_COLOR(face)) {
+ if (FT_HAS_COLOR(face) && face->num_fixed_sizes > 0) {
int best_match = 0;
int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width));
scale_color_font = float(id.size) / face->available_sizes[0].width;
diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp
deleted file mode 100644
index ccff617a16..0000000000
--- a/scene/resources/dynamic_font_stb.cpp
+++ /dev/null
@@ -1,524 +0,0 @@
-/*************************************************************************/
-/* dynamic_font_stb.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "dynamic_font_stb.h"
-
-#ifndef FREETYPE_ENABLED
-
-#define STB_TRUETYPE_IMPLEMENTATION
-#include "core/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.release();
-}
-
-void DynamicFontData::set_font_data(const PoolVector<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, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
-
- const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
-
- const Character *c = char_map.getptr(p_char);
-
- if (!c) {
- return 0;
- }
-
- if (!p_outline) {
- 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);
- 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;
- }
-
- 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 = next_power_of_2(texsize);
-
- texsize = MIN(texsize, 4096);
-
- CharTexture tex;
- tex.texture_size = texsize;
- tex.imgdata.resize(texsize * texsize * 2); //grayscale alpha
-
- {
- //zero texture
- PoolVector<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];
-
- {
- PoolVector<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
- {
- Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, 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);
-
- 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() {
-
- ClassDB::bind_method(D_METHOD("set_font_data", "data"), &DynamicFont::set_font_data);
- ClassDB::bind_method(D_METHOD("get_font_data"), &DynamicFont::get_font_data);
-
- ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "font/size"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font/font", PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"), "set_font_data", "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, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) 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, p_outline);
-}
-
-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());
-
- PoolVector<uint8_t> data;
-
- data.resize(f->get_len());
-
- ERR_FAIL_COND_V(data.size() == 0, RES());
-
- {
- PoolVector<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.get_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
deleted file mode 100644
index caee6e7e32..0000000000
--- a/scene/resources/dynamic_font_stb.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*************************************************************************/
-/* dynamic_font_stb.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef DYNAMICFONT_STB_H
-#define DYNAMICFONT_STB_H
-
-#ifndef FREETYPE_ENABLED
-
-#include "core/io/resource_loader.h"
-#include "font.h"
-
-#include "thirdparty/misc/stb_truetype.h"
-
-class DynamicFontAtSize;
-class DynamicFont;
-
-class DynamicFontData : public Resource {
-
- GDCLASS(DynamicFontData, Resource);
-
- bool valid;
-
- PoolVector<uint8_t> font_data;
- PoolVector<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 PoolVector<uint8_t> &p_font);
- DynamicFontData();
- ~DynamicFontData();
-};
-
-class DynamicFontAtSize : public Reference {
-
- GDCLASS(DynamicFontAtSize, Reference);
-
- int rect_margin;
-
- struct CharTexture {
-
- PoolVector<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, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const;
-
- DynamicFontAtSize();
- ~DynamicFontAtSize();
-};
-
-///////////////
-
-class DynamicFont : public Font {
-
- GDCLASS(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, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) 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/environment.cpp b/scene/resources/environment.cpp
index afb7f1102b..bc96b5e9f3 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -354,10 +354,6 @@ void Environment::_validate_property(PropertyInfo &property) const {
"tonemap_",
"ss_reflections_",
"ssao_",
- "dof_blur_far_",
- "dof_blur_near_",
- "glow_",
- "adjustment_",
NULL
};
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index cff77acdd7..124e4d37e6 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -96,7 +96,7 @@ void Font::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_height"), &Font::get_height);
ClassDB::bind_method(D_METHOD("is_distance_field_hint"), &Font::is_distance_field_hint);
ClassDB::bind_method(D_METHOD("get_string_size", "string"), &Font::get_string_size);
- ClassDB::bind_method(D_METHOD("get_wordwrap_string_size", "string", "p_width"), &Font::get_wordwrap_string_size);
+ ClassDB::bind_method(D_METHOD("get_wordwrap_string_size", "string", "width"), &Font::get_wordwrap_string_size);
ClassDB::bind_method(D_METHOD("has_outline"), &Font::has_outline);
ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "position", "char", "next", "modulate", "outline"), &Font::draw_char, DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes);
@@ -358,7 +358,7 @@ float BitmapFont::get_descent() const {
void BitmapFont::add_texture(const Ref<Texture> &p_texture) {
- ERR_FAIL_COND(p_texture.is_null());
+ ERR_FAIL_COND_MSG(p_texture.is_null(), "It's not a reference to a valid Texture object.");
textures.push_back(p_texture);
}
diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
index f763700d52..214706626d 100644
--- a/scene/resources/height_map_shape.cpp
+++ b/scene/resources/height_map_shape.cpp
@@ -31,7 +31,7 @@
#include "height_map_shape.h"
#include "servers/physics_server.h"
-Vector<Vector3> HeightMapShape::_gen_debug_mesh_lines() {
+Vector<Vector3> HeightMapShape::get_debug_mesh_lines() {
Vector<Vector3> points;
if ((map_width != 0) && (map_depth != 0)) {
diff --git a/scene/resources/height_map_shape.h b/scene/resources/height_map_shape.h
index b062f4e893..4cf2a76213 100644
--- a/scene/resources/height_map_shape.h
+++ b/scene/resources/height_map_shape.h
@@ -46,8 +46,6 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
-
public:
void set_map_width(int p_new);
int get_map_width() const;
@@ -56,6 +54,8 @@ public:
void set_map_data(PoolRealArray p_new);
PoolRealArray get_map_data() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
HeightMapShape();
};
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 0de462d616..fab0aace14 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -496,10 +496,16 @@ void SpatialMaterial::_update_shader() {
}
code += "uniform float roughness : hint_range(0,1);\n";
code += "uniform float point_size : hint_range(0,128);\n";
- code += "uniform sampler2D texture_metallic : hint_white;\n";
- code += "uniform vec4 metallic_texture_channel;\n";
- code += "uniform sampler2D texture_roughness : hint_white;\n";
- code += "uniform vec4 roughness_texture_channel;\n";
+
+ if (textures[TEXTURE_METALLIC] != NULL) {
+ code += "uniform sampler2D texture_metallic : hint_white;\n";
+ code += "uniform vec4 metallic_texture_channel;\n";
+ }
+
+ if (textures[TEXTURE_ROUGHNESS] != NULL) {
+ code += "uniform sampler2D texture_roughness : hint_white;\n";
+ code += "uniform vec4 roughness_texture_channel;\n";
+ }
if (billboard_mode == BILLBOARD_PARTICLES) {
code += "uniform int particles_anim_h_frames;\n";
code += "uniform int particles_anim_v_frames;\n";
@@ -790,20 +796,30 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) {
code += "\talbedo_tex *= COLOR;\n";
}
-
code += "\tALBEDO = albedo.rgb * albedo_tex.rgb;\n";
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n";
+
+ if (textures[TEXTURE_METALLIC] != NULL) {
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n";
+ } else {
+ code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
+ }
+ code += "\tMETALLIC = metallic_tex * metallic;\n";
} else {
- code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
+ code += "\tMETALLIC = metallic;\n";
}
- code += "\tMETALLIC = metallic_tex * metallic;\n";
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n";
+
+ if (textures[TEXTURE_ROUGHNESS] != NULL) {
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n";
+ } else {
+ code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
+ }
+ code += "\tROUGHNESS = roughness_tex * roughness;\n";
} else {
- code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
+ code += "\tROUGHNESS = roughness;\n";
}
- code += "\tROUGHNESS = roughness_tex * roughness;\n";
+
code += "\tSPECULAR = specular;\n";
if (features[FEATURE_NORMAL_MAPPING]) {
@@ -1389,6 +1405,8 @@ void SpatialMaterial::set_texture(TextureParam p_param, const Ref<Texture> &p_te
textures[p_param] = p_texture;
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
VS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid);
+ _queue_shader_change();
+ _change_notify();
}
Ref<Texture> SpatialMaterial::get_texture(TextureParam p_param) const {
@@ -1754,6 +1772,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_roughness_texture_channel()
void SpatialMaterial::set_ao_texture_channel(TextureChannel p_channel) {
+ ERR_FAIL_INDEX(p_channel, 5);
ao_texture_channel = p_channel;
VS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
}
@@ -1764,6 +1783,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_ao_texture_channel() const
void SpatialMaterial::set_refraction_texture_channel(TextureChannel p_channel) {
+ ERR_FAIL_INDEX(p_channel, 5);
refraction_texture_channel = p_channel;
VS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
}
@@ -1804,10 +1824,9 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent,
material->set_flag(FLAG_SRGB_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(FLAG_USE_ALPHA_SCISSOR, p_cut_alpha);
- if (p_billboard) {
- material->set_billboard_mode(BILLBOARD_ENABLED);
- } else if (p_billboard_y) {
- material->set_billboard_mode(BILLBOARD_FIXED_Y);
+ if (p_billboard || p_billboard_y) {
+ material->set_flag(FLAG_BILLBOARD_KEEP_SCALE, true);
+ material->set_billboard_mode(p_billboard_y ? BILLBOARD_FIXED_Y : BILLBOARD_ENABLED);
}
materials_for_2d[version] = material;
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index d40a5dee2e..f04af29761 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "mesh_library.h"
+#include "core/engine.h"
bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
@@ -117,7 +118,7 @@ void MeshLibrary::create_item(int p_item) {
void MeshLibrary::set_item_name(int p_item, const String &p_name) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].name = p_name;
emit_changed();
_change_notify();
@@ -125,7 +126,7 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) {
void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].mesh = p_mesh;
notify_change_to_owners();
emit_changed();
@@ -134,7 +135,7 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].shapes = p_shapes;
_change_notify();
notify_change_to_owners();
@@ -144,7 +145,7 @@ void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes)
void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navmesh = p_navmesh;
_change_notify();
notify_change_to_owners();
@@ -154,7 +155,7 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm
void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].navmesh_transform = p_transform;
notify_change_to_owners();
emit_changed();
@@ -163,7 +164,7 @@ void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_tran
void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].preview = p_preview;
emit_changed();
_change_notify();
@@ -171,37 +172,42 @@ void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) {
String MeshLibrary::get_item_name(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), "");
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), "", "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].name;
}
Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Mesh>());
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Mesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].mesh;
}
Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), Vector<ShapeData>());
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector<ShapeData>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].shapes;
}
Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), Ref<NavigationMesh>());
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<NavigationMesh>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navmesh;
}
Transform MeshLibrary::get_item_navmesh_transform(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), Transform());
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].navmesh_transform;
}
Ref<Texture> MeshLibrary::get_item_preview(int p_item) const {
- ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Texture>());
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ ERR_PRINT("MeshLibrary item previews are only generated in an editor context, which means they aren't available in a running project.");
+ return Ref<Texture>();
+ }
+
+ ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Ref<Texture>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
return item_map[p_item].preview;
}
@@ -211,7 +217,7 @@ bool MeshLibrary::has_item(int p_item) const {
}
void MeshLibrary::remove_item(int p_item) {
- ERR_FAIL_COND(!item_map.has(p_item));
+ ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map.erase(p_item);
notify_change_to_owners();
_change_notify();
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index dc6ef2b49c..969743f78c 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -567,8 +567,8 @@ void ParticlesMaterial::_update_shader() {
}
}
//scale by scale
- code += " float base_scale = mix(scale * tex_scale, 1.0, scale_random * scale_rand);\n";
- code += " if (base_scale == 0.0) {\n";
+ code += " float base_scale = tex_scale * mix(scale, 1.0, scale_random * scale_rand);\n";
+ code += " if (base_scale < 0.000001) {\n";
code += " base_scale = 0.000001;\n";
code += " }\n";
if (trail_size_modifier.is_valid()) {
diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp
index 08f6ccd764..d3274ec5f8 100644
--- a/scene/resources/plane_shape.cpp
+++ b/scene/resources/plane_shape.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server.h"
-Vector<Vector3> PlaneShape::_gen_debug_mesh_lines() {
+Vector<Vector3> PlaneShape::get_debug_mesh_lines() {
Plane p = get_plane();
Vector<Vector3> points;
diff --git a/scene/resources/plane_shape.h b/scene/resources/plane_shape.h
index 87c367cfde..f853d1966b 100644
--- a/scene/resources/plane_shape.h
+++ b/scene/resources/plane_shape.h
@@ -42,12 +42,12 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
-
public:
void set_plane(Plane p_plane);
Plane get_plane() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
PlaneShape();
};
#endif // PLANE_SHAPE_H
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 52fc21ac11..bd3236cb5b 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -466,11 +466,11 @@ Dictionary PolygonPathFinder::_get_data() const {
PoolVector<Vector2> p;
PoolVector<int> ind;
Array connections;
- p.resize(points.size() - 2);
- connections.resize(points.size() - 2);
+ p.resize(MAX(0, points.size() - 2));
+ connections.resize(MAX(0, points.size() - 2));
ind.resize(edges.size() * 2);
PoolVector<float> penalties;
- penalties.resize(points.size() - 2);
+ penalties.resize(MAX(0, points.size() - 2));
{
PoolVector<Vector2>::Write wp = p.write();
PoolVector<float>::Write pw = penalties.write();
diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp
index 0acfffdc06..f185263a36 100644
--- a/scene/resources/ray_shape.cpp
+++ b/scene/resources/ray_shape.cpp
@@ -32,7 +32,7 @@
#include "servers/physics_server.h"
-Vector<Vector3> RayShape::_gen_debug_mesh_lines() {
+Vector<Vector3> RayShape::get_debug_mesh_lines() {
Vector<Vector3> points;
points.push_back(Vector3());
@@ -90,6 +90,12 @@ void RayShape::_bind_methods() {
RayShape::RayShape() :
Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_RAY)) {
- set_length(1.0);
- set_slips_on_slope(false);
+ length = 1.0;
+ slips_on_slope = false;
+
+ /* Code copied from setters to prevent the use of uninitialized variables */
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("length");
+ _change_notify("slips_on_slope");
}
diff --git a/scene/resources/ray_shape.h b/scene/resources/ray_shape.h
index 89fc34051c..fee7475c69 100644
--- a/scene/resources/ray_shape.h
+++ b/scene/resources/ray_shape.h
@@ -41,7 +41,6 @@ class RayShape : public Shape {
protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_length(float p_length);
@@ -50,6 +49,8 @@ public:
void set_slips_on_slope(bool p_active);
bool get_slips_on_slope() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
RayShape();
};
#endif // RAY_SHAPE_H
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index cd229732ba..baffc1396d 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1225,7 +1225,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const
Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V(err != OK, Ref<ResourceInteractiveLoader>());
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<ResourceInteractiveLoader>(), "Cannot open file '" + p_path + "'.");
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText);
String path = p_original_path != "" ? p_original_path : p_path;
@@ -1321,7 +1321,7 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path,
Error err;
FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'.");
Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText);
const String &path = p_src_path;
@@ -1481,7 +1481,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
Error err;
f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(err, ERR_CANT_OPEN);
+ ERR_FAIL_COND_V_MSG(err, ERR_CANT_OPEN, "Cannot save file '" + p_path + "'.");
FileAccessRef _fref(f);
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
@@ -1713,6 +1713,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
if (groups.size()) {
+ groups.sort_custom<StringName::AlphCompare>();
String sgroups = " groups=[\n";
for (int j = 0; j < groups.size(); j++) {
sgroups += "\"" + String(groups[j]).c_escape() + "\",\n";
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 89570beb5f..57e2470164 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -222,10 +222,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc
Error err;
FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- if (err) {
-
- ERR_FAIL_COND_V(err, err);
- }
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save shader '" + p_path + "'.");
file->store_string(source);
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 6ba46f066c..3500fdb4bc 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -37,7 +37,7 @@
void Shape::add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform) {
- Vector<Vector3> toadd = _gen_debug_mesh_lines();
+ Vector<Vector3> toadd = get_debug_mesh_lines();
if (toadd.size()) {
@@ -64,7 +64,7 @@ Ref<ArrayMesh> Shape::get_debug_mesh() {
if (debug_mesh_cache.is_valid())
return debug_mesh_cache;
- Vector<Vector3> lines = _gen_debug_mesh_lines();
+ Vector<Vector3> lines = get_debug_mesh_lines();
debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh));
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
index ba763eaab1..2743fd0c65 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -50,13 +50,13 @@ protected:
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape(RID p_shape);
- virtual Vector<Vector3> _gen_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
virtual void _update_shape();
public:
virtual RID get_rid() const { return shape; }
Ref<ArrayMesh> get_debug_mesh();
+ virtual Vector<Vector3> get_debug_mesh_lines() = 0; // { return Vector<Vector3>(); }
void add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform);
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
new file mode 100644
index 0000000000..98c114e0e6
--- /dev/null
+++ b/scene/resources/skin.cpp
@@ -0,0 +1,132 @@
+/*************************************************************************/
+/* skin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "skin.h"
+
+void Skin::set_bind_count(int p_size) {
+ ERR_FAIL_COND(p_size < 0);
+ binds.resize(p_size);
+ binds_ptr = binds.ptrw();
+ bind_count = p_size;
+ emit_changed();
+}
+
+void Skin::add_bind(int p_bone, const Transform &p_pose) {
+ uint32_t index = bind_count;
+ set_bind_count(bind_count + 1);
+ set_bind_bone(index, p_bone);
+ set_bind_pose(index, p_pose);
+}
+
+void Skin::set_bind_bone(int p_index, int p_bone) {
+ ERR_FAIL_INDEX(p_index, bind_count);
+ binds_ptr[p_index].bone = p_bone;
+ emit_changed();
+}
+
+void Skin::set_bind_pose(int p_index, const Transform &p_pose) {
+ ERR_FAIL_INDEX(p_index, bind_count);
+ binds_ptr[p_index].pose = p_pose;
+ emit_changed();
+}
+
+void Skin::clear_binds() {
+ binds.clear();
+ binds_ptr = nullptr;
+ bind_count = 0;
+ emit_changed();
+}
+
+bool Skin::_set(const StringName &p_name, const Variant &p_value) {
+ String name = p_name;
+ if (name == "bind_count") {
+ set_bind_count(p_value);
+ return true;
+ } else if (name.begins_with("bind/")) {
+ int index = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+ if (what == "bone") {
+ set_bind_bone(index, p_value);
+ return true;
+ } else if (what == "pose") {
+ set_bind_pose(index, p_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
+
+ String name = p_name;
+ if (name == "bind_count") {
+ r_ret = get_bind_count();
+ return true;
+ } else if (name.begins_with("bind/")) {
+ int index = name.get_slicec('/', 1).to_int();
+ String what = name.get_slicec('/', 2);
+ if (what == "bone") {
+ r_ret = get_bind_bone(index);
+ return true;
+ } else if (what == "pose") {
+ r_ret = get_bind_pose(index);
+ return true;
+ }
+ }
+ return false;
+}
+void Skin::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ for (int i = 0; i < get_bind_count(); i++) {
+ p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose"));
+ }
+}
+
+void Skin::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_bind_count", "bind_count"), &Skin::set_bind_count);
+ ClassDB::bind_method(D_METHOD("get_bind_count"), &Skin::get_bind_count);
+
+ ClassDB::bind_method(D_METHOD("add_bind", "bone", "pose"), &Skin::add_bind);
+
+ ClassDB::bind_method(D_METHOD("set_bind_pose", "bind_index", "pose"), &Skin::set_bind_pose);
+ ClassDB::bind_method(D_METHOD("get_bind_pose", "bind_index"), &Skin::get_bind_pose);
+
+ ClassDB::bind_method(D_METHOD("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone);
+ ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_bind_bone);
+
+ ClassDB::bind_method(D_METHOD("clear_binds"), &Skin::clear_binds);
+}
+
+Skin::Skin() {
+ bind_count = 0;
+ binds_ptr = nullptr;
+}
diff --git a/scene/resources/skin.h b/scene/resources/skin.h
new file mode 100644
index 0000000000..7dd02eca5d
--- /dev/null
+++ b/scene/resources/skin.h
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* skin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef SKIN_H
+#define SKIN_H
+
+#include "core/resource.h"
+
+class Skin : public Resource {
+ GDCLASS(Skin, Resource)
+
+ struct Bind {
+ int bone;
+ Transform pose;
+ };
+
+ Vector<Bind> binds;
+
+ Bind *binds_ptr;
+ int bind_count;
+
+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:
+ void set_bind_count(int p_size);
+ inline int get_bind_count() const { return bind_count; }
+
+ void add_bind(int p_bone, const Transform &p_pose);
+
+ void set_bind_bone(int p_index, int p_bone);
+ void set_bind_pose(int p_index, const Transform &p_pose);
+
+ inline int get_bind_bone(int p_index) const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(p_index, bind_count, -1);
+#endif
+ return binds_ptr[p_index].bone;
+ }
+
+ inline Transform get_bind_pose(int p_index) const {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(p_index, bind_count, Transform());
+#endif
+ return binds_ptr[p_index].pose;
+ }
+
+ void clear_binds();
+
+ Skin();
+};
+
+#endif // SKIN_H
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
index af89413ced..019bc9189a 100644
--- a/scene/resources/sphere_shape.cpp
+++ b/scene/resources/sphere_shape.cpp
@@ -31,7 +31,7 @@
#include "sphere_shape.h"
#include "servers/physics_server.h"
-Vector<Vector3> SphereShape::_gen_debug_mesh_lines() {
+Vector<Vector3> SphereShape::get_debug_mesh_lines() {
float r = get_radius();
diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h
index 682928e885..679882fe23 100644
--- a/scene/resources/sphere_shape.h
+++ b/scene/resources/sphere_shape.h
@@ -42,12 +42,13 @@ protected:
static void _bind_methods();
virtual void _update_shape();
- virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_radius(float p_radius);
float get_radius() const;
+ virtual Vector<Vector3> get_debug_mesh_lines();
+
SphereShape();
};
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 5dd429fa75..9ee7c2936e 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -40,16 +40,22 @@ bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
void StyleBox::set_default_margin(Margin p_margin, float p_value) {
+ ERR_FAIL_INDEX((int)p_margin, 4);
+
margin[p_margin] = p_value;
emit_changed();
}
float StyleBox::get_default_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0);
+
return margin[p_margin];
}
float StyleBox::get_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0);
+
if (margin[p_margin] < 0)
return get_style_margin(p_margin);
else
@@ -157,11 +163,15 @@ void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) {
}
float StyleBoxTexture::get_margin_size(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0);
+
return margin[p_margin];
}
float StyleBoxTexture::get_style_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0);
+
return margin[p_margin];
}
@@ -250,6 +260,7 @@ Rect2 StyleBoxTexture::get_region_rect() const {
void StyleBoxTexture::set_h_axis_stretch_mode(AxisStretchMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 3);
axis_h = p_mode;
emit_changed();
}
@@ -261,6 +272,7 @@ StyleBoxTexture::AxisStretchMode StyleBoxTexture::get_h_axis_stretch_mode() cons
void StyleBoxTexture::set_v_axis_stretch_mode(AxisStretchMode p_mode) {
+ ERR_FAIL_INDEX((int)p_mode, 3);
axis_v = p_mode;
emit_changed();
}
@@ -391,11 +403,13 @@ int StyleBoxFlat::get_border_width_min() const {
}
void StyleBoxFlat::set_border_width(Margin p_margin, int p_width) {
+ ERR_FAIL_INDEX((int)p_margin, 4);
border_width[p_margin] = p_width;
emit_changed();
}
int StyleBoxFlat::get_border_width(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0);
return border_width[p_margin];
}
@@ -437,15 +451,19 @@ int StyleBoxFlat::get_corner_radius_min() const {
void StyleBoxFlat::set_corner_radius(const Corner p_corner, const int radius) {
+ ERR_FAIL_INDEX((int)p_corner, 4);
corner_radius[p_corner] = radius;
emit_changed();
}
int StyleBoxFlat::get_corner_radius(const Corner p_corner) const {
+
+ ERR_FAIL_INDEX_V((int)p_corner, 4, 0);
return corner_radius[p_corner];
}
void StyleBoxFlat::set_expand_margin_size(Margin p_expand_margin, float p_size) {
+ ERR_FAIL_INDEX((int)p_expand_margin, 4);
expand_margin[p_expand_margin] = p_size;
emit_changed();
}
@@ -468,6 +486,7 @@ void StyleBoxFlat::set_expand_margin_size_all(float p_expand_margin_size) {
float StyleBoxFlat::get_expand_margin_size(Margin p_expand_margin) const {
+ ERR_FAIL_INDEX_V((int)p_expand_margin, 4, 0.0);
return expand_margin[p_expand_margin];
}
void StyleBoxFlat::set_draw_center(bool p_enabled) {
@@ -713,6 +732,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<Point2> verts;
Vector<int> indices;
Vector<Color> colors;
+ Vector<Point2> uvs;
//DRAW SHADOW
if (draw_shadow) {
@@ -799,12 +819,21 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
}
+ //COMPUTE UV COORDINATES
+ Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
+ uvs.resize(verts.size());
+ for (int i = 0; i < verts.size(); i++) {
+ uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
+ uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
+ }
+
//DRAWING
VisualServer *vs = VisualServer::get_singleton();
- vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors);
+ vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
}
float StyleBoxFlat::get_style_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0);
return border_width[p_margin];
}
void StyleBoxFlat::_bind_methods() {
@@ -988,6 +1017,7 @@ void StyleBoxLine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
float StyleBoxLine::get_style_margin(Margin p_margin) const {
+ ERR_FAIL_INDEX_V((int)p_margin, 4, thickness);
return thickness;
}
Size2 StyleBoxLine::get_center_size() const {
diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp
index b84f3f1f9e..3faedc883d 100644
--- a/scene/resources/text_file.cpp
+++ b/scene/resources/text_file.cpp
@@ -53,9 +53,8 @@ Error TextFile::load_text(const String &p_path) {
PoolVector<uint8_t> sourcef;
Error err;
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (err) {
- ERR_FAIL_COND_V(err, err);
- }
+
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot open TextFile '" + p_path + "'.");
int len = f->get_len();
sourcef.resize(len + 1);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index e44b17584b..c2e2f85723 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -117,6 +117,7 @@ void ImageTexture::reload_from_file() {
} else {
Resource::reload_from_file();
_change_notify();
+ emit_changed();
}
}
@@ -175,11 +176,12 @@ void ImageTexture::_reload_hook(const RID &p_hook) {
img.instance();
Error err = ImageLoader::load_image(path, img);
- ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'.");
VisualServer::get_singleton()->texture_set_data(texture, img);
_change_notify();
+ emit_changed();
}
void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
@@ -190,6 +192,7 @@ void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uin
w = p_width;
h = p_height;
_change_notify();
+ emit_changed();
}
void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags) {
@@ -202,23 +205,23 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags
VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags);
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
+ emit_changed();
image_stored = true;
}
void ImageTexture::set_flags(uint32_t p_flags) {
- /* uint32_t cube = flags & FLAG_CUBEMAP;
- if (flags == p_flags&cube)
+ if (flags == p_flags)
return;
- flags=p_flags|cube; */
flags = p_flags;
if (w == 0 || h == 0) {
return; //uninitialized, do not set to texture
}
VisualServer::get_singleton()->texture_set_flags(texture, p_flags);
_change_notify("flags");
+ emit_changed();
}
uint32_t ImageTexture::get_flags() const {
@@ -250,6 +253,8 @@ void ImageTexture::set_data(const Ref<Image> &p_image) {
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
+ emit_changed();
+
alpha_cache.unref();
image_stored = true;
}
@@ -736,6 +741,7 @@ Error StreamTexture::load(const String &p_path) {
format = image->get_format();
_change_notify();
+ emit_changed();
return OK;
}
String StreamTexture::get_load_path() const {
@@ -827,6 +833,7 @@ void StreamTexture::set_flags(uint32_t p_flags) {
flags = p_flags;
VS::get_singleton()->texture_set_flags(texture, flags);
_change_notify("flags");
+ emit_changed();
}
void StreamTexture::reload_from_file() {
@@ -2355,7 +2362,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String
}
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V(!f, RES());
+ ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'.");
uint8_t header[5] = { 0, 0, 0, 0, 0 };
f->get_buffer(header, 4);
@@ -2372,7 +2379,7 @@ RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String
}
} else {
- ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format: " + String((const char *)header) + ".");
+ ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format '" + String((const char *)header) + "'.");
}
int tw = f->get_32();
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index ae18be1695..f1429a7d7b 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -37,6 +37,97 @@ void Theme::_emit_theme_changed() {
emit_changed();
}
+PoolVector<String> Theme::_get_icon_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_icon_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_stylebox_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_stylebox_types(void) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_types(&il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_font_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_font_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_color_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_color_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_constant_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_constant_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_type_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_type_list(&il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
@@ -300,6 +391,8 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_type) {
void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!icon_map.has(p_type))
return;
@@ -344,6 +437,9 @@ void Theme::clear_shader(const StringName &p_name, const StringName &p_type) {
}
void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list) const {
+
+ ERR_FAIL_NULL(p_list);
+
if (!shader_map.has(p_type))
return;
@@ -408,6 +504,8 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_type) {
void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!style_map.has(p_type))
return;
@@ -420,6 +518,8 @@ void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const
}
void Theme::get_stylebox_types(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
const StringName *key = NULL;
while ((key = style_map.next(key))) {
p_list->push_back(*key);
@@ -478,6 +578,8 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_type) {
void Theme::get_font_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!font_map.has(p_type))
return;
@@ -526,6 +628,8 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_type) {
void Theme::get_color_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!color_map.has(p_type))
return;
@@ -574,6 +678,8 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_type) {
void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!constant_map.has(p_type))
return;
@@ -637,6 +743,12 @@ void Theme::copy_default_theme() {
void Theme::copy_theme(const Ref<Theme> &p_other) {
+ if (p_other.is_null()) {
+ clear();
+
+ return;
+ }
+
//these need reconnecting, so add normally
{
const StringName *K = NULL;
@@ -680,8 +792,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
void Theme::get_type_list(List<StringName> *p_list) const {
- Set<StringName> types;
+ ERR_FAIL_NULL(p_list);
+ Set<StringName> types;
const StringName *key = NULL;
while ((key = icon_map.next(key))) {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 187694de65..471e5b1a51 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -52,6 +52,14 @@ class Theme : public Resource {
HashMap<StringName, HashMap<StringName, Color> > color_map;
HashMap<StringName, HashMap<StringName, int> > constant_map;
+ PoolVector<String> _get_icon_list(const String &p_type) const;
+ PoolVector<String> _get_stylebox_list(const String &p_type) const;
+ PoolVector<String> _get_stylebox_types(void) const;
+ PoolVector<String> _get_font_list(const String &p_type) const;
+ PoolVector<String> _get_color_list(const String &p_type) const;
+ PoolVector<String> _get_constant_list(const String &p_type) const;
+ PoolVector<String> _get_type_list(const String &p_type) const;
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -65,70 +73,6 @@ protected:
Ref<Font> default_theme_font;
- PoolVector<String> _get_icon_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_icon_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_stylebox_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_stylebox_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_stylebox_types(void) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_stylebox_types(&il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_font_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_font_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_color_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_color_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_constant_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_constant_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_type_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_type_list(&il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
-
static void _bind_methods();
public:
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index eb3bf6770f..81c7b062cc 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -63,7 +63,7 @@ public:
//virtual int mix(int16_t* p_buffer,int p_frames)=0;
- virtual Ref<Texture> get_texture() = 0;
+ virtual Ref<Texture> get_texture() const = 0;
virtual void update(float p_delta) = 0;
virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) = 0;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index f5ea6adc85..9f99732714 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -103,6 +103,10 @@ String VisualShaderNode::get_warning(Shader::Mode p_mode, VisualShader::Type p_t
return String();
}
+String VisualShaderNode::get_input_port_default_hint(int p_port) const {
+ return "";
+}
+
void VisualShaderNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview);
@@ -122,7 +126,8 @@ void VisualShaderNode::_bind_methods() {
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR);
BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN);
BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM);
- BIND_ENUM_CONSTANT(PORT_TYPE_ICON_COLOR);
+ BIND_ENUM_CONSTANT(PORT_TYPE_SAMPLER);
+ BIND_ENUM_CONSTANT(PORT_TYPE_MAX);
}
VisualShaderNode::VisualShaderNode() {
@@ -1058,7 +1063,16 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
String src_var = "n_out" + itos(from_node) + "p" + itos(from_port);
- if (in_type == out_type) {
+ if (in_type == VisualShaderNode::PORT_TYPE_SAMPLER && out_type == VisualShaderNode::PORT_TYPE_SAMPLER) {
+ VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr());
+ if (ptr->has_method("get_input_real_name")) {
+ inputs[i] = ptr->call("get_input_real_name");
+ } else if (ptr->has_method("get_uniform_name")) {
+ inputs[i] = ptr->call("get_uniform_name");
+ } else {
+ inputs[i] = "";
+ }
+ } else if (in_type == out_type) {
inputs[i] = src_var;
} else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_VECTOR) {
inputs[i] = "dot(" + src_var + ",vec3(0.333333,0.333333,0.333333))";
@@ -1139,12 +1153,16 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
global_code += vsnode->generate_global(get_mode(), type, node);
- if (!r_classes.has(vsnode->get_class_name())) {
+ String class_name = vsnode->get_class_name();
+ if (class_name == "VisualShaderNodeCustom") {
+ class_name = vsnode->get_script_instance()->get_script()->get_language()->get_global_class_name(vsnode->get_script_instance()->get_script()->get_path());
+ }
+ if (!r_classes.has(class_name)) {
global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node);
for (int i = 0; i < TYPE_MAX; i++) {
global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
}
- r_classes.insert(vsnode->get_class_name());
+ r_classes.insert(class_name);
}
}
@@ -1332,7 +1350,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id);
ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
- ClassDB::bind_method(D_METHOD("rebuild"), &VisualShader::rebuild);
ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
@@ -1426,6 +1443,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" },
// Spatial, Light
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
@@ -1472,6 +1491,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD,0.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light_pass", "float(AT_LIGHT_PASS ? 1.0 : 0.0)" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV,0.0)" },
@@ -1488,6 +1510,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD,0.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
// Particles, Vertex
{ Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
@@ -1583,11 +1606,15 @@ String VisualShaderNodeInput::get_output_port_name(int p_port) const {
}
String VisualShaderNodeInput::get_caption() const {
- return TTR("Input");
+ return "Input";
}
String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ if (get_output_port_type(0) == PORT_TYPE_SAMPLER) {
+ return "";
+ }
+
if (p_for_preview) {
int idx = 0;
@@ -1656,6 +1683,20 @@ String VisualShaderNodeInput::get_input_name() const {
return input_name;
}
+String VisualShaderNodeInput::get_input_real_name() const {
+
+ int idx = 0;
+
+ while (ports[idx].mode != Shader::MODE_MAX) {
+ if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type && ports[idx].name == input_name) {
+ return String(ports[idx].string);
+ }
+ idx++;
+ }
+
+ return "";
+}
+
VisualShaderNodeInput::PortType VisualShaderNodeInput::get_input_type_by_name(String p_name) const {
int idx = 0;
@@ -1752,6 +1793,7 @@ void VisualShaderNodeInput::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name);
ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name);
+ ClassDB::bind_method(D_METHOD("get_input_real_name"), &VisualShaderNodeInput::get_input_real_name);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_name", PROPERTY_HINT_ENUM, ""), "set_input_name", "get_input_name");
ADD_SIGNAL(MethodInfo("input_type_changed"));
@@ -1905,7 +1947,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
String VisualShaderNodeOutput::get_caption() const {
- return TTR("Output");
+ return "Output";
}
String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -2207,7 +2249,7 @@ void VisualShaderNodeGroupBase::clear_output_ports() {
void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) {
ERR_FAIL_COND(!has_input_port(p_id));
- ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM);
+ ERR_FAIL_COND(p_type < 0 || p_type >= PORT_TYPE_MAX);
if (input_ports[p_id].type == p_type)
return;
@@ -2273,7 +2315,7 @@ String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const {
void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) {
ERR_FAIL_COND(!has_output_port(p_id));
- ERR_FAIL_COND(p_type < 0 || p_type > PORT_TYPE_TRANSFORM);
+ ERR_FAIL_COND(p_type < 0 || p_type >= PORT_TYPE_MAX);
if (output_ports[p_id].type == p_type)
return;
@@ -2410,10 +2452,10 @@ void VisualShaderNodeGroupBase::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_output_port", "id"), &VisualShaderNodeGroupBase::has_output_port);
ClassDB::bind_method(D_METHOD("clear_output_ports"), &VisualShaderNodeGroupBase::clear_output_ports);
- ClassDB::bind_method(D_METHOD("set_input_port_name"), &VisualShaderNodeGroupBase::set_input_port_name);
- ClassDB::bind_method(D_METHOD("set_input_port_type"), &VisualShaderNodeGroupBase::set_input_port_type);
- ClassDB::bind_method(D_METHOD("set_output_port_name"), &VisualShaderNodeGroupBase::set_output_port_name);
- ClassDB::bind_method(D_METHOD("set_output_port_type"), &VisualShaderNodeGroupBase::set_output_port_type);
+ ClassDB::bind_method(D_METHOD("set_input_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_input_port_name);
+ ClassDB::bind_method(D_METHOD("set_input_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_input_port_type);
+ ClassDB::bind_method(D_METHOD("set_output_port_name", "id", "name"), &VisualShaderNodeGroupBase::set_output_port_name);
+ ClassDB::bind_method(D_METHOD("set_output_port_type", "id", "type"), &VisualShaderNodeGroupBase::set_output_port_type);
ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id);
ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 45beb8e6ca..09222c8d81 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -184,7 +184,8 @@ public:
PORT_TYPE_VECTOR,
PORT_TYPE_BOOLEAN,
PORT_TYPE_TRANSFORM,
- PORT_TYPE_ICON_COLOR // just a hint for node tree icons, do not use it as actual port type !
+ PORT_TYPE_SAMPLER,
+ PORT_TYPE_MAX,
};
virtual String get_caption() const = 0;
@@ -200,6 +201,8 @@ public:
virtual PortType get_output_port_type(int p_port) const = 0;
virtual String get_output_port_name(int p_port) const = 0;
+ virtual String get_input_port_default_hint(int p_port) const;
+
void set_output_port_for_preview(int p_index);
int get_output_port_for_preview() const;
@@ -296,6 +299,7 @@ public:
void set_input_name(String p_name);
String get_input_name() const;
+ String get_input_real_name() const;
int get_input_index_count() const;
PortType get_input_index_type(int p_index) const;
@@ -350,6 +354,7 @@ public:
class VisualShaderNodeUniform : public VisualShaderNode {
GDCLASS(VisualShaderNodeUniform, VisualShaderNode);
+private:
String uniform_name;
protected:
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index f5c599b67e..a94fdd9d7b 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "visual_shader_nodes.h"
+
////////////// Scalar
String VisualShaderNodeScalarConstant::get_caption() const {
@@ -38,9 +39,11 @@ String VisualShaderNodeScalarConstant::get_caption() const {
int VisualShaderNodeScalarConstant::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarConstant::get_input_port_name(int p_port) const {
return String();
}
@@ -48,9 +51,11 @@ String VisualShaderNodeScalarConstant::get_input_port_name(int p_port) const {
int VisualShaderNodeScalarConstant::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeScalarConstant::PortType VisualShaderNodeScalarConstant::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarConstant::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -158,9 +163,11 @@ String VisualShaderNodeColorConstant::get_caption() const {
int VisualShaderNodeColorConstant::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const {
return String();
}
@@ -168,9 +175,11 @@ String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const {
int VisualShaderNodeColorConstant::get_output_port_count() const {
return 2;
}
+
VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_output_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const {
return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port
}
@@ -222,9 +231,11 @@ String VisualShaderNodeVec3Constant::get_caption() const {
int VisualShaderNodeVec3Constant::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVec3Constant::get_input_port_name(int p_port) const {
return String();
}
@@ -232,9 +243,11 @@ String VisualShaderNodeVec3Constant::get_input_port_name(int p_port) const {
int VisualShaderNodeVec3Constant::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -280,9 +293,11 @@ String VisualShaderNodeTransformConstant::get_caption() const {
int VisualShaderNodeTransformConstant::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformConstant::get_input_port_name(int p_port) const {
return String();
}
@@ -290,9 +305,11 @@ String VisualShaderNodeTransformConstant::get_input_port_name(int p_port) const
int VisualShaderNodeTransformConstant::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -344,29 +361,60 @@ String VisualShaderNodeTexture::get_caption() const {
}
int VisualShaderNodeTexture::get_input_port_count() const {
- return 2;
+ return 3;
}
+
VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_input_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
+ }
}
+
String VisualShaderNodeTexture::get_input_port_name(int p_port) const {
- return p_port == 0 ? "uv" : "lod";
+
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "lod";
+ case 2:
+ return "sampler2D";
+ default:
+ return "";
+ }
}
int VisualShaderNodeTexture::get_output_port_count() const {
return 2;
}
+
VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_output_port_type(int p_port) const {
if (p_port == 0 && source == SOURCE_DEPTH)
return PORT_TYPE_SCALAR;
return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeTexture::get_output_port_name(int p_port) const {
if (p_port == 0 && source == SOURCE_DEPTH)
return "depth";
return p_port == 0 ? "rgb" : "alpha";
}
+String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const {
+ if (p_port == 0) {
+ return "UV.xy";
+ }
+ return "";
+}
+
static String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name) {
static const char *typepf[VisualShader::TYPE_MAX] = { "vtx", "frg", "lgt" };
@@ -403,9 +451,13 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
if (source == SOURCE_TEXTURE) {
String id = make_unique_id(p_type, p_id, "tex");
String code;
- if (p_input_vars[0] == String()) { //none bound, do nothing
+ if (p_input_vars[0] == String()) { // Use UV by default.
- code += "\tvec4 " + id + "_read = vec4(0.0);\n";
+ if (p_input_vars[1] == String()) {
+ code += "\tvec4 " + id + "_read = texture( " + id + " , UV.xy );\n";
+ } else {
+ code += "\tvec4 " + id + "_read = textureLod( " + id + " , UV.xy , " + p_input_vars[1] + " );\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
@@ -419,16 +471,50 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
return code;
}
+ if (source == SOURCE_PORT) {
+ String id = p_input_vars[2];
+
+ String code;
+ code += "\t{\n";
+ if (id == String()) {
+ code += "\t\tvec4 " + id + "_tex_read = vec4(0.0);\n";
+ } else {
+ if (p_input_vars[0] == String()) { // Use UV by default.
+
+ if (p_input_vars[1] == String()) {
+ code += "\t\tvec4 " + id + "_tex_read = texture( " + id + " , UV.xy );\n";
+ } else {
+ code += "\t\tvec4 " + id + "_tex_read = textureLod( " + id + " , UV.xy , " + p_input_vars[1] + " );\n";
+ }
+
+ } else if (p_input_vars[1] == String()) {
+ //no lod
+ code += "\t\tvec4 " + id + "_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n";
+ } else {
+ code += "\t\tvec4 " + id + "_tex_read = textureLod( " + id + " , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
+ }
+
+ code += "\t\t" + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n";
+ code += "\t\t" + p_output_vars[1] + " = " + id + "_tex_read.a;\n";
+ }
+ code += "\t}\n";
+ return code;
+ }
+
if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
String code = "\t{\n";
- if (p_input_vars[0] == String() || p_for_preview) { //none bound, do nothing
+ if (p_input_vars[0] == String() || p_for_preview) { // Use UV by default.
- code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+ if (p_input_vars[1] == String()) {
+ code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , UV.xy , 0.0 );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , UV.xy , " + p_input_vars[1] + ");\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
- code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy, 0.0 );\n";
+ code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy , 0.0 );\n";
} else {
code += "\t\tvec4 _tex_read = textureLod( SCREEN_TEXTURE , " + p_input_vars[0] + ".xy , " + p_input_vars[1] + " );\n";
}
@@ -442,9 +528,13 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
String code = "\t{\n";
- if (p_input_vars[0] == String()) { //none bound, do nothing
+ if (p_input_vars[0] == String()) { // Use UV by default.
- code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+ if (p_input_vars[1] == String()) {
+ code += "\t\tvec4 _tex_read = texture( TEXTURE , UV.xy );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( TEXTURE , UV.xy , " + p_input_vars[1] + " );\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
@@ -462,9 +552,13 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
String code = "\t{\n";
- if (p_input_vars[0] == String()) { //none bound, do nothing
+ if (p_input_vars[0] == String()) { // Use UV by default.
- code += "\t\tvec4 _tex_read = vec4(0.0);\n";
+ if (p_input_vars[1] == String()) {
+ code += "\t\tvec4 _tex_read = texture( NORMAL_TEXTURE , UV.xy );\n";
+ } else {
+ code += "\t\tvec4 _tex_read = textureLod( NORMAL_TEXTURE , UV.xy , " + p_input_vars[1] + " );\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
@@ -492,9 +586,13 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader:
if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
String code = "\t{\n";
- if (p_input_vars[0] == String()) { //none bound, do nothing
+ if (p_input_vars[0] == String()) { // Use UV by default.
- code += "\t\tfloat _depth = 0.0;\n";
+ if (p_input_vars[1] == String()) {
+ code += "\t\tfloat _depth = texture( DEPTH_TEXTURE , UV.xy ).r;\n";
+ } else {
+ code += "\t\tfloat _depth = textureLod( DEPTH_TEXTURE , UV.xy , " + p_input_vars[1] + " ).r;\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
@@ -567,6 +665,10 @@ String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::T
return String(); // all good
}
+ if (source == SOURCE_PORT) {
+ return String(); // all good
+ }
+
if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
return String(); // all good
@@ -604,7 +706,7 @@ void VisualShaderNodeTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth"), "set_source", "get_source");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
@@ -630,21 +732,43 @@ String VisualShaderNodeCubeMap::get_caption() const {
}
int VisualShaderNodeCubeMap::get_input_port_count() const {
- return 2;
+ return 3;
}
+
VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_input_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
+ }
}
+
String VisualShaderNodeCubeMap::get_input_port_name(int p_port) const {
- return p_port == 0 ? "uv" : "lod";
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "lod";
+ case 2:
+ return "samplerCube";
+ default:
+ return "";
+ }
}
int VisualShaderNodeCubeMap::get_output_port_count() const {
return 2;
}
+
VisualShaderNodeCubeMap::PortType VisualShaderNodeCubeMap::get_output_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeCubeMap::get_output_port_name(int p_port) const {
return p_port == 0 ? "rgb" : "alpha";
}
@@ -660,22 +784,44 @@ Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubeMap::get_default_t
String VisualShaderNodeCubeMap::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- String u = "uniform sampler2DCube " + make_unique_id(p_type, p_id, "cube");
- switch (texture_type) {
- case TYPE_DATA: break;
- case TYPE_COLOR: u += " : hint_albedo"; break;
- case TYPE_NORMALMAP: u += " : hint_normal"; break;
+ if (source == SOURCE_TEXTURE) {
+ String u = "uniform samplerCube " + make_unique_id(p_type, p_id, "cube");
+ switch (texture_type) {
+ case TYPE_DATA: break;
+ case TYPE_COLOR: u += " : hint_albedo"; break;
+ case TYPE_NORMALMAP: u += " : hint_normal"; break;
+ }
+ return u + ";";
}
- return u + ";";
+ return String();
}
String VisualShaderNodeCubeMap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- String id = make_unique_id(p_type, p_id, "cube");
String code;
- if (p_input_vars[0] == String()) { //none bound, do nothing
+ String id;
+ if (source == SOURCE_TEXTURE) {
+ id = make_unique_id(p_type, p_id, "cube");
+ } else if (source == SOURCE_PORT) {
+ id = p_input_vars[2];
+ } else {
+ return String();
+ }
+ if (id == String()) {
code += "\tvec4 " + id + "_read = vec4(0.0);\n";
+ code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n";
+ code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n";
+ return code;
+ }
+
+ if (p_input_vars[0] == String()) { // Use UV by default.
+
+ if (p_input_vars[1] == String()) {
+ code += "\tvec4 " + id + "_read = texture( " + id + " , vec3( UV, 0.0 ) );\n";
+ } else {
+ code += "\tvec4 " + id + "_read = textureLod( " + id + " , vec3( UV, 0.0 )" + " , " + p_input_vars[1] + " );\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
@@ -683,12 +829,29 @@ String VisualShaderNodeCubeMap::generate_code(Shader::Mode p_mode, VisualShader:
} else {
code += "\tvec4 " + id + "_read = textureLod( " + id + " , " + p_input_vars[0] + " , " + p_input_vars[1] + " );\n";
}
-
code += "\t" + p_output_vars[0] + " = " + id + "_read.rgb;\n";
code += "\t" + p_output_vars[1] + " = " + id + "_read.a;\n";
+
return code;
}
+String VisualShaderNodeCubeMap::get_input_port_default_hint(int p_port) const {
+ if (p_port == 0) {
+ return "vec3(UV, 0.0)";
+ }
+ return "";
+}
+
+void VisualShaderNodeCubeMap::set_source(Source p_source) {
+ source = p_source;
+ emit_changed();
+ emit_signal("editor_refresh_request");
+}
+
+VisualShaderNodeCubeMap::Source VisualShaderNodeCubeMap::get_source() const {
+ return source;
+}
+
void VisualShaderNodeCubeMap::set_cube_map(Ref<CubeMap> p_value) {
cube_map = p_value;
@@ -711,22 +874,32 @@ VisualShaderNodeCubeMap::TextureType VisualShaderNodeCubeMap::get_texture_type()
Vector<StringName> VisualShaderNodeCubeMap::get_editable_properties() const {
Vector<StringName> props;
- props.push_back("cube_map");
- props.push_back("texture_type");
+ props.push_back("source");
+ if (source == SOURCE_TEXTURE) {
+ props.push_back("cube_map");
+ props.push_back("texture_type");
+ }
return props;
}
void VisualShaderNodeCubeMap::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_source", "value"), &VisualShaderNodeCubeMap::set_source);
+ ClassDB::bind_method(D_METHOD("get_source"), &VisualShaderNodeCubeMap::get_source);
+
ClassDB::bind_method(D_METHOD("set_cube_map", "value"), &VisualShaderNodeCubeMap::set_cube_map);
ClassDB::bind_method(D_METHOD("get_cube_map"), &VisualShaderNodeCubeMap::get_cube_map);
ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeCubeMap::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeCubeMap::get_texture_type);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,SamplerPort"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "cube_map", PROPERTY_HINT_RESOURCE_TYPE, "CubeMap"), "set_cube_map", "get_cube_map");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normalmap"), "set_texture_type", "get_texture_type");
+ BIND_ENUM_CONSTANT(SOURCE_TEXTURE);
+ BIND_ENUM_CONSTANT(SOURCE_PORT);
+
BIND_ENUM_CONSTANT(TYPE_DATA);
BIND_ENUM_CONSTANT(TYPE_COLOR);
BIND_ENUM_CONSTANT(TYPE_NORMALMAP);
@@ -734,7 +907,9 @@ void VisualShaderNodeCubeMap::_bind_methods() {
VisualShaderNodeCubeMap::VisualShaderNodeCubeMap() {
texture_type = TYPE_DATA;
+ source = SOURCE_TEXTURE;
}
+
////////////// Scalar Op
String VisualShaderNodeScalarOp::get_caption() const {
@@ -744,9 +919,11 @@ String VisualShaderNodeScalarOp::get_caption() const {
int VisualShaderNodeScalarOp::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarOp::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -754,9 +931,11 @@ String VisualShaderNodeScalarOp::get_input_port_name(int p_port) const {
int VisualShaderNodeScalarOp::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeScalarOp::PortType VisualShaderNodeScalarOp::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarOp::get_output_port_name(int p_port) const {
return "op"; //no output port means the editor will be used as port
}
@@ -832,9 +1011,11 @@ String VisualShaderNodeVectorOp::get_caption() const {
int VisualShaderNodeVectorOp::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorOp::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -842,9 +1023,11 @@ String VisualShaderNodeVectorOp::get_input_port_name(int p_port) const {
int VisualShaderNodeVectorOp::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVectorOp::PortType VisualShaderNodeVectorOp::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorOp::get_output_port_name(int p_port) const {
return "op"; //no output port means the editor will be used as port
}
@@ -924,9 +1107,11 @@ String VisualShaderNodeColorOp::get_caption() const {
int VisualShaderNodeColorOp::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeColorOp::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -934,9 +1119,11 @@ String VisualShaderNodeColorOp::get_input_port_name(int p_port) const {
int VisualShaderNodeColorOp::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeColorOp::get_output_port_name(int p_port) const {
return "op"; //no output port means the editor will be used as port
}
@@ -1072,9 +1259,11 @@ String VisualShaderNodeTransformMult::get_caption() const {
int VisualShaderNodeTransformMult::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_input_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformMult::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -1082,9 +1271,11 @@ String VisualShaderNodeTransformMult::get_input_port_name(int p_port) const {
int VisualShaderNodeTransformMult::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeTransformMult::PortType VisualShaderNodeTransformMult::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformMult::get_output_port_name(int p_port) const {
return "mult"; //no output port means the editor will be used as port
}
@@ -1147,9 +1338,11 @@ String VisualShaderNodeTransformVecMult::get_caption() const {
int VisualShaderNodeTransformVecMult::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_input_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_TRANSFORM : PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformVecMult::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -1157,9 +1350,11 @@ String VisualShaderNodeTransformVecMult::get_input_port_name(int p_port) const {
int VisualShaderNodeTransformVecMult::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -1221,9 +1416,11 @@ String VisualShaderNodeScalarFunc::get_caption() const {
int VisualShaderNodeScalarFunc::get_input_port_count() const {
return 1;
}
+
VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarFunc::get_input_port_name(int p_port) const {
return "";
}
@@ -1231,9 +1428,11 @@ String VisualShaderNodeScalarFunc::get_input_port_name(int p_port) const {
int VisualShaderNodeScalarFunc::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeScalarFunc::PortType VisualShaderNodeScalarFunc::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -1350,9 +1549,11 @@ String VisualShaderNodeVectorFunc::get_caption() const {
int VisualShaderNodeVectorFunc::get_input_port_count() const {
return 1;
}
+
VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorFunc::get_input_port_name(int p_port) const {
return "";
}
@@ -1360,9 +1561,11 @@ String VisualShaderNodeVectorFunc::get_input_port_name(int p_port) const {
int VisualShaderNodeVectorFunc::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVectorFunc::PortType VisualShaderNodeVectorFunc::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -1675,9 +1878,11 @@ String VisualShaderNodeDotProduct::get_caption() const {
int VisualShaderNodeDotProduct::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeDotProduct::get_input_port_name(int p_port) const {
return p_port == 0 ? "a" : "b";
}
@@ -1685,9 +1890,11 @@ String VisualShaderNodeDotProduct::get_input_port_name(int p_port) const {
int VisualShaderNodeDotProduct::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeDotProduct::get_output_port_name(int p_port) const {
return "dot";
}
@@ -1710,9 +1917,11 @@ String VisualShaderNodeVectorLen::get_caption() const {
int VisualShaderNodeVectorLen::get_input_port_count() const {
return 1;
}
+
VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorLen::get_input_port_name(int p_port) const {
return "";
}
@@ -1720,9 +1929,11 @@ String VisualShaderNodeVectorLen::get_input_port_name(int p_port) const {
int VisualShaderNodeVectorLen::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVectorLen::PortType VisualShaderNodeVectorLen::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const {
return "length";
}
@@ -1745,7 +1956,7 @@ int VisualShaderNodeDeterminant::get_input_port_count() const {
return 1;
}
-VisualShaderNodeScalarClamp::PortType VisualShaderNodeDeterminant::get_input_port_type(int p_port) const {
+VisualShaderNodeDeterminant::PortType VisualShaderNodeDeterminant::get_input_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
@@ -1872,7 +2083,7 @@ int VisualShaderNodeVectorDerivativeFunc::get_output_port_count() const {
return 1;
}
-VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_output_port_type(int p_port) const {
+VisualShaderNodeVectorDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
@@ -2078,7 +2289,7 @@ int VisualShaderNodeOuterProduct::get_input_port_count() const {
return 2;
}
-VisualShaderNodeFaceForward::PortType VisualShaderNodeOuterProduct::get_input_port_type(int p_port) const {
+VisualShaderNodeOuterProduct::PortType VisualShaderNodeOuterProduct::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
@@ -2143,7 +2354,7 @@ int VisualShaderNodeVectorScalarStep::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const {
+VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
@@ -2234,7 +2445,7 @@ int VisualShaderNodeVectorSmoothStep::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const {
+VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
@@ -2285,7 +2496,7 @@ int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const {
+VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
@@ -2540,6 +2751,7 @@ VisualShaderNodeVectorScalarMix::VisualShaderNodeVectorScalarMix() {
}
////////////// Vector Compose
+
String VisualShaderNodeVectorCompose::get_caption() const {
return "VectorCompose";
}
@@ -2547,9 +2759,11 @@ String VisualShaderNodeVectorCompose::get_caption() const {
int VisualShaderNodeVectorCompose::get_input_port_count() const {
return 3;
}
+
VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const {
if (p_port == 0) {
return "x";
@@ -2563,9 +2777,11 @@ String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const {
int VisualShaderNodeVectorCompose::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorCompose::get_output_port_name(int p_port) const {
return "vec";
}
@@ -2590,9 +2806,11 @@ String VisualShaderNodeTransformCompose::get_caption() const {
int VisualShaderNodeTransformCompose::get_input_port_count() const {
return 4;
}
+
VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformCompose::get_input_port_name(int p_port) const {
if (p_port == 0) {
return "x";
@@ -2608,9 +2826,11 @@ String VisualShaderNodeTransformCompose::get_input_port_name(int p_port) const {
int VisualShaderNodeTransformCompose::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformCompose::get_output_port_name(int p_port) const {
return "xform";
}
@@ -2635,9 +2855,11 @@ String VisualShaderNodeVectorDecompose::get_caption() const {
int VisualShaderNodeVectorDecompose::get_input_port_count() const {
return 1;
}
+
VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVectorDecompose::get_input_port_name(int p_port) const {
return "vec";
}
@@ -2645,9 +2867,11 @@ String VisualShaderNodeVectorDecompose::get_input_port_name(int p_port) const {
int VisualShaderNodeVectorDecompose::get_output_port_count() const {
return 3;
}
+
VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const {
if (p_port == 0) {
return "x";
@@ -2679,9 +2903,11 @@ String VisualShaderNodeTransformDecompose::get_caption() const {
int VisualShaderNodeTransformDecompose::get_input_port_count() const {
return 1;
}
+
VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_input_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformDecompose::get_input_port_name(int p_port) const {
return "xform";
}
@@ -2689,9 +2915,11 @@ String VisualShaderNodeTransformDecompose::get_input_port_name(int p_port) const
int VisualShaderNodeTransformDecompose::get_output_port_count() const {
return 4;
}
+
VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) const {
if (p_port == 0) {
return "x";
@@ -2726,9 +2954,11 @@ String VisualShaderNodeScalarUniform::get_caption() const {
int VisualShaderNodeScalarUniform::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarUniform::get_input_port_name(int p_port) const {
return String();
}
@@ -2736,9 +2966,11 @@ String VisualShaderNodeScalarUniform::get_input_port_name(int p_port) const {
int VisualShaderNodeScalarUniform::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeScalarUniform::PortType VisualShaderNodeScalarUniform::get_output_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
@@ -2746,6 +2978,7 @@ String VisualShaderNodeScalarUniform::get_output_port_name(int p_port) const {
String VisualShaderNodeScalarUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
return "uniform float " + get_uniform_name() + ";\n";
}
+
String VisualShaderNodeScalarUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
}
@@ -2803,9 +3036,11 @@ String VisualShaderNodeColorUniform::get_caption() const {
int VisualShaderNodeColorUniform::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
return String();
}
@@ -2813,9 +3048,11 @@ String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const {
int VisualShaderNodeColorUniform::get_output_port_count() const {
return 2;
}
+
VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const {
return p_port == 0 ? "color" : "alpha"; //no output port means the editor will be used as port
}
@@ -2843,9 +3080,11 @@ String VisualShaderNodeVec3Uniform::get_caption() const {
int VisualShaderNodeVec3Uniform::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const {
return String();
}
@@ -2853,12 +3092,15 @@ String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const {
int VisualShaderNodeVec3Uniform::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
+
String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
return "uniform vec3 " + get_uniform_name() + ";\n";
}
@@ -2879,9 +3121,11 @@ String VisualShaderNodeTransformUniform::get_caption() const {
int VisualShaderNodeTransformUniform::get_input_port_count() const {
return 0;
}
+
VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const {
return PORT_TYPE_VECTOR;
}
+
String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const {
return String();
}
@@ -2889,12 +3133,15 @@ String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const {
int VisualShaderNodeTransformUniform::get_output_port_count() const {
return 1;
}
+
VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}
+
String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const {
return ""; //no output port means the editor will be used as port
}
+
String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
return "uniform mat4 " + get_uniform_name() + ";\n";
}
@@ -2915,21 +3162,45 @@ String VisualShaderNodeTextureUniform::get_caption() const {
int VisualShaderNodeTextureUniform::get_input_port_count() const {
return 2;
}
+
VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const {
return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const {
return p_port == 0 ? "uv" : "lod";
}
int VisualShaderNodeTextureUniform::get_output_port_count() const {
- return 2;
+ return 3;
}
+
VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SAMPLER;
+ default:
+ return PORT_TYPE_SCALAR;
+ }
}
+
String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
- return p_port == 0 ? "rgb" : "alpha";
+
+ switch (p_port) {
+ case 0:
+ return "rgb";
+ case 1:
+ return "alpha";
+ case 2:
+ return "sampler2D";
+ default:
+ return "";
+ }
}
String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
@@ -2959,9 +3230,12 @@ String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, Visual
String id = get_uniform_name();
String code = "\t{\n";
- if (p_input_vars[0] == String()) { //none bound, do nothing
-
- code += "\t\tvec4 n_tex_read = vec4(0.0);\n";
+ if (p_input_vars[0] == String()) { // Use UV by default.
+ if (p_input_vars[1] == String()) {
+ code += "\t\tvec4 n_tex_read = texture( " + id + " , UV.xy );\n";
+ } else {
+ code += "\t\tvec4 n_tex_read = textureLod( " + id + " , UV.xy , " + p_input_vars[1] + " );\n";
+ }
} else if (p_input_vars[1] == String()) {
//no lod
code += "\t\tvec4 n_tex_read = texture( " + id + " , " + p_input_vars[0] + ".xy );\n";
@@ -2989,6 +3263,7 @@ void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_default) {
color_default = p_default;
emit_changed();
}
+
VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const {
return color_default;
}
@@ -3019,6 +3294,13 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK);
}
+String VisualShaderNodeTextureUniform::get_input_port_default_hint(int p_port) const {
+ if (p_port == 0) {
+ return "UV.xy";
+ }
+ return "";
+}
+
VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
texture_type = TYPE_DATA;
color_default = COLOR_DEFAULT_WHITE;
@@ -3113,6 +3395,15 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod
return code;
}
+String VisualShaderNodeTextureUniformTriplanar::get_input_port_default_hint(int p_port) const {
+ if (p_port == 0) {
+ return "default";
+ } else if (p_port == 1) {
+ return "default";
+ }
+ return "";
+}
+
VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() {
}
@@ -3122,24 +3413,55 @@ String VisualShaderNodeCubeMapUniform::get_caption() const {
return "CubeMapUniform";
}
+int VisualShaderNodeCubeMapUniform::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SAMPLER;
+}
+
+String VisualShaderNodeCubeMapUniform::get_output_port_name(int p_port) const {
+ return "samplerCube";
+}
+
int VisualShaderNodeCubeMapUniform::get_input_port_count() const {
- return 2;
+ return 0;
}
+
VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_input_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+ return PORT_TYPE_SCALAR;
}
+
String VisualShaderNodeCubeMapUniform::get_input_port_name(int p_port) const {
- return p_port == 0 ? "normal" : "lod";
+ return "";
}
-int VisualShaderNodeCubeMapUniform::get_output_port_count() const {
- return 2;
-}
-VisualShaderNodeCubeMapUniform::PortType VisualShaderNodeCubeMapUniform::get_output_port_type(int p_port) const {
- return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR;
+String VisualShaderNodeCubeMapUniform::get_input_port_default_hint(int p_port) const {
+ return "";
}
-String VisualShaderNodeCubeMapUniform::get_output_port_name(int p_port) const {
- return p_port == 0 ? "rgb" : "alpha";
+
+String VisualShaderNodeCubeMapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ String code = "uniform samplerCube " + get_uniform_name();
+
+ switch (texture_type) {
+ case TYPE_DATA:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black;\n";
+ else
+ code += ";\n";
+ break;
+ case TYPE_COLOR:
+ if (color_default == COLOR_DEFAULT_BLACK)
+ code += " : hint_black_albedo;\n";
+ else
+ code += " : hint_albedo;\n";
+ break;
+ case TYPE_NORMALMAP: code += " : hint_normal;\n"; break;
+ case TYPE_ANISO: code += " : hint_aniso;\n"; break;
+ }
+
+ return code;
}
String VisualShaderNodeCubeMapUniform::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 0c6e060353..339e59bda9 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -199,7 +199,8 @@ public:
SOURCE_SCREEN,
SOURCE_2D_TEXTURE,
SOURCE_2D_NORMAL,
- SOURCE_DEPTH
+ SOURCE_DEPTH,
+ SOURCE_PORT,
};
enum TextureType {
@@ -226,6 +227,8 @@ public:
virtual PortType get_output_port_type(int p_port) const;
virtual String get_output_port_name(int p_port) const;
+ virtual String get_input_port_default_hint(int p_port) const;
+
virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
@@ -256,6 +259,11 @@ class VisualShaderNodeCubeMap : public VisualShaderNode {
Ref<CubeMap> cube_map;
public:
+ enum Source {
+ SOURCE_TEXTURE,
+ SOURCE_PORT
+ };
+
enum TextureType {
TYPE_DATA,
TYPE_COLOR,
@@ -263,6 +271,7 @@ public:
};
private:
+ Source source;
TextureType texture_type;
protected:
@@ -274,6 +283,7 @@ public:
virtual int get_input_port_count() const;
virtual PortType get_input_port_type(int p_port) const;
virtual String get_input_port_name(int p_port) const;
+ virtual String get_input_port_default_hint(int p_port) const;
virtual int get_output_port_count() const;
virtual PortType get_output_port_type(int p_port) const;
@@ -283,6 +293,9 @@ public:
virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
+ void set_source(Source p_source);
+ Source get_source() const;
+
void set_cube_map(Ref<CubeMap> p_value);
Ref<CubeMap> get_cube_map() const;
@@ -295,6 +308,7 @@ public:
};
VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::TextureType)
+VARIANT_ENUM_CAST(VisualShaderNodeCubeMap::Source)
///////////////////////////////////////
/// OPS
@@ -1409,7 +1423,7 @@ public:
COLOR_DEFAULT_BLACK
};
-private:
+protected:
TextureType texture_type;
ColorDefault color_default;
@@ -1422,6 +1436,7 @@ public:
virtual int get_input_port_count() const;
virtual PortType get_input_port_type(int p_port) const;
virtual String get_input_port_name(int p_port) const;
+ virtual String get_input_port_default_hint(int p_port) const;
virtual int get_output_port_count() const;
virtual PortType get_output_port_type(int p_port) const;
@@ -1456,6 +1471,8 @@ public:
virtual PortType get_input_port_type(int p_port) const;
virtual String get_input_port_name(int p_port) const;
+ virtual String get_input_port_default_hint(int p_port) const;
+
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
@@ -1465,8 +1482,8 @@ public:
///////////////////////////////////////
-class VisualShaderNodeCubeMapUniform : public VisualShaderNode {
- GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode);
+class VisualShaderNodeCubeMapUniform : public VisualShaderNodeTextureUniform {
+ GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNodeTextureUniform);
public:
virtual String get_caption() const;
@@ -1479,6 +1496,8 @@ public:
virtual PortType get_output_port_type(int p_port) const;
virtual String get_output_port_name(int p_port) const;
+ virtual String get_input_port_default_hint(int p_port) const;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
VisualShaderNodeCubeMapUniform();
diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp
index 0ca5d7eb36..2c22f45f9d 100644
--- a/scene/resources/world.cpp
+++ b/scene/resources/world.cpp
@@ -332,7 +332,9 @@ World::World() {
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/3d/default_gravity", 9.8));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF("physics/3d/default_linear_damp", 0.1));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_linear_damp", PropertyInfo(Variant::REAL, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
PhysicsServer::get_singleton()->area_set_param(space, PhysicsServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_angular_damp", PropertyInfo(Variant::REAL, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
#ifdef _3D_DISABLED
indexer = NULL;
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index 13b45f58dc..b5743ad416 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -394,7 +394,9 @@ World2D::World2D() {
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_linear_damp", 0.1));
- Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::REAL, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
+ Physics2DServer::get_singleton()->area_set_param(space, Physics2DServer::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0));
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_angular_damp", PropertyInfo(Variant::REAL, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"));
indexer = memnew(SpatialIndexer2D);
}