diff options
Diffstat (limited to 'scene')
150 files changed, 3013 insertions, 1916 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_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..a02cc4bee6 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) { @@ -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 b5c82ce4e3..95536bbb23 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..d932545da4 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"); 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 Binary files differindex ef226e3caf..ff2258281e 100644 --- a/scene/resources/default_theme/button_hover.png +++ b/scene/resources/default_theme/button_hover.png diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png Binary files differindex 7d0bd16221..c189b61b89 100644 --- a/scene/resources/default_theme/button_normal.png +++ b/scene/resources/default_theme/button_normal.png diff --git a/scene/resources/default_theme/color_picker_hue.png b/scene/resources/default_theme/color_picker_hue.png Binary files differindex de2cd0c2bf..7b46f03cb4 100644 --- a/scene/resources/default_theme/color_picker_hue.png +++ b/scene/resources/default_theme/color_picker_hue.png 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 Binary files differindex 00680db5df..30336b91a4 100644 --- a/scene/resources/default_theme/error_icon.png +++ b/scene/resources/default_theme/error_icon.png diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differindex cc4eb7f753..c52d88586b 100644 --- a/scene/resources/default_theme/graph_node_selected.png +++ b/scene/resources/default_theme/graph_node_selected.png diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differindex f33ae3baf3..358934f4d8 100644 --- a/scene/resources/default_theme/graph_port.png +++ b/scene/resources/default_theme/graph_port.png diff --git a/scene/resources/default_theme/icon_visibility.png b/scene/resources/default_theme/icon_visibility.png Binary files differindex 6402571f3e..b2df8cbdb8 100644 --- a/scene/resources/default_theme/icon_visibility.png +++ b/scene/resources/default_theme/icon_visibility.png diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png Binary files differindex 2dadb40338..43fc29e958 100644 --- a/scene/resources/default_theme/option_button_normal.png +++ b/scene/resources/default_theme/option_button_normal.png diff --git a/scene/resources/default_theme/overbright_indicator.png b/scene/resources/default_theme/overbright_indicator.png Binary files differnew file mode 100644 index 0000000000..89f800c230 --- /dev/null +++ b/scene/resources/default_theme/overbright_indicator.png diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png Binary files differindex 006cfa3361..21ee486e0b 100644 --- a/scene/resources/default_theme/scroll_grabber_hl.png +++ b/scene/resources/default_theme/scroll_grabber_hl.png diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png Binary files differindex 7e458a6c45..3c66316074 100644 --- a/scene/resources/default_theme/space.png +++ b/scene/resources/default_theme/space.png diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png Binary files differindex 7d0bd16221..c189b61b89 100644 --- a/scene/resources/default_theme/tab_container_bg.png +++ b/scene/resources/default_theme/tab_container_bg.png diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png Binary files differindex 520d147217..d5641e917a 100644 --- a/scene/resources/default_theme/tab_current.png +++ b/scene/resources/default_theme/tab_current.png diff --git a/scene/resources/default_theme/tab_disabled.png b/scene/resources/default_theme/tab_disabled.png Binary files differindex 97157a58dd..a7c04effa3 100644 --- a/scene/resources/default_theme/tab_disabled.png +++ b/scene/resources/default_theme/tab_disabled.png 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); } |