diff options
Diffstat (limited to 'scene')
349 files changed, 8064 insertions, 2964 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 4916eb573c..decb3d0dd8 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -417,7 +417,7 @@ void AnimatedSprite2D::_reset_timeout() { void AnimatedSprite2D::set_animation(const StringName &p_animation) { ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation)); - ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation)); if (animation == p_animation) { return; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index f4c0665f36..e8dfaf9c2e 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -530,7 +530,7 @@ Point2 Camera2D::get_camera_screen_center() const { Size2 Camera2D::_get_camera_screen_size() const { // special case if the camera2D is in the root viewport if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) { - return Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); + return Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height")); } return get_viewport_rect().size; } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 0f4e3c8bed..70c7e48fd4 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -268,7 +268,7 @@ uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { id = shapes.back()->key() + 1; } - sd.owner = p_owner; + sd.owner_id = p_owner ? p_owner->get_instance_id() : ObjectID(); shapes[id] = sd; @@ -382,7 +382,7 @@ Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); - return shapes[p_owner].owner; + return ObjectDB::get_instance(shapes[p_owner].owner_id); } void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 9463b2c429..f2b7eecc7b 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -59,7 +59,7 @@ private: PhysicsServer2D::BodyMode body_mode = PhysicsServer2D::BODY_MODE_STATIC; struct ShapeData { - Object *owner = nullptr; + ObjectID owner_id; Transform2D xform; struct Shape { Ref<Shape2D> shape; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index b6d1e5c934..11c036ac9c 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -335,6 +335,42 @@ Ref<Texture2D> GPUParticles2D::get_texture() const { void GPUParticles2D::_validate_property(PropertyInfo &property) const { } +void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { + Transform3D transform; + transform.basis.set_axis(0, Vector3(p_transform2d.get_axis(0).x, p_transform2d.get_axis(0).y, 0)); + transform.basis.set_axis(1, Vector3(p_transform2d.get_axis(1).x, p_transform2d.get_axis(1).y, 0)); + transform.set_origin(Vector3(p_transform2d.get_origin().x, p_transform2d.get_origin().y, 0)); + Vector3 velocity = Vector3(p_velocity2d.x, p_velocity2d.y, 0); + + RS::get_singleton()->particles_emit(particles, transform, velocity, p_color, p_custom, p_emit_flags); +} + +void GPUParticles2D::_attach_sub_emitter() { + Node *n = get_node_or_null(sub_emitter); + if (n) { + GPUParticles2D *sen = Object::cast_to<GPUParticles2D>(n); + if (sen && sen != this) { + RS::get_singleton()->particles_set_subemitter(particles, sen->particles); + } + } +} + +void GPUParticles2D::set_sub_emitter(const NodePath &p_path) { + if (is_inside_tree()) { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } + + sub_emitter = p_path; + + if (is_inside_tree() && sub_emitter != NodePath()) { + _attach_sub_emitter(); + } +} + +NodePath GPUParticles2D::get_sub_emitter() const { + return sub_emitter; +} + void GPUParticles2D::restart() { RS::get_singleton()->particles_restart(particles); RS::get_singleton()->particles_set_emitting(particles, true); @@ -462,6 +498,16 @@ void GPUParticles2D::_notification(int p_what) { #endif } + if (p_what == NOTIFICATION_ENTER_TREE) { + if (sub_emitter != NodePath()) { + _attach_sub_emitter(); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } + if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { if (can_process()) { RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); @@ -523,6 +569,11 @@ void GPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart); + ClassDB::bind_method(D_METHOD("set_sub_emitter", "path"), &GPUParticles2D::set_sub_emitter); + ClassDB::bind_method(D_METHOD("get_sub_emitter"), &GPUParticles2D::get_sub_emitter); + + ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles2D::emit_particle); + ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled); ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length); @@ -538,6 +589,7 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles2D"), "set_sub_emitter", "get_sub_emitter"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -566,6 +618,12 @@ void GPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME); + + BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION); + BIND_ENUM_CONSTANT(EMIT_FLAG_ROTATION_SCALE); + BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY); + BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR); + BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM); } GPUParticles2D::GPUParticles2D() { diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index aa9a8da129..fc95ae27b2 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -79,6 +79,8 @@ private: RID mesh; + void _attach_sub_emitter(); + protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; @@ -139,6 +141,19 @@ public: TypedArray<String> get_configuration_warnings() const override; + void set_sub_emitter(const NodePath &p_path); + NodePath get_sub_emitter() const; + + enum EmitFlags { + EMIT_FLAG_POSITION = RS::PARTICLES_EMIT_FLAG_POSITION, + EMIT_FLAG_ROTATION_SCALE = RS::PARTICLES_EMIT_FLAG_ROTATION_SCALE, + EMIT_FLAG_VELOCITY = RS::PARTICLES_EMIT_FLAG_VELOCITY, + EMIT_FLAG_COLOR = RS::PARTICLES_EMIT_FLAG_COLOR, + EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM + }; + + void emit_particle(const Transform2D &p_transform, const Vector2 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + void restart(); Rect2 capture_rect() const; GPUParticles2D(); @@ -146,5 +161,6 @@ public: }; VARIANT_ENUM_CAST(GPUParticles2D::DrawOrder) +VARIANT_ENUM_CAST(GPUParticles2D::EmitFlags) #endif // PARTICLES_2D_H diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 1a6aaecaa8..7f2290bdc7 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -133,7 +133,7 @@ int Line2D::get_point_count() const { void Line2D::clear_points() { int count = _points.size(); if (count > 0) { - _points.resize(0); + _points.clear(); update(); } } diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index e5df089771..fad54070a5 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -53,9 +53,9 @@ void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const { void NavigationObstacle2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - initialize_agent(); + case NOTIFICATION_ENTER_TREE: { parent_node2d = Object::cast_to<Node2D>(get_parent()); + reevaluate_agent_radius(); if (parent_node2d != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map()); @@ -83,6 +83,7 @@ void NavigationObstacle2D::_notification(int p_what) { NavigationObstacle2D::NavigationObstacle2D() { agent = NavigationServer2D::get_singleton()->agent_create(); + initialize_agent(); } NavigationObstacle2D::~NavigationObstacle2D() { @@ -110,7 +111,7 @@ void NavigationObstacle2D::initialize_agent() { void NavigationObstacle2D::reevaluate_agent_radius() { if (!estimate_radius) { NavigationServer2D::get_singleton()->agent_set_radius(agent, radius); - } else if (parent_node2d) { + } else if (parent_node2d && parent_node2d->is_inside_tree()) { NavigationServer2D::get_singleton()->agent_set_radius(agent, estimate_agent_radius()); } } diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 34f5830d8d..4bead978f1 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -299,7 +299,7 @@ void NavigationPolygon::make_polygons_from_outlines() { } polygons.clear(); - vertices.resize(0); + vertices.clear(); Map<Vector2, int> points; for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 9331340e1b..9d26543243 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -413,7 +413,7 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index b2cc8164b6..fb611addf8 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); - ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -54,11 +54,8 @@ PhysicsBody2D::~PhysicsBody2D() { } } -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_linear_velocity, bool p_test_only, real_t p_margin) { - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin); +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin) { + PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); PhysicsServer2D::MotionResult result; if (move_and_collide(parameters, result, p_test_only)) { @@ -129,7 +126,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_ return colliding; } -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer2D::MotionResult *r = nullptr; @@ -141,10 +138,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear r = &temp_result; } - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer2D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin); + PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin); bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); @@ -1162,7 +1156,7 @@ bool CharacterBody2D::move_and_slide() { if (motion_mode == MOTION_MODE_GROUNDED) { _move_and_slide_grounded(delta, was_on_floor); } else { - _move_and_slide_free(delta); + _move_and_slide_floating(delta); } // Compute real velocity. @@ -1350,7 +1344,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo } } -void CharacterBody2D::_move_and_slide_free(double p_delta) { +void CharacterBody2D::_move_and_slide_floating(double p_delta) { Vector2 motion = motion_velocity * p_delta; platform_rid = RID(); @@ -1376,7 +1370,7 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { break; } - if (free_mode_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < free_mode_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector2(); } else if (first_slide) { Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); @@ -1668,12 +1662,12 @@ void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) { floor_snap_length = p_floor_snap_length; } -real_t CharacterBody2D::get_free_mode_min_slide_angle() const { - return free_mode_min_slide_angle; +real_t CharacterBody2D::get_wall_min_slide_angle() const { + return wall_min_slide_angle; } -void CharacterBody2D::set_free_mode_min_slide_angle(real_t p_radians) { - free_mode_min_slide_angle = p_radians; +void CharacterBody2D::set_wall_min_slide_angle(real_t p_radians) { + wall_min_slide_angle = p_radians; } const Vector2 &CharacterBody2D::get_up_direction() const { @@ -1681,7 +1675,7 @@ const Vector2 &CharacterBody2D::get_up_direction() const { } void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { - ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Free motion mode instead."); + ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Floating motion mode instead."); up_direction = p_up_direction.normalized(); } @@ -1728,8 +1722,8 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length); ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length); - ClassDB::bind_method(D_METHOD("get_free_mode_min_slide_angle"), &CharacterBody2D::get_free_mode_min_slide_angle); - ClassDB::bind_method(D_METHOD("set_free_mode_min_slide_angle", "radians"), &CharacterBody2D::set_free_mode_min_slide_angle); + ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody2D::get_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody2D::set_wall_min_slide_angle); ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); @@ -1754,14 +1748,12 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision); - ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); - - ADD_GROUP("Free Mode", "free_mode_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "free_mode_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_free_mode_min_slide_angle", "get_free_mode_min_slide_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); ADD_GROUP("Floor", "floor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); @@ -1775,7 +1767,7 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); - BIND_ENUM_CONSTANT(MOTION_MODE_FREE); + BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY); @@ -1783,12 +1775,12 @@ void CharacterBody2D::_bind_methods() { } void CharacterBody2D::_validate_property(PropertyInfo &property) const { - if (motion_mode == MOTION_MODE_FREE) { + if (motion_mode == MOTION_MODE_FLOATING) { if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } else { - if (property.name == "free_mode_min_slide_angle") { + if (property.name == "wall_min_slide_angle") { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 649d67d759..cfaa2570fb 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -47,11 +47,11 @@ protected: Ref<KinematicCollision2D> motion_cache; - Ref<KinematicCollision2D> _move(const Vector2 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.08); + Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08); public: bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); + bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody @@ -328,7 +328,7 @@ class CharacterBody2D : public PhysicsBody2D { public: enum MotionMode { MOTION_MODE_GROUNDED, - MOTION_MODE_FREE, + MOTION_MODE_FLOATING, }; enum MovingPlatformApplyVelocityOnLeave { PLATFORM_VEL_ON_LEAVE_ALWAYS, @@ -374,7 +374,7 @@ private: int platform_layer = 0; real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t floor_snap_length = 1; - real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0); + real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); Vector2 up_direction = Vector2(0.0, -1.0); uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_wall_layers = 0; @@ -420,8 +420,8 @@ private: real_t get_floor_snap_length(); void set_floor_snap_length(real_t p_floor_snap_length); - real_t get_free_mode_min_slide_angle() const; - void set_free_mode_min_slide_angle(real_t p_radians); + real_t get_wall_min_slide_angle() const; + void set_wall_min_slide_angle(real_t p_radians); uint32_t get_moving_platform_floor_layers() const; void set_moving_platform_floor_layers(const uint32_t p_exclude_layer); @@ -435,7 +435,7 @@ private: void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity); MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const; - void _move_and_slide_free(double p_delta); + void _move_and_slide_floating(double p_delta); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 1fdd8b05a6..9521667854 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -263,26 +263,18 @@ void RayCast2D::add_exception_rid(const RID &p_rid) { exclude.insert(p_rid); } -void RayCast2D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); +void RayCast2D::add_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + add_exception_rid(p_node->get_rid()); } void RayCast2D::remove_exception_rid(const RID &p_rid) { exclude.erase(p_rid); } -void RayCast2D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - remove_exception_rid(co->get_rid()); +void RayCast2D::remove_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + remove_exception_rid(p_node->get_rid()); } void RayCast2D::clear_exceptions() { diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index a1015c6ce0..2c6f2d5c00 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -33,6 +33,8 @@ #include "scene/2d/node_2d.h" +class CollisionObject2D; + class RayCast2D : public Node2D { GDCLASS(RayCast2D, Node2D); @@ -94,9 +96,9 @@ public: Vector2 get_collision_normal() const; void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); + void add_exception(const CollisionObject2D *p_node); void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); + void remove_exception(const CollisionObject2D *p_node); void clear_exceptions(); RayCast2D(); diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 10194861b4..24199c96b5 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -322,26 +322,18 @@ void ShapeCast2D::add_exception_rid(const RID &p_rid) { exclude.insert(p_rid); } -void ShapeCast2D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); +void ShapeCast2D::add_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + add_exception_rid(p_node->get_rid()); } void ShapeCast2D::remove_exception_rid(const RID &p_rid) { exclude.erase(p_rid); } -void ShapeCast2D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - remove_exception_rid(co->get_rid()); +void ShapeCast2D::remove_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + remove_exception_rid(p_node->get_rid()); } void ShapeCast2D::clear_exceptions() { diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h index 7e1ebeb315..ea36b25068 100644 --- a/scene/2d/shape_cast_2d.h +++ b/scene/2d/shape_cast_2d.h @@ -34,6 +34,8 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +class CollisionObject2D; + class ShapeCast2D : public Node2D { GDCLASS(ShapeCast2D, Node2D); @@ -109,9 +111,9 @@ public: real_t get_closest_collision_unsafe_fraction() const; void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); + void add_exception(const CollisionObject2D *p_node); void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); + void remove_exception(const CollisionObject2D *p_node); void clear_exceptions(); TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 62dc4d1c15..02ca1ba2aa 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1119,7 +1119,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (q.runtime_tile_data_cache.has(E_cell.value)) { tile_data = q.runtime_tile_data_cache[E_cell.value]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } Ref<ShaderMaterial> mat = tile_data->get_material(); @@ -1311,7 +1311,7 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe } // Get tile data. - const TileData *tile_data = p_tile_data_override ? p_tile_data_override : Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile)); + const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile); // Get the tile modulation. Color modulate = tile_data->get_modulate() * p_modulation; @@ -1474,7 +1474,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r if (q.runtime_tile_data_cache.has(E_cell->get())) { tile_data = q.runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } for (int tile_set_physics_layer = 0; tile_set_physics_layer < tile_set->get_physics_layers_count(); tile_set_physics_layer++) { Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer); @@ -1671,7 +1671,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (q.runtime_tile_data_cache.has(E_cell->get())) { tile_data = q.runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } q.navigation_regions[E_cell->get()].resize(tile_set->get_navigation_layers_count()); @@ -1760,7 +1760,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { if (p_quadrant->runtime_tile_data_cache.has(E_cell->get())) { tile_data = p_quadrant->runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } Transform2D xform; @@ -1809,7 +1809,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ // Clear the scenes. for (const KeyValue<Vector2i, String> &E : q.scenes) { - Node *node = get_node(E.value); + Node *node = get_node_or_null(E.value); if (node) { node->queue_delete(); } @@ -1857,7 +1857,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) { // Clear the scenes. for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) { - Node *node = get_node(E.value); + Node *node = get_node_or_null(E.value); if (node) { node->queue_delete(); } @@ -2204,7 +2204,7 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ce Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile); if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { neighbor_tile_data = tile_data; } @@ -2580,7 +2580,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r if (atlas_source) { bool ret = false; if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, q.layer, E_cell.value, ret) && ret) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); // Create the runtime TileData. TileData *tile_data_runtime_use = tile_data->duplicate(); @@ -2725,7 +2725,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { } Vector2 TileMap::map_to_world(const Vector2i &p_pos) const { - // SHOULD RETURN THE CENTER OF THE TILE + // SHOULD RETURN THE CENTER OF THE CELL ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2()); Vector2 ret = p_pos; @@ -3648,9 +3648,6 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants); - ClassDB::bind_method(D_METHOD("_set_tile_data", "layer", "data"), &TileMap::_set_tile_data); - ClassDB::bind_method(D_METHOD("_get_tile_data", "layer"), &TileMap::_get_tile_data); - ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update); GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords"); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index df7c044f9e..3ab09550fa 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -484,7 +484,7 @@ uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) { id = shapes.back()->key() + 1; } - sd.owner = p_owner; + sd.owner_id = p_owner ? p_owner->get_instance_id() : ObjectID(); shapes[id] = sd; @@ -563,7 +563,7 @@ Transform3D CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const Object *CollisionObject3D::shape_owner_get_owner(uint32_t p_owner) const { ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); - return shapes[p_owner].owner; + return ObjectDB::get_instance(shapes[p_owner].owner_id); } void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3D> &p_shape) { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index f560753543..e92843d784 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -57,7 +57,7 @@ private: PhysicsServer3D::BodyMode body_mode = PhysicsServer3D::BODY_MODE_STATIC; struct ShapeData { - Object *owner = nullptr; + ObjectID owner_id; Transform3D xform; struct ShapeBase { RID debug_shape; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 0a0507207a..d88bb815bc 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -247,7 +247,7 @@ void Light3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); - ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disabled,Dynamic,Static"), "set_bake_mode", "get_bake_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI/SDFGI only)"), "set_bake_mode", "get_bake_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow"); @@ -284,8 +284,8 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(BAKE_DISABLED); - BIND_ENUM_CONSTANT(BAKE_DYNAMIC); BIND_ENUM_CONSTANT(BAKE_STATIC); + BIND_ENUM_CONSTANT(BAKE_DYNAMIC); } Light3D::Light3D(RenderingServer::LightType p_type) { diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 93dc8155bb..d5d2aee43d 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -63,8 +63,8 @@ public: enum BakeMode { BAKE_DISABLED, + BAKE_STATIC, BAKE_DYNAMIC, - BAKE_STATIC }; private: diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 715c421632..825742da35 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -217,7 +217,7 @@ LightmapGIData::~LightmapGIData() { void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); - if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) { + if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) { Ref<Mesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { bool all_have_uv2_and_normal = true; diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index b1f6f0cf91..ba6c50d98c 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -54,9 +54,9 @@ void NavigationObstacle3D::_validate_property(PropertyInfo &p_property) const { void NavigationObstacle3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - initialize_agent(); + case NOTIFICATION_ENTER_TREE: { parent_node3d = Object::cast_to<Node3D>(get_parent()); + reevaluate_agent_radius(); if (parent_node3d != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map()); @@ -91,6 +91,7 @@ void NavigationObstacle3D::_notification(int p_what) { NavigationObstacle3D::NavigationObstacle3D() { agent = NavigationServer3D::get_singleton()->agent_create(); + initialize_agent(); } NavigationObstacle3D::~NavigationObstacle3D() { @@ -118,7 +119,7 @@ void NavigationObstacle3D::initialize_agent() { void NavigationObstacle3D::reevaluate_agent_radius() { if (!estimate_radius) { NavigationServer3D::get_singleton()->agent_set_radius(agent, radius); - } else if (parent_node3d) { + } else if (parent_node3d && parent_node3d->is_inside_tree()) { NavigationServer3D::get_singleton()->agent_set_radius(agent, estimate_agent_radius()); } } diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index a992d2aaf2..cad1201d63 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -300,8 +300,9 @@ Node3D *Node3D::get_parent_node_3d() const { } Transform3D Node3D::get_relative_transform(const Node *p_parent) const { - if (p_parent == this) + if (p_parent == this) { return Transform3D(); + } ERR_FAIL_COND_V(!data.parent, Transform3D()); @@ -990,7 +991,7 @@ void Node3D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index b3192a5bb5..13a38f3b9f 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1)); ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); @@ -91,11 +91,8 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_linear_velocity, bool p_test_only, real_t p_margin, int p_max_collisions) { - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin); +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_distance, bool p_test_only, real_t p_margin, int p_max_collisions) { + PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_distance, p_margin); parameters.max_collisions = p_max_collisions; PhysicsServer3D::MotionResult result; @@ -170,7 +167,7 @@ bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_ return colliding; } -bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) { +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer3D::MotionResult *r = nullptr; @@ -182,10 +179,7 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear r = &temp_result; } - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer3D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin); + PhysicsServer3D::MotionParameters parameters(p_from, p_distance, p_margin); bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r); @@ -1233,7 +1227,7 @@ bool CharacterBody3D::move_and_slide() { if (motion_mode == MOTION_MODE_GROUNDED) { _move_and_slide_grounded(delta, was_on_floor); } else { - _move_and_slide_free(delta); + _move_and_slide_floating(delta); } // Compute real velocity. @@ -1512,7 +1506,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo } } -void CharacterBody3D::_move_and_slide_free(double p_delta) { +void CharacterBody3D::_move_and_slide_floating(double p_delta) { Vector3 motion = motion_velocity * p_delta; platform_rid = RID(); @@ -1929,7 +1923,7 @@ const Vector3 &CharacterBody3D::get_up_direction() const { } void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { - ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Free motion mode instead."); + ERR_FAIL_COND_MSG(p_up_direction == Vector3(), "up_direction can't be equal to Vector3.ZERO, consider using Floating motion mode instead."); up_direction = p_up_direction.normalized(); } @@ -2000,12 +1994,11 @@ void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody3D::_get_last_slide_collision); - ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); - ADD_GROUP("Free Mode", "free_mode_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); ADD_GROUP("Floor", "floor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); @@ -2020,7 +2013,7 @@ void CharacterBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); - BIND_ENUM_CONSTANT(MOTION_MODE_FREE); + BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY); @@ -2028,7 +2021,7 @@ void CharacterBody3D::_bind_methods() { } void CharacterBody3D::_validate_property(PropertyInfo &property) const { - if (motion_mode == MOTION_MODE_FREE) { + if (motion_mode == MOTION_MODE_FLOATING) { if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index e37b841117..67dc7382c3 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -50,11 +50,11 @@ protected: uint16_t locked_axis = 0; - Ref<KinematicCollision3D> _move(const Vector3 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1); + Ref<KinematicCollision3D> _move(const Vector3 &p_distance, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1); public: bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1); + bool test_move(const Transform3D &p_from, const Vector3 &p_distance, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1); void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; @@ -345,7 +345,7 @@ class CharacterBody3D : public PhysicsBody3D { public: enum MotionMode { MOTION_MODE_GROUNDED, - MOTION_MODE_FREE, + MOTION_MODE_FLOATING, }; enum MovingPlatformApplyVelocityOnLeave { PLATFORM_VEL_ON_LEAVE_ALWAYS, @@ -468,7 +468,7 @@ private: void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity); MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const; - void _move_and_slide_free(double p_delta); + void _move_and_slide_floating(double p_delta); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); Ref<KinematicCollision3D> _get_slide_collision(int p_bounce); diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index 3bb65d07a0..b71c54dcf9 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -243,26 +243,18 @@ void RayCast3D::add_exception_rid(const RID &p_rid) { exclude.insert(p_rid); } -void RayCast3D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); +void RayCast3D::add_exception(const CollisionObject3D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject3D."); + add_exception_rid(p_node->get_rid()); } void RayCast3D::remove_exception_rid(const RID &p_rid) { exclude.erase(p_rid); } -void RayCast3D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object); - if (!co) { - return; - } - remove_exception_rid(co->get_rid()); +void RayCast3D::remove_exception(const CollisionObject3D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject3D."); + remove_exception_rid(p_node->get_rid()); } void RayCast3D::clear_exceptions() { diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h index a53e2c83fc..ad85001591 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/ray_cast_3d.h @@ -33,6 +33,8 @@ #include "scene/3d/node_3d.h" +class CollisionObject3D; + class RayCast3D : public Node3D { GDCLASS(RayCast3D, Node3D); @@ -116,9 +118,9 @@ public: Vector3 get_collision_normal() const; void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); + void add_exception(const CollisionObject3D *p_node); void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); + void remove_exception(const CollisionObject3D *p_node); void clear_exceptions(); RayCast3D(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 3957a1653f..b6b5920f69 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -506,7 +506,7 @@ int Skeleton3D::get_bone_axis_forward_enum(int p_bone) { // Skeleton creation api void Skeleton3D::add_bone(const String &p_name) { - ERR_FAIL_COND(p_name.is_empty() || p_name.find(":") != -1 || p_name.find("/") != -1); + ERR_FAIL_COND(p_name.is_empty() || p_name.contains(":") || p_name.contains("/")); for (int i = 0; i < bones.size(); i++) { ERR_FAIL_COND(bones[i].name == p_name); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a37fce9469..331d58927b 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1088,8 +1088,9 @@ void AnimatedSprite3D::set_frame(int p_frame) { if (frames->has_animation(animation)) { int limit = frames->get_frame_count(animation); - if (p_frame >= limit) + if (p_frame >= limit) { p_frame = limit - 1; + } } if (p_frame < 0) { diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 0db2fe9fc6..005bb5a737 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -247,7 +247,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) } #ifndef DISABLE_DEPRECATED if (p_name == SceneStringNames::get_singleton()->use_in_baked_light && bool(p_value)) { - set_gi_mode(GI_MODE_BAKED); + set_gi_mode(GI_MODE_STATIC); return true; } @@ -358,7 +358,7 @@ void GeometryInstance3D::set_gi_mode(GIMode p_mode) { RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false); RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_USE_DYNAMIC_GI, false); } break; - case GI_MODE_BAKED: { + case GI_MODE_STATIC: { RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_USE_BAKED_LIGHT, true); RS::get_singleton()->instance_geometry_set_flag(get_instance(), RS::INSTANCE_FLAG_USE_DYNAMIC_GI, false); @@ -462,7 +462,7 @@ void GeometryInstance3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_occlusion_culling"), "set_ignore_occlusion_culling", "is_ignoring_occlusion_culling"); ADD_GROUP("Global Illumination", "gi_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI only)"), "set_gi_mode", "get_gi_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, String::utf8("1×,2×,4×,8×")), "set_lightmap_scale", "get_lightmap_scale"); ADD_GROUP("Visibility Range", "visibility_range_"); @@ -479,7 +479,7 @@ void GeometryInstance3D::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); BIND_ENUM_CONSTANT(GI_MODE_DISABLED); - BIND_ENUM_CONSTANT(GI_MODE_BAKED); + BIND_ENUM_CONSTANT(GI_MODE_STATIC); BIND_ENUM_CONSTANT(GI_MODE_DYNAMIC); BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_1X); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index dd0eb25001..be964e5080 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -89,7 +89,7 @@ public: enum GIMode { GI_MODE_DISABLED, - GI_MODE_BAKED, + GI_MODE_STATIC, GI_MODE_DYNAMIC }; diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 35ac1792e9..bfe3c80a4f 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -282,7 +282,7 @@ Vector3 VoxelGI::get_extents() const { void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); - if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) { + if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) { Ref<Mesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { AABB aabb = mesh->get_aabb(); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index a054f35d2e..66d1b97056 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -482,22 +482,22 @@ void XRController3D::_unbind_tracker() { void XRController3D::_button_pressed(const String &p_name) { // just pass it on... - emit_signal("button_pressed", p_name); + emit_signal(SNAME("button_pressed"), p_name); } void XRController3D::_button_released(const String &p_name) { // just pass it on... - emit_signal("button_released", p_name); + emit_signal(SNAME("button_released"), p_name); } void XRController3D::_input_value_changed(const String &p_name, float p_value) { // just pass it on... - emit_signal("input_value_changed", p_name, p_value); + emit_signal(SNAME("input_value_changed"), p_name, p_value); } void XRController3D::_input_axis_changed(const String &p_name, Vector2 p_value) { // just pass it on... - emit_signal("input_axis_changed", p_name, p_value); + emit_signal(SNAME("input_axis_changed"), p_name, p_value); } bool XRController3D::is_button_pressed(const StringName &p_name) const { diff --git a/scene/SCsub b/scene/SCsub index 92288211bb..a7b23af598 100644 --- a/scene/SCsub +++ b/scene/SCsub @@ -9,6 +9,7 @@ env.add_source_files(env.scene_sources, "*.cpp") # Chain load SCsubs SConscript("main/SCsub") +SConscript("multiplayer/SCsub") SConscript("gui/SCsub") if not env["disable_3d"]: SConscript("3d/SCsub") diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 33939d4cd6..849316c568 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -292,10 +292,10 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek) { // actually blend the animations now - float max_time_remaining = 0.0; + double max_time_remaining = 0.0; for (int i = 0; i < blend_points_used; i++) { - float remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false); + double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false); max_time_remaining = MAX(max_time_remaining, remaining); } diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index f169e79751..a3aa3f6cc8 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -438,7 +438,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek) { Vector2 blend_pos = get_parameter(blend_position); int closest = get_parameter(this->closest); double length_internal = get_parameter(this->length_internal); - float mind = 0.0; //time of min distance point + double mind = 0.0; //time of min distance point if (blend_mode == BLEND_MODE_INTERPOLATED) { if (triangles.size() == 0) { @@ -502,7 +502,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek) { for (int j = 0; j < 3; j++) { if (i == triangle_points[j]) { //blend with the given weight - float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); + double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); if (first || t < mind) { mind = t; first = false; @@ -530,7 +530,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek) { } if (new_closest != closest && new_closest != -1) { - float from = 0.0; + double from = 0.0; if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) { //for ping-pong loop Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[closest].node); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 2740103a4a..3d0ac291b8 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -371,6 +371,8 @@ void AnimationNodeOneShot::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync); ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_mode", PROPERTY_HINT_ENUM, "Blend,Add"), "set_mix_mode", "get_mix_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadein_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadein_time", "get_fadein_time"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater"), "set_fadeout_time", "get_fadeout_time"); @@ -748,7 +750,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek) { return 0; } - float rem = 0.0; + double rem = 0.0; if (prev < 0) { // process current animation, check for transition @@ -855,7 +857,7 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod ERR_FAIL_COND(nodes.has(p_name)); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); - ERR_FAIL_COND(String(p_name).find("/") != -1); + ERR_FAIL_COND(String(p_name).contains("/")); Node n; n.node = p_node; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index a23e1b689c..a68f7e037d 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -50,7 +50,7 @@ bool AnimationNodeStateMachineTransition::has_auto_advance() const { void AnimationNodeStateMachineTransition::set_advance_condition(const StringName &p_condition) { String cs = p_condition; - ERR_FAIL_COND(cs.find("/") != -1 || cs.find(":") != -1); + ERR_FAIL_COND(cs.contains("/") || cs.contains(":")); advance_condition = p_condition; if (!cs.is_empty()) { advance_condition_name = "conditions/" + cs; @@ -536,7 +536,7 @@ Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) { ERR_FAIL_COND(states.has(p_name)); ERR_FAIL_COND(p_node.is_null()); - ERR_FAIL_COND(String(p_name).find("/") != -1); + ERR_FAIL_COND(String(p_name).contains("/")); State state; state.node = p_node; @@ -553,7 +553,7 @@ void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<Animation void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<AnimationNode> p_node) { ERR_FAIL_COND(states.has(p_name) == false); ERR_FAIL_COND(p_node.is_null()); - ERR_FAIL_COND(String(p_name).find("/") != -1); + ERR_FAIL_COND(String(p_name).contains("/")); { Ref<AnimationNode> node = states[p_name].node; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 128c6cae8b..4a3fd72080 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1171,7 +1171,7 @@ void AnimationPlayer::_animation_process(double p_delta) { Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) { #ifdef DEBUG_ENABLED - ERR_FAIL_COND_V_MSG(String(p_name).find("/") != -1 || String(p_name).find(":") != -1 || String(p_name).find(",") != -1 || String(p_name).find("[") != -1, ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + "."); + ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + "."); #endif ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER); @@ -1213,7 +1213,7 @@ void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) { void AnimationPlayer::rename_animation(const StringName &p_name, const StringName &p_new_name) { ERR_FAIL_COND(!animation_set.has(p_name)); - ERR_FAIL_COND(String(p_new_name).find("/") != -1 || String(p_new_name).find(":") != -1); + ERR_FAIL_COND(String(p_new_name).contains("/") || String(p_new_name).contains(":")); ERR_FAIL_COND(animation_set.has(p_new_name)); stop(); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index a551417778..f2f69fc439 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -88,7 +88,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { } } -void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend, int p_pingponged) { +void AnimationNode::blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, real_t p_blend, int p_pingponged) { ERR_FAIL_COND(!state); ERR_FAIL_COND(!state->player->has_animation(p_animation)); @@ -119,13 +119,13 @@ void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time state->animation_states.push_back(anim_state); } -real_t AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, real_t p_time, bool p_seek, const Vector<StringName> &p_connections) { +double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, const Vector<StringName> &p_connections) { base_path = p_base_path; parent = p_parent; connections = p_connections; state = p_state; - real_t t = process(p_time, p_seek); + double t = process(p_time, p_seek); state = nullptr; parent = nullptr; @@ -144,7 +144,7 @@ void AnimationNode::make_invalid(const String &p_reason) { state->invalid_reasons += String::utf8("• ") + p_reason; } -real_t AnimationNode::blend_input(int p_input, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { +double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); ERR_FAIL_COND_V(!state, 0); @@ -163,7 +163,7 @@ real_t AnimationNode::blend_input(int p_input, real_t p_time, bool p_seek, real_ //inputs.write[p_input].last_pass = state->last_pass; real_t activity = 0.0; - real_t ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); + double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path); @@ -174,11 +174,11 @@ real_t AnimationNode::blend_input(int p_input, real_t p_time, bool p_seek, real_ return ret; } -real_t AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { +double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_blend, p_filter, p_optimize); } -real_t AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize, real_t *r_max) { +double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize, real_t *r_max) { ERR_FAIL_COND_V(!p_node.is_valid(), 0); ERR_FAIL_COND_V(!state, 0); @@ -314,7 +314,7 @@ void AnimationNode::add_input(const String &p_name) { //root nodes can't add inputs ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != nullptr); Input input; - ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); + ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/")); input.name = p_name; inputs.push_back(input); emit_changed(); @@ -322,7 +322,7 @@ void AnimationNode::add_input(const String &p_name) { void AnimationNode::set_input_name(int p_input, const String &p_name) { ERR_FAIL_INDEX(p_input, inputs.size()); - ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); + ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/")); inputs.write[p_input].name = p_name; emit_changed(); } @@ -796,7 +796,7 @@ void AnimationTree::_clear_caches() { cache_valid = false; } -void AnimationTree::_process_graph(real_t p_delta) { +void AnimationTree::_process_graph(double p_delta) { _update_properties(); //if properties need updating, update them //check all tracks, see if they need modification @@ -1335,10 +1335,10 @@ void AnimationTree::_process_graph(real_t p_delta) { t->playing = false; playing_caches.erase(t); } else { - real_t start_ofs = a->audio_track_get_key_start_offset(i, idx); + double start_ofs = a->audio_track_get_key_start_offset(i, idx); start_ofs += time - a->track_get_key_time(i, idx); - real_t end_ofs = a->audio_track_get_key_end_offset(i, idx); - real_t len = stream->get_length(); + double end_ofs = a->audio_track_get_key_end_offset(i, idx); + double len = stream->get_length(); if (start_ofs > len - end_ofs) { t->object->call("stop"); @@ -1374,9 +1374,9 @@ void AnimationTree::_process_graph(real_t p_delta) { t->playing = false; playing_caches.erase(t); } else { - real_t start_ofs = a->audio_track_get_key_start_offset(i, idx); - real_t end_ofs = a->audio_track_get_key_end_offset(i, idx); - real_t len = stream->get_length(); + double start_ofs = a->audio_track_get_key_start_offset(i, idx); + double end_ofs = a->audio_track_get_key_end_offset(i, idx); + double len = stream->get_length(); t->object->call("set_stream", stream); t->object->call("play", start_ofs); @@ -1407,7 +1407,7 @@ void AnimationTree::_process_graph(real_t p_delta) { } } } else if (t->len > 0) { - real_t len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; + double len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; if (len > t->len) { stop = true; @@ -1455,7 +1455,7 @@ void AnimationTree::_process_graph(real_t p_delta) { Ref<Animation> anim = player2->get_animation(anim_name); - real_t at_anim_pos = 0.0; + double at_anim_pos = 0.0; switch (anim->get_loop_mode()) { case Animation::LoopMode::LOOP_NONE: { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 11c9bcd4ef..705ee91c76 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -83,7 +83,7 @@ public: Vector<real_t> blends; State *state = nullptr; - real_t _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, real_t p_time, bool p_seek, const Vector<StringName> &p_connections); + double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, const Vector<StringName> &p_connections); //all this is temporary StringName base_path; @@ -96,12 +96,12 @@ public: Array _get_filters() const; void _set_filters(const Array &p_filters); friend class AnimationNodeBlendTree; - real_t _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, real_t *r_max = nullptr); + double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, real_t *r_max = nullptr); protected: - void blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend, int p_pingponged = 0); - real_t blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); - real_t blend_input(int p_input, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); + void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, real_t p_blend, int p_pingponged = 0); + double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); + double blend_input(int p_input, double p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); void make_invalid(const String &p_reason); @@ -234,8 +234,8 @@ private: struct TrackCacheAudio : public TrackCache { bool playing = false; - real_t start = 0.0; - real_t len = 0.0; + double start = 0.0; + double len = 0.0; TrackCacheAudio() { type = Animation::TYPE_AUDIO; @@ -265,7 +265,7 @@ private: void _clear_caches(); bool _update_caches(AnimationPlayer *player); - void _process_graph(real_t p_delta); + void _process_graph(double p_delta); uint64_t setup_pass = 1; uint64_t process_pass = 1; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index a37c6f5355..a2fed718be 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -249,8 +249,6 @@ bool Tween::custom_step(float p_delta) { } bool Tween::step(float p_delta) { - ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners."); - if (dead) { return false; } @@ -271,6 +269,7 @@ bool Tween::step(float p_delta) { } if (!started) { + ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners."); current_step = 0; loops_done = 0; start_tweeners(); @@ -284,6 +283,10 @@ bool Tween::step(float p_delta) { float step_delta = rem_delta; step_active = false; +#ifdef DEBUG_ENABLED + float prev_delta = rem_delta; +#endif + for (Ref<Tweener> &tweener : tweeners.write[current_step]) { // Modified inside Tweener.step(). float temp_delta = rem_delta; @@ -313,6 +316,12 @@ bool Tween::step(float p_delta) { start_tweeners(); } } + +#ifdef DEBUG_ENABLED + if (Math::is_equal_approx(rem_delta, prev_delta) && running && loops <= 0) { + ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info."); + } +#endif } return true; diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index 432317a423..c8298391bb 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -37,6 +37,7 @@ #include "core/variant/array.h" class Script; +class Node; class SceneDebugger { public: diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index eee7663b09..da2ef6c5ec 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -382,8 +382,11 @@ Ref<ButtonGroup> BaseButton::get_button_group() const { } void BaseButton::set_shortcut_context(Node *p_node) { - ERR_FAIL_NULL_MSG(p_node, "Shortcut context node can't be null."); - shortcut_context = p_node->get_instance_id(); + if (p_node != nullptr) { + shortcut_context = p_node->get_instance_id(); + } else { + shortcut_context = ObjectID(); + } } Node *BaseButton::get_shortcut_context() const { @@ -400,7 +403,7 @@ bool BaseButton::_is_focus_owner_in_shorcut_context() const { } Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_focus_owner(); + Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); @@ -441,10 +444,11 @@ void BaseButton::_bind_methods() { ADD_SIGNAL(MethodInfo("button_up")); ADD_SIGNAL(MethodInfo("button_down")); ADD_SIGNAL(MethodInfo("toggled", PropertyInfo(Variant::BOOL, "button_pressed"))); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_in_tooltip"), "set_shortcut_in_tooltip", "is_shortcut_in_tooltip_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "button_pressed"), "set_pressed", "is_pressed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); @@ -500,7 +504,8 @@ BaseButton *ButtonGroup::get_pressed_button() { void ButtonGroup::_bind_methods() { ClassDB::bind_method(D_METHOD("get_pressed_button"), &ButtonGroup::get_pressed_button); ClassDB::bind_method(D_METHOD("get_buttons"), &ButtonGroup::_get_buttons); - ADD_SIGNAL(MethodInfo("pressed", PropertyInfo(Variant::OBJECT, "button"))); + + ADD_SIGNAL(MethodInfo("pressed", PropertyInfo(Variant::OBJECT, "button", PROPERTY_HINT_RESOURCE_TYPE, "BaseButton"))); } ButtonGroup::ButtonGroup() { diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 046b9c18c7..3ed1b873af 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -197,6 +197,8 @@ void Button::_notification(int p_what) { color = get_theme_color(SNAME("font_disabled_color")); if (has_theme_color(SNAME("icon_disabled_color"))) { color_icon = get_theme_color(SNAME("icon_disabled_color")); + } else { + color_icon.a = 0.4; } } break; @@ -232,9 +234,6 @@ void Button::_notification(int p_what) { } if (!_icon.is_null()) { int valign = size.height - style->get_minimum_size().y; - if (is_disabled()) { - color_icon.a = 0.4; - } float icon_ofs_region = 0.0; Point2 style_offset; @@ -569,7 +568,7 @@ void Button::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_button_icon", "get_button_icon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 040075150b..8cb8a78e8d 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -34,14 +34,6 @@ #include "core/string/string_builder.h" #include "core/string/ustring.h" -static bool _is_whitespace(char32_t c) { - return c == '\t' || c == ' '; -} - -static bool _is_char(char32_t c) { - return !is_symbol(c); -} - void CodeEdit::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: @@ -232,7 +224,7 @@ void CodeEdit::_notification(int p_what) { int begin = 0; int end = 0; - if (line.find(String::chr(0xFFFF)) != -1) { + if (line.contains(String::chr(0xFFFF))) { begin = font->get_string_size(line.substr(0, line.find(String::chr(0xFFFF))), font_size).x; end = font->get_string_size(line.substr(0, line.rfind(String::chr(0xFFFF))), font_size).x; } @@ -571,6 +563,8 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const { // Overridable actions void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode) { bool had_selection = has_selection(); + String selection_text = (had_selection ? get_selected_text() : ""); + if (had_selection) { begin_complex_operation(); delete_selection(); @@ -591,27 +585,38 @@ void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode) { if (auto_brace_completion_enabled) { int cl = get_caret_line(); int cc = get_caret_column(); - int caret_move_offset = 1; - int post_brace_pair = cc < get_line(cl).length() ? _get_auto_brace_pair_close_at_pos(cl, cc) : -1; - - if (has_string_delimiter(chr) && cc > 0 && _is_char(get_line(cl)[cc - 1]) && post_brace_pair == -1) { - insert_text_at_caret(chr); - } else if (cc < get_line(cl).length() && _is_char(get_line(cl)[cc])) { - insert_text_at_caret(chr); - } else if (post_brace_pair != -1 && auto_brace_completion_pairs[post_brace_pair].close_key[0] == chr[0]) { - caret_move_offset = auto_brace_completion_pairs[post_brace_pair].close_key.length(); - } else if (is_in_comment(cl, cc) != -1 || (is_in_string(cl, cc) != -1 && has_string_delimiter(chr))) { + if (had_selection) { insert_text_at_caret(chr); + + String close_key = get_auto_brace_completion_close_key(chr); + if (!close_key.is_empty()) { + insert_text_at_caret(selection_text + close_key); + set_caret_column(get_caret_column() - 1); + } } else { - insert_text_at_caret(chr); + int caret_move_offset = 1; + + int post_brace_pair = cc < get_line(cl).length() ? _get_auto_brace_pair_close_at_pos(cl, cc) : -1; + + if (has_string_delimiter(chr) && cc > 0 && !is_symbol(get_line(cl)[cc - 1]) && post_brace_pair == -1) { + insert_text_at_caret(chr); + } else if (cc < get_line(cl).length() && !is_symbol(get_line(cl)[cc])) { + insert_text_at_caret(chr); + } else if (post_brace_pair != -1 && auto_brace_completion_pairs[post_brace_pair].close_key[0] == chr[0]) { + caret_move_offset = auto_brace_completion_pairs[post_brace_pair].close_key.length(); + } else if (is_in_comment(cl, cc) != -1 || (is_in_string(cl, cc) != -1 && has_string_delimiter(chr))) { + insert_text_at_caret(chr); + } else { + insert_text_at_caret(chr); - int pre_brace_pair = _get_auto_brace_pair_open_at_pos(cl, cc + 1); - if (pre_brace_pair != -1) { - insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key); + int pre_brace_pair = _get_auto_brace_pair_open_at_pos(cl, cc + 1); + if (pre_brace_pair != -1) { + insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key); + } } + set_caret_column(cc + caret_move_offset); } - set_caret_column(cc + caret_move_offset); } else { insert_text_at_caret(chr); } @@ -937,8 +942,10 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) { return; } - const int cc = get_caret_column(); + /* When not splitting the line, we need to factor in indentation from the end of the current line. */ + const int cc = p_split_current_line ? get_caret_column() : get_line(get_caret_line()).length(); const int cl = get_caret_line(); + const String line = get_line(cl); String ins = "\n"; @@ -986,7 +993,7 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) { } /* Make sure this is the last char, trailing whitespace or comments are okay. */ - if (should_indent && (!_is_whitespace(c) && is_in_comment(cl, cc) == -1)) { + if (should_indent && (!is_whitespace(c) && is_in_comment(cl, cc) == -1)) { should_indent = false; } } @@ -1012,6 +1019,8 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) { bool first_line = false; if (!p_split_current_line) { + deselect(); + if (p_above) { if (cl > 0) { set_caret_line(cl - 1, false); @@ -1793,17 +1802,17 @@ void CodeEdit::request_code_completion(bool p_force) { } if (p_force) { - emit_signal(SNAME("request_code_completion")); + emit_signal(SNAME("code_completion_requested")); return; } String line = get_line(get_caret_line()); int ofs = CLAMP(get_caret_column(), 0, line.length()); - if (ofs > 0 && (is_in_string(get_caret_line(), ofs) != -1 || _is_char(line[ofs - 1]) || code_completion_prefixes.has(line[ofs - 1]))) { - emit_signal(SNAME("request_code_completion")); + if (ofs > 0 && (is_in_string(get_caret_line(), ofs) != -1 || !is_symbol(line[ofs - 1]) || code_completion_prefixes.has(line[ofs - 1]))) { + emit_signal(SNAME("code_completion_requested")); } else if (ofs > 1 && line[ofs - 1] == ' ' && code_completion_prefixes.has(line[ofs - 2])) { - emit_signal(SNAME("request_code_completion")); + emit_signal(SNAME("code_completion_requested")); } } @@ -1909,7 +1918,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) { if (merge_text) { for (; caret_col < line.length(); caret_col++) { - if (!_is_char(line[caret_col])) { + if (is_symbol(line[caret_col])) { break; } } @@ -2085,8 +2094,6 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_auto_brace_completion_close_key", "open_key"), &CodeEdit::get_auto_brace_completion_close_key); /* Main Gutter */ - ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback); - ClassDB::bind_method(D_METHOD("set_draw_breakpoints_gutter", "enable"), &CodeEdit::set_draw_breakpoints_gutter); ClassDB::bind_method(D_METHOD("is_drawing_breakpoints_gutter"), &CodeEdit::is_drawing_breakpoints_gutter); @@ -2115,16 +2122,12 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_executing_lines"), &CodeEdit::get_executing_lines); /* Line numbers */ - ClassDB::bind_method(D_METHOD("_line_number_draw_callback"), &CodeEdit::_line_number_draw_callback); - ClassDB::bind_method(D_METHOD("set_draw_line_numbers", "enable"), &CodeEdit::set_draw_line_numbers); ClassDB::bind_method(D_METHOD("is_draw_line_numbers_enabled"), &CodeEdit::is_draw_line_numbers_enabled); ClassDB::bind_method(D_METHOD("set_line_numbers_zero_padded", "enable"), &CodeEdit::set_line_numbers_zero_padded); ClassDB::bind_method(D_METHOD("is_line_numbers_zero_padded"), &CodeEdit::is_line_numbers_zero_padded); /* Fold Gutter */ - ClassDB::bind_method(D_METHOD("_fold_gutter_draw_callback"), &CodeEdit::_fold_gutter_draw_callback); - ClassDB::bind_method(D_METHOD("set_draw_fold_gutter", "enable"), &CodeEdit::set_draw_fold_gutter); ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &CodeEdit::is_drawing_fold_gutter); @@ -2267,7 +2270,7 @@ void CodeEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line"))); /* Code Completion */ - ADD_SIGNAL(MethodInfo("request_code_completion")); + ADD_SIGNAL(MethodInfo("code_completion_requested")); /* Symbol lookup */ ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::INT, "column"))); @@ -2551,7 +2554,7 @@ int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) c region = E->value(); in_region = true; for (int i = E->key() - 2; i >= 0; i--) { - if (!_is_whitespace(line[i])) { + if (!is_whitespace(line[i])) { return -1; } } @@ -2570,7 +2573,7 @@ int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) c } for (int i = end_col; i < line.length(); i++) { - if (!_is_whitespace(line[i])) { + if (!is_whitespace(line[i])) { return -1; } } @@ -2786,11 +2789,11 @@ void CodeEdit::_filter_code_completion_candidates_impl() { while (ofs > 0 && line[ofs] == ' ') { ofs--; } - prev_is_word = _is_char(line[ofs]); + prev_is_word = !is_symbol(line[ofs]); /* Otherwise get current word and set cofs to the start. */ } else { int start_cofs = cofs; - while (cofs > 0 && line[cofs - 1] > 32 && (line[cofs - 1] == '/' || _is_char(line[cofs - 1]))) { + while (cofs > 0 && line[cofs - 1] > 32 && (line[cofs - 1] == '/' || !is_symbol(line[cofs - 1]))) { cofs--; } string_to_complete = line.substr(cofs, start_cofs - cofs); @@ -2859,7 +2862,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { completion_options_casei.push_back(option); } else if (s.is_subsequence_of(option.display)) { completion_options_subseq.push_back(option); - } else if (s.is_subsequence_ofi(option.display)) { + } else if (s.is_subsequence_ofn(option.display)) { completion_options_subseq_casei.push_back(option); } @@ -3084,7 +3087,7 @@ CodeEdit::CodeEdit() { set_gutter_draw(gutter_idx, false); set_gutter_overwritable(gutter_idx, true); set_gutter_type(gutter_idx, GUTTER_TYPE_CUSTOM); - set_gutter_custom_draw(gutter_idx, this, "_main_gutter_draw_callback"); + set_gutter_custom_draw(gutter_idx, callable_mp(this, &CodeEdit::_main_gutter_draw_callback)); gutter_idx++; /* Line numbers */ @@ -3092,7 +3095,7 @@ CodeEdit::CodeEdit() { set_gutter_name(gutter_idx, "line_numbers"); set_gutter_draw(gutter_idx, false); set_gutter_type(gutter_idx, GUTTER_TYPE_CUSTOM); - set_gutter_custom_draw(gutter_idx, this, "_line_number_draw_callback"); + set_gutter_custom_draw(gutter_idx, callable_mp(this, &CodeEdit::_line_number_draw_callback)); gutter_idx++; /* Fold Gutter */ @@ -3100,7 +3103,7 @@ CodeEdit::CodeEdit() { set_gutter_name(gutter_idx, "fold_gutter"); set_gutter_draw(gutter_idx, false); set_gutter_type(gutter_idx, GUTTER_TYPE_CUSTOM); - set_gutter_custom_draw(gutter_idx, this, "_fold_gutter_draw_callback"); + set_gutter_custom_draw(gutter_idx, callable_mp(this, &CodeEdit::_fold_gutter_draw_callback)); gutter_idx++; connect("lines_edited_from", callable_mp(this, &CodeEdit::_lines_edited_from)); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 69e6d74292..fdae8e2f1f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -240,7 +240,7 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { return false; } - if (p_value.get_type() == Variant::NIL) { + if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) { if (name.begins_with("theme_override_icons/") || name.begins_with("custom_icons/")) { String dname = name.get_slicec('/', 1); if (data.icon_override.has(dname)) { @@ -576,6 +576,11 @@ void Control::_update_canvas_item_transform() { Transform2D xform = _get_internal_transform(); xform[2] += get_position(); + // We use a little workaround to avoid flickering when moving the pivot with _edit_set_pivot() + if (is_inside_tree() && Math::abs(Math::sin(data.rotation * 4.0f)) < 0.00001f && get_viewport()->is_snap_controls_to_pixels_enabled()) { + xform[2] = xform[2].round(); + } + RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), xform); } @@ -733,8 +738,10 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - data.is_rtl_dirty = true; - _size_changed(); + if (is_inside_tree()) { + data.is_rtl_dirty = true; + _size_changed(); + } } break; } } @@ -1306,7 +1313,7 @@ Rect2 Control::get_parent_anchorable_rect() const { #ifdef TOOLS_ENABLED Node *edited_root = get_tree()->get_edited_scene_root(); if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) { - parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); + parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height")); } else { parent_rect = get_viewport()->get_visible_rect(); } @@ -2189,8 +2196,7 @@ void Control::release_focus() { return; } - get_viewport()->_gui_remove_focus(); - update(); + get_viewport()->gui_release_focus(); } bool Control::is_top_level_control() const { @@ -2593,11 +2599,6 @@ Control::MouseFilter Control::get_mouse_filter() const { return data.mouse_filter; } -Control *Control::get_focus_owner() const { - ERR_FAIL_COND_V(!is_inside_tree(), nullptr); - return get_viewport()->_gui_get_focus_owner(); -} - void Control::warp_mouse(const Point2 &p_to_pos) { ERR_FAIL_COND(!is_inside_tree()); get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos)); @@ -2887,7 +2888,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus); ClassDB::bind_method(D_METHOD("find_prev_valid_focus"), &Control::find_prev_valid_focus); ClassDB::bind_method(D_METHOD("find_next_valid_focus"), &Control::find_next_valid_focus); - ClassDB::bind_method(D_METHOD("get_focus_owner"), &Control::get_focus_owner); ClassDB::bind_method(D_METHOD("set_h_size_flags", "flags"), &Control::set_h_size_flags); ClassDB::bind_method(D_METHOD("get_h_size_flags"), &Control::get_h_size_flags); diff --git a/scene/gui/control.h b/scene/gui/control.h index bf79f790e7..962135280f 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -462,8 +462,6 @@ public: void set_focus_previous(const NodePath &p_prev); NodePath get_focus_previous() const; - Control *get_focus_owner() const; - void set_mouse_filter(MouseFilter p_filter); MouseFilter get_mouse_filter() const; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 44ef641cb8..dad84461f4 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -110,6 +110,9 @@ void FileDialog::_notification(int p_what) { show_hidden->set_icon(vbox->get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog"))); _theme_changed(); } + if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { + update_filters(); + } } void FileDialog::unhandled_input(const Ref<InputEvent> &p_event) { @@ -166,7 +169,14 @@ void FileDialog::update_dir() { dir->set_text(dir_access->get_current_dir(false)); if (drives->is_visible()) { - drives->select(dir_access->get_current_drive()); + if (dir_access->get_current_dir().is_network_share_path()) { + _update_drives(false); + drives->add_item(RTR("Network")); + drives->set_item_disabled(drives->get_item_count() - 1, true); + drives->select(drives->get_item_count() - 1); + } else { + drives->select(dir_access->get_current_drive()); + } } // Deselect any item, to make "Select Current Folder" button text by default. @@ -638,7 +648,7 @@ void FileDialog::update_filters() { all_filters += ", ..."; } - filter->add_item(String(TTRC("All Recognized")) + " (" + all_filters + ")"); + filter->add_item(RTR("All Recognized") + " (" + all_filters + ")"); } for (int i = 0; i < filters.size(); i++) { String flt = filters[i].get_slice(";", 0).strip_edges(); @@ -650,7 +660,7 @@ void FileDialog::update_filters() { } } - filter->add_item(TTRC("All Files (*)")); + filter->add_item(RTR("All Files") + " (*)"); } void FileDialog::clear_filters() { @@ -843,7 +853,7 @@ void FileDialog::_select_drive(int p_idx) { _push_history(); } -void FileDialog::_update_drives() { +void FileDialog::_update_drives(bool p_select) { int dc = dir_access->get_drive_count(); if (dc == 0 || access != ACCESS_FILESYSTEM) { drives->hide(); @@ -861,7 +871,9 @@ void FileDialog::_update_drives() { drives->add_item(dir_access->get_drive(i)); } - drives->select(dir_access->get_current_drive()); + if (p_select) { + drives->select(dir_access->get_current_drive()); + } } } diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 9f8bc02b2a..36a6b262b0 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -132,7 +132,7 @@ private: void _go_back(); void _go_forward(); - void _update_drives(); + void _update_drives(bool p_select = true); virtual void unhandled_input(const Ref<InputEvent> &p_event) override; diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp new file mode 100644 index 0000000000..d1ac60b325 --- /dev/null +++ b/scene/gui/flow_container.cpp @@ -0,0 +1,252 @@ +/*************************************************************************/ +/* flow_container.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene/gui/container.h" + +#include "flow_container.h" + +struct _LineData { + int child_count = 0; + int min_line_height = 0; + int min_line_length = 0; + int stretch_avail = 0; + float stretch_ratio_total = 0; +}; + +void FlowContainer::_resort() { + int separation_horizontal = get_theme_constant(SNAME("hseparation")); + int separation_vertical = get_theme_constant(SNAME("vseparation")); + + bool rtl = is_layout_rtl(); + + Map<Control *, Size2i> children_minsize_cache; + + Vector<_LineData> lines_data; + + Vector2i ofs; + int line_height = 0; + int line_length = 0; + float line_stretch_ratio_total = 0; + int current_container_size = vertical ? get_rect().size.y : get_rect().size.x; + int children_in_current_line = 0; + + // First pass for line wrapping and minimum size calculation. + for (int i = 0; i < get_child_count(); i++) { + Control *child = Object::cast_to<Control>(get_child(i)); + if (!child || !child->is_visible_in_tree()) { + continue; + } + if (child->is_set_as_top_level()) { + continue; + } + + Size2i child_msc = child->get_combined_minimum_size(); + + if (vertical) { /* VERTICAL */ + if (children_in_current_line > 0) { + ofs.y += separation_vertical; + } + if (ofs.y + child_msc.y > current_container_size) { + line_length = ofs.y - separation_vertical; + lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total }); + + // Move in new column (vertical line). + ofs.x += line_height + separation_horizontal; + ofs.y = 0; + line_height = 0; + line_stretch_ratio_total = 0; + children_in_current_line = 0; + } + + line_height = MAX(line_height, child_msc.x); + if (child->get_v_size_flags() & SIZE_EXPAND) { + line_stretch_ratio_total += child->get_stretch_ratio(); + } + ofs.y += child_msc.y; + + } else { /* HORIZONTAL */ + if (children_in_current_line > 0) { + ofs.x += separation_horizontal; + } + if (ofs.x + child_msc.x > current_container_size) { + line_length = ofs.x - separation_horizontal; + lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total }); + + // Move in new line. + ofs.y += line_height + separation_vertical; + ofs.x = 0; + line_height = 0; + line_stretch_ratio_total = 0; + children_in_current_line = 0; + } + + line_height = MAX(line_height, child_msc.y); + if (child->get_h_size_flags() & SIZE_EXPAND) { + line_stretch_ratio_total += child->get_stretch_ratio(); + } + ofs.x += child_msc.x; + } + + children_minsize_cache[child] = child_msc; + children_in_current_line++; + } + line_length = vertical ? (ofs.y) : (ofs.x); + lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total }); + + // Second pass for in-line expansion and alignment. + + int current_line_idx = 0; + int child_idx_in_line = 0; + + ofs.x = 0; + ofs.y = 0; + + for (int i = 0; i < get_child_count(); i++) { + Control *child = Object::cast_to<Control>(get_child(i)); + if (!child || !child->is_visible_in_tree()) { + continue; + } + if (child->is_set_as_top_level()) { + continue; + } + Size2i child_size = children_minsize_cache[child]; + + _LineData line_data = lines_data[current_line_idx]; + if (child_idx_in_line >= lines_data[current_line_idx].child_count) { + current_line_idx++; + child_idx_in_line = 0; + if (vertical) { + ofs.x += line_data.min_line_height + separation_horizontal; + ofs.y = 0; + } else { + ofs.x = 0; + ofs.y += line_data.min_line_height + separation_vertical; + } + line_data = lines_data[current_line_idx]; + } + + if (vertical) { /* VERTICAL */ + if (child->get_h_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)) { + child_size.width = line_data.min_line_height; + } + + if (child->get_v_size_flags() & SIZE_EXPAND) { + int stretch = line_data.stretch_avail * child->get_stretch_ratio() / line_data.stretch_ratio_total; + child_size.height += stretch; + } + + } else { /* HORIZONTAL */ + if (child->get_v_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)) { + child_size.height = line_data.min_line_height; + } + + if (child->get_h_size_flags() & SIZE_EXPAND) { + int stretch = line_data.stretch_avail * child->get_stretch_ratio() / line_data.stretch_ratio_total; + child_size.width += stretch; + } + } + + Rect2 child_rect = Rect2(ofs, child_size); + if (rtl) { + child_rect.position.x = get_rect().size.x - child_rect.position.x - child_rect.size.width; + } + + fit_child_in_rect(child, child_rect); + + if (vertical) { /* VERTICAL */ + ofs.y += child_size.height + separation_vertical; + } else { /* HORIZONTAL */ + ofs.x += child_size.width + separation_horizontal; + } + + child_idx_in_line++; + } + cached_size = (vertical ? ofs.x : ofs.y) + line_height; + cached_line_count = lines_data.size(); +} + +Size2 FlowContainer::get_minimum_size() const { + Size2i minimum; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) { + continue; + } + if (c->is_set_as_top_level()) { + continue; + } + + if (!c->is_visible()) { + continue; + } + + Size2i size = c->get_combined_minimum_size(); + + if (vertical) { /* VERTICAL */ + minimum.height = MAX(minimum.height, size.height); + minimum.width = cached_size; + + } else { /* HORIZONTAL */ + minimum.width = MAX(minimum.width, size.width); + minimum.height = cached_size; + } + } + + return minimum; +} + +void FlowContainer::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_SORT_CHILDREN: { + _resort(); + update_minimum_size(); + } break; + case NOTIFICATION_THEME_CHANGED: { + update_minimum_size(); + } break; + case NOTIFICATION_TRANSLATION_CHANGED: + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + queue_sort(); + } break; + } +} + +int FlowContainer::get_line_count() const { + return cached_line_count; +} + +FlowContainer::FlowContainer(bool p_vertical) { + vertical = p_vertical; +} + +void FlowContainer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count); +} diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h new file mode 100644 index 0000000000..e3ed423ae1 --- /dev/null +++ b/scene/gui/flow_container.h @@ -0,0 +1,76 @@ +/*************************************************************************/ +/* flow_container.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 FLOW_CONTAINER_H +#define FLOW_CONTAINER_H + +class Container; + +class FlowContainer : public Container { + GDCLASS(FlowContainer, Container); + +private: + int cached_size = 0; + int cached_line_count = 0; + + bool vertical = false; + + void _resort(); + +protected: + void _notification(int p_what); + + static void _bind_methods(); + +public: + int get_line_count() const; + + virtual Size2 get_minimum_size() const override; + + FlowContainer(bool p_vertical = false); +}; + +class HFlowContainer : public FlowContainer { + GDCLASS(HFlowContainer, FlowContainer); + +public: + HFlowContainer() : + FlowContainer(false) {} +}; + +class VFlowContainer : public FlowContainer { + GDCLASS(VFlowContainer, FlowContainer); + +public: + VFlowContainer() : + FlowContainer(true) {} +}; + +#endif // FLOW_CONTAINER_H diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index 407f61f7c1..67531d4f4a 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -33,7 +33,6 @@ #include "scene/gui/color_picker.h" #include "scene/gui/popup.h" -#include "scene/resources/default_theme/theme_data.h" #include "scene/resources/gradient.h" class GradientEdit : public Control { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 79b73f7cc3..95575a8226 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1070,7 +1070,9 @@ void GraphEdit::set_selected(Node *p_child) { void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { ERR_FAIL_COND(p_ev.is_null()); - panner->gui_input(p_ev); + if (panner->gui_input(p_ev, warped_panning ? get_global_rect() : Rect2())) { + return; + } Ref<InputEventMouseMotion> mm = p_ev; @@ -1272,7 +1274,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { if (_filter_input(b->get_position())) { return; } - if (Input::get_singleton()->is_key_pressed(Key::SPACE)) { + if (panner->is_panning()) { return; } @@ -1354,7 +1356,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { } } -void GraphEdit::_scroll_callback(Vector2 p_scroll_vec) { +void GraphEdit::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) { if (p_scroll_vec.x != 0) { h_scroll->set_value(h_scroll->get_value() + (h_scroll->get_page() * Math::abs(p_scroll_vec.x) / 8) * SIGN(p_scroll_vec.x)); } else { @@ -1367,7 +1369,7 @@ void GraphEdit::_pan_callback(Vector2 p_scroll_vec) { v_scroll->set_value(v_scroll->get_value() - p_scroll_vec.y); } -void GraphEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin) { +void GraphEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) { set_zoom_custom(p_scroll_vec.y < 0 ? zoom * zoom_step : zoom / zoom_step, p_origin); } @@ -1678,12 +1680,21 @@ HBoxContainer *GraphEdit::get_zoom_hbox() { return zoom_hb; } +Ref<ViewPanner> GraphEdit::get_panner() { + return panner; +} + +void GraphEdit::set_warped_panning(bool p_warped) { + warped_panning = p_warped; +} + int GraphEdit::_set_operations(SET_OPERATIONS p_operation, Set<StringName> &r_u, const Set<StringName> &r_v) { switch (p_operation) { case GraphEdit::IS_EQUAL: { for (Set<StringName>::Element *E = r_u.front(); E; E = E->next()) { - if (!r_v.has(E->get())) + if (!r_v.has(E->get())) { return 0; + } } return r_u.size() == r_v.size(); } break; @@ -1692,8 +1703,9 @@ int GraphEdit::_set_operations(SET_OPERATIONS p_operation, Set<StringName> &r_u, return 1; } for (Set<StringName>::Element *E = r_u.front(); E; E = E->next()) { - if (!r_v.has(E->get())) + if (!r_v.has(E->get())) { return 0; + } } return 1; } break; @@ -2305,7 +2317,6 @@ GraphEdit::GraphEdit() { panner.instantiate(); panner->set_callbacks(callable_mp(this, &GraphEdit::_scroll_callback), callable_mp(this, &GraphEdit::_pan_callback), callable_mp(this, &GraphEdit::_zoom_callback)); - panner->set_disable_rmb(true); top_layer = memnew(GraphEditFilter(this)); add_child(top_layer, false, INTERNAL_MODE_BACK); @@ -2313,6 +2324,7 @@ GraphEdit::GraphEdit() { top_layer->set_anchors_and_offsets_preset(Control::PRESET_WIDE); top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw)); top_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_layer_input)); + top_layer->connect("focus_exited", callable_mp(panner.ptr(), &ViewPanner::release_pan_key)); connections_layer = memnew(Control); add_child(connections_layer, false, INTERNAL_MODE_FRONT); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 4e998d30a7..da973b46f0 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -130,9 +130,10 @@ private: float port_grab_distance_vertical; Ref<ViewPanner> panner; - void _scroll_callback(Vector2 p_scroll_vec); + bool warped_panning = true; + void _scroll_callback(Vector2 p_scroll_vec, bool p_alt); void _pan_callback(Vector2 p_scroll_vec); - void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin); + void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt); bool connecting = false; String connecting_from; @@ -348,6 +349,8 @@ public: bool is_connection_lines_antialiased() const; HBoxContainer *get_zoom_hbox(); + Ref<ViewPanner> get_panner(); + void set_warped_panning(bool p_warped); void arrange_nodes(); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index d6569e3de4..30f6cf4a14 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -1022,7 +1022,7 @@ void GraphNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset"), "set_position_offset", "get_position_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable"); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 861b70f17e..852aaaab24 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -82,8 +82,11 @@ void Label::_shape() { Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label")); int width = (get_size().width - style->get_minimum_size().width); - if (dirty) { - TS->shaped_text_clear(text_rid); + if (dirty || font_dirty) { + String lang = (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale(); + if (dirty) { + TS->shaped_text_clear(text_rid); + } if (text_direction == Control::TEXT_DIRECTION_INHERITED) { TS->shaped_text_set_direction(text_rid, is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { @@ -92,13 +95,21 @@ void Label::_shape() { const Ref<Font> &font = get_theme_font(SNAME("font")); int font_size = get_theme_font_size(SNAME("font_size")); ERR_FAIL_COND(font.is_null()); - String text = (uppercase) ? xl_text.to_upper() : xl_text; + String text = (uppercase) ? TS->string_to_upper(xl_text, lang) : xl_text; if (visible_chars >= 0 && visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) { text = text.substr(0, visible_chars); } - TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); + if (dirty) { + TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, lang); + } else { + int spans = TS->shaped_get_span_count(text_rid); + for (int i = 0; i < spans; i++) { + TS->shaped_set_span_update_font(text_rid, i, font->get_rids(), font_size, opentype_features); + } + } TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text)); dirty = false; + font_dirty = false; lines_dirty = true; } @@ -275,7 +286,7 @@ void Label::_notification(int p_what) { RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); } - if (dirty || lines_dirty) { + if (dirty || font_dirty || lines_dirty) { _shape(); } @@ -520,7 +531,7 @@ void Label::_notification(int p_what) { } if (p_what == NOTIFICATION_THEME_CHANGED) { - dirty = true; + font_dirty = true; update(); } if (p_what == NOTIFICATION_RESIZED) { @@ -530,7 +541,7 @@ void Label::_notification(int p_what) { Size2 Label::get_minimum_size() const { // don't want to mutable everything - if (dirty || lines_dirty) { + if (dirty || font_dirty || lines_dirty) { const_cast<Label *>(this)->_shape(); } @@ -554,7 +565,7 @@ int Label::get_line_count() const { if (!is_inside_tree()) { return 1; } - if (dirty || lines_dirty) { + if (dirty || font_dirty || lines_dirty) { const_cast<Label *>(this)->_shape(); } @@ -629,7 +640,7 @@ void Label::set_text_direction(Control::TextDirection p_text_direction) { ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); if (text_direction != p_text_direction) { text_direction = p_text_direction; - dirty = true; + font_dirty = true; update(); } } @@ -637,7 +648,7 @@ void Label::set_text_direction(Control::TextDirection p_text_direction) { void Label::set_structured_text_bidi_override(Control::StructuredTextParser p_parser) { if (st_parser != p_parser) { st_parser = p_parser; - dirty = true; + font_dirty = true; update(); } } @@ -648,7 +659,7 @@ Control::StructuredTextParser Label::get_structured_text_bidi_override() const { void Label::set_structured_text_bidi_override_options(Array p_args) { st_args = p_args; - dirty = true; + font_dirty = true; update(); } @@ -662,7 +673,7 @@ Control::TextDirection Label::get_text_direction() const { void Label::clear_opentype_features() { opentype_features.clear(); - dirty = true; + font_dirty = true; update(); } @@ -670,7 +681,7 @@ void Label::set_opentype_feature(const String &p_name, int p_value) { int32_t tag = TS->name_to_tag(p_name); if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) { opentype_features[tag] = p_value; - dirty = true; + font_dirty = true; update(); } } @@ -797,7 +808,7 @@ int Label::get_max_lines_visible() const { } int Label::get_total_character_count() const { - if (dirty || lines_dirty) { + if (dirty || font_dirty || lines_dirty) { const_cast<Label *>(this)->_shape(); } @@ -813,13 +824,13 @@ bool Label::_set(const StringName &p_name, const Variant &p_value) { if (value == -1) { if (opentype_features.has(tag)) { opentype_features.erase(tag); - dirty = true; + font_dirty = true; update(); } } else { if (!opentype_features.has(tag) || (int)opentype_features[tag] != value) { opentype_features[tag] = value; - dirty = true; + font_dirty = true; update(); } } @@ -915,7 +926,7 @@ void Label::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); ADD_GROUP("Locale", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom,Fill"), "set_vertical_alignment", "get_vertical_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode"); diff --git a/scene/gui/label.h b/scene/gui/label.h index 354e9c664d..0b931b3084 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -73,6 +73,7 @@ private: bool lines_dirty = true; bool dirty = true; + bool font_dirty = true; RID text_rid; Vector<RID> lines_rid; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index f7d6850a88..3aae3377bc 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -752,7 +752,7 @@ void LineEdit::_notification(int p_what) { // Draw placeholder color. if (using_placeholder) { - font_color.a *= placeholder_alpha; + font_color = get_theme_color(SNAME("font_placeholder_color")); } bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; @@ -1476,15 +1476,6 @@ String LineEdit::get_placeholder() const { return placeholder; } -void LineEdit::set_placeholder_alpha(float p_alpha) { - placeholder_alpha = p_alpha; - update(); -} - -float LineEdit::get_placeholder_alpha() const { - return placeholder_alpha; -} - void LineEdit::set_caret_column(int p_column) { if (p_column > (int)text.length()) { p_column = text.length(); @@ -2245,8 +2236,6 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &LineEdit::get_structured_text_bidi_override_options); ClassDB::bind_method(D_METHOD("set_placeholder", "text"), &LineEdit::set_placeholder); ClassDB::bind_method(D_METHOD("get_placeholder"), &LineEdit::get_placeholder); - ClassDB::bind_method(D_METHOD("set_placeholder_alpha", "alpha"), &LineEdit::set_placeholder_alpha); - ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha); ClassDB::bind_method(D_METHOD("set_caret_column", "position"), &LineEdit::set_caret_column); ClassDB::bind_method(D_METHOD("get_caret_column"), &LineEdit::get_caret_column); ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset); @@ -2328,6 +2317,7 @@ void LineEdit::_bind_methods() { BIND_ENUM_CONSTANT(MENU_MAX); ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_length", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_max_length", "get_max_length"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); @@ -2344,14 +2334,11 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars"); ADD_GROUP("Structured Text", "structured_text_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options"); - ADD_GROUP("Placeholder", "placeholder_"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha"); ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed"); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 0c313f71c2..1519c09d73 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -82,7 +82,6 @@ private: String placeholder; String placeholder_translated; String secret_character = "*"; - float placeholder_alpha = 0.6; String ime_text; Point2 ime_selection; @@ -262,9 +261,6 @@ public: void set_placeholder(String p_text); String get_placeholder() const; - void set_placeholder_alpha(float p_alpha); - float get_placeholder_alpha() const; - void set_caret_column(int p_column); int get_caret_column() const; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 67ffa2c7ed..0ff05faf85 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -308,7 +308,7 @@ void LinkButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::INT, "underline", PROPERTY_HINT_ENUM, "Always,On Hover,Never"), "set_underline_mode", "get_underline_mode"); ADD_GROUP("Structured Text", "structured_text_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override"); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index f7805136f9..a985a9d031 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -98,7 +98,13 @@ void MenuButton::pressed() { popup->set_position(gp); popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size)); - popup->take_mouse_focus(); + // If not triggered by the mouse, start the popup with its first item selected. + if (popup->get_item_count() > 0 && + ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) || + (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) { + popup->set_current_index(0); + } + popup->popup(); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 90bb316448..9984ab240a 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -32,6 +32,8 @@ #include "core/string/print_string.h" +static const int NONE_SELECTED = -1; + Size2 OptionButton::get_minimum_size() const { Size2 minsize = Button::get_minimum_size(); @@ -119,7 +121,7 @@ bool OptionButton::_set(const StringName &p_name, const Variant &p_value) { int idx = components[1].get_slice("_", 1).to_int(); if (idx == current) { // Force refreshing currently displayed item. - current = -1; + current = NONE_SELECTED; _select(idx, false); } @@ -154,7 +156,7 @@ void OptionButton::_get_property_list(List<PropertyInfo> *p_list) const { pi.usage &= ~(!popup->is_item_checked(i) ? PROPERTY_USAGE_STORAGE : 0); p_list->push_back(pi); - pi = PropertyInfo(Variant::INT, vformat("popup/item_%d/id", i), PROPERTY_HINT_RANGE, "1,10,1,or_greater"); + pi = PropertyInfo(Variant::INT, vformat("popup/item_%d/id", i), PROPERTY_HINT_RANGE, "0,10,1,or_greater"); p_list->push_back(pi); pi = PropertyInfo(Variant::BOOL, vformat("popup/item_%d/disabled", i)); @@ -179,7 +181,14 @@ void OptionButton::pressed() { Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); popup->set_size(Size2(size.width, 0)); - popup->set_current_index(current); + + // If not triggered by the mouse, start the popup with the checked item selected. + if (popup->get_item_count() > 0 && + ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) || + (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) { + popup->set_current_index(current > -1 ? current : 0); + } + popup->popup(); } @@ -234,6 +243,10 @@ Ref<Texture2D> OptionButton::get_item_icon(int p_idx) const { } int OptionButton::get_item_id(int p_idx) const { + if (p_idx == NONE_SELECTED) { + return NONE_SELECTED; + } + return popup->get_item_id(p_idx); } @@ -266,26 +279,33 @@ void OptionButton::add_separator() { void OptionButton::clear() { popup->clear(); set_text(""); - current = -1; + current = NONE_SELECTED; } void OptionButton::_select(int p_which, bool p_emit) { - if (p_which < 0) { - return; - } if (p_which == current) { return; } - ERR_FAIL_INDEX(p_which, popup->get_item_count()); + if (p_which == NONE_SELECTED) { + for (int i = 0; i < popup->get_item_count(); i++) { + popup->set_item_checked(i, false); + } - for (int i = 0; i < popup->get_item_count(); i++) { - popup->set_item_checked(i, i == p_which); - } + current = NONE_SELECTED; + set_text(""); + set_icon(NULL); + } else { + ERR_FAIL_INDEX(p_which, popup->get_item_count()); - current = p_which; - set_text(popup->get_item_text(current)); - set_icon(popup->get_item_icon(current)); + for (int i = 0; i < popup->get_item_count(); i++) { + popup->set_item_checked(i, i == p_which); + } + + current = p_which; + set_text(popup->get_item_text(current)); + set_icon(popup->get_item_icon(current)); + } if (is_inside_tree() && p_emit) { emit_signal(SNAME("item_selected"), current); @@ -293,7 +313,7 @@ void OptionButton::_select(int p_which, bool p_emit) { } void OptionButton::_select_int(int p_which) { - if (p_which < 0 || p_which >= popup->get_item_count()) { + if (p_which < NONE_SELECTED || p_which >= popup->get_item_count()) { return; } _select(p_which, false); @@ -308,10 +328,6 @@ int OptionButton::get_selected() const { } int OptionButton::get_selected_id() const { - int idx = get_selected(); - if (idx < 0) { - return 0; - } return get_item_id(current); } @@ -325,6 +341,9 @@ Variant OptionButton::get_selected_metadata() const { void OptionButton::remove_item(int p_idx) { popup->remove_item(p_idx); + if (current == p_idx) { + _select(NONE_SELECTED); + } } PopupMenu *OptionButton::get_popup() const { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index d7139d0140..4798019720 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -67,7 +67,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { size.width += items[i].h_ofs; - if (items[i].checkable_type) { + if (items[i].checkable_type && !items[i].separator) { has_check = true; } @@ -111,7 +111,7 @@ int PopupMenu::_get_item_height(int p_item) const { ERR_FAIL_COND_V(p_item < 0, 0); int icon_height = items[p_item].get_icon_size().height; - if (items[p_item].checkable_type) { + if (items[p_item].checkable_type && !items[p_item].separator) { icon_height = MAX(icon_height, MAX(get_theme_icon(SNAME("checked"))->get_height(), get_theme_icon(SNAME("radio_checked"))->get_height())); } @@ -192,7 +192,7 @@ void PopupMenu::_activate_submenu(int p_over) { Popup *submenu_popup = Object::cast_to<Popup>(n); ERR_FAIL_COND_MSG(!submenu_popup, "Item subnode is not a Popup: " + items[p_over].submenu + "."); if (submenu_popup->is_visible()) { - return; //already visible! + return; // Already visible. } Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); @@ -223,24 +223,33 @@ void PopupMenu::_activate_submenu(int p_over) { submenu_popup->set_close_on_parent_focus(false); submenu_popup->set_position(submenu_pos); submenu_popup->set_as_minsize(); // Shrink the popup size to its contents. - submenu_popup->popup(); - // Set autohide areas PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup); - if (submenu_pum) { - submenu_pum->take_mouse_focus(); - // Make the position of the parent popup relative to submenu popup - this_rect.position = this_rect.position - submenu_pum->get_position(); - - // Autohide area above the submenu item - submenu_pum->clear_autohide_areas(); - submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2)); - - // If there is an area below the submenu item, add an autohide area there. - if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) { - int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height; - submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from)); - } + if (!submenu_pum) { + submenu_popup->popup(); + return; + } + + // If not triggered by the mouse, start the popup with its first item selected. + if (submenu_pum->get_item_count() > 0 && Input::get_singleton()->is_action_just_pressed("ui_accept")) { + submenu_pum->set_current_index(0); + } + + submenu_pum->popup(); + + // Set autohide areas. + + // Make the position of the parent popup relative to submenu popup. + this_rect.position = this_rect.position - submenu_pum->get_position(); + + // Autohide area above the submenu item. + submenu_pum->clear_autohide_areas(); + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2)); + + // If there is an area below the submenu item, add an autohide area there. + if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) { + int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height; + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from)); } } @@ -486,7 +495,7 @@ void PopupMenu::_draw_items() { bool rtl = control->is_layout_rtl(); Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); Ref<StyleBox> hover = get_theme_stylebox(SNAME("hover")); - // In Item::checkable_type enum order (less the non-checkable member) + // In Item::checkable_type enum order (less the non-checkable member). Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")) }; Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")) }; Ref<Texture2D> submenu; @@ -515,6 +524,10 @@ void PopupMenu::_draw_items() { float icon_ofs = 0.0; bool has_check = false; for (int i = 0; i < items.size(); i++) { + if (items[i].separator) { + continue; + } + icon_ofs = MAX(items[i].get_icon_size().width, icon_ofs); if (items[i].checkable_type) { @@ -558,29 +571,33 @@ void PopupMenu::_draw_items() { if (items[i].separator) { int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); - if (!text.is_empty()) { - int text_size = items[i].text_buf->get_size().width; - int text_center = display_width / 2; - int text_left = text_center - text_size / 2; - int text_right = text_center + text_size / 2; - if (text_left > item_ofs.x) { - labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, text_left - item_ofs.x), sep_h))); + if (!text.is_empty() || !items[i].icon.is_null()) { + int content_size = items[i].text_buf->get_size().width; + if (!items[i].icon.is_null()) { + content_size += icon_size.width + hseparation; } - if (text_right < display_width) { - labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - text_right), sep_h))); + + int content_center = display_width / 2; + int content_left = content_center - content_size / 2; + int content_right = content_center + content_size / 2; + if (content_left > item_ofs.x) { + labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h))); + } + if (content_right < display_width) { + labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h))); } } else { separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h))); } } - Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1); // For non-separator items, add some padding for the content. item_ofs.x += item_start_padding; // Checkboxes - if (items[i].checkable_type) { + if (items[i].checkable_type && !items[i].separator) { Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); if (rtl) { icon->draw(ci, Size2(control->get_size().width - item_ofs.x - icon->get_width(), item_ofs.y) + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color); @@ -589,16 +606,28 @@ void PopupMenu::_draw_items() { } } + int separator_ofs = (display_width - items[i].text_buf->get_size().width) / 2; + // Icon if (!items[i].icon.is_null()) { - if (rtl) { - items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - check_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + if (items[i].separator) { + separator_ofs -= (icon_size.width + hseparation) / 2; + + if (rtl) { + items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - separator_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + } else { + items[i].icon->draw(ci, item_ofs + Size2(separator_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + } } else { - items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + if (rtl) { + items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - check_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + } else { + items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); + } } } - // Submenu arrow on right hand side + // Submenu arrow on right hand side. if (!items[i].submenu.is_empty()) { if (rtl) { submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); @@ -612,8 +641,11 @@ void PopupMenu::_draw_items() { int outline_size = get_theme_constant(SNAME("outline_size")); if (items[i].separator) { if (!text.is_empty()) { - int center = (display_width - items[i].text_buf->get_size().width) / 2; - Vector2 text_pos = Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + Vector2 text_pos = Point2(separator_ofs, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + if (!items[i].icon.is_null()) { + text_pos.x = rtl ? text_pos.x - (icon_size.width + hseparation) : text_pos.x + icon_size.width + hseparation; + } + if (outline_size > 0 && font_outline_color.a > 0) { items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); } @@ -650,7 +682,7 @@ void PopupMenu::_draw_items() { items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color); } - // Cache the item vertical offset from the first item and the height + // Cache the item vertical offset from the first item and the height. items.write[i]._ofs_cache = ofs.y; items.write[i]._height_cache = h; @@ -810,7 +842,7 @@ void PopupMenu::_notification(int p_what) { #define ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel) \ item.text = p_label; \ item.xl_text = atr(p_label); \ - item.id = p_id == -1 ? items.size() : p_id; \ + item.id = p_id == -1 ? items.size() - 1 : p_id; \ item.accel = p_accel; void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) { @@ -892,7 +924,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int _ref_shortcut(p_shortcut); \ item.text = p_shortcut->get_name(); \ item.xl_text = atr(item.text); \ - item.id = p_id == -1 ? items.size() : p_id; \ + item.id = p_id == -1 ? items.size() - 1 : p_id; \ item.shortcut = p_shortcut; \ item.shortcut_is_global = p_global; @@ -961,7 +993,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, Item item; item.text = p_label; item.xl_text = atr(p_label); - item.id = p_id == -1 ? items.size() : p_id; + item.id = p_id == -1 ? items.size() - 1 : p_id; item.submenu = p_submenu; items.push_back(item); _shape_item(items.size() - 1); @@ -1403,12 +1435,12 @@ void PopupMenu::activate_item(int p_item) { need_hide = false; } - emit_signal(SNAME("id_pressed"), id); - emit_signal(SNAME("index_pressed"), p_item); - if (need_hide) { hide(); } + + emit_signal(SNAME("id_pressed"), id); + emit_signal(SNAME("index_pressed"), p_item); } void PopupMenu::remove_item(int p_idx) { @@ -1747,6 +1779,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_tooltip", "index"), &PopupMenu::get_item_tooltip); ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut); + ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index); ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index); ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count); ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 863555120d..4865b9770e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -205,6 +205,49 @@ String RichTextLabel::_letters(int p_num, bool p_capitalize) const { return s; } +void RichTextLabel::_update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size) { + ERR_FAIL_COND(p_frame == nullptr); + ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); + + Line &l = p_frame->lines.write[p_line]; + + RID t = l.text_buf->get_rid(); + int spans = TS->shaped_get_span_count(t); + for (int i = 0; i < spans; i++) { + ItemText *it = (ItemText *)(uint64_t)TS->shaped_get_span_meta(t, i); + if (it) { + Ref<Font> font = _find_font(it); + if (font.is_null()) { + font = p_base_font; + } + int font_size = _find_font_size(it); + if (font_size == -1) { + font_size = p_base_font_size; + } + Dictionary font_ftr = _find_font_features(it); + TS->shaped_set_span_update_font(t, i, font->get_rids(), font_size, font_ftr); + } + } + + Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; + for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) { + switch (it->type) { + case ITEM_TABLE: { + ItemTable *table = static_cast<ItemTable *>(it); + for (Item *E : table->subitems) { + ERR_CONTINUE(E->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E); + for (int i = 0; i < frame->lines.size(); i++) { + _update_line_font(frame, i, p_base_font, p_base_font_size); + } + } + } break; + default: + break; + } + } +} + void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width) { ERR_FAIL_COND(p_frame == nullptr); ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); @@ -238,7 +281,8 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> ERR_CONTINUE(E->type != ITEM_FRAME); // Children should all be frames. ItemFrame *frame = static_cast<ItemFrame *>(E); for (int i = 0; i < frame->lines.size(); i++) { - _resize_line(frame, i, p_base_font, p_base_font_size, 1); + int w = _find_margin(frame->lines[i].from, p_base_font, p_base_font_size) + 1; + _resize_line(frame, i, p_base_font, p_base_font_size, w); } idx++; } @@ -264,7 +308,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> // Assign actual widths. for (int i = 0; i < col_count; i++) { table->columns.write[i].width = table->columns[i].min_width; - if (table->columns[i].expand && total_ratio > 0) { + if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) { table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; } table->total_width += table->columns[i].width + hseparation; @@ -325,13 +369,16 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x)); if (i > 0) { - frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y; + frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y + frame->lines[i - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } else { frame->lines.write[i].offset.y = 0; } frame->lines.write[i].offset += offset; - float h = frame->lines[i].text_buf->get_size().y; + float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation")); + if (i > 0) { + h += get_theme_constant(SNAME("line_separation")); + } if (frame->min_size_over.y > 0) { h = MAX(h, frame->min_size_over.y); } @@ -362,7 +409,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> } if (p_line > 0) { - l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + p_frame->lines[p_line - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } else { l.offset.y = 0; } @@ -374,9 +421,24 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> Line &l = p_frame->lines.write[p_line]; + uint16_t autowrap_flags = TextServer::BREAK_MANDATORY; + switch (autowrap_mode) { + case AUTOWRAP_WORD_SMART: + autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY; + break; + case AUTOWRAP_WORD: + autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY; + break; + case AUTOWRAP_ARBITRARY: + autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY; + break; + case AUTOWRAP_OFF: + break; + } + // Clear cache. l.text_buf->clear(); - l.text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_TRIM_EDGE_SPACES); + l.text_buf->set_flags(autowrap_flags | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_TRIM_EDGE_SPACES); l.char_offset = *r_char_offset; l.char_count = 0; @@ -445,7 +507,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> } remaining_characters -= tx.length(); - l.text_buf->add_string(tx, font, font_size, font_ftr, lang); + l.text_buf->add_string(tx, font, font_size, font_ftr, lang, (uint64_t)it); text += tx; l.char_count += tx.length(); } break; @@ -479,7 +541,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> int column = idx % col_count; for (int i = 0; i < frame->lines.size(); i++) { int char_offset = l.char_offset + l.char_count; - _shape_line(frame, i, p_base_font, p_base_font_size, 1, &char_offset); + int w = _find_margin(frame->lines[i].from, p_base_font, p_base_font_size) + 1; + _shape_line(frame, i, p_base_font, p_base_font_size, w, &char_offset); int cell_ch = (char_offset - (l.char_offset + l.char_count)); l.char_count += cell_ch; t_char_count += cell_ch; @@ -509,7 +572,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> // Assign actual widths. for (int i = 0; i < col_count; i++) { table->columns.write[i].width = table->columns[i].min_width; - if (table->columns[i].expand && total_ratio > 0) { + if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) { table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; } table->total_width += table->columns[i].width + hseparation; @@ -570,13 +633,16 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> table->columns.write[column].width = MAX(table->columns.write[column].width, ceil(frame->lines[i].text_buf->get_size().x)); if (i > 0) { - frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y; + frame->lines.write[i].offset.y = frame->lines[i - 1].offset.y + frame->lines[i - 1].text_buf->get_size().y + frame->lines[i - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } else { frame->lines.write[i].offset.y = 0; } frame->lines.write[i].offset += offset; - float h = frame->lines[i].text_buf->get_size().y; + float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation")); + if (i > 0) { + h += get_theme_constant(SNAME("line_separation")); + } if (frame->min_size_over.y > 0) { h = MAX(h, frame->min_size_over.y); } @@ -615,18 +681,19 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> *r_char_offset = l.char_offset + l.char_count; if (p_line > 0) { - l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + p_frame->lines[p_line - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } else { l.offset.y = 0; } } int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) { - Vector2 off; - ERR_FAIL_COND_V(p_frame == nullptr, 0); ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), 0); + Vector2 off; + int line_spacing = get_theme_constant(SNAME("line_separation")); + Line &l = p_frame->lines.write[p_line]; Item *it_from = l.from; @@ -712,6 +779,10 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o Size2 ctrl_size = get_size(); // Draw text. for (int line = 0; line < l.text_buf->get_line_count(); line++) { + if (line > 0) { + off.y += line_spacing; + } + RID rid = l.text_buf->get_line_rid(line); if (p_ofs.y + off.y >= ctrl_size.height) { break; @@ -1177,7 +1248,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item //TODO, change to binary search ? while (from_line < main->lines.size()) { - if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y >= vofs) { + if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")) >= vofs) { break; } from_line++; @@ -1190,7 +1261,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); while (ofs.y < size.height && from_line < main->lines.size()) { _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); - ofs.y += main->lines[from_line].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); + ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { if (r_outside != nullptr) { *r_outside = false; @@ -1309,7 +1380,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (rect.has_point(p_click) && !table_hit) { char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); } - off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom(); + off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom() + get_theme_constant(SNAME("line_separation")); } if (char_pos >= 0) { @@ -1435,7 +1506,10 @@ void RichTextLabel::_notification(int p_what) { update(); } break; - case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_THEME_CHANGED: { + main->first_invalid_font_line = 0; //invalidate ALL + update(); + } break; case NOTIFICATION_ENTER_TREE: { if (!text.is_empty()) { set_text(text); @@ -1473,7 +1547,7 @@ void RichTextLabel::_notification(int p_what) { //TODO, change to binary search ? while (from_line < main->lines.size()) { - if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y >= vofs) { + if (main->lines[from_line].offset.y + main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")) >= vofs) { break; } from_line++; @@ -1499,7 +1573,7 @@ void RichTextLabel::_notification(int p_what) { while (ofs.y < size.height && from_line < main->lines.size()) { visible_paragraph_count++; visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, shadow_outline_size, shadow_ofs, processed_glyphs); - ofs.y += main->lines[from_line].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); + ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); from_line++; } } break; @@ -1532,6 +1606,10 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const return get_default_cursor_shape(); //invalid } + if (main->first_invalid_font_line < main->lines.size()) { + return get_default_cursor_shape(); //invalid + } + if (main->first_resized_line < main->lines.size()) { return get_default_cursor_shape(); //invalid } @@ -1556,6 +1634,9 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (main->first_invalid_line < main->lines.size()) { return; } + if (main->first_invalid_font_line < main->lines.size()) { + return; + } if (main->first_resized_line < main->lines.size()) { return; } @@ -1719,6 +1800,9 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (main->first_invalid_line < main->lines.size()) { return; } + if (main->first_invalid_font_line < main->lines.size()) { + return; + } if (main->first_resized_line < main->lines.size()) { return; } @@ -2171,27 +2255,32 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) { void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { if (p_frame->first_invalid_line == p_frame->lines.size()) { + Ref<Font> base_font = get_theme_font(SNAME("normal_font")); + int base_font_size = get_theme_font_size(SNAME("normal_font_size")); + + // Update fonts. + if (p_frame->first_invalid_font_line != p_frame->lines.size()) { + for (int i = p_frame->first_invalid_font_line; i < p_frame->lines.size(); i++) { + _update_line_font(p_frame, i, base_font, base_font_size); + } + p_frame->first_resized_line = p_frame->first_invalid_font_line; + p_frame->first_invalid_font_line = p_frame->lines.size(); + } + if (p_frame->first_resized_line == p_frame->lines.size()) { return; } // Resize lines without reshaping. - Size2 size = get_size(); - if (fixed_width != -1) { - size.width = fixed_width; - } Rect2 text_rect = _get_text_rect(); - Ref<Font> base_font = get_theme_font(SNAME("normal_font")); - int base_font_size = get_theme_font_size(SNAME("normal_font_size")); - for (int i = p_frame->first_resized_line; i < p_frame->lines.size(); i++) { _resize_line(p_frame, i, base_font, base_font_size, text_rect.get_size().width - scroll_w); } int total_height = 0; if (p_frame->lines.size()) { - total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y; + total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } p_frame->first_resized_line = p_frame->lines.size(); @@ -2200,7 +2289,7 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { vscroll->set_max(total_height); vscroll->set_page(text_rect.size.height); if (scroll_follow && scroll_following) { - vscroll->set_value(total_height - size.height); + vscroll->set_value(total_height); } updating_scroll = false; @@ -2211,10 +2300,6 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { } // Shape invalid lines. - Size2 size = get_size(); - if (fixed_width != -1) { - size.width = fixed_width; - } Rect2 text_rect = _get_text_rect(); Ref<Font> base_font = get_theme_font(SNAME("normal_font")); @@ -2227,17 +2312,18 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { int total_height = 0; if (p_frame->lines.size()) { - total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y; + total_height = p_frame->lines[p_frame->lines.size() - 1].offset.y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_size().y + p_frame->lines[p_frame->lines.size() - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } p_frame->first_invalid_line = p_frame->lines.size(); p_frame->first_resized_line = p_frame->lines.size(); + p_frame->first_invalid_font_line = p_frame->lines.size(); updating_scroll = true; vscroll->set_max(total_height); vscroll->set_page(text_rect.size.height); if (scroll_follow && scroll_following) { - vscroll->set_value(total_height - size.height); + vscroll->set_value(total_height); } updating_scroll = false; @@ -3141,7 +3227,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { indent_level++; push_list(indent_level, LIST_NUMBERS, false); pos = brk_end + 1; - tag_stack.push_front(tag); + tag_stack.push_front("ol"); } else if (tag == "ol type=a") { indent_level++; push_list(indent_level, LIST_LETTERS, false); @@ -4006,6 +4092,19 @@ String RichTextLabel::get_language() const { return language; } +void RichTextLabel::set_autowrap_mode(RichTextLabel::AutowrapMode p_mode) { + if (autowrap_mode != p_mode) { + autowrap_mode = p_mode; + main->first_invalid_line = 0; //invalidate ALL + _validate_line_caches(main); + update(); + } +} + +RichTextLabel::AutowrapMode RichTextLabel::get_autowrap_mode() const { + return autowrap_mode; +} + void RichTextLabel::set_percent_visible(float p_percent) { if (percent_visible != p_percent) { if (p_percent < 0 || p_percent >= 1) { @@ -4053,7 +4152,7 @@ void RichTextLabel::install_effect(const Variant effect) { int RichTextLabel::get_content_height() const { int total_height = 0; if (main->lines.size()) { - total_height = main->lines[main->lines.size() - 1].offset.y + main->lines[main->lines.size() - 1].text_buf->get_size().y; + total_height = main->lines[main->lines.size() - 1].offset.y + main->lines[main->lines.size() - 1].text_buf->get_size().y + main->lines[main->lines.size() - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); } return total_height; } @@ -4117,6 +4216,9 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_language", "language"), &RichTextLabel::set_language); ClassDB::bind_method(D_METHOD("get_language"), &RichTextLabel::get_language); + ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &RichTextLabel::set_autowrap_mode); + ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &RichTextLabel::get_autowrap_mode); + ClassDB::bind_method(D_METHOD("set_meta_underline", "enable"), &RichTextLabel::set_meta_underline); ClassDB::bind_method(D_METHOD("is_meta_underlined"), &RichTextLabel::is_meta_underlined); @@ -4207,7 +4309,9 @@ void RichTextLabel::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode"); ADD_GROUP("Structured Text", "structured_text_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override"); @@ -4217,6 +4321,11 @@ void RichTextLabel::_bind_methods() { ADD_SIGNAL(MethodInfo("meta_hover_started", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); ADD_SIGNAL(MethodInfo("meta_hover_ended", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); + BIND_ENUM_CONSTANT(AUTOWRAP_OFF); + BIND_ENUM_CONSTANT(AUTOWRAP_ARBITRARY); + BIND_ENUM_CONSTANT(AUTOWRAP_WORD); + BIND_ENUM_CONSTANT(AUTOWRAP_WORD_SMART); + BIND_ENUM_CONSTANT(LIST_NUMBERS); BIND_ENUM_CONSTANT(LIST_LETTERS); BIND_ENUM_CONSTANT(LIST_ROMAN); @@ -4340,7 +4449,7 @@ Size2 RichTextLabel::get_minimum_size() const { size.x += fixed_width; } - if (fixed_width != -1 || fit_content_height) { + if (fit_content_height) { const_cast<RichTextLabel *>(this)->_validate_line_caches(main); size.y += get_content_height(); } @@ -4489,6 +4598,7 @@ RichTextLabel::RichTextLabel() { main->lines.write[0].from = main; main->first_invalid_line = 0; main->first_resized_line = 0; + main->first_invalid_font_line = 0; current_frame = main; vscroll = memnew(VScrollBar); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 70467e7e7c..e79244f2e4 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -39,6 +39,13 @@ class RichTextLabel : public Control { GDCLASS(RichTextLabel, Control); public: + enum AutowrapMode { + AUTOWRAP_OFF, + AUTOWRAP_ARBITRARY, + AUTOWRAP_WORD, + AUTOWRAP_WORD_SMART + }; + enum ListType { LIST_NUMBERS, LIST_LETTERS, @@ -129,6 +136,7 @@ private: Vector<Line> lines; int first_invalid_line = 0; + int first_invalid_font_line = 0; int first_resized_line = 0; ItemFrame *parent_frame = nullptr; @@ -345,6 +353,8 @@ private: VScrollBar *vscroll = nullptr; + AutowrapMode autowrap_mode = AUTOWRAP_WORD_SMART; + bool scroll_visible = false; bool scroll_follow = false; bool scroll_following = false; @@ -414,6 +424,7 @@ private: void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset); void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width); + void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size); int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs); float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr); @@ -572,6 +583,9 @@ public: void set_language(const String &p_language); String get_language() const; + void set_autowrap_mode(AutowrapMode p_mode); + AutowrapMode get_autowrap_mode() const; + void set_structured_text_bidi_override(Control::StructuredTextParser p_parser); Control::StructuredTextParser get_structured_text_bidi_override() const; @@ -601,6 +615,7 @@ public: ~RichTextLabel(); }; +VARIANT_ENUM_CAST(RichTextLabel::AutowrapMode); VARIANT_ENUM_CAST(RichTextLabel::ListType); VARIANT_ENUM_CAST(RichTextLabel::ItemType); VARIANT_ENUM_CAST(RichTextLabel::VisibleCharactersBehavior); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 9da030f0a2..5a551ec5a5 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -38,48 +38,71 @@ #include "scene/gui/texture_rect.h" Size2 TabBar::get_minimum_size() const { + Size2 ms; + + if (tabs.is_empty()) { + return ms; + } + Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); + Ref<StyleBox> button_highlight = get_theme_stylebox(SNAME("button_highlight")); + Ref<Texture2D> close = get_theme_icon(SNAME("close")); + int hseparation = get_theme_constant(SNAME("hseparation")); int y_margin = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height); - Size2 ms(0, 0); - for (int i = 0; i < tabs.size(); i++) { - Ref<Texture2D> tex = tabs[i].icon; - if (tex.is_valid()) { - ms.height = MAX(ms.height, tex->get_size().height); - if (!tabs[i].text.is_empty()) { - ms.width += get_theme_constant(SNAME("hseparation")); - } + if (tabs[i].hidden) { + continue; } - ms.width += Math::ceil(tabs[i].text_buf->get_size().x); - ms.height = MAX(ms.height, tabs[i].text_buf->get_size().y + y_margin); + int ofs = ms.width; + Ref<StyleBox> style; if (tabs[i].disabled) { - ms.width += tab_disabled->get_minimum_size().width; + style = tab_disabled; } else if (current == i) { - ms.width += tab_selected->get_minimum_size().width; + style = tab_selected; } else { - ms.width += tab_unselected->get_minimum_size().width; + style = tab_unselected; + } + ms.width += style->get_minimum_size().width; + + Ref<Texture2D> tex = tabs[i].icon; + if (tex.is_valid()) { + ms.height = MAX(ms.height, tex->get_size().height); + ms.width += tex->get_size().width + hseparation; } + if (!tabs[i].text.is_empty()) { + ms.width += tabs[i].size_text + hseparation; + } + ms.height = MAX(ms.height, tabs[i].text_buf->get_size().y + y_margin); + + bool close_visible = cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current); + if (tabs[i].right_button.is_valid()) { Ref<Texture2D> rb = tabs[i].right_button; - Size2 bms = rb->get_size(); - bms.width += get_theme_constant(SNAME("hseparation")); - ms.width += bms.width; - ms.height = MAX(bms.height + tab_unselected->get_minimum_size().height, ms.height); + + if (close_visible) { + ms.width += button_highlight->get_minimum_size().width + rb->get_width(); + } else { + ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation; + } + + ms.height = MAX(rb->get_height() + style->get_minimum_size().height, ms.height); + } + + if (close_visible) { + ms.width += button_highlight->get_margin(SIDE_LEFT) + close->get_width() + hseparation; + + ms.height = MAX(close->get_height() + style->get_minimum_size().height, ms.height); } - if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { - Ref<Texture2D> cb = get_theme_icon(SNAME("close")); - Size2 bms = cb->get_size(); - bms.width += get_theme_constant(SNAME("hseparation")); - ms.width += bms.width; - ms.height = MAX(bms.height + tab_unselected->get_minimum_size().height, ms.height); + if (ms.width - ofs > style->get_minimum_size().width) { + ms.width -= hseparation; } } @@ -165,8 +188,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (rb_hover != -1) { - // Right mouse button clicked. - emit_signal(SNAME("tab_rmb_clicked"), rb_hover); + emit_signal(SNAME("tab_button_pressed"), rb_hover); } rb_pressing = false; @@ -175,7 +197,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (cb_hover != -1) { - // Close button pressed. emit_signal(SNAME("tab_close_pressed"), cb_hover); } @@ -184,7 +205,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || (select_with_rmb && mb->get_button_index() == MouseButton::RIGHT))) { - // Clicks. Point2 pos = mb->get_position(); if (buttons_visible) { @@ -234,6 +254,10 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { int found = -1; for (int i = offset; i <= max_drawn_tab; i++) { + if (tabs[i].hidden) { + continue; + } + if (tabs[i].rb_rect.has_point(pos)) { rb_pressing = true; update(); @@ -256,6 +280,12 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { if (found != -1) { set_current_tab(found); + + if (mb->get_button_index() == MouseButton::RIGHT) { + // Right mouse button clicked. + emit_signal(SNAME("tab_rmb_clicked"), found); + } + emit_signal(SNAME("tab_clicked"), found); } } @@ -275,13 +305,12 @@ void TabBar::_shape(int p_tab) { tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction); } - tabs.write[p_tab].text_buf->add_string(tabs.write[p_tab].xl_text, font, font_size, tabs[p_tab].opentype_features, !tabs[p_tab].language.is_empty() ? tabs[p_tab].language : TranslationServer::get_singleton()->get_tool_locale()); + tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, font, font_size, tabs[p_tab].opentype_features, !tabs[p_tab].language.is_empty() ? tabs[p_tab].language : TranslationServer::get_singleton()->get_tool_locale()); } void TabBar::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - _update_cache(); update(); } break; case NOTIFICATION_THEME_CHANGED: @@ -289,14 +318,19 @@ void TabBar::_notification(int p_what) { for (int i = 0; i < tabs.size(); ++i) { _shape(i); } - _update_cache(); - update_minimum_size(); - update(); - } break; + + [[fallthrough]]; + } case NOTIFICATION_RESIZED: { + int ofs_old = offset; + int max_old = max_drawn_tab; + _update_cache(); _ensure_no_over_offset(); - ensure_tab_visible(current); + + if (scroll_to_selected && (offset != ofs_old || max_drawn_tab != max_old)) { + ensure_tab_visible(current); + } } break; case NOTIFICATION_DRAW: { if (tabs.is_empty()) { @@ -322,6 +356,10 @@ void TabBar::_notification(int p_what) { // Draw unselected tabs in the back. for (int i = offset; i <= max_drawn_tab; i++) { + if (tabs[i].hidden) { + continue; + } + if (i != current) { Ref<StyleBox> sb; Color col; @@ -344,14 +382,14 @@ void TabBar::_notification(int p_what) { } // Draw selected tab in the front, but only if it's visible. - if (current >= offset && current <= max_drawn_tab) { + if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) { Ref<StyleBox> sb = tabs[current].disabled ? tab_disabled : tab_selected; float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache; _draw_tab(sb, font_selected_color, current, x); } - if (offset > 0 || missing_right) { + if (buttons_visible) { int vofs = (get_size().height - incr->get_size().height) / 2; if (rtl) { @@ -386,47 +424,52 @@ void TabBar::_notification(int p_what) { void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) { RID ci = get_canvas_item(); + bool rtl = is_layout_rtl(); Color font_outline_color = get_theme_color(SNAME("font_outline_color")); int outline_size = get_theme_constant(SNAME("outline_size")); + int hseparation = get_theme_constant(SNAME("hseparation")); - Tab tab = tabs[p_index]; - - Rect2 sb_rect = Rect2(p_x, 0, tab.size_cache, get_size().height); + Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height); p_tab_style->draw(ci, sb_rect); - p_x += p_tab_style->get_margin(SIDE_LEFT); + p_x += rtl ? tabs[p_index].size_cache - p_tab_style->get_margin(SIDE_LEFT) : p_tab_style->get_margin(SIDE_LEFT); Size2i sb_ms = p_tab_style->get_minimum_size(); - Ref<Texture2D> icon = tab.icon; + // Draw the icon. + Ref<Texture2D> icon = tabs[p_index].icon; if (icon.is_valid()) { - icon->draw(ci, Point2i(p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); + icon->draw(ci, Point2i(rtl ? p_x - icon->get_width() : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); - if (!tab.text.is_empty()) { - p_x += icon->get_width() + get_theme_constant(SNAME("hseparation")); - } + p_x = rtl ? p_x - icon->get_width() - hseparation : p_x + icon->get_width() + hseparation; } - Vector2 text_pos = Point2i(p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tab.text_buf->get_size().y) / 2); - if (outline_size > 0 && font_outline_color.a > 0) { - tab.text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); - } - tab.text_buf->draw(ci, text_pos, p_font_color); + // Draw the text. + if (!tabs[p_index].text.is_empty()) { + Point2i text_pos = Point2i(rtl ? p_x - tabs[p_index].size_text : p_x, + p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[p_index].text_buf->get_size().y) / 2); - p_x += tab.size_text; + if (outline_size > 0 && font_outline_color.a > 0) { + tabs[p_index].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + tabs[p_index].text_buf->draw(ci, text_pos, p_font_color); - if (tab.right_button.is_valid()) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("close_bg_highlight")); - Ref<Texture2D> rb = tab.right_button; + p_x = rtl ? p_x - tabs[p_index].size_text - hseparation : p_x + tabs[p_index].size_text + hseparation; + } - p_x += get_theme_constant(SNAME("hseparation")); + // Draw and calculate rect of the right button. + if (tabs[p_index].right_button.is_valid()) { + Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight")); + Ref<Texture2D> rb = tabs[p_index].right_button; Rect2 rb_rect; rb_rect.size = style->get_minimum_size() + rb->get_size(); - rb_rect.position.x = p_x; + rb_rect.position.x = rtl ? p_x - rb_rect.size.width : p_x; rb_rect.position.y = p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - (rb_rect.size.y)) / 2; + tabs.write[p_index].rb_rect = rb_rect; + if (rb_hover == p_index) { if (rb_pressing) { get_theme_stylebox(SNAME("button_pressed"))->draw(ci, rb_rect); @@ -435,41 +478,61 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in } } - rb->draw(ci, Point2i(p_x + style->get_margin(SIDE_LEFT), rb_rect.position.y + style->get_margin(SIDE_TOP))); - p_x += rb->get_width(); - tabs.write[p_index].rb_rect = rb_rect; + rb->draw(ci, Point2i(rb_rect.position.x + style->get_margin(SIDE_LEFT), rb_rect.position.y + style->get_margin(SIDE_TOP))); + + p_x = rtl ? rb_rect.position.x : rb_rect.position.x + rb_rect.size.width; } + // Draw and calculate rect of the close button. if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_index == current)) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("close_bg_highlight")); + Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight")); Ref<Texture2D> cb = get_theme_icon(SNAME("close")); - p_x += get_theme_constant(SNAME("hseparation")); - Rect2 cb_rect; cb_rect.size = style->get_minimum_size() + cb->get_size(); - cb_rect.position.x = p_x; + cb_rect.position.x = rtl ? p_x - cb_rect.size.width : p_x; cb_rect.position.y = p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - (cb_rect.size.y)) / 2; - if (!tab.disabled && cb_hover == p_index) { + tabs.write[p_index].cb_rect = cb_rect; + + if (!tabs[p_index].disabled && cb_hover == p_index) { if (cb_pressing) { - get_theme_stylebox(SNAME("close_bg_pressed"))->draw(ci, cb_rect); + get_theme_stylebox(SNAME("button_pressed"))->draw(ci, cb_rect); } else { style->draw(ci, cb_rect); } } - cb->draw(ci, Point2i(p_x + style->get_margin(SIDE_LEFT), cb_rect.position.y + style->get_margin(SIDE_TOP))); - p_x += cb->get_width(); - tabs.write[p_index].cb_rect = cb_rect; + cb->draw(ci, Point2i(cb_rect.position.x + style->get_margin(SIDE_LEFT), cb_rect.position.y + style->get_margin(SIDE_TOP))); } } void TabBar::set_tab_count(int p_count) { + if (p_count == tabs.size()) { + return; + } + ERR_FAIL_COND(p_count < 0); tabs.resize(p_count); + + if (p_count == 0) { + offset = 0; + max_drawn_tab = 0; + current = 0; + previous = 0; + } else { + offset = MIN(offset, p_count - 1); + max_drawn_tab = MIN(max_drawn_tab, p_count - 1); + current = MIN(current, p_count - 1); + } + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); notify_property_list_changed(); } @@ -478,15 +541,26 @@ int TabBar::get_tab_count() const { } void TabBar::set_current_tab(int p_current) { - if (current == p_current) { - return; - } ERR_FAIL_INDEX(p_current, get_tab_count()); previous = current; current = p_current; + if (current == previous) { + emit_signal(SNAME("tab_selected"), current); + return; + } + // Triggered by dragging a tab from another TabBar to the selected index, to ensure that tab_changed is emitted. + if (previous == -1) { + previous = current; + } + + emit_signal(SNAME("tab_selected"), current); + _update_cache(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); emit_signal(SNAME("tab_changed"), p_current); @@ -515,8 +589,13 @@ bool TabBar::get_offset_buttons_visible() const { void TabBar::set_tab_title(int p_tab, const String &p_title) { ERR_FAIL_INDEX(p_tab, tabs.size()); tabs.write[p_tab].text = p_title; + _shape(p_tab); _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); update_minimum_size(); } @@ -529,6 +608,7 @@ String TabBar::get_tab_title(int p_tab) const { void TabBar::set_tab_text_direction(int p_tab, Control::TextDirection p_text_direction) { ERR_FAIL_INDEX(p_tab, tabs.size()); ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); + if (tabs[p_tab].text_direction != p_text_direction) { tabs.write[p_tab].text_direction = p_text_direction; _shape(p_tab); @@ -544,24 +624,38 @@ Control::TextDirection TabBar::get_tab_text_direction(int p_tab) const { void TabBar::clear_tab_opentype_features(int p_tab) { ERR_FAIL_INDEX(p_tab, tabs.size()); tabs.write[p_tab].opentype_features.clear(); + _shape(p_tab); _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); } void TabBar::set_tab_opentype_feature(int p_tab, const String &p_name, int p_value) { ERR_FAIL_INDEX(p_tab, tabs.size()); + int32_t tag = TS->name_to_tag(p_name); if (!tabs[p_tab].opentype_features.has(tag) || (int)tabs[p_tab].opentype_features[tag] != p_value) { tabs.write[p_tab].opentype_features[tag] = p_value; + _shape(p_tab); _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); } } int TabBar::get_tab_opentype_feature(int p_tab, const String &p_name) const { ERR_FAIL_INDEX_V(p_tab, tabs.size(), -1); + int32_t tag = TS->name_to_tag(p_name); if (!tabs[p_tab].opentype_features.has(tag)) { return -1; @@ -571,10 +665,17 @@ int TabBar::get_tab_opentype_feature(int p_tab, const String &p_name) const { void TabBar::set_tab_language(int p_tab, const String &p_language) { ERR_FAIL_INDEX(p_tab, tabs.size()); + if (tabs[p_tab].language != p_language) { tabs.write[p_tab].language = p_language; _shape(p_tab); + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); } } @@ -586,7 +687,12 @@ String TabBar::get_tab_language(int p_tab) const { void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_tab, tabs.size()); tabs.write[p_tab].icon = p_icon; + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); update_minimum_size(); } @@ -599,7 +705,14 @@ Ref<Texture2D> TabBar::get_tab_icon(int p_tab) const { void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { ERR_FAIL_INDEX(p_tab, tabs.size()); tabs.write[p_tab].disabled = p_disabled; + + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); } bool TabBar::is_tab_disabled(int p_tab) const { @@ -607,15 +720,38 @@ bool TabBar::is_tab_disabled(int p_tab) const { return tabs[p_tab].disabled; } -void TabBar::set_tab_right_button(int p_tab, const Ref<Texture2D> &p_right_button) { +void TabBar::set_tab_hidden(int p_tab, bool p_hidden) { + ERR_FAIL_INDEX(p_tab, tabs.size()); + tabs.write[p_tab].hidden = p_hidden; + + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } + update(); + update_minimum_size(); +} + +bool TabBar::is_tab_hidden(int p_tab) const { + ERR_FAIL_INDEX_V(p_tab, tabs.size(), false); + return tabs[p_tab].hidden; +} + +void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_tab, tabs.size()); - tabs.write[p_tab].right_button = p_right_button; + tabs.write[p_tab].right_button = p_icon; + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); update_minimum_size(); } -Ref<Texture2D> TabBar::get_tab_right_button(int p_tab) const { +Ref<Texture2D> TabBar::get_tab_button_icon(int p_tab) const { ERR_FAIL_INDEX_V(p_tab, tabs.size(), Ref<Texture2D>()); return tabs[p_tab].right_button; } @@ -626,34 +762,53 @@ void TabBar::_update_hover() { } const Point2 &pos = get_local_mouse_position(); - // test hovering to display right or close button. + // Test hovering to display right or close button. int hover_now = -1; int hover_buttons = -1; - for (int i = offset; i < tabs.size(); i++) { + for (int i = offset; i <= max_drawn_tab; i++) { + if (tabs[i].hidden) { + continue; + } + Rect2 rect = get_tab_rect(i); if (rect.has_point(pos)) { hover_now = i; } + if (tabs[i].rb_rect.has_point(pos)) { rb_hover = i; cb_hover = -1; hover_buttons = i; - break; } else if (!tabs[i].disabled && tabs[i].cb_rect.has_point(pos)) { cb_hover = i; rb_hover = -1; hover_buttons = i; + } + + if (hover_buttons != -1) { + update(); break; } } + if (hover != hover_now) { hover = hover_now; - emit_signal(SNAME("tab_hovered"), hover); + + if (hover != -1) { + emit_signal(SNAME("tab_hovered"), hover); + } } if (hover_buttons == -1) { // No hover. + int rb_hover_old = rb_hover; + int cb_hover_old = cb_hover; + rb_hover = hover_buttons; cb_hover = hover_buttons; + + if (rb_hover != rb_hover_old || cb_hover != cb_hover_old) { + update(); + } } } @@ -677,16 +832,20 @@ void TabBar::_update_cache() { int count_resize = 0; for (int i = 0; i < tabs.size(); i++) { - tabs.write[i].ofs_cache = 0; - tabs.write[i].size_cache = get_tab_width(i); tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x); tabs.write[i].text_buf->set_width(-1); - mw += tabs[i].size_cache; - if (tabs[i].size_cache <= min_width || i == current) { - size_fixed += tabs[i].size_cache; - } else { - count_resize++; + tabs.write[i].ofs_cache = 0; + tabs.write[i].size_cache = get_tab_width(i); + + if (!tabs[i].hidden) { + mw += tabs[i].size_cache; + + if (tabs[i].size_cache <= min_width || i == current) { + size_fixed += tabs[i].size_cache; + } else { + count_resize++; + } } } @@ -696,34 +855,20 @@ void TabBar::_update_cache() { } for (int i = offset; i < tabs.size(); i++) { - Ref<StyleBox> sb; - if (tabs[i].disabled) { - sb = tab_disabled; - } else if (i == current) { - sb = tab_selected; - } else { - sb = tab_unselected; + if (tabs[i].hidden) { + tabs.write[i].ofs_cache = w; + max_drawn_tab = i; + + continue; } int lsize = tabs[i].size_cache; int slen = tabs[i].size_text; - if (min_width > 0 && mw > limit_minus_buttons && i != current) { - if (lsize > m_width) { - slen = m_width - (sb->get_margin(SIDE_LEFT) + sb->get_margin(SIDE_RIGHT)); - if (tabs[i].icon.is_valid()) { - slen -= tabs[i].icon->get_width(); - slen -= get_theme_constant(SNAME("hseparation")); - } - if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { - Ref<Texture2D> cb = get_theme_icon(SNAME("close")); - slen -= cb->get_width(); - slen -= get_theme_constant(SNAME("hseparation")); - } - - slen = MAX(slen, 1); - lsize = m_width; - } + // FIXME: This is completely broken. + if (min_width > 0 && (mw > limit || (offset > 0 && mw > limit_minus_buttons)) && i != current && lsize > m_width) { + slen = MAX(m_width - tabs[i].size_cache + tabs[i].size_text, 1); + lsize = m_width; } tabs.write[i].ofs_cache = w; @@ -735,13 +880,22 @@ void TabBar::_update_cache() { max_drawn_tab = i; // Check if all tabs would fit inside the area. - if (i > offset && (w > limit || (offset > 0 && w > limit_minus_buttons))) { - w -= get_tab_width(i); - max_drawn_tab -= 1; + if (clip_tabs && i > offset && (w > limit || (offset > 0 && w > limit_minus_buttons))) { + tabs.write[i].ofs_cache = 0; + tabs.write[i].text_buf->set_width(-1); + + w -= tabs[i].size_cache; + max_drawn_tab--; while (w > limit_minus_buttons && max_drawn_tab > offset) { - w -= get_tab_width(max_drawn_tab); - max_drawn_tab -= 1; + tabs.write[max_drawn_tab].ofs_cache = 0; + + if (!tabs[max_drawn_tab].hidden) { + tabs.write[max_drawn_tab].text_buf->set_width(-1); + w -= tabs[max_drawn_tab].size_cache; + } + + max_drawn_tab--; } break; @@ -752,21 +906,25 @@ void TabBar::_update_cache() { buttons_visible = offset > 0 || missing_right; if (tab_alignment == ALIGNMENT_LEFT) { + _update_hover(); return; - } else if (tab_alignment == ALIGNMENT_CENTER) { + } + + if (tab_alignment == ALIGNMENT_CENTER) { w = ((buttons_visible ? limit_minus_buttons : limit) - w) / 2; } else if (tab_alignment == ALIGNMENT_RIGHT) { w = (buttons_visible ? limit_minus_buttons : limit) - w; } - if (w < 0) { - w = 0; - } - for (int i = offset; i <= max_drawn_tab; i++) { tabs.write[i].ofs_cache = w; - w += tabs.write[i].size_cache; + + if (!tabs[i].hidden) { + w += tabs[i].size_cache; + } } + + _update_hover(); } void TabBar::_on_mouse_exited() { @@ -784,20 +942,26 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { t.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); t.text_buf->add_string(t.xl_text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); t.icon = p_icon; - tabs.push_back(t); + _update_cache(); - call_deferred(SNAME("_update_hover")); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); update_minimum_size(); } void TabBar::clear_tabs() { tabs.clear(); + offset = 0; + max_drawn_tab = 0; current = 0; previous = 0; - call_deferred(SNAME("_update_hover")); + + _update_cache(); update(); + update_minimum_size(); notify_property_list_changed(); } @@ -807,10 +971,6 @@ void TabBar::remove_tab(int p_idx) { if (current >= p_idx) { current--; } - _update_cache(); - call_deferred(SNAME("_update_hover")); - update(); - update_minimum_size(); if (current < 0) { current = 0; @@ -820,7 +980,13 @@ void TabBar::remove_tab(int p_idx) { current = tabs.size() - 1; } + _update_cache(); _ensure_no_over_offset(); + if (scroll_to_selected && !tabs.is_empty()) { + ensure_tab_visible(current); + } + update(); + update_minimum_size(); notify_property_list_changed(); } @@ -840,15 +1006,13 @@ Variant TabBar::get_drag_data(const Point2 &p_point) { if (!tabs[tab_over].icon.is_null()) { TextureRect *tf = memnew(TextureRect); tf->set_texture(tabs[tab_over].icon); + tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); drag_preview->add_child(tf); } + 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); - tf->set_texture(tabs[tab_over].right_button); - drag_preview->add_child(tf); - } + set_drag_preview(drag_preview); Dictionary drag_data; @@ -901,31 +1065,40 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { int tab_from_id = d["tab_element"]; NodePath from_path = d["from_path"]; NodePath to_path = get_path(); + if (from_path == to_path) { if (hover_now < 0) { hover_now = get_tab_count() - 1; } + move_tab(tab_from_id, hover_now); emit_signal(SNAME("active_tab_rearranged"), hover_now); set_current_tab(hover_now); } else if (get_tabs_rearrange_group() != -1) { // Drag and drop between Tabs. + Node *from_node = get_node(from_path); TabBar *from_tabs = Object::cast_to<TabBar>(from_node); + if (from_tabs && from_tabs->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { if (tab_from_id >= from_tabs->get_tab_count()) { return; } + Tab moving_tab = from_tabs->tabs[tab_from_id]; if (hover_now < 0) { hover_now = get_tab_count(); } + + // Workaround to ensure that tab_changed is emitted. + if (current == hover_now) { + current = -1; + } + tabs.insert(hover_now, moving_tab); from_tabs->remove_tab(tab_from_id); set_current_tab(hover_now); - emit_signal(SNAME("tab_changed"), hover_now); - _update_cache(); - update(); + update_minimum_size(); } } } @@ -946,6 +1119,7 @@ int TabBar::get_tab_idx_at_point(const Point2 &p_point) const { void TabBar::set_tab_alignment(AlignmentMode p_alignment) { ERR_FAIL_INDEX(p_alignment, ALIGNMENT_MAX); tab_alignment = p_alignment; + _update_cache(); update(); } @@ -959,7 +1133,16 @@ void TabBar::set_clip_tabs(bool p_clip_tabs) { return; } clip_tabs = p_clip_tabs; + + if (!clip_tabs) { + offset = 0; + max_drawn_tab = 0; + } + _update_cache(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); update_minimum_size(); } @@ -981,6 +1164,10 @@ void TabBar::move_tab(int from, int to) { tabs.insert(to, tab_from); _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); notify_property_list_changed(); } @@ -991,37 +1178,49 @@ int TabBar::get_tab_width(int p_idx) const { Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); + int hseparation = get_theme_constant(SNAME("hseparation")); - int x = 0; + Ref<StyleBox> style; + + if (tabs[p_idx].disabled) { + style = tab_disabled; + } else if (current == p_idx) { + style = tab_selected; + } else { + style = tab_unselected; + } + int x = style->get_minimum_size().width; Ref<Texture2D> tex = tabs[p_idx].icon; if (tex.is_valid()) { - x += tex->get_width(); - if (!tabs[p_idx].text.is_empty()) { - x += get_theme_constant(SNAME("hseparation")); - } + x += tex->get_width() + hseparation; } - x += Math::ceil(tabs[p_idx].text_buf->get_size().x); - - if (tabs[p_idx].disabled) { - x += tab_disabled->get_minimum_size().width; - } else if (current == p_idx) { - x += tab_selected->get_minimum_size().width; - } else { - x += tab_unselected->get_minimum_size().width; + if (!tabs[p_idx].text.is_empty()) { + x += tabs[p_idx].size_text + hseparation; } + bool close_visible = cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current); + if (tabs[p_idx].right_button.is_valid()) { + Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight")); Ref<Texture2D> rb = tabs[p_idx].right_button; - x += rb->get_width(); - x += get_theme_constant(SNAME("hseparation")); + + if (close_visible) { + x += btn_style->get_minimum_size().width + rb->get_width(); + } else { + x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + hseparation; + } } - if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current)) { + if (close_visible) { + Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight")); Ref<Texture2D> cb = get_theme_icon(SNAME("close")); - x += cb->get_width(); - x += get_theme_constant(SNAME("hseparation")); + x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + hseparation; + } + + if (x > style->get_minimum_size().width) { + x -= hseparation; } return x; @@ -1039,8 +1238,12 @@ void TabBar::_ensure_no_over_offset() { int prev_offset = offset; int total_w = tabs[max_drawn_tab].ofs_cache + tabs[max_drawn_tab].size_cache - tabs[offset].ofs_cache; - while (offset > 0) { - total_w += tabs[offset - 1].size_cache; + for (int i = offset; i > 0; i--) { + if (tabs[i - 1].hidden) { + continue; + } + + total_w += tabs[i - 1].size_cache; if (total_w < limit_minus_buttons) { offset--; @@ -1061,7 +1264,7 @@ void TabBar::ensure_tab_visible(int p_idx) { } ERR_FAIL_INDEX(p_idx, tabs.size()); - if (p_idx >= offset && p_idx <= max_drawn_tab) { + if (tabs[p_idx].hidden || (p_idx >= offset && p_idx <= max_drawn_tab)) { return; } @@ -1079,12 +1282,20 @@ void TabBar::ensure_tab_visible(int p_idx) { int total_w = tabs[max_drawn_tab].ofs_cache - tabs[offset].ofs_cache; for (int i = max_drawn_tab; i <= p_idx; i++) { + if (tabs[i].hidden) { + continue; + } + total_w += tabs[i].size_cache; } int prev_offset = offset; for (int i = offset; i < p_idx; i++) { + if (tabs[i].hidden) { + continue; + } + if (total_w > limit_minus_buttons) { total_w -= tabs[i].size_cache; offset++; @@ -1111,8 +1322,14 @@ Rect2 TabBar::get_tab_rect(int p_tab) const { void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { ERR_FAIL_INDEX(p_policy, CLOSE_BUTTON_MAX); cb_displaypolicy = p_policy; + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } update(); + update_minimum_size(); } TabBar::CloseButtonDisplayPolicy TabBar::get_tab_close_display_policy() const { @@ -1147,6 +1364,17 @@ int TabBar::get_tabs_rearrange_group() const { return tabs_rearrange_group; } +void TabBar::set_scroll_to_selected(bool p_enabled) { + scroll_to_selected = p_enabled; + if (p_enabled) { + ensure_tab_visible(current); + } +} + +bool TabBar::get_scroll_to_selected() const { + return scroll_to_selected; +} + void TabBar::set_select_with_rmb(bool p_enabled) { select_with_rmb = p_enabled; } @@ -1225,8 +1453,12 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_language", "tab_idx"), &TabBar::get_tab_language); ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabBar::set_tab_icon); ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabBar::get_tab_icon); + ClassDB::bind_method(D_METHOD("set_tab_button_icon", "tab_idx", "icon"), &TabBar::set_tab_button_icon); + ClassDB::bind_method(D_METHOD("get_tab_button_icon", "tab_idx"), &TabBar::get_tab_button_icon); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabBar::set_tab_disabled); ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabBar::is_tab_disabled); + ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabBar::set_tab_hidden); + ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabBar::is_tab_hidden); ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &TabBar::remove_tab); ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &TabBar::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabBar::set_tab_alignment); @@ -1246,16 +1478,19 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &TabBar::get_drag_to_rearrange_enabled); ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabBar::set_tabs_rearrange_group); ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabBar::get_tabs_rearrange_group); - + ClassDB::bind_method(D_METHOD("set_scroll_to_selected", "enabled"), &TabBar::set_scroll_to_selected); + ClassDB::bind_method(D_METHOD("get_scroll_to_selected"), &TabBar::get_scroll_to_selected); ClassDB::bind_method(D_METHOD("set_select_with_rmb", "enabled"), &TabBar::set_select_with_rmb); ClassDB::bind_method(D_METHOD("get_select_with_rmb"), &TabBar::get_select_with_rmb); + ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_rmb_clicked", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_close_pressed", PropertyInfo(Variant::INT, "tab"))); + ADD_SIGNAL(MethodInfo("tab_button_pressed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_hovered", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("active_tab_rearranged", PropertyInfo(Variant::INT, "idx_to"))); - ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab"))); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); @@ -1263,6 +1498,8 @@ void TabBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_to_selected"), "set_scroll_to_selected", "get_scroll_to_selected"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_with_rmb"), "set_select_with_rmb", "get_select_with_rmb"); ADD_ARRAY_COUNT("Tabs", "tab_count", "set_tab_count", "get_tab_count", "tab_"); @@ -1278,5 +1515,6 @@ void TabBar::_bind_methods() { } TabBar::TabBar() { + set_size(Size2(get_size().width, get_minimum_size().height)); connect("mouse_exited", callable_mp(this, &TabBar::_on_mouse_exited)); } diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index d0055ae4d2..b428538570 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -63,12 +63,11 @@ private: Ref<TextLine> text_buf; Ref<Texture2D> icon; - int ofs_cache = 0; bool disabled = false; + bool hidden = false; + int ofs_cache = 0; int size_cache = 0; int size_text = 0; - int x_cache = 0; - int x_size_cache = 0; Ref<Texture2D> right_button; Rect2 rb_rect; @@ -102,6 +101,7 @@ private: int min_width = 0; bool scrolling_enabled = true; bool drag_to_rearrange_enabled = false; + bool scroll_to_selected = true; int tabs_rearrange_group = -1; int get_tab_width(int p_idx) const; @@ -150,8 +150,11 @@ public: void set_tab_disabled(int p_tab, bool p_disabled); bool is_tab_disabled(int p_tab) const; - void set_tab_right_button(int p_tab, const Ref<Texture2D> &p_right_button); - Ref<Texture2D> get_tab_right_button(int p_tab) const; + void set_tab_hidden(int p_tab, bool p_hidden); + bool is_tab_hidden(int p_tab) const; + + void set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon); + Ref<Texture2D> get_tab_button_icon(int p_tab) const; void set_tab_alignment(AlignmentMode p_alignment); AlignmentMode get_tab_alignment() const; @@ -187,6 +190,9 @@ public: void set_tabs_rearrange_group(int p_group_id); int get_tabs_rearrange_group() const; + void set_scroll_to_selected(bool p_enabled); + bool get_scroll_to_selected() const; + void set_select_with_rmb(bool p_enabled); bool get_select_with_rmb() const; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index c3fc08731e..818431a6a0 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -704,7 +704,7 @@ void TabContainer::add_child_notify(Node *p_child) { } _refresh_texts(); - call_deferred("_repaint"); + call_deferred(SNAME("_repaint")); update(); bool first = (_get_tabs().size() == 1); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2b10ead8f6..bb259843b8 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -43,18 +43,6 @@ #include "scene/main/window.h" -static bool _is_text_char(char32_t c) { - return !is_symbol(c); -} - -static bool _is_whitespace(char32_t c) { - return c == '\t' || c == ' '; -} - -static bool _is_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} - /////////////////////////////////////////////////////////////////////////////// /// TEXT /// /////////////////////////////////////////////////////////////////////////////// @@ -128,6 +116,10 @@ void TextEdit::Text::set_width(float p_width) { width = p_width; } +float TextEdit::Text::get_width() const { + return width; +} + int TextEdit::Text::get_line_wrap_amount(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); @@ -183,29 +175,44 @@ void TextEdit::Text::_calculate_max_line_width() { max_width = width; } -void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ime_text, const Array &p_bidi_override) { +void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_changed, const String &p_ime_text, const Array &p_bidi_override) { ERR_FAIL_INDEX(p_line, text.size()); if (font.is_null() || font_size <= 0) { return; // Not in tree? } - text.write[p_line].data_buf->clear(); + if (p_text_changed) { + text.write[p_line].data_buf->clear(); + } + text.write[p_line].data_buf->set_width(width); text.write[p_line].data_buf->set_direction((TextServer::Direction)direction); text.write[p_line].data_buf->set_preserve_control(draw_control_chars); if (p_ime_text.length() > 0) { - text.write[p_line].data_buf->add_string(p_ime_text, font, font_size, opentype_features, language); + if (p_text_changed) { + text.write[p_line].data_buf->add_string(p_ime_text, font, font_size, opentype_features, language); + } if (!p_bidi_override.is_empty()) { TS->shaped_text_set_bidi_override(text.write[p_line].data_buf->get_rid(), p_bidi_override); } } else { - text.write[p_line].data_buf->add_string(text[p_line].data, font, font_size, opentype_features, language); + if (p_text_changed) { + text.write[p_line].data_buf->add_string(text[p_line].data, font, font_size, opentype_features, language); + } if (!text[p_line].bidi_override.is_empty()) { TS->shaped_text_set_bidi_override(text.write[p_line].data_buf->get_rid(), text[p_line].bidi_override); } } + if (!p_text_changed) { + RID r = text.write[p_line].data_buf->get_rid(); + int spans = TS->shaped_get_span_count(r); + for (int i = 0; i < spans; i++) { + TS->shaped_set_span_update_font(r, i, font->get_rids(), font_size, opentype_features); + } + } + // Apply tab align. if (tab_size > 0) { Vector<float> tabs; @@ -262,6 +269,24 @@ void TextEdit::Text::invalidate_all_lines() { } } +void TextEdit::Text::invalidate_font() { + if (!is_dirty) { + return; + } + + max_width = -1; + line_height = -1; + + if (!font.is_null() && font_size > 0) { + font_height = font->get_height(font_size); + } + + for (int i = 0; i < text.size(); i++) { + invalidate_cache(i, -1, false); + } + is_dirty = false; +} + void TextEdit::Text::invalidate_all() { if (!is_dirty) { return; @@ -275,7 +300,7 @@ void TextEdit::Text::invalidate_all() { } for (int i = 0; i < text.size(); i++) { - invalidate_cache(i); + invalidate_cache(i, -1, true); } is_dirty = false; } @@ -290,7 +315,7 @@ void TextEdit::Text::clear() { line.gutters.resize(gutter_count); line.data = ""; text.insert(0, line); - invalidate_cache(0); + invalidate_cache(0, -1, true); } int TextEdit::Text::get_max_width() const { @@ -302,7 +327,7 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_o text.write[p_line].data = p_text; text.write[p_line].bidi_override = p_bidi_override; - invalidate_cache(p_line); + invalidate_cache(p_line, -1, true); } void TextEdit::Text::insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override) { @@ -327,7 +352,7 @@ void TextEdit::Text::insert(int p_at, const Vector<String> &p_text, const Vector line.data = p_text[i]; line.bidi_override = p_bidi_override[i]; text.write[p_at + i] = line; - invalidate_cache(p_at + i); + invalidate_cache(p_at + i, -1, true); } } @@ -646,6 +671,8 @@ void TextEdit::_notification(int p_what) { } } + bool draw_placeholder = text.size() == 1 && text[0].length() == 0; + // Get the highlighted words. String highlighted_text = get_selected_text(); @@ -656,7 +683,7 @@ void TextEdit::_notification(int p_what) { int first_visible_line = get_first_visible_line() - 1; int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0); - draw_amount += get_line_wrap_count(first_visible_line + 1); + draw_amount += draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(first_visible_line + 1); // Draw minimap. if (draw_minimap) { @@ -781,8 +808,8 @@ void TextEdit::_notification(int p_what) { int xpos = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * j)) + tabs; bool out_of_bounds = (xpos >= xmargin_end + minimap_width); - bool is_whitespace = _is_whitespace(str[j]); - if (!is_whitespace) { + bool whitespace = is_whitespace(str[j]); + if (!whitespace) { characters++; if (j < str.length() - 1 && color == previous_color && !out_of_bounds) { @@ -804,7 +831,7 @@ void TextEdit::_notification(int p_what) { if (characters > 0) { previous_color.a *= 0.6; // take one for zero indexing, and if we hit whitespace / the end of a word. - int chars = MAX(0, (j - (characters - 1)) - (is_whitespace ? 1 : 0)) + 1; + int chars = MAX(0, (j - (characters - 1)) - (whitespace ? 1 : 0)) + 1; int char_x_ofs = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * chars)) + tabs; if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - char_x_ofs - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), previous_color); @@ -841,7 +868,7 @@ void TextEdit::_notification(int p_what) { // Draw main text. caret.visible = false; line_drawing_cache.clear(); - int row_height = get_line_height(); + int row_height = draw_placeholder ? placeholder_line_height + line_spacing : get_line_height(); int line = first_visible_line; for (int i = 0; i < draw_amount; i++) { line++; @@ -867,11 +894,14 @@ void TextEdit::_notification(int p_what) { // Ensure we at least use the font color. Color current_color = !editable ? font_readonly_color : font_color; + if (draw_placeholder) { + current_color = font_placeholder_color; + } - const Ref<TextParagraph> ldata = text.get_line_data(line); + const Ref<TextParagraph> ldata = draw_placeholder ? placeholder_data_buf : text.get_line_data(line); - Vector<String> wrap_rows = get_line_wrapped_text(line); - int line_wrap_amount = get_line_wrap_count(line); + Vector<String> wrap_rows = draw_placeholder ? placeholder_wraped_rows : get_line_wrapped_text(line); + int line_wrap_amount = draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(line); for (int line_wrap_index = 0; line_wrap_index <= line_wrap_amount; line_wrap_index++) { if (line_wrap_index != 0) { @@ -1008,15 +1038,17 @@ void TextEdit::_notification(int p_what) { icon->draw_rect(ci, gutter_rect, false, get_line_gutter_item_color(line, g)); } break; case GUTTER_TYPE_CUSTOM: { - if (gutter.custom_draw_obj.is_valid()) { - Object *cdo = ObjectDB::get_instance(gutter.custom_draw_obj); - if (cdo) { - Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, row_height)); - if (rtl) { - gutter_rect.position.x = size.width - gutter_rect.position.x - gutter_rect.size.x; - } - cdo->call(gutter.custom_draw_callback, line, g, Rect2(gutter_rect)); + if (gutter.custom_draw_callback.is_valid()) { + Rect2i gutter_rect = Rect2i(Point2i(gutter_offset, ofs_y), Size2i(gutter.width, row_height)); + if (rtl) { + gutter_rect.position.x = size.width - gutter_rect.position.x - gutter_rect.size.x; } + + Variant args[3] = { line, g, Rect2(gutter_rect) }; + const Variant *argp[] = { &args[0], &args[1], &args[2] }; + Callable::CallError ce; + Variant ret; + gutter.custom_draw_callback.call(argp, 3, ret, ce); } } break; } @@ -1100,7 +1132,7 @@ void TextEdit::_notification(int p_what) { } if (!clipped && lookup_symbol_word.length() != 0) { // Highlight word - if (_is_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '.') { + if (is_ascii_char(lookup_symbol_word[0]) || lookup_symbol_word[0] == '_' || lookup_symbol_word[0] == '.') { int highlighted_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); while (highlighted_word_col != -1) { Vector<Vector2> sel = TS->shaped_text_get_selection(rid, highlighted_word_col + start, highlighted_word_col + lookup_symbol_word.length() + start); @@ -1383,7 +1415,9 @@ void TextEdit::_notification(int p_what) { } } - line_drawing_cache[line] = cache_entry; + if (draw_placeholder) { + line_drawing_cache[line] = cache_entry; + } } if (has_focus()) { @@ -1433,9 +1467,11 @@ void TextEdit::_notification(int p_what) { DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); } - ime_text = ""; - ime_selection = Point2(); - text.invalidate_cache(caret.line, caret.column, ime_text); + if (!ime_text.is_empty()) { + ime_text = ""; + ime_selection = Point2(); + text.invalidate_cache(caret.line, caret.column, true, ime_text); + } if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); @@ -1457,7 +1493,7 @@ void TextEdit::_notification(int p_what) { t = ime_text; } - text.invalidate_cache(caret.line, caret.column, t, structured_text_parser(st_parser, st_args, t)); + text.invalidate_cache(caret.line, caret.column, true, t, structured_text_parser(st_parser, st_args, t)); update(); } } break; @@ -2045,6 +2081,7 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) { bool first_line = false; if (!p_split_current_line) { + deselect(); if (p_above) { if (caret.line > 0) { set_caret_line(caret.line - 1, false); @@ -2430,6 +2467,47 @@ void TextEdit::_move_caret_document_end(bool p_select) { } } +void TextEdit::_update_placeholder() { + if (font.is_null() || font_size <= 0) { + return; // Not in tree? + } + + // Placeholder is generally smaller then text docuemnts, and updates less so this should be fast enough for now. + placeholder_data_buf->clear(); + placeholder_data_buf->set_width(text.get_width()); + placeholder_data_buf->set_direction((TextServer::Direction)text_direction); + placeholder_data_buf->set_preserve_control(draw_control_chars); + placeholder_data_buf->add_string(placeholder_text, font, font_size, opentype_features, language); + + placeholder_bidi_override = structured_text_parser(st_parser, st_args, placeholder_text); + if (placeholder_bidi_override.is_empty()) { + TS->shaped_text_set_bidi_override(placeholder_data_buf->get_rid(), placeholder_bidi_override); + } + + if (get_tab_size() > 0) { + Vector<float> tabs; + tabs.push_back(font->get_char_size(' ', 0, font_size).width * get_tab_size()); + placeholder_data_buf->tab_align(tabs); + } + + // Update height. + const int wrap_amount = placeholder_data_buf->get_line_count() - 1; + placeholder_line_height = font->get_height(font_size); + for (int i = 0; i <= wrap_amount; i++) { + placeholder_line_height = MAX(placeholder_line_height, placeholder_data_buf->get_line_size(i).y); + } + + // Update width. + placeholder_max_width = placeholder_data_buf->get_size().x; + + // Update wrapped rows. + placeholder_wraped_rows.clear(); + for (int i = 0; i <= wrap_amount; i++) { + Vector2i line_range = placeholder_data_buf->get_line_range(i); + placeholder_wraped_rows.push_back(placeholder_text.substr(line_range.x, line_range.y - line_range.x)); + } +} + void TextEdit::_update_caches() { /* Internal API for CodeEdit. */ brace_mismatch_color = get_theme_color(SNAME("brace_mismatch_color"), SNAME("CodeEdit")); @@ -2460,6 +2538,7 @@ void TextEdit::_update_caches() { font_size = get_theme_font_size(SNAME("font_size")); font_color = get_theme_color(SNAME("font_color")); font_readonly_color = get_theme_color(SNAME("font_readonly_color")); + font_placeholder_color = get_theme_color(SNAME("font_placeholder_color")); outline_size = get_theme_constant(SNAME("outline_size")); outline_color = get_theme_color(SNAME("font_outline_color")); @@ -2482,7 +2561,8 @@ void TextEdit::_update_caches() { text.set_draw_control_chars(draw_control_chars); text.set_font(font); text.set_font_size(font_size); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); /* Syntax highlighting. */ if (syntax_highlighter.is_valid()) { @@ -2598,8 +2678,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { } String TextEdit::get_tooltip(const Point2 &p_pos) const { - Object *tooltip_obj = ObjectDB::get_instance(tooltip_obj_id); - if (!tooltip_obj) { + if (!tooltip_callback.is_valid()) { return Control::get_tooltip(p_pos); } Point2i pos = get_line_column_at_pos(p_pos); @@ -2612,19 +2691,20 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const { } int beg, end; if (select_word(s, col, beg, end)) { - String tt = tooltip_obj->call(tooltip_func, s.substr(beg, end - beg), tooltip_ud); - - return tt; + Variant args[1] = { s.substr(beg, end - beg) }; + const Variant *argp[] = { &args[0] }; + Callable::CallError ce; + Variant ret; + tooltip_callback.call(argp, 1, ret, ce); + ERR_FAIL_COND_V_MSG(ce.error != Callable::CallError::CALL_OK, "", "Failed to call custom tooltip."); + return ret; } return Control::get_tooltip(p_pos); } -void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata) { - ERR_FAIL_NULL(p_obj); - tooltip_obj_id = p_obj->get_instance_id(); - tooltip_func = p_function; - tooltip_ud = p_udata; +void TextEdit::set_tooltip_request_func(const Callable &p_tooltip_callback) { + tooltip_callback = p_tooltip_callback; } /* Text */ @@ -2661,7 +2741,8 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) { dir = (TextServer::Direction)text_direction; } text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); if (menu_dir) { menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); @@ -2682,7 +2763,8 @@ void TextEdit::set_opentype_feature(const String &p_name, int p_value) { if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) { opentype_features[tag] = p_value; text.set_font_features(opentype_features); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); update(); } } @@ -2698,7 +2780,8 @@ int TextEdit::get_opentype_feature(const String &p_name) const { void TextEdit::clear_opentype_features() { opentype_features.clear(); text.set_font_features(opentype_features); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); update(); } @@ -2713,6 +2796,7 @@ void TextEdit::set_language(const String &p_language) { } text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); text.invalidate_all(); + _update_placeholder(); update(); } } @@ -2754,6 +2838,7 @@ void TextEdit::set_tab_size(const int p_size) { } text.set_tab_size(p_size); text.invalidate_all_lines(); + _update_placeholder(); update(); } @@ -2876,6 +2961,16 @@ int TextEdit::get_line_count() const { return text.size(); } +void TextEdit::set_placeholder(const String &p_text) { + placeholder_text = p_text; + _update_placeholder(); + update(); +} + +String TextEdit::get_placeholder() const { + return placeholder_text; +} + void TextEdit::set_line(int p_line, const String &p_new_text) { if (p_line < 0 || p_line >= text.size()) { return; @@ -2930,7 +3025,7 @@ int TextEdit::get_first_non_whitespace_column(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); int col = 0; - while (col < text[p_line].length() && _is_whitespace(text[p_line][col])) { + while (col < text[p_line].length() && is_whitespace(text[p_line][col])) { col++; } return col; @@ -3515,9 +3610,9 @@ Point2i TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_fro if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) { // Validate for whole words. - if (pos > 0 && _is_text_char(text_line[pos - 1])) { + if (pos > 0 && !is_symbol(text_line[pos - 1])) { is_match = false; - } else if (pos + p_key.length() < text_line.length() && _is_text_char(text_line[pos + p_key.length()])) { + } else if (pos + p_key.length() < text_line.length() && !is_symbol(text_line[pos + p_key.length()])) { is_match = false; } } @@ -4658,12 +4753,10 @@ void TextEdit::merge_gutters(int p_from_line, int p_to_line) { update(); } -void TextEdit::set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback) { +void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback) { ERR_FAIL_INDEX(p_gutter, gutters.size()); - ERR_FAIL_NULL(p_object); - gutters.write[p_gutter].custom_draw_obj = p_object->get_instance_id(); - gutters.write[p_gutter].custom_draw_callback = p_callback; + gutters.write[p_gutter].custom_draw_callback = p_draw_callback; update(); } @@ -4782,7 +4875,8 @@ void TextEdit::set_draw_control_chars(bool p_enabled) { menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); } text.set_draw_control_chars(draw_control_chars); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); update(); } } @@ -4862,6 +4956,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text); ClassDB::bind_method(D_METHOD("get_line_count"), &TextEdit::get_line_count); + ClassDB::bind_method(D_METHOD("set_placeholder", "text"), &TextEdit::set_placeholder); + ClassDB::bind_method(D_METHOD("get_placeholder"), &TextEdit::get_placeholder); + ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line); ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line); @@ -4953,7 +5050,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("search", "text", "flags", "from_line", "from_colum"), &TextEdit::search); /* Tooltip */ - ClassDB::bind_method(D_METHOD("set_tooltip_request_func", "object", "callback", "data"), &TextEdit::set_tooltip_request_func); + ClassDB::bind_method(D_METHOD("set_tooltip_request_func", "callback"), &TextEdit::set_tooltip_request_func); /* Mouse */ ClassDB::bind_method(D_METHOD("get_local_mouse_pos"), &TextEdit::get_local_mouse_pos); @@ -5125,7 +5222,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_gutter_overwritable", "gutter", "overwritable"), &TextEdit::set_gutter_overwritable); ClassDB::bind_method(D_METHOD("is_gutter_overwritable", "gutter"), &TextEdit::is_gutter_overwritable); ClassDB::bind_method(D_METHOD("merge_gutters", "from_line", "to_line"), &TextEdit::merge_gutters); - ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "object", "callback"), &TextEdit::set_gutter_custom_draw); + ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "draw_callback"), &TextEdit::set_gutter_custom_draw); ClassDB::bind_method(D_METHOD("get_total_gutter_width"), &TextEdit::get_total_gutter_width); // Line gutters. @@ -5170,8 +5267,9 @@ void TextEdit::_bind_methods() { /* Inspector */ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text", PROPERTY_HINT_MULTILINE_TEXT), "set_placeholder", "get_placeholder"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); @@ -5244,14 +5342,16 @@ bool TextEdit::_set(const StringName &p_name, const Variant &p_value) { if (opentype_features.has(tag)) { opentype_features.erase(tag); text.set_font_features(opentype_features); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); update(); } } else { if (!opentype_features.has(tag) || (int)opentype_features[tag] != value) { opentype_features[tag] = value; text.set_font_features(opentype_features); - text.invalidate_all(); + text.invalidate_font(); + _update_placeholder(); update(); } } @@ -5667,9 +5767,9 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) { p_from_column = col; - if (col > 0 && _is_text_char(p_search[col - 1])) { + if (col > 0 && !is_symbol(p_search[col - 1])) { col = -1; - } else if ((col + p_key.length()) < p_search.length() && _is_text_char(p_search[col + p_key.length()])) { + } else if ((col + p_key.length()) < p_search.length() && !is_symbol(p_search[col + p_key.length()])) { col = -1; } } @@ -5903,6 +6003,7 @@ void TextEdit::_update_wrap_at_column(bool p_force) { text.set_width(-1); } text.invalidate_all_lines(); + _update_placeholder(); } _update_caret_wrap_offset(); @@ -5930,14 +6031,16 @@ void TextEdit::_update_scrollbars() { h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); + bool draw_placeholder = text.size() == 1 && text[0].length() == 0; + int visible_rows = get_visible_line_count(); - int total_rows = get_total_visible_line_count(); + int total_rows = draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_total_visible_line_count(); if (scroll_past_end_of_file_enabled) { total_rows += visible_rows - 1; } int visible_width = size.width - style_normal->get_minimum_size().width; - int total_width = text.get_max_width() + vmin.x + gutters_width + gutter_padding; + int total_width = (draw_placeholder ? placeholder_max_width : text.get_max_width()) + vmin.x + gutters_width + gutter_padding; if (draw_minimap) { total_width += minimap_width; @@ -6009,20 +6112,22 @@ void TextEdit::_scroll_moved(double p_to_val) { } if (v_scroll->is_visible_in_tree()) { // Set line ofs and wrap ofs. + bool draw_placeholder = text.size() == 1 && text[0].length() == 0; + int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; for (n_line = 0; n_line < text.size(); n_line++) { if (!_is_line_hidden(n_line)) { sc++; - sc += get_line_wrap_count(n_line); + sc += draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(n_line); if (sc > v_scroll_i) { break; } } } n_line = MIN(n_line, text.size() - 1); - int line_wrap_amount = get_line_wrap_count(n_line); + int line_wrap_amount = draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(n_line); int wi = line_wrap_amount - (sc - v_scroll_i - 1); wi = CLAMP(wi, 0, line_wrap_amount); @@ -6450,6 +6555,8 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li } TextEdit::TextEdit() { + placeholder_data_buf.instantiate(); + clear(); set_focus_mode(FOCUS_ALL); _update_caches(); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 57b48b5f52..83a63ae40a 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -120,8 +120,7 @@ private: bool clickable = false; bool overwritable = false; - ObjectID custom_draw_obj = ObjectID(); - StringName custom_draw_callback; + Callable custom_draw_callback; }; class Text { @@ -190,6 +189,7 @@ private: int get_max_width() const; void set_width(float p_width); + float get_width() const; int get_line_wrap_amount(int p_line) const; Vector<Vector2i> get_line_wrap_ranges(int p_line) const; @@ -210,7 +210,8 @@ private: int size() const { return text.size(); } void clear(); - void invalidate_cache(int p_line, int p_column = -1, const String &p_ime_text = String(), const Array &p_bidi_override = Array()); + void invalidate_cache(int p_line, int p_column = -1, bool p_text_changed = false, const String &p_ime_text = String(), const Array &p_bidi_override = Array()); + void invalidate_font(); void invalidate_all(); void invalidate_all_lines(); @@ -250,6 +251,17 @@ private: String ime_text = ""; Point2 ime_selection; + // Placeholder + String placeholder_text = ""; + Array placeholder_bidi_override; + Ref<TextParagraph> placeholder_data_buf; + int placeholder_line_height = -1; + int placeholder_max_width = -1; + + Vector<String> placeholder_wraped_rows; + + void _update_placeholder(); + /* Initialise to opposite first, so we get past the early-out in set_editable. */ bool editable = false; @@ -332,9 +344,7 @@ private: int _get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) const; /* Tooltip. */ - ObjectID tooltip_obj_id; - StringName tooltip_func; - Variant tooltip_ud; + Callable tooltip_callback; /* Mouse */ struct LineDrawingCache { @@ -514,6 +524,7 @@ private: int font_size = 16; Color font_color = Color(1, 1, 1); Color font_readonly_color = Color(1, 1, 1); + Color font_placeholder_color = Color(1, 1, 1, 0.6); int outline_size = 0; Color outline_color = Color(1, 1, 1); @@ -620,7 +631,7 @@ public: virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; virtual void drop_data(const Point2 &p_point, const Variant &p_data) override; virtual String get_tooltip(const Point2 &p_pos) const override; - void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata); + void set_tooltip_request_func(const Callable &p_tooltip_callback); /* Text */ // Text properties. @@ -670,6 +681,9 @@ public: String get_text() const; int get_line_count() const; + void set_placeholder(const String &p_text); + String get_placeholder() const; + void set_line(int p_line, const String &p_new_text); String get_line(int p_line) const; @@ -884,7 +898,7 @@ public: void merge_gutters(int p_from_line, int p_to_line); - void set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback); + void set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback); // Line gutters. void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index da202c1c8f..26acfaaa70 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -37,7 +37,7 @@ Size2 TextureButton::get_minimum_size() const { Size2 rscale = Control::get_minimum_size(); - if (!expand) { + if (!ignore_texture_size) { if (normal.is_null()) { if (pressed.is_null()) { if (hover.is_null()) { @@ -173,7 +173,8 @@ void TextureButton::_notification(int p_what) { bool draw_focus = (has_focus() && focused.is_valid()); // If no other texture is valid, try using focused texture. - if (!texdraw.is_valid() && draw_focus) { + bool draw_focus_only = draw_focus && !texdraw.is_valid(); + if (draw_focus_only) { texdraw = focused; } @@ -181,50 +182,48 @@ void TextureButton::_notification(int p_what) { size = texdraw->get_size(); _texture_region = Rect2(Point2(), texdraw->get_size()); _tile = false; - if (expand) { - switch (stretch_mode) { - case STRETCH_KEEP: - size = texdraw->get_size(); - break; - case STRETCH_SCALE: - size = get_size(); - break; - case STRETCH_TILE: - size = get_size(); - _tile = true; - break; - case STRETCH_KEEP_CENTERED: - ofs = (get_size() - texdraw->get_size()) / 2; - size = texdraw->get_size(); - break; - case STRETCH_KEEP_ASPECT_CENTERED: - case STRETCH_KEEP_ASPECT: { - Size2 _size = get_size(); - float tex_width = texdraw->get_width() * _size.height / texdraw->get_height(); - float tex_height = _size.height; - - if (tex_width > _size.width) { - tex_width = _size.width; - tex_height = texdraw->get_height() * tex_width / texdraw->get_width(); - } + switch (stretch_mode) { + case STRETCH_KEEP: + size = texdraw->get_size(); + break; + case STRETCH_SCALE: + size = get_size(); + break; + case STRETCH_TILE: + size = get_size(); + _tile = true; + break; + case STRETCH_KEEP_CENTERED: + ofs = (get_size() - texdraw->get_size()) / 2; + size = texdraw->get_size(); + break; + case STRETCH_KEEP_ASPECT_CENTERED: + case STRETCH_KEEP_ASPECT: { + Size2 _size = get_size(); + float tex_width = texdraw->get_width() * _size.height / texdraw->get_height(); + float tex_height = _size.height; + + if (tex_width > _size.width) { + tex_width = _size.width; + tex_height = texdraw->get_height() * tex_width / texdraw->get_width(); + } - if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { - ofs.x = (_size.width - tex_width) / 2; - ofs.y = (_size.height - tex_height) / 2; - } - size.width = tex_width; - size.height = tex_height; - } break; - case STRETCH_KEEP_ASPECT_COVERED: { - size = get_size(); - Size2 tex_size = texdraw->get_size(); - Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); - float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; - Size2 scaled_tex_size = tex_size * scale; - Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f; - _texture_region = Rect2(ofs2, size / scale); - } break; - } + if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { + ofs.x = (_size.width - tex_width) / 2; + ofs.y = (_size.height - tex_height) / 2; + } + size.width = tex_width; + size.height = tex_height; + } break; + case STRETCH_KEEP_ASPECT_COVERED: { + size = get_size(); + Size2 tex_size = texdraw->get_size(); + Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); + float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; + Size2 scaled_tex_size = tex_size * scale; + Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f; + _texture_region = Rect2(ofs2, size / scale); + } break; } _position_rect = Rect2(ofs, size); @@ -232,7 +231,7 @@ void TextureButton::_notification(int p_what) { size.width *= hflip ? -1.0f : 1.0f; size.height *= vflip ? -1.0f : 1.0f; - if (texdraw == focused) { + if (draw_focus_only) { // Do nothing, we only needed to calculate the rectangle. } else if (_tile) { draw_texture_rect(texdraw, Rect2(ofs, size), _tile); @@ -257,7 +256,7 @@ void TextureButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disabled_texture", "texture"), &TextureButton::set_disabled_texture); ClassDB::bind_method(D_METHOD("set_focused_texture", "texture"), &TextureButton::set_focused_texture); ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask); - ClassDB::bind_method(D_METHOD("set_expand", "expand"), &TextureButton::set_expand); + ClassDB::bind_method(D_METHOD("set_ignore_texture_size", "ignore"), &TextureButton::set_ignore_texture_size); ClassDB::bind_method(D_METHOD("set_stretch_mode", "mode"), &TextureButton::set_stretch_mode); ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &TextureButton::set_flip_h); ClassDB::bind_method(D_METHOD("is_flipped_h"), &TextureButton::is_flipped_h); @@ -270,7 +269,7 @@ void TextureButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_disabled_texture"), &TextureButton::get_disabled_texture); ClassDB::bind_method(D_METHOD("get_focused_texture"), &TextureButton::get_focused_texture); ClassDB::bind_method(D_METHOD("get_click_mask"), &TextureButton::get_click_mask); - ClassDB::bind_method(D_METHOD("get_expand"), &TextureButton::get_expand); + ClassDB::bind_method(D_METHOD("get_ignore_texture_size"), &TextureButton::get_ignore_texture_size); ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureButton::get_stretch_mode); ADD_GROUP("Textures", "texture_"); @@ -280,7 +279,7 @@ void TextureButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_disabled_texture", "get_disabled_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_focused_texture", "get_focused_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_texture_size", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_ignore_texture_size", "get_ignore_texture_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_flip_h", "is_flipped_h"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_flip_v", "is_flipped_v"); @@ -351,12 +350,12 @@ void TextureButton::set_focused_texture(const Ref<Texture2D> &p_focused) { focused = p_focused; }; -bool TextureButton::get_expand() const { - return expand; +bool TextureButton::get_ignore_texture_size() const { + return ignore_texture_size; } -void TextureButton::set_expand(bool p_expand) { - expand = p_expand; +void TextureButton::set_ignore_texture_size(bool p_ignore) { + ignore_texture_size = p_ignore; update_minimum_size(); update(); } diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index 1428a79a1d..5762949acd 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -54,8 +54,8 @@ private: Ref<Texture2D> disabled; Ref<Texture2D> focused; Ref<BitMap> click_mask; - bool expand = false; - StretchMode stretch_mode = STRETCH_SCALE; + bool ignore_texture_size = false; + StretchMode stretch_mode = STRETCH_KEEP; Rect2 _texture_region; Rect2 _position_rect; @@ -85,8 +85,8 @@ public: Ref<Texture2D> get_focused_texture() const; Ref<BitMap> get_click_mask() const; - bool get_expand() const; - void set_expand(bool p_expand); + bool get_ignore_texture_size() const; + void set_ignore_texture_size(bool p_ignore); void set_stretch_mode(StretchMode p_stretch_mode); StretchMode get_stretch_mode() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index e46de43f1e..e33ce0b017 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -198,6 +198,65 @@ bool TreeItem::is_indeterminate(int p_column) const { return cells[p_column].indeterminate; } +void TreeItem::propagate_check(int p_column, bool p_emit_signal) { + bool ch = cells[p_column].checked; + + if (p_emit_signal) { + tree->emit_signal(SNAME("check_propagated_to_item"), this, p_column); + } + _propagate_check_through_children(p_column, ch, p_emit_signal); + _propagate_check_through_parents(p_column, p_emit_signal); +} + +void TreeItem::_propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal) { + TreeItem *current = get_first_child(); + while (current) { + current->set_checked(p_column, p_checked); + if (p_emit_signal) { + current->tree->emit_signal(SNAME("check_propagated_to_item"), current, p_column); + } + current->_propagate_check_through_children(p_column, p_checked, p_emit_signal); + current = current->get_next(); + } +} + +void TreeItem::_propagate_check_through_parents(int p_column, bool p_emit_signal) { + TreeItem *current = get_parent(); + if (!current) { + return; + } + + bool all_unchecked_and_not_indeterminate = true; + bool any_unchecked_or_indeterminate = false; + + TreeItem *child_item = current->get_first_child(); + while (child_item) { + if (!child_item->is_checked(p_column)) { + any_unchecked_or_indeterminate = true; + if (child_item->is_indeterminate(p_column)) { + all_unchecked_and_not_indeterminate = false; + break; + } + } else { + all_unchecked_and_not_indeterminate = false; + } + child_item = child_item->get_next(); + } + + if (all_unchecked_and_not_indeterminate) { + current->set_checked(p_column, false); + } else if (any_unchecked_or_indeterminate) { + current->set_indeterminate(p_column, true); + } else { + current->set_checked(p_column, true); + } + + if (p_emit_signal) { + current->tree->emit_signal(SNAME("check_propagated_to_item"), current, p_column); + } + current->_propagate_check_through_parents(p_column, p_emit_signal); +} + void TreeItem::set_text(int p_column, String p_text) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].text = p_text; @@ -496,8 +555,9 @@ void TreeItem::uncollapse_tree() { void TreeItem::set_custom_minimum_height(int p_height) { custom_min_height = p_height; - for (Cell &c : cells) + for (Cell &c : cells) { c.cached_minimum_size_dirty = true; + } _changed_notify(); } @@ -1033,8 +1093,9 @@ bool TreeItem::get_expand_right(int p_column) const { void TreeItem::set_disable_folding(bool p_disable) { disable_folding = p_disable; - for (Cell &c : cells) + for (Cell &c : cells) { c.cached_minimum_size_dirty = true; + } _changed_notify(0); } @@ -1141,6 +1202,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("is_checked", "column"), &TreeItem::is_checked); ClassDB::bind_method(D_METHOD("is_indeterminate", "column"), &TreeItem::is_indeterminate); + ClassDB::bind_method(D_METHOD("propagate_check", "column", "emit_signal"), &TreeItem::propagate_check, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_text", "column", "text"), &TreeItem::set_text); ClassDB::bind_method(D_METHOD("get_text", "column"), &TreeItem::get_text); @@ -1256,10 +1319,10 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children); ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index); - ClassDB::bind_method(D_METHOD("move_before", "item"), &TreeItem::_move_before); - ClassDB::bind_method(D_METHOD("move_after", "item"), &TreeItem::_move_after); + ClassDB::bind_method(D_METHOD("move_before", "item"), &TreeItem::move_before); + ClassDB::bind_method(D_METHOD("move_after", "item"), &TreeItem::move_after); - ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::_remove_child); + ClassDB::bind_method(D_METHOD("remove_child", "child"), &TreeItem::remove_child); { MethodInfo mi; @@ -2427,7 +2490,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int /* process selection */ if (p_double_click && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check - + // Emits the "item_activated" signal. propagate_mouse_activated = true; incr_search.clear(); @@ -4752,7 +4815,7 @@ bool Tree::get_allow_reselect() const { void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &Tree::clear); - ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width); @@ -4767,7 +4830,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hide_root", "enable"), &Tree::set_hide_root); ClassDB::bind_method(D_METHOD("is_root_hidden"), &Tree::is_root_hidden); - ClassDB::bind_method(D_METHOD("get_next_selected", "from"), &Tree::_get_next_selected); + ClassDB::bind_method(D_METHOD("get_next_selected", "from"), &Tree::get_next_selected); ClassDB::bind_method(D_METHOD("get_selected"), &Tree::get_selected); ClassDB::bind_method(D_METHOD("get_selected_column"), &Tree::get_selected_column); ClassDB::bind_method(D_METHOD("get_pressed_button"), &Tree::get_pressed_button); @@ -4781,7 +4844,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column); ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected); ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect); - ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::_get_item_rect, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::get_item_rect, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position); ClassDB::bind_method(D_METHOD("get_column_at_position", "position"), &Tree::get_column_at_position); ClassDB::bind_method(D_METHOD("get_drop_section_at_position", "position"), &Tree::get_drop_section_at_position); @@ -4805,7 +4868,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_column_title_language", "column"), &Tree::get_column_title_language); ClassDB::bind_method(D_METHOD("get_scroll"), &Tree::get_scroll); - ClassDB::bind_method(D_METHOD("scroll_to_item", "item"), &Tree::_scroll_to_item); + ClassDB::bind_method(D_METHOD("scroll_to_item", "item"), &Tree::scroll_to_item); ClassDB::bind_method(D_METHOD("set_h_scroll_enabled", "h_scroll"), &Tree::set_h_scroll_enabled); ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &Tree::is_h_scroll_enabled); @@ -4847,6 +4910,7 @@ void Tree::_bind_methods() { ADD_SIGNAL(MethodInfo("item_custom_button_pressed")); ADD_SIGNAL(MethodInfo("item_double_clicked")); ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"))); + ADD_SIGNAL(MethodInfo("check_propagated_to_item", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"))); //ADD_SIGNAL( MethodInfo("item_double_clicked" ) ); ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked"))); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index c60c87564e..c24763a0e4 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -188,16 +188,6 @@ protected: return d; } - void _remove_child(Object *p_child) { - remove_child(Object::cast_to<TreeItem>(p_child)); - } - - void _move_before(Object *p_item) { - move_before(Object::cast_to<TreeItem>(p_item)); - } - void _move_after(Object *p_item) { - move_after(Object::cast_to<TreeItem>(p_item)); - } Variant _call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -212,6 +202,14 @@ public: bool is_checked(int p_column) const; bool is_indeterminate(int p_column) const; + void propagate_check(int p_column, bool p_emit_signal = true); + +private: + // Check helpers. + void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal); + void _propagate_check_through_parents(int p_column, bool p_emit_signal); + +public: void set_text(int p_column, String p_text); String get_text(int p_column) const; @@ -609,23 +607,6 @@ private: protected: static void _bind_methods(); - //bind helpers - TreeItem *_create_item(Object *p_parent, int p_idx = -1) { - return create_item(Object::cast_to<TreeItem>(p_parent), p_idx); - } - - TreeItem *_get_next_selected(Object *p_item) { - return get_next_selected(Object::cast_to<TreeItem>(p_item)); - } - - Rect2 _get_item_rect(Object *p_item, int p_column) const { - return get_item_rect(Object::cast_to<TreeItem>(p_item), p_column); - } - - void _scroll_to_item(Object *p_item) { - scroll_to_item(Object::cast_to<TreeItem>(p_item)); - } - public: virtual void gui_input(const Ref<InputEvent> &p_event) override; diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp index ba5e8d4a17..71865b4864 100644 --- a/scene/gui/view_panner.cpp +++ b/scene/gui/view_panner.cpp @@ -31,22 +31,18 @@ #include "view_panner.h" #include "core/input/input.h" +#include "core/input/shortcut.h" #include "core/os/keyboard.h" bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - // Alt modifier is unused, so ignore such events. - if (mb->is_alt_pressed()) { - return false; - } - Vector2i scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP)); if (scroll_vec != Vector2()) { if (control_scheme == SCROLL_PANS) { if (mb->is_ctrl_pressed()) { scroll_vec.y *= mb->get_factor(); - callback_helper(zoom_callback, scroll_vec, mb->get_position()); + callback_helper(zoom_callback, varray(scroll_vec, mb->get_position(), mb->is_alt_pressed())); return true; } else { Vector2 panning; @@ -57,7 +53,7 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) panning.y += mb->get_factor() * scroll_vec.y; panning.x += mb->get_factor() * scroll_vec.x; } - callback_helper(scroll_callback, panning); + callback_helper(scroll_callback, varray(panning, mb->is_alt_pressed())); return true; } } else { @@ -70,23 +66,33 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) panning.y += mb->get_factor() * scroll_vec.y; panning.x += mb->get_factor() * scroll_vec.x; } - callback_helper(scroll_callback, panning); + callback_helper(scroll_callback, varray(panning, mb->is_alt_pressed())); return true; } else if (!mb->is_shift_pressed()) { scroll_vec.y *= mb->get_factor(); - callback_helper(zoom_callback, scroll_vec, mb->get_position()); + callback_helper(zoom_callback, varray(scroll_vec, mb->get_position(), mb->is_alt_pressed())); return true; } } } - if (mb->get_button_index() == MouseButton::MIDDLE || (mb->get_button_index() == MouseButton::RIGHT && !disable_rmb) || (mb->get_button_index() == MouseButton::LEFT && (Input::get_singleton()->is_key_pressed(Key::SPACE) || (is_dragging && !mb->is_pressed())))) { + // Alt is not used for button presses, so ignore it. + if (mb->is_alt_pressed()) { + return false; + } + + bool is_drag_event = mb->get_button_index() == MouseButton::MIDDLE || + (enable_rmb && mb->get_button_index() == MouseButton::RIGHT) || + (!simple_panning_enabled && mb->get_button_index() == MouseButton::LEFT && is_panning()) || + (force_drag && mb->get_button_index() == MouseButton::LEFT); + + if (is_drag_event) { if (mb->is_pressed()) { is_dragging = true; } else { is_dragging = false; } - return true; + return mb->get_button_index() != MouseButton::LEFT || mb->is_pressed(); // Don't consume LMB release events (it fixes some selection problems). } } @@ -94,9 +100,20 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) if (mm.is_valid()) { if (is_dragging) { if (p_canvas_rect != Rect2()) { - callback_helper(pan_callback, Input::get_singleton()->warp_mouse_motion(mm, p_canvas_rect)); + callback_helper(pan_callback, varray(Input::get_singleton()->warp_mouse_motion(mm, p_canvas_rect))); } else { - callback_helper(pan_callback, mm->get_relative()); + callback_helper(pan_callback, varray(mm->get_relative())); + } + return true; + } + } + + Ref<InputEventKey> k = p_event; + if (k.is_valid()) { + if (pan_view_shortcut.is_valid() && pan_view_shortcut->matches_event(k)) { + pan_key_pressed = k->is_pressed(); + if (simple_panning_enabled || (Input::get_singleton()->get_mouse_button_mask() & MouseButton::LEFT) != MouseButton::NONE) { + is_dragging = pan_key_pressed; } return true; } @@ -105,26 +122,20 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) return false; } -void ViewPanner::callback_helper(Callable p_callback, Vector2 p_arg1, Vector2 p_arg2) { - if (p_callback == zoom_callback) { - const Variant **argptr = (const Variant **)alloca(sizeof(Variant *) * 2); - Variant var1 = p_arg1; - argptr[0] = &var1; - Variant var2 = p_arg2; - argptr[1] = &var2; - - Variant result; - Callable::CallError ce; - p_callback.call(argptr, 2, result, ce); - } else { - const Variant **argptr = (const Variant **)alloca(sizeof(Variant *)); - Variant var = p_arg1; - argptr[0] = &var; - - Variant result; - Callable::CallError ce; - p_callback.call(argptr, 1, result, ce); +void ViewPanner::release_pan_key() { + pan_key_pressed = false; + is_dragging = false; +} + +void ViewPanner::callback_helper(Callable p_callback, Vector<Variant> p_args) { + const Variant **argptr = (const Variant **)alloca(sizeof(Variant *) * p_args.size()); + for (int i = 0; i < p_args.size(); i++) { + argptr[i] = &p_args[i]; } + + Variant result; + Callable::CallError ce; + p_callback.call(argptr, p_args.size(), result, ce); } void ViewPanner::set_callbacks(Callable p_scroll_callback, Callable p_pan_callback, Callable p_zoom_callback) { @@ -137,6 +148,37 @@ void ViewPanner::set_control_scheme(ControlScheme p_scheme) { control_scheme = p_scheme; } -void ViewPanner::set_disable_rmb(bool p_disable) { - disable_rmb = p_disable; +void ViewPanner::set_enable_rmb(bool p_enable) { + enable_rmb = p_enable; +} + +void ViewPanner::set_pan_shortcut(Ref<Shortcut> p_shortcut) { + pan_view_shortcut = p_shortcut; + pan_key_pressed = false; +} + +void ViewPanner::set_simple_panning_enabled(bool p_enabled) { + simple_panning_enabled = p_enabled; +} + +void ViewPanner::setup(ControlScheme p_scheme, Ref<Shortcut> p_shortcut, bool p_simple_panning) { + set_control_scheme(p_scheme); + set_pan_shortcut(p_shortcut); + set_simple_panning_enabled(p_simple_panning); +} + +bool ViewPanner::is_panning() const { + return is_dragging || pan_key_pressed; +} + +void ViewPanner::set_force_drag(bool p_force) { + force_drag = p_force; +} + +ViewPanner::ViewPanner() { + Array inputs; + inputs.append(InputEventKey::create_reference(Key::SPACE)); + + pan_view_shortcut.instantiate(); + pan_view_shortcut->set_events(inputs); } diff --git a/scene/gui/view_panner.h b/scene/gui/view_panner.h index 0a92cb3dfd..5b820c5f8f 100644 --- a/scene/gui/view_panner.h +++ b/scene/gui/view_panner.h @@ -34,6 +34,7 @@ #include "core/object/ref_counted.h" class InputEvent; +class Shortcut; class ViewPanner : public RefCounted { GDCLASS(ViewPanner, RefCounted); @@ -46,23 +47,37 @@ public: private: bool is_dragging = false; - bool disable_rmb = false; + bool pan_key_pressed = false; + bool force_drag = false; + + bool enable_rmb = false; + bool simple_panning_enabled = false; + + Ref<Shortcut> pan_view_shortcut; Callable scroll_callback; Callable pan_callback; Callable zoom_callback; - void callback_helper(Callable p_callback, Vector2 p_arg1, Vector2 p_arg2 = Vector2()); + void callback_helper(Callable p_callback, Vector<Variant> p_args); ControlScheme control_scheme = SCROLL_ZOOMS; public: void set_callbacks(Callable p_scroll_callback, Callable p_pan_callback, Callable p_zoom_callback); void set_control_scheme(ControlScheme p_scheme); - void set_disable_rmb(bool p_disable); + void set_enable_rmb(bool p_enable); + void set_pan_shortcut(Ref<Shortcut> p_shortcut); + void set_simple_panning_enabled(bool p_enabled); - bool is_panning() const { return is_dragging; } + void setup(ControlScheme p_scheme, Ref<Shortcut> p_shortcut, bool p_simple_panning); + + bool is_panning() const; + void set_force_drag(bool p_force); bool gui_input(const Ref<InputEvent> &p_ev, Rect2 p_canvas_rect = Rect2()); + void release_pan_key(); + + ViewPanner(); }; #endif // VIEW_PANNER_H diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 59d933fa1d..a62bbb146c 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -72,6 +72,15 @@ bool CanvasItem::is_visible_in_tree() const { p = p->get_parent_item(); } + const Node *n = get_parent(); + while (n) { + const CanvasLayer *c = Object::cast_to<CanvasLayer>(n); + if (c && !c->is_visible()) { + return false; + } + n = n->get_parent(); + } + return true; } @@ -1017,8 +1026,8 @@ void CanvasItem::set_notify_transform(bool p_enable) { notify_transform = p_enable; if (notify_transform && is_inside_tree()) { - //this ensures that invalid globals get resolved, so notifications can be received - get_global_transform(); + // This ensures that invalid globals get resolved, so notifications can be received. + _ALLOW_DISCARD_ get_global_transform(); } } diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 3d49d89746..08fea52c3a 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -46,6 +46,8 @@ class World2D; class CanvasItem : public Node { GDCLASS(CanvasItem, Node); + friend class CanvasLayer; + public: enum TextureFilter { TEXTURE_FILTER_PARENT_NODE, diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 282ab6b497..3f3e72357b 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "canvas_layer.h" +#include "canvas_item.h" #include "viewport.h" void CanvasLayer::set_layer(int p_xform) { @@ -42,6 +43,32 @@ int CanvasLayer::get_layer() const { return layer; } +void CanvasLayer::set_visible(bool p_visible) { + if (p_visible == visible) { + return; + } + + visible = p_visible; + emit_signal(SNAME("visibility_changed")); + + for (int i = 0; i < get_child_count(); i++) { + CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i)); + if (c) { + RenderingServer::get_singleton()->canvas_item_set_visible(c->get_canvas_item(), p_visible && c->is_visible()); + + if (c->is_visible()) { + c->_propagate_visibility_changed(p_visible); + } else { + c->notification(CanvasItem::NOTIFICATION_VISIBILITY_CHANGED); + } + } + } +} + +bool CanvasLayer::is_visible() const { + return visible; +} + void CanvasLayer::set_transform(const Transform2D &p_xform) { transform = p_xform; locrotscale_dirty = true; @@ -264,6 +291,9 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer); ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer); + ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasLayer::set_visible); + ClassDB::bind_method(D_METHOD("is_visible"), &CanvasLayer::is_visible); + ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CanvasLayer::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &CanvasLayer::get_transform); @@ -289,6 +319,7 @@ void CanvasLayer::_bind_methods() { ADD_GROUP("Layer", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); @@ -299,6 +330,8 @@ void CanvasLayer::_bind_methods() { ADD_GROUP("Follow Viewport", "follow_viewport"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); + + ADD_SIGNAL(MethodInfo("visibility_changed")); } CanvasLayer::CanvasLayer() { diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 93a0152787..b7bd793440 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -52,6 +52,7 @@ class CanvasLayer : public Node { Viewport *vp = nullptr; int sort_index = 0; + bool visible = true; bool follow_viewport = false; float follow_viewport_scale = 1.0; @@ -69,6 +70,9 @@ public: void set_layer(int p_xform); int get_layer() const; + void set_visible(bool p_visible); + bool is_visible() const; + void set_transform(const Transform2D &p_xform); Transform2D get_transform() const; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 34cc4aceb8..4e91548d14 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -46,7 +46,7 @@ Error HTTPRequest::_parse_url(const String &p_url) { request_sent = false; got_response = false; body_len = -1; - body.resize(0); + body.clear(); downloaded.set(0); redirections = 0; @@ -86,9 +86,9 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S String lowwer_case_header_name = p_header_name.to_lower(); for (int i = 0; i < p_headers.size(); i++) { - if (p_headers[i].find(":", 0) >= 0) { + if (p_headers[i].find(":") > 0) { Vector<String> parts = p_headers[i].split(":", false, 1); - if (parts[0].strip_edges().to_lower() == lowwer_case_header_name) { + if (parts.size() > 1 && parts[0].strip_edges().to_lower() == lowwer_case_header_name) { value = parts[1].strip_edges(); break; } @@ -99,7 +99,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S } Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { - // Copy the string into a raw buffer + // Copy the string into a raw buffer. Vector<uint8_t> raw_data; CharString charstr = p_request_data.utf8(); @@ -134,7 +134,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust headers = p_custom_headers; if (accept_gzip) { - // If the user has specified a different Accept-Encoding, don't overwrite it + // If the user has specified an Accept-Encoding header, don't overwrite it. if (!has_header(headers, "Accept-Encoding")) { headers.push_back("Accept-Encoding: gzip, deflate"); } @@ -202,7 +202,7 @@ void HTTPRequest::cancel_request() { file = nullptr; } client->close(); - body.resize(0); + body.clear(); got_response = false; response_code = -1; request_sent = false; @@ -220,14 +220,14 @@ bool HTTPRequest::_handle_response(bool *ret_value) { response_code = client->get_response_code(); List<String> rheaders; client->get_response_headers(&rheaders); - response_headers.resize(0); + response_headers.clear(); downloaded.set(0); for (const String &E : rheaders) { response_headers.push_back(E); } if (response_code == 301 || response_code == 302) { - // Handle redirect + // Handle redirect. if (max_redirects >= 0 && redirections >= max_redirects) { call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray()); @@ -244,12 +244,12 @@ bool HTTPRequest::_handle_response(bool *ret_value) { } if (!new_request.is_empty()) { - // Process redirect + // Process redirect. client->close(); - int new_redirs = redirections + 1; // Because _request() will clear it + int new_redirs = redirections + 1; // Because _request() will clear it. Error err; if (new_request.begins_with("http")) { - // New url, request all again + // New url, new request. _parse_url(new_request); } else { request_string = new_request; @@ -260,7 +260,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { request_sent = false; got_response = false; body_len = -1; - body.resize(0); + body.clear(); downloaded.set(0); redirections = new_redirs; *ret_value = false; @@ -276,11 +276,11 @@ bool HTTPRequest::_update_connection() { switch (client->get_status()) { case HTTPClient::STATUS_DISCONNECTED: { call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); - return true; // End it, since it's doing something + return true; // End it, since it's disconnected. } break; case HTTPClient::STATUS_RESOLVING: { client->poll(); - // Must wait + // Must wait. return false; } break; case HTTPClient::STATUS_CANT_RESOLVE: { @@ -290,9 +290,9 @@ bool HTTPRequest::_update_connection() { } break; case HTTPClient::STATUS_CONNECTING: { client->poll(); - // Must wait + // Must wait. return false; - } break; // Connecting to IP + } break; // Connecting to IP. case HTTPClient::STATUS_CANT_CONNECT: { call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); return true; @@ -301,7 +301,7 @@ bool HTTPRequest::_update_connection() { case HTTPClient::STATUS_CONNECTED: { if (request_sent) { if (!got_response) { - // No body + // No body. bool ret_value; @@ -313,16 +313,16 @@ bool HTTPRequest::_update_connection() { return true; } if (body_len < 0) { - // Chunked transfer is done + // Chunked transfer is done. call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body); return true; } call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); return true; - // Request might have been done + // Request might have been done. } else { - // Did not request yet, do request + // Did not request yet, do request. int size = request_data.size(); Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size); @@ -334,13 +334,13 @@ bool HTTPRequest::_update_connection() { request_sent = true; return false; } - } break; // Connected: break requests only accepted here + } break; // Connected: break requests only accepted here. case HTTPClient::STATUS_REQUESTING: { - // Must wait, still requesting + // Must wait, still requesting. client->poll(); return false; - } break; // Request in progress + } break; // Request in progress. case HTTPClient::STATUS_BODY: { if (!got_response) { bool ret_value; @@ -411,7 +411,7 @@ bool HTTPRequest::_update_connection() { return false; - } break; // Request resulted in body: break which must be read + } break; // Request resulted in body: break which must be read. case HTTPClient::STATUS_CONNECTION_ERROR: { call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; @@ -428,7 +428,7 @@ bool HTTPRequest::_update_connection() { void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) { cancel_request(); - // Determine if the request body is compressed + // Determine if the request body is compressed. bool is_compressed; String content_encoding = get_header_value(p_headers, "Content-Encoding").to_lower(); Compression::Mode mode; @@ -442,30 +442,25 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra is_compressed = false; } - const PackedByteArray *data = nullptr; - if (accept_gzip && is_compressed && p_data.size() > 0) { // Decompress request body - PackedByteArray *decompressed = memnew(PackedByteArray); - int result = Compression::decompress_dynamic(decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode); + PackedByteArray decompressed; + int result = Compression::decompress_dynamic(&decompressed, body_size_limit, p_data.ptr(), p_data.size(), mode); if (result == OK) { - data = decompressed; + emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, decompressed); + return; } else if (result == -5) { WARN_PRINT("Decompressed size of HTTP response body exceeded body_size_limit"); p_status = RESULT_BODY_SIZE_LIMIT_EXCEEDED; - // Just return the raw data if we failed to decompress it - data = &p_data; + // Just return the raw data if we failed to decompress it. } else { WARN_PRINT("Failed to decompress HTTP response body"); p_status = RESULT_BODY_DECOMPRESS_FAILED; - // Just return the raw data if we failed to decompress it - data = &p_data; + // Just return the raw data if we failed to decompress it. } - } else { - data = &p_data; } - emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, *data); + emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, p_data); } void HTTPRequest::_notification(int p_what) { @@ -476,7 +471,6 @@ void HTTPRequest::_notification(int p_what) { bool done = _update_connection(); if (done) { set_process_internal(false); - // cancel_request(); called from _request done now } } @@ -624,7 +618,6 @@ void HTTPRequest::_bind_methods() { ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "result"), PropertyInfo(Variant::INT, "response_code"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "headers"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "body"))); BIND_ENUM_CONSTANT(RESULT_SUCCESS); - //BIND_ENUM_CONSTANT( RESULT_NO_BODY ); BIND_ENUM_CONSTANT(RESULT_CHUNKED_BODY_SIZE_MISMATCH); BIND_ENUM_CONSTANT(RESULT_CANT_CONNECT); BIND_ENUM_CONSTANT(RESULT_CANT_RESOLVE); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 9d96c71113..6b9d8ab211 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "core/io/resource_loader.h" +#include "core/multiplayer/multiplayer_api.h" #include "core/object/message_queue.h" #include "core/string/print_string.h" #include "instance_placeholder.h" @@ -110,9 +111,6 @@ void Node::_notification(int p_notification) { memdelete(data.path_cache); data.path_cache = nullptr; } - if (data.scene_file_path.length()) { - get_multiplayer()->scene_enter_exit_notify(data.scene_file_path, this, false); - } } break; case NOTIFICATION_PATH_RENAMED: { if (data.path_cache) { @@ -141,12 +139,6 @@ void Node::_notification(int p_notification) { } GDVIRTUAL_CALL(_ready); - - if (data.scene_file_path.length()) { - ERR_FAIL_COND(!is_inside_tree()); - get_multiplayer()->scene_enter_exit_notify(data.scene_file_path, this, true); - } - } break; case NOTIFICATION_POSTINITIALIZE: { data.in_constructor = false; @@ -211,6 +203,12 @@ void Node::_propagate_enter_tree() { data.tree->node_added(this); + if (data.parent) { + Variant c = this; + const Variant *cptr = &c; + data.parent->emit_signal(SNAME("child_entered_tree"), &cptr, 1); + } + data.blocked++; //block while adding children @@ -281,6 +279,12 @@ void Node::_propagate_exit_tree() { data.tree->node_removed(this); } + if (data.parent) { + Variant c = this; + const Variant *cptr = &c; + data.parent->emit_signal(SNAME("child_exited_tree"), &cptr, 1); + } + // exit groups for (KeyValue<StringName, GroupData> &E : data.grouped) { @@ -1049,7 +1053,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co String nums; for (int i = name_string.length() - 1; i >= 0; i--) { char32_t n = name_string[i]; - if (n >= '0' && n <= '9') { + if (is_digit(n)) { nums = String::chr(name_string[i]) + nums; } else { break; @@ -1316,12 +1320,14 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { Node *Node::get_node(const NodePath &p_path) const { Node *node = get_node_or_null(p_path); - if (p_path.is_absolute()) { - ERR_FAIL_COND_V_MSG(!node, nullptr, - vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path())); - } else { - ERR_FAIL_COND_V_MSG(!node, nullptr, - vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path())); + if (unlikely(!node)) { + if (p_path.is_absolute()) { + ERR_FAIL_V_MSG(nullptr, + vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path())); + } else { + ERR_FAIL_V_MSG(nullptr, + vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path())); + } } return node; @@ -2186,7 +2192,7 @@ void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_re } Variant v = p_node->get(E.name); - if (v.is_ref()) { + if (v.is_ref_counted()) { RES res = v; if (res.is_valid()) { if (p_resource_remap.has(res)) { @@ -2212,7 +2218,7 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc } Variant v = p_resource->get(E.name); - if (v.is_ref()) { + if (v.is_ref_counted()) { RES res = v; if (res.is_valid()) { if (p_resource_remap.has(res)) { @@ -2863,6 +2869,8 @@ void Node::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_entered")); ADD_SIGNAL(MethodInfo("tree_exiting")); ADD_SIGNAL(MethodInfo("tree_exited")); + ADD_SIGNAL(MethodInfo("child_entered_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); + ADD_SIGNAL(MethodInfo("child_exited_tree", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT, "Node"))); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_name", "get_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "scene_file_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_scene_file_path", "get_scene_file_path"); diff --git a/scene/main/node.h b/scene/main/node.h index a1fc672a15..0ac10f4381 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -212,7 +212,6 @@ protected: static String _get_name_num_separator(); friend class SceneState; - friend class MultiplayerReplicator; void _add_child_nocheck(Node *p_child, const StringName &p_name); void _set_owner_nocheck(Node *p_owner); @@ -467,7 +466,7 @@ public: bool is_displayed_folded() const; /* NETWORK */ - void set_multiplayer_authority(int p_peer_id, bool p_recursive = true); + virtual void set_multiplayer_authority(int p_peer_id, bool p_recursive = true); int get_multiplayer_authority() const; bool is_multiplayer_authority() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index cafa4a43fd..69d781cbfc 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -36,6 +36,7 @@ #include "core/io/dir_access.h" #include "core/io/marshalls.h" #include "core/io/resource_loader.h" +#include "core/multiplayer/multiplayer_api.h" #include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -130,7 +131,7 @@ SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_nod E = group_map.insert(p_group, Group()); } - ERR_FAIL_COND_V_MSG(E->get().nodes.find(p_node) != -1, &E->get(), "Already in group: " + p_group + "."); + ERR_FAIL_COND_V_MSG(E->get().nodes.has(p_node), &E->get(), "Already in group: " + p_group + "."); E->get().nodes.push_back(p_node); //E->get().last_tree_version=0; E->get().changed = true; @@ -1164,7 +1165,7 @@ void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { ERR_FAIL_COND(!p_multiplayer.is_valid()); multiplayer = p_multiplayer; - multiplayer->set_root_node(root); + multiplayer->set_root_path("/" + root->get_name()); } void SceneTree::_bind_methods() { @@ -1328,6 +1329,8 @@ SceneTree::SceneTree() { root = memnew(Window); root->set_process_mode(Node::PROCESS_MODE_PAUSABLE); root->set_name("root"); + root->set_title(ProjectSettings::get_singleton()->get("application/config/name")); + #ifndef _3D_DISABLED if (!root->get_world_3d().is_valid()) { root->set_world_3d(Ref<World3D>(memnew(World3D))); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 1dff1dab4f..a5cd52b4ca 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -31,7 +31,6 @@ #ifndef SCENE_TREE_H #define SCENE_TREE_H -#include "core/multiplayer/multiplayer_api.h" #include "core/os/main_loop.h" #include "core/os/thread_safe.h" #include "core/templates/self_list.h" @@ -46,6 +45,7 @@ class Node; class Window; class Material; class Mesh; +class MultiplayerAPI; class SceneDebugger; class Tween; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 4ad250ff54..522997cdf5 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -492,20 +492,26 @@ void Viewport::_notification(int p_what) { } #endif // _3D_DISABLED } break; + case NOTIFICATION_WM_MOUSE_ENTER: { + gui.mouse_in_window = true; + } break; case NOTIFICATION_WM_MOUSE_EXIT: { + gui.mouse_in_window = false; _drop_physics_mouseover(); - - // Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not - // drop the gui mouseover here, as a scrollbar may be dragged while the - // mouse is outside the window (without the window having lost focus). - // See bug #39634 + _drop_mouse_over(); + // When the mouse exits the window, we want to end mouse_over, but + // not mouse_focus, because, for example, we want to continue + // dragging a scrollbar even if the mouse has left the window. } break; case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { _drop_physics_mouseover(); - if (gui.mouse_focus && !gui.forced_mouse_focus) { _drop_mouse_focus(); } + // When the window focus changes, we want to end mouse_focus, but + // not the mouse_over. Note: The OS will trigger a separate mouse + // exit event if the change in focus results in the mouse exiting + // the window. } break; } } @@ -523,6 +529,13 @@ void Viewport::_process_picking() { _drop_physics_mouseover(true); +#ifndef _3D_DISABLED + Vector2 last_pos(1e20, 1e20); + CollisionObject3D *last_object = nullptr; + ObjectID last_id; + PhysicsDirectSpaceState3D::RayResult result; +#endif // _3D_DISABLED + PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); if (physics_has_last_mousepos) { @@ -690,10 +703,6 @@ void Viewport::_process_picking() { } #ifndef _3D_DISABLED - Vector2 last_pos(1e20, 1e20); - CollisionObject3D *last_object = nullptr; - ObjectID last_id; - PhysicsDirectSpaceState3D::RayResult result; bool captured = false; if (physics_object_capture.is_valid()) { @@ -790,7 +799,7 @@ void Viewport::update_canvas_items() { } void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) { - if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect) { + if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect == p_to_screen_rect) { return; } @@ -1090,7 +1099,7 @@ Transform2D Viewport::_get_input_pre_xform() const { if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) { pre_xf.elements[2] = -to_screen_rect.position; - pre_xf.scale(size / to_screen_rect.size); + pre_xf.scale(Vector2(size) / to_screen_rect.size); } return pre_xf; @@ -1222,7 +1231,7 @@ void Viewport::_gui_show_tooltip() { base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE); - panel->set_transient(false); + panel->set_transient(true); panel->set_flag(Window::FLAG_NO_FOCUS, true); panel->set_wrap_controls(true); panel->add_child(base_tooltip); @@ -1444,8 +1453,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (mb.is_valid()) { gui.key_event_accepted = false; - Control *over = nullptr; - Point2 mpos = mb->get_position(); gui.last_mouse_pos = mpos; if (mb->is_pressed()) { @@ -1591,6 +1598,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { // it is different, rather than wait for it to be updated the next time the // mouse is moved, notify the control so that it can e.g. drop the highlight. // This code is duplicated from the mm.is_valid()-case further below. + Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; } else { @@ -1598,10 +1606,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (gui.mouse_focus_mask == MouseButton::NONE && over != gui.mouse_over) { - if (gui.mouse_over) { - _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT); - } - + _drop_mouse_over(); _gui_cancel_tooltip(); if (over) { @@ -1622,8 +1627,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.last_mouse_pos = mpos; - Control *over = nullptr; - // Drag & drop. if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { gui.drag_accum += mm->get_relative(); @@ -1671,29 +1674,23 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } } - // These sections of code are reused in the mb.is_valid() case further up - // for the purpose of notifying controls about potential changes in focus - // when the mousebutton is released. + Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; - } else { + } else if (gui.mouse_in_window) { over = gui_find_control(mpos); } if (over != gui.mouse_over) { - if (gui.mouse_over) { - _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT); - } - + _drop_mouse_over(); _gui_cancel_tooltip(); if (over) { _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER); + gui.mouse_over = over; } } - gui.mouse_over = over; - DisplayServer::CursorShape ds_cursor_shape = (DisplayServer::CursorShape)Input::get_singleton()->get_default_cursor_shape(); if (over) { @@ -2095,7 +2092,7 @@ void Viewport::_gui_hide_control(Control *p_control) { } if (gui.key_focus == p_control) { - _gui_remove_focus(); + gui_release_focus(); } if (gui.mouse_over == p_control) { gui.mouse_over = nullptr; @@ -2145,15 +2142,7 @@ Window *Viewport::get_base_window() const { } void Viewport::_gui_remove_focus_for_window(Node *p_window) { if (get_base_window() == p_window) { - _gui_remove_focus(); - } -} - -void Viewport::_gui_remove_focus() { - if (gui.key_focus) { - Node *f = gui.key_focus; - gui.key_focus = nullptr; - f->notification(Control::NOTIFICATION_FOCUS_EXIT, true); + gui_release_focus(); } } @@ -2180,6 +2169,13 @@ void Viewport::_gui_accept_event() { } } +void Viewport::_drop_mouse_over() { + if (gui.mouse_over) { + _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT); + gui.mouse_over = nullptr; + } +} + void Viewport::_drop_mouse_focus() { Control *c = gui.mouse_focus; MouseButton mask = gui.mouse_focus_mask; @@ -2275,10 +2271,6 @@ void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paus } } -Control *Viewport::_gui_get_focus_owner() { - return gui.key_focus; -} - void Viewport::_gui_grab_click_focus(Control *p_control) { gui.mouse_click_grabber = p_control; call_deferred(SNAME("_post_gui_grab_click_focus")); @@ -2348,7 +2340,7 @@ void Viewport::push_text_input(const String &p_text) { } Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point) { - if (p_subwindow->get_flag(Window::FLAG_BORDERLESS)) { + if (p_subwindow->get_flag(Window::FLAG_BORDERLESS) || p_subwindow->get_flag(Window::FLAG_RESIZE_DISABLED)) { return SUB_WINDOW_RESIZE_DISABLED; } @@ -2794,6 +2786,19 @@ int Viewport::gui_get_canvas_sort_index() { return gui.canvas_sort_index++; } +void Viewport::gui_release_focus() { + if (gui.key_focus) { + Control *f = gui.key_focus; + gui.key_focus = nullptr; + f->notification(Control::NOTIFICATION_FOCUS_EXIT, true); + f->update(); + } +} + +Control *Viewport::gui_get_focus_owner() { + return gui.key_focus; +} + void Viewport::set_msaa(MSAA p_msaa) { ERR_FAIL_INDEX(p_msaa, MSAA_MAX); if (msaa == p_msaa) { @@ -3587,6 +3592,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful); + ClassDB::bind_method(D_METHOD("gui_release_focus"), &Viewport::gui_release_focus); + ClassDB::bind_method(D_METHOD("gui_get_focus_owner"), &Viewport::gui_get_focus_owner); + ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input); ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a3127811f5..3a71745f44 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -335,6 +335,7 @@ private: // info used when this is a window bool forced_mouse_focus = false; //used for menu buttons + bool mouse_in_window = true; bool key_event_accepted = false; Control *mouse_focus = nullptr; Control *last_mouse_focus = nullptr; @@ -410,7 +411,6 @@ private: Control *_gui_get_drag_preview(); void _gui_remove_focus_for_window(Node *p_window); - void _gui_remove_focus(); void _gui_unfocus_control(Control *p_control); bool _gui_control_has_focus(const Control *p_control); void _gui_control_grab_focus(Control *p_control); @@ -418,8 +418,6 @@ private: void _post_gui_grab_click_focus(); void _gui_accept_event(); - Control *_gui_get_focus_owner(); - bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check); friend class AudioListener2D; @@ -433,6 +431,7 @@ private: void _canvas_layer_add(CanvasLayer *p_canvas_layer); void _canvas_layer_remove(CanvasLayer *p_canvas_layer); + void _drop_mouse_over(); void _drop_mouse_focus(); void _drop_physics_mouseover(bool p_paused_only = false); @@ -557,6 +556,9 @@ public: void gui_reset_canvas_sort_index(); int gui_get_canvas_sort_index(); + void gui_release_focus(); + Control *gui_get_focus_owner(); + TypedArray<String> get_configuration_warnings() const override; void set_debug_draw(DebugDraw p_debug_draw); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 43de4187d4..f2ebe50fa3 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -41,7 +41,16 @@ void Window::set_title(const String &p_title) { if (embedder) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_set_title(atr(p_title), window_id); + String tr_title = atr(p_title); +#ifdef DEBUG_ENABLED + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + // Append a suffix to the window title to denote that the project is running + // from a debug build (including the editor). Since this results in lower performance, + // this should be clearly presented to the user. + tr_title = vformat("%s (DEBUG)", tr_title); + } +#endif + DisplayServer::get_singleton()->window_set_title(tr_title, window_id); } } @@ -234,7 +243,16 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); - DisplayServer::get_singleton()->window_set_title(atr(title), window_id); + String tr_title = atr(title); +#ifdef DEBUG_ENABLED + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + // Append a suffix to the window title to denote that the project is running + // from a debug build (including the editor). Since this results in lower performance, + // this should be clearly presented to the user. + tr_title = vformat("%s (DEBUG)", tr_title); + } +#endif + DisplayServer::get_singleton()->window_set_title(tr_title, window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); _update_window_size(); @@ -281,6 +299,11 @@ void Window::_clear_window() { DisplayServer::get_singleton()->delete_sub_window(window_id); window_id = DisplayServer::INVALID_WINDOW_ID; + // If closing window was focused and has a parent, return focus. + if (focused && transient_parent) { + transient_parent->grab_focus(); + } + _update_viewport_size(); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); } @@ -768,7 +791,16 @@ void Window::_notification(int p_what) { if (embedder) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { - DisplayServer::get_singleton()->window_set_title(atr(title), window_id); + String tr_title = atr(title); +#ifdef DEBUG_ENABLED + if (window_id == DisplayServer::MAIN_WINDOW_ID) { + // Append a suffix to the window title to denote that the project is running + // from a debug build (including the editor). Since this results in lower performance, + // this should be clearly presented to the user. + tr_title = vformat("%s (DEBUG)", tr_title); + } +#endif + DisplayServer::get_singleton()->window_set_title(tr_title, window_id); } child_controls_changed(); @@ -1574,6 +1606,7 @@ void Window::_bind_methods() { ADD_SIGNAL(MethodInfo("go_back_requested")); ADD_SIGNAL(MethodInfo("visibility_changed")); ADD_SIGNAL(MethodInfo("about_to_popup")); + ADD_SIGNAL(MethodInfo("theme_changed")); BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); @@ -1581,6 +1614,7 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(MODE_MINIMIZED); BIND_ENUM_CONSTANT(MODE_MAXIMIZED); BIND_ENUM_CONSTANT(MODE_FULLSCREEN); + BIND_ENUM_CONSTANT(MODE_EXCLUSIVE_FULLSCREEN); BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED); BIND_ENUM_CONSTANT(FLAG_BORDERLESS); diff --git a/scene/main/window.h b/scene/main/window.h index 2dd1dd6601..f37689f905 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -46,6 +46,7 @@ public: MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED, MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED, MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN, + MODE_EXCLUSIVE_FULLSCREEN = DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN, }; enum Flags { diff --git a/scene/multiplayer/SCsub b/scene/multiplayer/SCsub new file mode 100644 index 0000000000..fc61250247 --- /dev/null +++ b/scene/multiplayer/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/multiplayer/multiplayer_spawner.cpp b/scene/multiplayer/multiplayer_spawner.cpp new file mode 100644 index 0000000000..4f2a9d9e83 --- /dev/null +++ b/scene/multiplayer/multiplayer_spawner.cpp @@ -0,0 +1,227 @@ +/*************************************************************************/ +/* multiplayer_spawner.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "multiplayer_spawner.h" + +#include "core/io/marshalls.h" +#include "core/multiplayer/multiplayer_api.h" +#include "scene/main/window.h" +#include "scene/scene_string_names.h" + +void MultiplayerSpawner::_bind_methods() { + ClassDB::bind_method(D_METHOD("spawn", "data"), &MultiplayerSpawner::spawn, DEFVAL(Variant())); + + ClassDB::bind_method(D_METHOD("get_spawnable_scenes"), &MultiplayerSpawner::get_spawnable_scenes); + ClassDB::bind_method(D_METHOD("set_spawnable_scenes", "scenes"), &MultiplayerSpawner::set_spawnable_scenes); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "replication", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_spawnable_scenes", "get_spawnable_scenes"); + + ClassDB::bind_method(D_METHOD("get_spawn_path"), &MultiplayerSpawner::get_spawn_path); + ClassDB::bind_method(D_METHOD("set_spawn_path", "path"), &MultiplayerSpawner::set_spawn_path); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "spawn_path", PROPERTY_HINT_NONE, ""), "set_spawn_path", "get_spawn_path"); + + ClassDB::bind_method(D_METHOD("get_spawn_limit"), &MultiplayerSpawner::get_spawn_limit); + ClassDB::bind_method(D_METHOD("set_spawn_limit", "limit"), &MultiplayerSpawner::set_spawn_limit); + ADD_PROPERTY(PropertyInfo(Variant::INT, "spawn_limit", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_spawn_limit", "get_spawn_limit"); + + ClassDB::bind_method(D_METHOD("set_auto_spawning", "enabled"), &MultiplayerSpawner::set_auto_spawning); + ClassDB::bind_method(D_METHOD("is_auto_spawning"), &MultiplayerSpawner::is_auto_spawning); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_spawn"), "set_auto_spawning", "is_auto_spawning"); + + GDVIRTUAL_BIND(_spawn_custom, "data"); + + ADD_SIGNAL(MethodInfo("despawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("spawned", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); +} + +void MultiplayerSpawner::_update_spawn_node() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + if (spawn_node.is_valid()) { + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)); + if (node && node->is_connected("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added))) { + node->disconnect("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added)); + } + } + Node *node = spawn_path.is_empty() && is_inside_tree() ? nullptr : get_node_or_null(spawn_path); + if (node) { + spawn_node = node->get_instance_id(); + if (auto_spawn) { + node->connect("child_entered_tree", callable_mp(this, &MultiplayerSpawner::_node_added)); + } + } else { + spawn_node = ObjectID(); + } +} + +void MultiplayerSpawner::_notification(int p_what) { + if (p_what == NOTIFICATION_POST_ENTER_TREE) { + _update_spawn_node(); + } else if (p_what == NOTIFICATION_EXIT_TREE) { + _update_spawn_node(); + const ObjectID *oid = nullptr; + while ((oid = tracked_nodes.next(oid))) { + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid)); + ERR_CONTINUE(!node); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit)); + // This is unlikely, but might still crash the engine. + if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) { + node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready)); + } + get_multiplayer()->despawn(node, this); + } + tracked_nodes.clear(); + } +} + +void MultiplayerSpawner::_node_added(Node *p_node) { + if (!get_multiplayer()->has_multiplayer_peer() || !is_multiplayer_authority()) { + return; + } + if (tracked_nodes.has(p_node->get_instance_id())) { + return; + } + const Node *parent = get_spawn_node(); + if (!parent || p_node->get_parent() != parent) { + return; + } + int id = get_scene_id(p_node->get_scene_file_path()); + if (id == INVALID_ID) { + return; + } + const String name = p_node->get_name(); + ERR_FAIL_COND_MSG(name.validate_node_name() != name, vformat("Unable to auto-spawn node with reserved name: %s. Make sure to add your replicated scenes via 'add_child(node, true)' to produce valid names.", name)); + _track(p_node, Variant(), id); +} + +void MultiplayerSpawner::set_auto_spawning(bool p_enabled) { + auto_spawn = p_enabled; + _update_spawn_node(); +} + +bool MultiplayerSpawner::is_auto_spawning() const { + return auto_spawn; +} + +TypedArray<PackedScene> MultiplayerSpawner::get_spawnable_scenes() { + return spawnable_scenes; +} + +void MultiplayerSpawner::set_spawnable_scenes(TypedArray<PackedScene> p_scenes) { + spawnable_scenes = p_scenes; +} + +NodePath MultiplayerSpawner::get_spawn_path() const { + return spawn_path; +} + +void MultiplayerSpawner::set_spawn_path(const NodePath &p_path) { + spawn_path = p_path; + _update_spawn_node(); +} + +void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_scene_id) { + ObjectID oid = p_node->get_instance_id(); + if (!tracked_nodes.has(oid)) { + tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id); + p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit), varray(p_node->get_instance_id()), CONNECT_ONESHOT); + p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready), varray(p_node->get_instance_id()), CONNECT_ONESHOT); + } +} + +void MultiplayerSpawner::_node_ready(ObjectID p_id) { + get_multiplayer()->spawn(ObjectDB::get_instance(p_id), this); +} + +void MultiplayerSpawner::_node_exit(ObjectID p_id) { + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id)); + ERR_FAIL_COND(!node); + if (tracked_nodes.has(p_id)) { + tracked_nodes.erase(p_id); + get_multiplayer()->despawn(node, this); + } +} + +int MultiplayerSpawner::get_scene_id(const String &p_scene) const { + for (int i = 0; i < spawnable_scenes.size(); i++) { + Ref<PackedScene> ps = spawnable_scenes[i]; + ERR_CONTINUE(ps.is_null()); + if (ps->get_path() == p_scene) { + return i; + } + } + return INVALID_ID; +} + +int MultiplayerSpawner::get_spawn_id(const ObjectID &p_id) const { + const SpawnInfo *info = tracked_nodes.getptr(p_id); + return info ? info->id : INVALID_ID; +} + +const Variant MultiplayerSpawner::get_spawn_argument(const ObjectID &p_id) const { + const SpawnInfo *info = tracked_nodes.getptr(p_id); + return info ? info->args : Variant(); +} + +Node *MultiplayerSpawner::instantiate_scene(int p_id) { + ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!"); + ERR_FAIL_INDEX_V(p_id, spawnable_scenes.size(), nullptr); + Ref<PackedScene> scene = spawnable_scenes[p_id]; + ERR_FAIL_COND_V(scene.is_null(), nullptr); + return scene->instantiate(); +} + +Node *MultiplayerSpawner::instantiate_custom(const Variant &p_data) { + ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!"); + Object *obj = nullptr; + Node *node = nullptr; + if (GDVIRTUAL_CALL(_spawn_custom, p_data, obj)) { + node = Object::cast_to<Node>(obj); + } + return node; +} + +Node *MultiplayerSpawner::spawn(const Variant &p_data) { + ERR_FAIL_COND_V(!is_inside_tree() || !get_multiplayer()->has_multiplayer_peer() || !is_multiplayer_authority(), nullptr); + ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!"); + ERR_FAIL_COND_V_MSG(!GDVIRTUAL_IS_OVERRIDDEN(_spawn_custom), nullptr, "Custom spawn requires the '_spawn_custom' virtual method to be implemented via script."); + + Node *parent = get_spawn_node(); + ERR_FAIL_COND_V_MSG(!parent, nullptr, "Cannot find spawn node."); + + Node *node = instantiate_custom(p_data); + ERR_FAIL_COND_V_MSG(!node, nullptr, "The '_spawn_custom' implementation must return a valid Node."); + + _track(node, p_data); + parent->add_child(node, true); + return node; +} diff --git a/scene/multiplayer/multiplayer_spawner.h b/scene/multiplayer/multiplayer_spawner.h new file mode 100644 index 0000000000..63948e39a5 --- /dev/null +++ b/scene/multiplayer/multiplayer_spawner.h @@ -0,0 +1,101 @@ +/*************************************************************************/ +/* multiplayer_spawner.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 MULTIPLAYER_SPAWNER_H +#define MULTIPLAYER_SPAWNER_H + +#include "scene/main/node.h" + +#include "core/variant/typed_array.h" +#include "scene/resources/packed_scene.h" +#include "scene/resources/scene_replication_config.h" + +class MultiplayerSpawner : public Node { + GDCLASS(MultiplayerSpawner, Node); + +public: + enum { + INVALID_ID = 0xFF, + }; + +private: + TypedArray<PackedScene> spawnable_scenes; + Set<ResourceUID::ID> spawnable_ids; + NodePath spawn_path; + + struct SpawnInfo { + Variant args; + int id = INVALID_ID; + SpawnInfo(Variant p_args, int p_id) { + id = p_id; + args = p_args; + } + SpawnInfo() {} + }; + + ObjectID spawn_node; + HashMap<ObjectID, SpawnInfo> tracked_nodes; + bool auto_spawn = false; + uint32_t spawn_limit = 0; + + void _update_spawn_node(); + void _track(Node *p_node, const Variant &p_argument, int p_scene_id = INVALID_ID); + void _node_added(Node *p_node); + void _node_exit(ObjectID p_id); + void _node_ready(ObjectID p_id); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + Node *get_spawn_node() const { return spawn_node.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(spawn_node)) : nullptr; } + TypedArray<PackedScene> get_spawnable_scenes(); + void set_spawnable_scenes(TypedArray<PackedScene> p_scenes); + NodePath get_spawn_path() const; + void set_spawn_path(const NodePath &p_path); + uint32_t get_spawn_limit() const { return spawn_limit; } + void set_spawn_limit(uint32_t p_limit) { spawn_limit = p_limit; } + bool is_auto_spawning() const; + void set_auto_spawning(bool p_enabled); + + const Variant get_spawn_argument(const ObjectID &p_id) const; + int get_spawn_id(const ObjectID &p_id) const; + int get_scene_id(const String &p_path) const; + Node *spawn(const Variant &p_data = Variant()); + Node *instantiate_custom(const Variant &p_data); + Node *instantiate_scene(int p_idx); + + GDVIRTUAL1R(Object *, _spawn_custom, const Variant &); + + MultiplayerSpawner() {} +}; + +#endif // MULTIPLAYER_SPAWNER_H diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp new file mode 100644 index 0000000000..fbe1b99cc9 --- /dev/null +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -0,0 +1,158 @@ +/*************************************************************************/ +/* multiplayer_synchronizer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "multiplayer_synchronizer.h" + +#include "core/config/engine.h" +#include "core/multiplayer/multiplayer_api.h" + +Object *MultiplayerSynchronizer::_get_prop_target(Object *p_obj, const NodePath &p_path) { + if (p_path.get_name_count() == 0) { + return p_obj; + } + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V_MSG(!node || !node->has_node(p_path), nullptr, vformat("Node '%s' not found.", p_path)); + return node->get_node(p_path); +} + +void MultiplayerSynchronizer::_stop() { + Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; + if (node) { + get_multiplayer()->replication_stop(node, this); + } +} + +void MultiplayerSynchronizer::_start() { + Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; + if (node) { + get_multiplayer()->replication_start(node, this); + } +} + +Error MultiplayerSynchronizer::get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs) { + ERR_FAIL_COND_V(!p_obj, ERR_INVALID_PARAMETER); + r_variant.resize(p_properties.size()); + r_variant_ptrs.resize(r_variant.size()); + int i = 0; + for (const NodePath &prop : p_properties) { + bool valid = false; + const Object *obj = _get_prop_target(p_obj, prop); + ERR_FAIL_COND_V(!obj, FAILED); + r_variant.write[i] = obj->get(prop.get_concatenated_subnames(), &valid); + r_variant_ptrs.write[i] = &r_variant[i]; + ERR_FAIL_COND_V_MSG(!valid, ERR_INVALID_DATA, vformat("Property '%s' not found.", prop)); + i++; + } + return OK; +} + +Error MultiplayerSynchronizer::set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state) { + ERR_FAIL_COND_V(!p_obj, ERR_INVALID_PARAMETER); + int i = 0; + for (const NodePath &prop : p_properties) { + Object *obj = _get_prop_target(p_obj, prop); + ERR_FAIL_COND_V(!obj, FAILED); + obj->set(prop.get_concatenated_subnames(), p_state[i]); + i += 1; + } + return OK; +} + +void MultiplayerSynchronizer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_root_path", "path"), &MultiplayerSynchronizer::set_root_path); + ClassDB::bind_method(D_METHOD("get_root_path"), &MultiplayerSynchronizer::get_root_path); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path"), "set_root_path", "get_root_path"); + + ClassDB::bind_method(D_METHOD("set_replication_interval", "milliseconds"), &MultiplayerSynchronizer::set_replication_interval); + ClassDB::bind_method(D_METHOD("get_replication_interval"), &MultiplayerSynchronizer::get_replication_interval); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "replication_interval", PROPERTY_HINT_RANGE, "0,5,0.001"), "set_replication_interval", "get_replication_interval"); + + ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config); + ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); +} + +void MultiplayerSynchronizer::_notification(int p_what) { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + if (root_path.is_empty()) { + return; + } + if (p_what == NOTIFICATION_ENTER_TREE) { + _start(); + } else if (p_what == NOTIFICATION_EXIT_TREE) { + _stop(); + } +} + +void MultiplayerSynchronizer::set_replication_interval(double p_interval) { + ERR_FAIL_COND_MSG(p_interval < 0, "Interval must be greater or equal to 0 (where 0 means default)"); + interval_msec = uint64_t(p_interval * 1000); +} + +double MultiplayerSynchronizer::get_replication_interval() const { + return double(interval_msec) / 1000.0; +} + +uint64_t MultiplayerSynchronizer::get_replication_interval_msec() const { + return interval_msec; +} + +void MultiplayerSynchronizer::set_replication_config(Ref<SceneReplicationConfig> p_config) { + replication_config = p_config; +} + +Ref<SceneReplicationConfig> MultiplayerSynchronizer::get_replication_config() { + return replication_config; +} + +void MultiplayerSynchronizer::set_root_path(const NodePath &p_path) { + _stop(); + root_path = p_path; + _start(); +} + +NodePath MultiplayerSynchronizer::get_root_path() const { + return root_path; +} + +void MultiplayerSynchronizer::set_multiplayer_authority(int p_peer_id, bool p_recursive) { + Node *node = is_inside_tree() ? get_node_or_null(root_path) : nullptr; + if (!node) { + Node::set_multiplayer_authority(p_peer_id, p_recursive); + return; + } + get_multiplayer()->replication_stop(node, this); + Node::set_multiplayer_authority(p_peer_id, p_recursive); + get_multiplayer()->replication_start(node, this); +} diff --git a/scene/multiplayer/multiplayer_synchronizer.h b/scene/multiplayer/multiplayer_synchronizer.h new file mode 100644 index 0000000000..e856745379 --- /dev/null +++ b/scene/multiplayer/multiplayer_synchronizer.h @@ -0,0 +1,72 @@ +/*************************************************************************/ +/* multiplayer_synchronizer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 MULTIPLAYER_SYNCHRONIZER_H +#define MULTIPLAYER_SYNCHRONIZER_H + +#include "scene/main/node.h" + +#include "scene/resources/scene_replication_config.h" + +class MultiplayerSynchronizer : public Node { + GDCLASS(MultiplayerSynchronizer, Node); + +private: + Ref<SceneReplicationConfig> replication_config; + NodePath root_path; + uint64_t interval_msec = 0; + + static Object *_get_prop_target(Object *p_obj, const NodePath &p_prop); + void _start(); + void _stop(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + static Error get_state(const List<NodePath> &p_properties, Object *p_obj, Vector<Variant> &r_variant, Vector<const Variant *> &r_variant_ptrs); + static Error set_state(const List<NodePath> &p_properties, Object *p_obj, const Vector<Variant> &p_state); + + void set_replication_interval(double p_interval); + double get_replication_interval() const; + uint64_t get_replication_interval_msec() const; + + void set_replication_config(Ref<SceneReplicationConfig> p_config); + Ref<SceneReplicationConfig> get_replication_config(); + + void set_root_path(const NodePath &p_path); + NodePath get_root_path() const; + virtual void set_multiplayer_authority(int p_peer_id, bool p_recursive = true) override; + + MultiplayerSynchronizer() {} +}; + +#endif // MULTIPLAYER_SYNCHRONIZER_H diff --git a/scene/multiplayer/scene_cache_interface.cpp b/scene/multiplayer/scene_cache_interface.cpp new file mode 100644 index 0000000000..de4a94470a --- /dev/null +++ b/scene/multiplayer/scene_cache_interface.cpp @@ -0,0 +1,249 @@ +/*************************************************************************/ +/* scene_cache_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene_cache_interface.h" + +#include "core/io/marshalls.h" +#include "scene/main/node.h" +#include "scene/main/window.h" + +MultiplayerCacheInterface *SceneCacheInterface::_create(MultiplayerAPI *p_multiplayer) { + return memnew(SceneCacheInterface(p_multiplayer)); +} + +void SceneCacheInterface::make_default() { + MultiplayerAPI::create_default_cache_interface = _create; +} + +void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) { + if (p_connected) { + path_get_cache.insert(p_id, PathGetCache()); + } else { + // Cleanup get cache. + path_get_cache.erase(p_id); + // Cleanup sent cache. + // Some refactoring is needed to make this faster and do paths GC. + List<NodePath> keys; + path_send_cache.get_key_list(&keys); + for (const NodePath &E : keys) { + PathSentCache *psc = path_send_cache.getptr(E); + psc->confirmed_peers.erase(p_id); + } + } +} + +void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); + ERR_FAIL_COND(!root_node); + ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); + int ofs = 1; + + String methods_md5; + methods_md5.parse_utf8((const char *)(p_packet + ofs), 32); + ofs += 33; + + int id = decode_uint32(&p_packet[ofs]); + ofs += 4; + + String paths; + paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs); + + NodePath path = paths; + + if (!path_get_cache.has(p_from)) { + path_get_cache[p_from] = PathGetCache(); + } + + Node *node = root_node->get_node(path); + ERR_FAIL_COND(node == nullptr); + const bool valid_rpc_checksum = multiplayer->get_rpc_md5(node) == methods_md5; + if (valid_rpc_checksum == false) { + ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); + } + + PathGetCache::NodeInfo ni; + ni.path = path; + + path_get_cache[p_from].nodes[id] = ni; + + // Encode path to send ack. + CharString pname = String(path).utf8(); + int len = encode_cstring(pname.get_data(), nullptr); + + Vector<uint8_t> packet; + + packet.resize(1 + 1 + len); + packet.write[0] = MultiplayerAPI::NETWORK_COMMAND_CONFIRM_PATH; + packet.write[1] = valid_rpc_checksum; + encode_cstring(pname.get_data(), &packet.write[2]); + + Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND(multiplayer_peer.is_null()); + + multiplayer_peer->set_transfer_channel(0); + multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); + multiplayer_peer->set_target_peer(p_from); + multiplayer_peer->put_packet(packet.ptr(), packet.size()); +} + +void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small."); + + const bool valid_rpc_checksum = p_packet[1]; + + String paths; + paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2); + + NodePath path = paths; + + if (valid_rpc_checksum == false) { + ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); + } + + PathSentCache *psc = path_send_cache.getptr(path); + ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache."); + + Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from); + ERR_FAIL_COND_MSG(!E, "Invalid packet received. Source peer was not found in cache for the given path."); + E->get() = true; +} + +bool SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) { + bool has_all_peers = true; + List<int> peers_to_add; // If one is missing, take note to add it. + + for (const Set<int>::Element *E = multiplayer->get_connected_peers().front(); E; E = E->next()) { + if (p_target < 0 && E->get() == -p_target) { + continue; // Continue, excluded. + } + + if (p_target > 0 && E->get() != p_target) { + continue; // Continue, not for this peer. + } + + Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); + + if (!F || !F->get()) { + // Path was not cached, or was cached but is unconfirmed. + if (!F) { + // Not cached at all, take note. + peers_to_add.push_back(E->get()); + } + + has_all_peers = false; + } + } + + if (peers_to_add.size() > 0) { + // Those that need to be added, send a message for this. + + // Encode function name. + const CharString path = String(p_path).utf8(); + const int path_len = encode_cstring(path.get_data(), nullptr); + + // Extract MD5 from rpc methods list. + const String methods_md5 = multiplayer->get_rpc_md5(p_node); + const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. + + Vector<uint8_t> packet; + packet.resize(1 + 4 + path_len + methods_md5_len); + int ofs = 0; + + packet.write[ofs] = MultiplayerAPI::NETWORK_COMMAND_SIMPLIFY_PATH; + ofs += 1; + + ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); + + ofs += encode_uint32(psc->id, &packet.write[ofs]); + + ofs += encode_cstring(path.get_data(), &packet.write[ofs]); + + Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND_V(multiplayer_peer.is_null(), false); + + for (int &E : peers_to_add) { + multiplayer_peer->set_target_peer(E); // To all of you. + multiplayer_peer->set_transfer_channel(0); + multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); + multiplayer_peer->put_packet(packet.ptr(), packet.size()); + + psc->confirmed_peers.insert(E, false); // Insert into confirmed, but as false since it was not confirmed. + } + } + + return has_all_peers; +} + +bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { + const PathSentCache *psc = path_send_cache.getptr(p_path); + ERR_FAIL_COND_V(!psc, false); + const Map<int, bool>::Element *F = psc->confirmed_peers.find(p_peer); + ERR_FAIL_COND_V(!F, false); // Should never happen. + return F->get(); +} + +bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int p_peer_id, int &r_id) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node, false); + // See if the path is cached. + PathSentCache *psc = path_send_cache.getptr(p_path); + if (!psc) { + // Path is not cached, create. + path_send_cache[p_path] = PathSentCache(); + psc = path_send_cache.getptr(p_path); + psc->id = last_send_cache_id++; + } + r_id = psc->id; + + return _send_confirm_path(node, p_path, psc, p_peer_id); +} + +Object *SceneCacheInterface::get_cached_object(int p_from, uint32_t p_cache_id) { + Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); + ERR_FAIL_COND_V(!root_node, nullptr); + Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); + ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("No cache found for peer %d.", p_from)); + + Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(p_cache_id); + ERR_FAIL_COND_V_MSG(!F, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from)); + + PathGetCache::NodeInfo *ni = &F->get(); + Node *node = root_node->get_node(ni->path); + if (!node) { + ERR_PRINT("Failed to get cached path: " + String(ni->path) + "."); + } + return node; +} + +void SceneCacheInterface::clear() { + path_get_cache.clear(); + path_send_cache.clear(); + last_send_cache_id = 1; +} diff --git a/scene/multiplayer/scene_cache_interface.h b/scene/multiplayer/scene_cache_interface.h new file mode 100644 index 0000000000..91a53cb948 --- /dev/null +++ b/scene/multiplayer/scene_cache_interface.h @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* scene_cache_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 SCENE_CACHE_INTERFACE_H +#define SCENE_CACHE_INTERFACE_H + +#include "core/multiplayer/multiplayer_api.h" + +class SceneCacheInterface : public MultiplayerCacheInterface { + GDCLASS(SceneCacheInterface, MultiplayerCacheInterface); + +private: + MultiplayerAPI *multiplayer; + + //path sent caches + struct PathSentCache { + Map<int, bool> confirmed_peers; + int id; + }; + + //path get caches + struct PathGetCache { + struct NodeInfo { + NodePath path; + ObjectID instance; + }; + + Map<int, NodeInfo> nodes; + }; + + HashMap<NodePath, PathSentCache> path_send_cache; + Map<int, PathGetCache> path_get_cache; + int last_send_cache_id = 1; + +protected: + bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); + static MultiplayerCacheInterface *_create(MultiplayerAPI *p_multiplayer); + +public: + static void make_default(); + + virtual void clear() override; + virtual void on_peer_change(int p_id, bool p_connected) override; + virtual void process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) override; + virtual void process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) override; + + // Returns true if all peers have cached path. + virtual bool send_object_cache(Object *p_obj, NodePath p_path, int p_target, int &p_id) override; + virtual Object *get_cached_object(int p_from, uint32_t p_cache_id) override; + virtual bool is_cache_confirmed(NodePath p_path, int p_peer) override; + + SceneCacheInterface(MultiplayerAPI *p_multiplayer) { multiplayer = p_multiplayer; } +}; + +#endif // SCENE_CACHE_INTERFACE_H diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp new file mode 100644 index 0000000000..2088a43ba7 --- /dev/null +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -0,0 +1,411 @@ +/*************************************************************************/ +/* scene_replication_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene_replication_interface.h" + +#include "core/io/marshalls.h" +#include "scene/main/node.h" +#include "scene/multiplayer/multiplayer_spawner.h" +#include "scene/multiplayer/multiplayer_synchronizer.h" + +#define MAKE_ROOM(m_amount) \ + if (packet_cache.size() < m_amount) \ + packet_cache.resize(m_amount); + +MultiplayerReplicationInterface *SceneReplicationInterface::_create(MultiplayerAPI *p_multiplayer) { + return memnew(SceneReplicationInterface(p_multiplayer)); +} + +void SceneReplicationInterface::make_default() { + MultiplayerAPI::create_default_replication_interface = _create; +} + +void SceneReplicationInterface::_free_remotes(int p_id) { + const HashMap<uint32_t, ObjectID> remotes = rep_state->peer_get_remotes(p_id); + const uint32_t *k = nullptr; + while ((k = remotes.next(k))) { + Node *node = rep_state->get_node(remotes.get(*k)); + ERR_CONTINUE(!node); + node->queue_delete(); + } +} + +void SceneReplicationInterface::on_peer_change(int p_id, bool p_connected) { + if (p_connected) { + rep_state->on_peer_change(p_id, p_connected); + for (const ObjectID &oid : rep_state->get_spawned_nodes()) { + _send_spawn(rep_state->get_node(oid), rep_state->get_spawner(oid), p_id); + } + for (const ObjectID &oid : rep_state->get_path_only_nodes()) { + Node *node = rep_state->get_node(oid); + MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); + ERR_CONTINUE(!node || !sync); + if (sync->is_multiplayer_authority()) { + rep_state->peer_add_node(p_id, oid); + } + } + } else { + _free_remotes(p_id); + rep_state->on_peer_change(p_id, p_connected); + } +} + +void SceneReplicationInterface::on_reset() { + for (int pid : rep_state->get_peers()) { + _free_remotes(pid); + } + rep_state->reset(); +} + +void SceneReplicationInterface::on_network_process() { + uint64_t msec = OS::get_singleton()->get_ticks_msec(); + for (int peer : rep_state->get_peers()) { + _send_sync(peer, msec); + } +} + +Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); + MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); + ERR_FAIL_COND_V(!spawner, ERR_INVALID_PARAMETER); + Error err = rep_state->config_add_spawn(node, spawner); + ERR_FAIL_COND_V(err != OK, err); + return _send_spawn(node, spawner, 0); +} + +Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); + MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(p_config.get_validated_object()); + ERR_FAIL_COND_V(!p_obj || !spawner, ERR_INVALID_PARAMETER); + Error err = rep_state->config_del_spawn(node, spawner); + ERR_FAIL_COND_V(err != OK, err); + return _send_despawn(node, 0); +} + +Error SceneReplicationInterface::on_replication_start(Object *p_obj, Variant p_config) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); + MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); + ERR_FAIL_COND_V(!sync, ERR_INVALID_PARAMETER); + rep_state->config_add_sync(node, sync); + // Try to apply initial state if spawning (hack to apply if before ready). + if (pending_spawn == p_obj->get_instance_id()) { + pending_spawn = ObjectID(); // Make sure this only happens once. + const List<NodePath> props = sync->get_replication_config()->get_spawn_properties(); + Vector<Variant> vars; + vars.resize(props.size()); + int consumed; + Error err = MultiplayerAPI::decode_and_decompress_variants(vars, pending_buffer, pending_buffer_size, consumed); + ERR_FAIL_COND_V(err, err); + err = MultiplayerSynchronizer::set_state(props, node, vars); + ERR_FAIL_COND_V(err, err); + } else if (multiplayer->has_multiplayer_peer() && sync->is_multiplayer_authority()) { + // Either it's a spawn or a static sync, in any case add it to the list of known nodes. + rep_state->peer_add_node(0, p_obj->get_instance_id()); + } + return OK; +} + +Error SceneReplicationInterface::on_replication_stop(Object *p_obj, Variant p_config) { + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node || p_config.get_type() != Variant::OBJECT, ERR_INVALID_PARAMETER); + MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(p_config.get_validated_object()); + ERR_FAIL_COND_V(!p_obj || !sync, ERR_INVALID_PARAMETER); + return rep_state->config_del_sync(node, sync); +} + +Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable) { + ERR_FAIL_COND_V(!p_buffer || p_size < 1, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!multiplayer, ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!multiplayer->has_multiplayer_peer(), ERR_UNCONFIGURED); + Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer(); + peer->set_target_peer(p_peer); + peer->set_transfer_channel(0); + peer->set_transfer_mode(p_reliable ? Multiplayer::TRANSFER_MODE_RELIABLE : Multiplayer::TRANSFER_MODE_UNRELIABLE); + return peer->put_packet(p_buffer, p_size); +} + +Error SceneReplicationInterface::_send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer) { + ERR_FAIL_COND_V(p_peer < 0, ERR_BUG); + ERR_FAIL_COND_V(!multiplayer, ERR_BUG); + ERR_FAIL_COND_V(!p_spawner || !p_node, ERR_BUG); + + const ObjectID oid = p_node->get_instance_id(); + uint32_t nid = rep_state->ensure_net_id(oid); + + // Prepare custom arg and scene_id + uint8_t scene_id = p_spawner->get_spawn_id(oid); + bool is_custom = scene_id == MultiplayerSpawner::INVALID_ID; + Variant spawn_arg = p_spawner->get_spawn_argument(oid); + int spawn_arg_size = 0; + if (is_custom) { + Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, nullptr, spawn_arg_size, false); + ERR_FAIL_COND_V(err, err); + } + + // Prepare spawn state. + int state_size = 0; + Vector<Variant> state_vars; + Vector<const Variant *> state_varp; + MultiplayerSynchronizer *synchronizer = rep_state->get_synchronizer(oid); + if (synchronizer && synchronizer->get_replication_config().is_valid()) { + const List<NodePath> props = synchronizer->get_replication_config()->get_spawn_properties(); + Error err = MultiplayerSynchronizer::get_state(props, p_node, state_vars, state_varp); + ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to retrieve spawn state."); + err = MultiplayerAPI::encode_and_compress_variants(state_varp.ptrw(), state_varp.size(), nullptr, state_size); + ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to encode spawn state."); + } + + // Prepare simplified path. + NodePath rel_path = multiplayer->get_root_path().rel_path_to(p_spawner->get_path()); + + int path_id = 0; + multiplayer->send_object_cache(p_spawner, rel_path, p_peer, path_id); + + // Encode name and parent ID. + CharString cname = p_node->get_name().operator String().utf8(); + int nlen = encode_cstring(cname.get_data(), nullptr); + MAKE_ROOM(1 + 1 + 4 + 4 + 4 + nlen + (is_custom ? 4 + spawn_arg_size : 0) + state_size); + uint8_t *ptr = packet_cache.ptrw(); + ptr[0] = (uint8_t)MultiplayerAPI::NETWORK_COMMAND_SPAWN; + ptr[1] = scene_id; + int ofs = 2; + ofs += encode_uint32(path_id, &ptr[ofs]); + ofs += encode_uint32(nid, &ptr[ofs]); + ofs += encode_uint32(nlen, &ptr[ofs]); + ofs += encode_cstring(cname.get_data(), &ptr[ofs]); + // Write args + if (is_custom) { + ofs += encode_uint32(spawn_arg_size, &ptr[ofs]); + Error err = MultiplayerAPI::encode_and_compress_variant(spawn_arg, &ptr[ofs], spawn_arg_size, false); + ERR_FAIL_COND_V(err, err); + ofs += spawn_arg_size; + } + // Write state. + if (state_size) { + Error err = MultiplayerAPI::encode_and_compress_variants(state_varp.ptrw(), state_varp.size(), &ptr[ofs], state_size); + ERR_FAIL_COND_V(err, err); + ofs += state_size; + } + Error err = _send_raw(ptr, ofs, p_peer, true); + ERR_FAIL_COND_V(err, err); + return rep_state->peer_add_node(p_peer, oid); +} + +Error SceneReplicationInterface::_send_despawn(Node *p_node, int p_peer) { + const ObjectID oid = p_node->get_instance_id(); + MAKE_ROOM(5); + uint8_t *ptr = packet_cache.ptrw(); + ptr[0] = (uint8_t)MultiplayerAPI::NETWORK_COMMAND_DESPAWN; + int ofs = 1; + uint32_t nid = rep_state->get_net_id(oid); + ofs += encode_uint32(nid, &ptr[ofs]); + Error err = _send_raw(ptr, ofs, p_peer, true); + ERR_FAIL_COND_V(err, err); + return rep_state->peer_del_node(p_peer, oid); +} + +Error SceneReplicationInterface::on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) { + ERR_FAIL_COND_V_MSG(p_buffer_len < 14, ERR_INVALID_DATA, "Invalid spawn packet received"); + int ofs = 1; // The spawn/despawn command. + uint8_t scene_id = p_buffer[ofs]; + ofs += 1; + uint32_t node_target = decode_uint32(&p_buffer[ofs]); + ofs += 4; + MultiplayerSpawner *spawner = Object::cast_to<MultiplayerSpawner>(multiplayer->get_cached_object(p_from, node_target)); + ERR_FAIL_COND_V(!spawner, ERR_DOES_NOT_EXIST); + ERR_FAIL_COND_V(p_from != spawner->get_multiplayer_authority(), ERR_UNAUTHORIZED); + + uint32_t net_id = decode_uint32(&p_buffer[ofs]); + ofs += 4; + uint32_t name_len = decode_uint32(&p_buffer[ofs]); + ofs += 4; + ERR_FAIL_COND_V_MSG(name_len > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA, vformat("Invalid spawn packet size: %d, wants: %d", p_buffer_len, ofs + name_len)); + ERR_FAIL_COND_V_MSG(name_len < 1, ERR_INVALID_DATA, "Zero spawn name size."); + + // We need to make sure no trickery happens here, but we want to allow autogenerated ("@") node names. + const String name = String::utf8((const char *)&p_buffer[ofs], name_len); + ERR_FAIL_COND_V_MSG(name.validate_node_name() != name, ERR_INVALID_DATA, vformat("Invalid node name received: '%s'. Make sure to add nodes via 'add_child(node, true)' remotely.", name)); + ofs += name_len; + + // Check that we can spawn. + Node *parent = spawner->get_node_or_null(spawner->get_spawn_path()); + ERR_FAIL_COND_V(!parent, ERR_UNCONFIGURED); + ERR_FAIL_COND_V(parent->has_node(name), ERR_INVALID_DATA); + + Node *node = nullptr; + if (scene_id == MultiplayerSpawner::INVALID_ID) { + // Custom spawn. + ERR_FAIL_COND_V(p_buffer_len - ofs < 4, ERR_INVALID_DATA); + uint32_t arg_size = decode_uint32(&p_buffer[ofs]); + ofs += 4; + ERR_FAIL_COND_V(arg_size > uint32_t(p_buffer_len - ofs), ERR_INVALID_DATA); + Variant v; + Error err = MultiplayerAPI::decode_and_decompress_variant(v, &p_buffer[ofs], arg_size, nullptr, false); + ERR_FAIL_COND_V(err != OK, err); + ofs += arg_size; + node = spawner->instantiate_custom(v); + } else { + // Scene based spawn. + node = spawner->instantiate_scene(scene_id); + } + ERR_FAIL_COND_V(!node, ERR_UNAUTHORIZED); + node->set_name(name); + rep_state->peer_add_remote(p_from, net_id, node, spawner); + // The initial state will be applied during the sync config (i.e. before _ready). + int state_len = p_buffer_len - ofs; + if (state_len) { + pending_spawn = node->get_instance_id(); + pending_buffer = &p_buffer[ofs]; + pending_buffer_size = state_len; + } + parent->add_child(node); + pending_spawn = ObjectID(); + pending_buffer = nullptr; + pending_buffer_size = 0; + return OK; +} + +Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) { + ERR_FAIL_COND_V_MSG(p_buffer_len < 5, ERR_INVALID_DATA, "Invalid spawn packet received"); + int ofs = 1; // The spawn/despawn command. + uint32_t net_id = decode_uint32(&p_buffer[ofs]); + ofs += 4; + Node *node = nullptr; + Error err = rep_state->peer_del_remote(p_from, net_id, &node); + ERR_FAIL_COND_V(err != OK, err); + ERR_FAIL_COND_V(!node, ERR_BUG); + node->queue_delete(); + return OK; +} + +void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { + const Set<ObjectID> &known = rep_state->get_known_nodes(p_peer); + if (known.is_empty()) { + return; + } + MAKE_ROOM(sync_mtu); + uint8_t *ptr = packet_cache.ptrw(); + ptr[0] = MultiplayerAPI::NETWORK_COMMAND_SYNC; + int ofs = 1; + ofs += encode_uint16(rep_state->peer_sync_next(p_peer), &ptr[1]); + // Can only send updates for already notified nodes. + // This is a lazy implementation, we could optimize much more here with by grouping by replication config. + for (const ObjectID &oid : known) { + if (!rep_state->update_sync_time(oid, p_msec)) { + continue; // nothing to sync. + } + MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); + ERR_CONTINUE(!sync); + Node *node = rep_state->get_node(oid); + ERR_CONTINUE(!node); + int size; + Vector<Variant> vars; + Vector<const Variant *> varp; + const List<NodePath> props = sync->get_replication_config()->get_sync_properties(); + Error err = MultiplayerSynchronizer::get_state(props, node, vars, varp); + ERR_CONTINUE_MSG(err != OK, "Unable to retrieve sync state."); + err = MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), nullptr, size); + ERR_CONTINUE_MSG(err != OK, "Unable to encode sync state."); + // TODO Handle single state above MTU. + ERR_CONTINUE_MSG(size > 3 + 4 + 4 + sync_mtu, vformat("Node states bigger then MTU will not be sent (%d > %d): %s", size, sync_mtu, node->get_path())); + if (ofs + 4 + 4 + size > sync_mtu) { + // Send what we got, and reset write. + _send_raw(packet_cache.ptr(), ofs, p_peer, false); + ofs = 3; + } + if (size) { + uint32_t net_id = rep_state->get_net_id(oid); + if (net_id == 0) { + // First time path based ID. + NodePath rel_path = multiplayer->get_root_path().rel_path_to(sync->get_path()); + int path_id = 0; + multiplayer->send_object_cache(sync, rel_path, p_peer, path_id); + net_id = path_id; + rep_state->set_net_id(oid, net_id | 0x80000000); + } + ofs += encode_uint32(rep_state->get_net_id(oid), &ptr[ofs]); + ofs += encode_uint32(size, &ptr[ofs]); + MultiplayerAPI::encode_and_compress_variants(varp.ptrw(), varp.size(), &ptr[ofs], size); + ofs += size; + } + } + if (ofs > 3) { + // Got some left over to send. + _send_raw(packet_cache.ptr(), ofs, p_peer, false); + } +} + +Error SceneReplicationInterface::on_sync_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) { + ERR_FAIL_COND_V_MSG(p_buffer_len < 11, ERR_INVALID_DATA, "Invalid sync packet received"); + uint16_t time = decode_uint16(&p_buffer[1]); + int ofs = 3; + rep_state->peer_sync_recv(p_from, time); + while (ofs + 8 < p_buffer_len) { + uint32_t net_id = decode_uint32(&p_buffer[ofs]); + ofs += 4; + uint32_t size = decode_uint32(&p_buffer[ofs]); + ofs += 4; + Node *node = nullptr; + if (net_id & 0x80000000) { + MultiplayerSynchronizer *sync = Object::cast_to<MultiplayerSynchronizer>(multiplayer->get_cached_object(p_from, net_id & 0x7FFFFFFF)); + ERR_FAIL_COND_V(!sync || sync->get_multiplayer_authority() != p_from, ERR_UNAUTHORIZED); + node = sync->get_node(sync->get_root_path()); + } else { + node = rep_state->peer_get_remote(p_from, net_id); + } + if (!node) { + // Not received yet. + ofs += size; + continue; + } + const ObjectID oid = node->get_instance_id(); + if (!rep_state->update_last_node_sync(oid, time)) { + // State is too old. + ofs += size; + continue; + } + MultiplayerSynchronizer *sync = rep_state->get_synchronizer(oid); + ERR_FAIL_COND_V(!sync, ERR_BUG); + ERR_FAIL_COND_V(size > uint32_t(p_buffer_len - ofs), ERR_BUG); + const List<NodePath> props = sync->get_replication_config()->get_sync_properties(); + Vector<Variant> vars; + vars.resize(props.size()); + int consumed; + Error err = MultiplayerAPI::decode_and_decompress_variants(vars, &p_buffer[ofs], size, consumed); + ERR_FAIL_COND_V(err, err); + err = MultiplayerSynchronizer::set_state(props, node, vars); + ERR_FAIL_COND_V(err, err); + ofs += size; + } + return OK; +} diff --git a/scene/multiplayer/scene_replication_interface.h b/scene/multiplayer/scene_replication_interface.h new file mode 100644 index 0000000000..855878d029 --- /dev/null +++ b/scene/multiplayer/scene_replication_interface.h @@ -0,0 +1,84 @@ +/*************************************************************************/ +/* scene_replication_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 SCENE_TREE_REPLICATOR_INTERFACE_H +#define SCENE_TREE_REPLICATOR_INTERFACE_H + +#include "core/multiplayer/multiplayer_api.h" + +#include "scene/multiplayer/scene_replication_state.h" + +class SceneReplicationInterface : public MultiplayerReplicationInterface { + GDCLASS(SceneReplicationInterface, MultiplayerReplicationInterface); + +private: + void _send_sync(int p_peer, uint64_t p_msec); + Error _send_spawn(Node *p_node, MultiplayerSpawner *p_spawner, int p_peer); + Error _send_despawn(Node *p_node, int p_peer); + Error _send_raw(const uint8_t *p_buffer, int p_size, int p_peer, bool p_reliable); + + void _free_remotes(int p_peer); + + Ref<SceneReplicationState> rep_state; + MultiplayerAPI *multiplayer; + PackedByteArray packet_cache; + int sync_mtu = 1350; // Highly dependent on underlying protocol. + + // An hack to apply the initial state before ready. + ObjectID pending_spawn; + const uint8_t *pending_buffer = nullptr; + int pending_buffer_size = 0; + +protected: + static MultiplayerReplicationInterface *_create(MultiplayerAPI *p_multiplayer); + +public: + static void make_default(); + + virtual void on_reset() override; + virtual void on_peer_change(int p_id, bool p_connected) override; + + virtual Error on_spawn(Object *p_obj, Variant p_config) override; + virtual Error on_despawn(Object *p_obj, Variant p_config) override; + virtual Error on_replication_start(Object *p_obj, Variant p_config) override; + virtual Error on_replication_stop(Object *p_obj, Variant p_config) override; + virtual void on_network_process() override; + + virtual Error on_spawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) override; + virtual Error on_despawn_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) override; + virtual Error on_sync_receive(int p_from, const uint8_t *p_buffer, int p_buffer_len) override; + + SceneReplicationInterface(MultiplayerAPI *p_multiplayer) { + rep_state.instantiate(); + multiplayer = p_multiplayer; + } +}; + +#endif // SCENE_TREE_REPLICATOR_INTERFACE_H diff --git a/scene/multiplayer/scene_replication_state.cpp b/scene/multiplayer/scene_replication_state.cpp new file mode 100644 index 0000000000..b8dadeff24 --- /dev/null +++ b/scene/multiplayer/scene_replication_state.cpp @@ -0,0 +1,258 @@ +/*************************************************************************/ +/* scene_replication_state.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene/multiplayer/scene_replication_state.h" + +#include "core/multiplayer/multiplayer_api.h" +#include "scene/multiplayer/multiplayer_spawner.h" +#include "scene/multiplayer/multiplayer_synchronizer.h" +#include "scene/scene_string_names.h" + +SceneReplicationState::TrackedNode &SceneReplicationState::_track(const ObjectID &p_id) { + if (!tracked_nodes.has(p_id)) { + tracked_nodes[p_id] = TrackedNode(p_id); + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(p_id)); + node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack), varray(p_id), Node::CONNECT_ONESHOT); + } + return tracked_nodes[p_id]; +} + +void SceneReplicationState::_untrack(const ObjectID &p_id) { + if (tracked_nodes.has(p_id)) { + uint32_t net_id = tracked_nodes[p_id].net_id; + uint32_t peer = tracked_nodes[p_id].remote_peer; + tracked_nodes.erase(p_id); + // If it was spawned by a remote, remove it from the received nodes. + if (peer && peers_info.has(peer)) { + peers_info[peer].recv_nodes.erase(net_id); + } + // If we spawned or synced it, we need to remove it from any peer it was sent to. + if (net_id || peer == 0) { + const int *k = nullptr; + while ((k = peers_info.next(k))) { + peers_info.get(*k).known_nodes.erase(p_id); + } + } + } +} + +const HashMap<uint32_t, ObjectID> SceneReplicationState::peer_get_remotes(int p_peer) const { + return peers_info.has(p_peer) ? peers_info[p_peer].recv_nodes : HashMap<uint32_t, ObjectID>(); +} + +bool SceneReplicationState::update_last_node_sync(const ObjectID &p_id, uint16_t p_time) { + TrackedNode *tnode = tracked_nodes.getptr(p_id); + ERR_FAIL_COND_V(!tnode, false); + if (p_time <= tnode->last_sync && tnode->last_sync - p_time < 32767) { + return false; + } + tnode->last_sync = p_time; + return true; +} + +bool SceneReplicationState::update_sync_time(const ObjectID &p_id, uint64_t p_msec) { + TrackedNode *tnode = tracked_nodes.getptr(p_id); + ERR_FAIL_COND_V(!tnode, false); + MultiplayerSynchronizer *sync = get_synchronizer(p_id); + if (!sync) { + return false; + } + if (tnode->last_sync_msec == p_msec) { + return true; + } + if (p_msec >= tnode->last_sync_msec + sync->get_replication_interval_msec()) { + tnode->last_sync_msec = p_msec; + return true; + } + return false; +} + +const Set<ObjectID> SceneReplicationState::get_known_nodes(int p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), Set<ObjectID>()); + return peers_info[p_peer].known_nodes; +} + +uint32_t SceneReplicationState::get_net_id(const ObjectID &p_id) const { + const TrackedNode *tnode = tracked_nodes.getptr(p_id); + ERR_FAIL_COND_V(!tnode, 0); + return tnode->net_id; +} + +void SceneReplicationState::set_net_id(const ObjectID &p_id, uint32_t p_net_id) { + TrackedNode *tnode = tracked_nodes.getptr(p_id); + ERR_FAIL_COND(!tnode); + tnode->net_id = p_net_id; +} + +uint32_t SceneReplicationState::ensure_net_id(const ObjectID &p_id) { + TrackedNode *tnode = tracked_nodes.getptr(p_id); + ERR_FAIL_COND_V(!tnode, 0); + if (tnode->net_id == 0) { + tnode->net_id = ++last_net_id; + } + return tnode->net_id; +} + +void SceneReplicationState::on_peer_change(int p_peer, bool p_connected) { + if (p_connected) { + peers_info[p_peer] = PeerInfo(); + known_peers.insert(p_peer); + } else { + peers_info.erase(p_peer); + known_peers.erase(p_peer); + } +} + +void SceneReplicationState::reset() { + peers_info.clear(); + known_peers.clear(); + // Tracked nodes are cleared on deletion, here we only reset the ids so they can be later re-assigned. + const ObjectID *oid = nullptr; + while ((oid = tracked_nodes.next(oid))) { + TrackedNode &tobj = tracked_nodes[*oid]; + tobj.net_id = 0; + tobj.remote_peer = 0; + tobj.last_sync = 0; + } +} + +Error SceneReplicationState::config_add_spawn(Node *p_node, MultiplayerSpawner *p_spawner) { + const ObjectID oid = p_node->get_instance_id(); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE); + tobj.spawner = p_spawner->get_instance_id(); + spawned_nodes.insert(oid); + // The spawner may be notified after the synchronizer. + path_only_nodes.erase(oid); + return OK; +} + +Error SceneReplicationState::config_del_spawn(Node *p_node, MultiplayerSpawner *p_spawner) { + const ObjectID oid = p_node->get_instance_id(); + ERR_FAIL_COND_V(!is_tracked(oid), ERR_INVALID_PARAMETER); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.spawner != p_spawner->get_instance_id(), ERR_INVALID_PARAMETER); + tobj.spawner = ObjectID(); + spawned_nodes.erase(oid); + return OK; +} + +Error SceneReplicationState::config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync) { + const ObjectID oid = p_node->get_instance_id(); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.synchronizer != ObjectID(), ERR_ALREADY_IN_USE); + tobj.synchronizer = p_sync->get_instance_id(); + // If it doesn't have a spawner, we might need to assign ID for this node using it's path. + if (tobj.spawner.is_null()) { + path_only_nodes.insert(oid); + } + return OK; +} + +Error SceneReplicationState::config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync) { + const ObjectID oid = p_node->get_instance_id(); + ERR_FAIL_COND_V(!is_tracked(oid), ERR_INVALID_PARAMETER); + TrackedNode &tobj = _track(oid); + ERR_FAIL_COND_V(tobj.synchronizer != p_sync->get_instance_id(), ERR_INVALID_PARAMETER); + tobj.synchronizer = ObjectID(); + if (path_only_nodes.has(oid)) { + p_node->disconnect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneReplicationState::_untrack)); + _untrack(oid); + path_only_nodes.erase(oid); + } + return OK; +} + +Error SceneReplicationState::peer_add_node(int p_peer, const ObjectID &p_id) { + if (p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].known_nodes.insert(p_id); + } else { + const int *pid = nullptr; + while ((pid = peers_info.next(pid))) { + peers_info.get(*pid).known_nodes.insert(p_id); + } + } + return OK; +} + +Error SceneReplicationState::peer_del_node(int p_peer, const ObjectID &p_id) { + if (p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_INVALID_PARAMETER); + peers_info[p_peer].known_nodes.erase(p_id); + } else { + const int *pid = nullptr; + while ((pid = peers_info.next(pid))) { + peers_info.get(*pid).known_nodes.erase(p_id); + } + } + return OK; +} + +Node *SceneReplicationState::peer_get_remote(int p_peer, uint32_t p_net_id) { + PeerInfo *info = peers_info.getptr(p_peer); + return info && info->recv_nodes.has(p_net_id) ? Object::cast_to<Node>(ObjectDB::get_instance(info->recv_nodes[p_net_id])) : nullptr; +} + +Error SceneReplicationState::peer_add_remote(int p_peer, uint32_t p_net_id, Node *p_node, MultiplayerSpawner *p_spawner) { + ERR_FAIL_COND_V(!p_node || !p_spawner, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_UNAVAILABLE); + PeerInfo &pinfo = peers_info[p_peer]; + ObjectID oid = p_node->get_instance_id(); + TrackedNode &tobj = _track(oid); + tobj.spawner = p_spawner->get_instance_id(); + tobj.net_id = p_net_id; + tobj.remote_peer = p_peer; + tobj.last_sync = pinfo.last_recv_sync; + // Also track as a remote. + ERR_FAIL_COND_V(pinfo.recv_nodes.has(p_net_id), ERR_ALREADY_IN_USE); + pinfo.recv_nodes[p_net_id] = oid; + return OK; +} + +Error SceneReplicationState::peer_del_remote(int p_peer, uint32_t p_net_id, Node **r_node) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), ERR_UNAUTHORIZED); + PeerInfo &info = peers_info[p_peer]; + ERR_FAIL_COND_V(!info.recv_nodes.has(p_net_id), ERR_UNAUTHORIZED); + *r_node = Object::cast_to<Node>(ObjectDB::get_instance(info.recv_nodes[p_net_id])); + info.recv_nodes.erase(p_net_id); + return OK; +} + +uint16_t SceneReplicationState::peer_sync_next(int p_peer) { + ERR_FAIL_COND_V(!peers_info.has(p_peer), 0); + PeerInfo &info = peers_info[p_peer]; + return ++info.last_sent_sync; +} + +void SceneReplicationState::peer_sync_recv(int p_peer, uint16_t p_time) { + ERR_FAIL_COND(!peers_info.has(p_peer)); + peers_info[p_peer].last_recv_sync = p_time; +} diff --git a/scene/multiplayer/scene_replication_state.h b/scene/multiplayer/scene_replication_state.h new file mode 100644 index 0000000000..18e4d9fa39 --- /dev/null +++ b/scene/multiplayer/scene_replication_state.h @@ -0,0 +1,121 @@ +/*************************************************************************/ +/* scene_replication_state.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 SCENE_REPLICATON_STATE_H +#define SCENE_REPLICATON_STATE_H + +#include "core/object/ref_counted.h" + +class MultiplayerSpawner; +class MultiplayerSynchronizer; +class Node; + +class SceneReplicationState : public RefCounted { +private: + struct TrackedNode { + ObjectID id; + uint32_t net_id = 0; + uint32_t remote_peer = 0; + ObjectID spawner; + ObjectID synchronizer; + uint16_t last_sync = 0; + uint64_t last_sync_msec = 0; + + bool operator==(const ObjectID &p_other) { return id == p_other; } + + Node *get_node() const { return id.is_valid() ? Object::cast_to<Node>(ObjectDB::get_instance(id)) : nullptr; } + MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; } + MultiplayerSynchronizer *get_synchronizer() const { return synchronizer.is_valid() ? Object::cast_to<MultiplayerSynchronizer>(ObjectDB::get_instance(synchronizer)) : nullptr; } + TrackedNode() {} + TrackedNode(const ObjectID &p_id) { id = p_id; } + TrackedNode(const ObjectID &p_id, uint32_t p_net_id) { + id = p_id; + net_id = p_net_id; + } + }; + + struct PeerInfo { + Set<ObjectID> known_nodes; + HashMap<uint32_t, ObjectID> recv_nodes; + uint16_t last_sent_sync = 0; + uint16_t last_recv_sync = 0; + }; + + Set<int> known_peers; + uint32_t last_net_id = 0; + HashMap<ObjectID, TrackedNode> tracked_nodes; + HashMap<int, PeerInfo> peers_info; + Set<ObjectID> spawned_nodes; + Set<ObjectID> path_only_nodes; + + TrackedNode &_track(const ObjectID &p_id); + void _untrack(const ObjectID &p_id); + bool is_tracked(const ObjectID &p_id) const { return tracked_nodes.has(p_id); } + +public: + const Set<int> get_peers() const { return known_peers; } + const Set<ObjectID> get_spawned_nodes() const { return spawned_nodes; } + const Set<ObjectID> get_path_only_nodes() const { return path_only_nodes; } + + MultiplayerSynchronizer *get_synchronizer(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_synchronizer() : nullptr; } + MultiplayerSpawner *get_spawner(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_spawner() : nullptr; } + Node *get_node(const ObjectID &p_id) { return tracked_nodes.has(p_id) ? tracked_nodes[p_id].get_node() : nullptr; } + bool update_last_node_sync(const ObjectID &p_id, uint16_t p_time); + bool update_sync_time(const ObjectID &p_id, uint64_t p_msec); + + const Set<ObjectID> get_known_nodes(int p_peer); + uint32_t get_net_id(const ObjectID &p_id) const; + void set_net_id(const ObjectID &p_id, uint32_t p_net_id); + uint32_t ensure_net_id(const ObjectID &p_id); + + void reset(); + void on_peer_change(int p_peer, bool p_connected); + + Error config_add_spawn(Node *p_node, MultiplayerSpawner *p_spawner); + Error config_del_spawn(Node *p_node, MultiplayerSpawner *p_spawner); + + Error config_add_sync(Node *p_node, MultiplayerSynchronizer *p_sync); + Error config_del_sync(Node *p_node, MultiplayerSynchronizer *p_sync); + + Error peer_add_node(int p_peer, const ObjectID &p_id); + Error peer_del_node(int p_peer, const ObjectID &p_id); + + const HashMap<uint32_t, ObjectID> peer_get_remotes(int p_peer) const; + Node *peer_get_remote(int p_peer, uint32_t p_net_id); + Error peer_add_remote(int p_peer, uint32_t p_net_id, Node *p_node, MultiplayerSpawner *p_spawner); + Error peer_del_remote(int p_peer, uint32_t p_net_id, Node **r_node); + + uint16_t peer_sync_next(int p_peer); + void peer_sync_recv(int p_peer, uint16_t p_time); + + SceneReplicationState() {} +}; + +#endif // SCENE_REPLICATON_STATE_H diff --git a/scene/multiplayer/scene_rpc_interface.cpp b/scene/multiplayer/scene_rpc_interface.cpp new file mode 100644 index 0000000000..7d7f57b9a1 --- /dev/null +++ b/scene/multiplayer/scene_rpc_interface.cpp @@ -0,0 +1,512 @@ +/*************************************************************************/ +/* scene_rpc_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene/multiplayer/scene_rpc_interface.h" + +#include "core/debugger/engine_debugger.h" +#include "core/io/marshalls.h" +#include "core/multiplayer/multiplayer_api.h" +#include "scene/main/node.h" +#include "scene/main/window.h" + +MultiplayerRPCInterface *SceneRPCInterface::_create(MultiplayerAPI *p_multiplayer) { + return memnew(SceneRPCInterface(p_multiplayer)); +} + +void SceneRPCInterface::make_default() { + MultiplayerAPI::create_default_rpc_interface = _create; +} + +#ifdef DEBUG_ENABLED +_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) { + if (EngineDebugger::is_profiling("multiplayer")) { + Array values; + values.push_back("node"); + values.push_back(p_id); + values.push_back(p_what); + EngineDebugger::profiler_add_frame_data("multiplayer", values); + } +} +#else +_FORCE_INLINE_ void SceneRPCInterface::_profile_node_data(const String &p_what, ObjectID p_id) {} +#endif + +// Returns the packet size stripping the node path added when the node is not yet cached. +int get_packet_len(uint32_t p_node_target, int p_packet_len) { + if (p_node_target & 0x80000000) { + int ofs = p_node_target & 0x7FFFFFFF; + return p_packet_len - (p_packet_len - ofs); + } else { + return p_packet_len; + } +} + +const Multiplayer::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { + const Vector<Multiplayer::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + if (node_config[i].name == p_method) { + r_id = ((uint16_t)i) | (1 << 15); + return node_config[i]; + } + } + if (p_node->get_script_instance()) { + const Vector<Multiplayer::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + if (script_config[i].name == p_method) { + r_id = (uint16_t)i; + return script_config[i]; + } + } + } + return Multiplayer::RPCConfig(); +} + +const Multiplayer::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { + Vector<Multiplayer::RPCConfig> config; + uint16_t id = p_id; + if (id & (1 << 15)) { + id = id & ~(1 << 15); + config = p_node->get_node_rpc_methods(); + } else if (p_node->get_script_instance()) { + config = p_node->get_script_instance()->get_rpc_methods(); + } + if (id < config.size()) { + return config[id]; + } + return Multiplayer::RPCConfig(); +} + +_FORCE_INLINE_ bool _can_call_mode(Node *p_node, Multiplayer::RPCMode mode, int p_remote_id) { + switch (mode) { + case Multiplayer::RPC_MODE_DISABLED: { + return false; + } break; + case Multiplayer::RPC_MODE_ANY_PEER: { + return true; + } break; + case Multiplayer::RPC_MODE_AUTHORITY: { + return !p_node->is_multiplayer_authority() && p_remote_id == p_node->get_multiplayer_authority(); + } break; + } + + return false; +} + +String SceneRPCInterface::get_rpc_md5(const Object *p_obj) const { + const Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND_V(!node, ""); + String rpc_list; + const Vector<Multiplayer::RPCConfig> node_config = node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + rpc_list += String(node_config[i].name); + } + if (node->get_script_instance()) { + const Vector<Multiplayer::RPCConfig> script_config = node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + rpc_list += String(script_config[i].name); + } + } + return rpc_list.md5_text(); +} + +Node *SceneRPCInterface::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) { + Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); + ERR_FAIL_COND_V(!root_node, nullptr); + Node *node = nullptr; + + if (p_node_target & 0x80000000) { + // Use full path (not cached yet). + int ofs = p_node_target & 0x7FFFFFFF; + + ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, nullptr, "Invalid packet received. Size smaller than declared."); + + String paths; + paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); + + NodePath np = paths; + + node = root_node->get_node(np); + + if (!node) { + ERR_PRINT("Failed to get path from RPC: " + String(np) + "."); + } + return node; + } else { + // Use cached path. + return Object::cast_to<Node>(multiplayer->get_cached_object(p_from, p_node_target)); + } +} + +void SceneRPCInterface::process_rpc(int p_from, const uint8_t *p_packet, int p_packet_len) { + // Extract packet meta + int packet_min_size = 1; + int name_id_offset = 1; + ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); + // Compute the meta size, which depends on the compression level. + int node_id_compression = (p_packet[0] & NODE_ID_COMPRESSION_FLAG) >> NODE_ID_COMPRESSION_SHIFT; + int name_id_compression = (p_packet[0] & NAME_ID_COMPRESSION_FLAG) >> NAME_ID_COMPRESSION_SHIFT; + + switch (node_id_compression) { + case NETWORK_NODE_ID_COMPRESSION_8: + packet_min_size += 1; + name_id_offset += 1; + break; + case NETWORK_NODE_ID_COMPRESSION_16: + packet_min_size += 2; + name_id_offset += 2; + break; + case NETWORK_NODE_ID_COMPRESSION_32: + packet_min_size += 4; + name_id_offset += 4; + break; + default: + ERR_FAIL_MSG("Was not possible to extract the node id compression mode."); + } + switch (name_id_compression) { + case NETWORK_NAME_ID_COMPRESSION_8: + packet_min_size += 1; + break; + case NETWORK_NAME_ID_COMPRESSION_16: + packet_min_size += 2; + break; + default: + ERR_FAIL_MSG("Was not possible to extract the name id compression mode."); + } + ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); + + uint32_t node_target = 0; + switch (node_id_compression) { + case NETWORK_NODE_ID_COMPRESSION_8: + node_target = p_packet[1]; + break; + case NETWORK_NODE_ID_COMPRESSION_16: + node_target = decode_uint16(p_packet + 1); + break; + case NETWORK_NODE_ID_COMPRESSION_32: + node_target = decode_uint32(p_packet + 1); + break; + default: + // Unreachable, checked before. + CRASH_NOW(); + } + + Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len); + ERR_FAIL_COND_MSG(node == nullptr, "Invalid packet received. Requested node was not found."); + + uint16_t name_id = 0; + switch (name_id_compression) { + case NETWORK_NAME_ID_COMPRESSION_8: + name_id = p_packet[name_id_offset]; + break; + case NETWORK_NAME_ID_COMPRESSION_16: + name_id = decode_uint16(p_packet + name_id_offset); + break; + default: + // Unreachable, checked before. + CRASH_NOW(); + } + + const int packet_len = get_packet_len(node_target, p_packet_len); + _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); +} + +void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { + ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); + + // Check that remote can call the RPC on this node. + const Multiplayer::RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); + ERR_FAIL_COND(config.name == StringName()); + + bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", authority is " + itos(p_node->get_multiplayer_authority()) + "."); + + int argc = 0; + + const bool byte_only_or_no_args = p_packet[0] & BYTE_ONLY_OR_NO_ARGS_FLAG; + if (byte_only_or_no_args) { + if (p_offset < p_packet_len) { + // This packet contains only bytes. + argc = 1; + } + } else { + // Normal variant, takes the argument count from the packet. + ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); + argc = p_packet[p_offset]; + p_offset += 1; + } + + Vector<Variant> args; + Vector<const Variant *> argp; + args.resize(argc); + argp.resize(argc); + +#ifdef DEBUG_ENABLED + _profile_node_data("in_rpc", p_node->get_instance_id()); +#endif + + int out; + MultiplayerAPI::decode_and_decompress_variants(args, &p_packet[p_offset], p_packet_len - p_offset, out, byte_only_or_no_args, multiplayer->is_object_decoding_allowed()); + for (int i = 0; i < argc; i++) { + argp.write[i] = &args[i]; + } + + Callable::CallError ce; + + p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); + error = "RPC - " + error; + ERR_PRINT(error); + } +} + +void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const Multiplayer::RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { + Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND_MSG(peer.is_null(), "Attempt to call RPC without active multiplayer peer."); + + ERR_FAIL_COND_MSG(peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to call RPC while multiplayer peer is not connected yet."); + + ERR_FAIL_COND_MSG(peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to call RPC while multiplayer peer is disconnected."); + + ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments (>255)."); + + if (p_to != 0 && !multiplayer->get_connected_peers().has(ABS(p_to))) { + ERR_FAIL_COND_MSG(p_to == peer->get_unique_id(), "Attempt to call RPC on yourself! Peer unique ID: " + itos(peer->get_unique_id()) + "."); + + ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + "."); + } + + NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path()); + ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); + + // See if all peers have cached path (if so, call can be fast). + int psc_id; + const bool has_all_peers = multiplayer->send_object_cache(p_from, from_path, p_to, psc_id); + + // Create base packet, lots of hardcode because it must be tight. + + int ofs = 0; + +#define MAKE_ROOM(m_amount) \ + if (packet_cache.size() < m_amount) \ + packet_cache.resize(m_amount); + + // Encode meta. + uint8_t command_type = MultiplayerAPI::NETWORK_COMMAND_REMOTE_CALL; + uint8_t node_id_compression = UINT8_MAX; + uint8_t name_id_compression = UINT8_MAX; + bool byte_only_or_no_args = false; + + MAKE_ROOM(1); + // The meta is composed along the way, so just set 0 for now. + packet_cache.write[0] = 0; + ofs += 1; + + // Encode Node ID. + if (has_all_peers) { + // Compress the node ID only if all the target peers already know it. + if (psc_id >= 0 && psc_id <= 255) { + // We can encode the id in 1 byte + node_id_compression = NETWORK_NODE_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(psc_id); + ofs += 1; + } else if (psc_id >= 0 && psc_id <= 65535) { + // We can encode the id in 2 bytes + node_id_compression = NETWORK_NODE_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(static_cast<uint16_t>(psc_id), &(packet_cache.write[ofs])); + ofs += 2; + } else { + // Too big, let's use 4 bytes. + node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; + MAKE_ROOM(ofs + 4); + encode_uint32(psc_id, &(packet_cache.write[ofs])); + ofs += 4; + } + } else { + // The targets don't know the node yet, so we need to use 32 bits int. + node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; + MAKE_ROOM(ofs + 4); + encode_uint32(psc_id, &(packet_cache.write[ofs])); + ofs += 4; + } + + // Encode method ID + if (p_rpc_id <= UINT8_MAX) { + // The ID fits in 1 byte + name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); + ofs += 1; + } else { + // The ID is larger, let's use 2 bytes + name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); + ofs += 2; + } + + int len; + Error err = MultiplayerAPI::encode_and_compress_variants(p_arg, p_argcount, nullptr, len, &byte_only_or_no_args, multiplayer->is_object_decoding_allowed()); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC arguments. THIS IS LIKELY A BUG IN THE ENGINE!"); + if (byte_only_or_no_args) { + MAKE_ROOM(ofs + len); + } else { + MAKE_ROOM(ofs + 1 + len); + packet_cache.write[ofs] = p_argcount; + ofs += 1; + } + if (len) { + MultiplayerAPI::encode_and_compress_variants(p_arg, p_argcount, &packet_cache.write[ofs], len, &byte_only_or_no_args, multiplayer->is_object_decoding_allowed()); + ofs += len; + } + + ERR_FAIL_COND(command_type > 7); + ERR_FAIL_COND(node_id_compression > 3); + ERR_FAIL_COND(name_id_compression > 1); + + // We can now set the meta + packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + (byte_only_or_no_args ? BYTE_ONLY_OR_NO_ARGS_FLAG : 0); + +#ifdef DEBUG_ENABLED + multiplayer->profile_bandwidth("out", ofs); +#endif + + // Take chance and set transfer mode, since all send methods will use it. + peer->set_transfer_channel(p_config.channel); + peer->set_transfer_mode(p_config.transfer_mode); + + if (has_all_peers) { + // They all have verified paths, so send fast. + peer->set_target_peer(p_to); // To all of you. + peer->put_packet(packet_cache.ptr(), ofs); // A message with love. + } else { + // Unreachable because the node ID is never compressed if the peers doesn't know it. + CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32); + + // Not all verified path, so send one by one. + + // Append path at the end, since we will need it for some packets. + CharString pname = String(from_path).utf8(); + int path_len = encode_cstring(pname.get_data(), nullptr); + MAKE_ROOM(ofs + path_len); + encode_cstring(pname.get_data(), &(packet_cache.write[ofs])); + + for (const int &P : multiplayer->get_connected_peers()) { + if (p_to < 0 && P == -p_to) { + continue; // Continue, excluded. + } + + if (p_to > 0 && P != p_to) { + continue; // Continue, not for this peer. + } + + bool confirmed = multiplayer->is_cache_confirmed(from_path, P); + + peer->set_target_peer(P); // To this one specifically. + + if (confirmed) { + // This one confirmed path, so use id. + encode_uint32(psc_id, &(packet_cache.write[1])); + peer->put_packet(packet_cache.ptr(), ofs); + } else { + // This one did not confirm path yet, so use entire path (sorry!). + encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. + peer->put_packet(packet_cache.ptr(), ofs + path_len); + } + } + } +} + +void SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { + Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND_MSG(!peer.is_valid(), "Trying to call an RPC while no multiplayer peer is active."); + Node *node = Object::cast_to<Node>(p_obj); + ERR_FAIL_COND(!node); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); + ERR_FAIL_COND_MSG(peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a multiplayer peer which is not connected."); + + int node_id = peer->get_unique_id(); + bool call_local_native = false; + bool call_local_script = false; + uint16_t rpc_id = UINT16_MAX; + const Multiplayer::RPCConfig config = _get_rpc_config(node, p_method, rpc_id); + ERR_FAIL_COND_MSG(config.name == StringName(), + vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, node->get_path())); + if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { + if (rpc_id & (1 << 15)) { + call_local_native = config.call_local; + } else { + call_local_script = config.call_local; + } + } + + if (p_peer_id != node_id) { +#ifdef DEBUG_ENABLED + _profile_node_data("out_rpc", node->get_instance_id()); +#endif + + _send_rpc(node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); + } + + if (call_local_native) { + Callable::CallError ce; + + multiplayer->set_remote_sender_override(peer->get_unique_id()); + node->call(p_method, p_arg, p_argcount, ce); + multiplayer->set_remote_sender_override(0); + + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in local call: - " + error + "."; + ERR_PRINT(error); + return; + } + } + + if (call_local_script) { + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; + + multiplayer->set_remote_sender_override(peer->get_unique_id()); + node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); + multiplayer->set_remote_sender_override(0); + + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in script local call: - " + error + "."; + ERR_PRINT(error); + return; + } + } + + ERR_FAIL_COND_MSG(p_peer_id == node_id && !config.call_local, "RPC '" + p_method + "' on yourself is not allowed by selected mode."); +} diff --git a/scene/multiplayer/scene_rpc_interface.h b/scene/multiplayer/scene_rpc_interface.h new file mode 100644 index 0000000000..86e1d0d280 --- /dev/null +++ b/scene/multiplayer/scene_rpc_interface.h @@ -0,0 +1,91 @@ +/*************************************************************************/ +/* scene_rpc_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 SCENE_RPC_INTERFACE_H +#define SCENE_RPC_INTERFACE_H + +#include "core/multiplayer/multiplayer.h" +#include "core/multiplayer/multiplayer_api.h" + +class SceneRPCInterface : public MultiplayerRPCInterface { + GDCLASS(SceneRPCInterface, MultiplayerRPCInterface); + +private: + enum NetworkNodeIdCompression { + NETWORK_NODE_ID_COMPRESSION_8 = 0, + NETWORK_NODE_ID_COMPRESSION_16, + NETWORK_NODE_ID_COMPRESSION_32, + }; + + enum NetworkNameIdCompression { + NETWORK_NAME_ID_COMPRESSION_8 = 0, + NETWORK_NAME_ID_COMPRESSION_16, + }; + + // The RPC meta is composed by a single byte that contains (starting from the least significant bit): + // - `NetworkCommands` in the first four bits. + // - `NetworkNodeIdCompression` in the next 2 bits. + // - `NetworkNameIdCompression` in the next 1 bit. + // - `byte_only_or_no_args` in the next 1 bit. + enum { + NODE_ID_COMPRESSION_SHIFT = MultiplayerAPI::CMD_FLAG_0_SHIFT, // 2 bits for this. + NAME_ID_COMPRESSION_SHIFT = MultiplayerAPI::CMD_FLAG_2_SHIFT, + BYTE_ONLY_OR_NO_ARGS_SHIFT = MultiplayerAPI::CMD_FLAG_3_SHIFT, + }; + + enum { + NODE_ID_COMPRESSION_FLAG = (1 << NODE_ID_COMPRESSION_SHIFT) | (1 << (NODE_ID_COMPRESSION_SHIFT + 1)), // 2 bits for this. + NAME_ID_COMPRESSION_FLAG = (1 << NAME_ID_COMPRESSION_SHIFT), + BYTE_ONLY_OR_NO_ARGS_FLAG = (1 << BYTE_ONLY_OR_NO_ARGS_SHIFT), + }; + + MultiplayerAPI *multiplayer = nullptr; + Vector<uint8_t> packet_cache; + +protected: + static MultiplayerRPCInterface *_create(MultiplayerAPI *p_multiplayer); + + _FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id); + void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); + + void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const Multiplayer::RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); + Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); + +public: + static void make_default(); + + virtual void rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) override; + virtual void process_rpc(int p_from, const uint8_t *p_packet, int p_packet_len) override; + virtual String get_rpc_md5(const Object *p_obj) const override; + + SceneRPCInterface(MultiplayerAPI *p_multiplayer) { multiplayer = p_multiplayer; } +}; + +#endif // SCENE_RPC_INTERFACE_H diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp index 2540a633a9..a9b7e9acbe 100644 --- a/scene/property_utils.cpp +++ b/scene/property_utils.cpp @@ -130,7 +130,7 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const if (p != -1 && p < prop_str.length() - 1) { bool all_digits = true; for (int i = p + 1; i < prop_str.length(); i++) { - if (prop_str[i] < '0' || prop_str[i] > '9') { + if (!is_digit(prop_str[i])) { all_digits = false; break; } diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index e6b73b7780..9ed83eb8c3 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -91,6 +91,7 @@ #include "scene/gui/control.h" #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/flow_container.h" #include "scene/gui/graph_edit.h" #include "scene/gui/graph_node.h" #include "scene/gui/grid_container.h" @@ -133,6 +134,11 @@ #include "scene/main/timer.h" #include "scene/main/viewport.h" #include "scene/main/window.h" +#include "scene/multiplayer/multiplayer_spawner.h" +#include "scene/multiplayer/multiplayer_synchronizer.h" +#include "scene/multiplayer/scene_cache_interface.h" +#include "scene/multiplayer/scene_replication_interface.h" +#include "scene/multiplayer/scene_rpc_interface.h" #include "scene/resources/audio_stream_sample.h" #include "scene/resources/bit_map.h" #include "scene/resources/box_shape_3d.h" @@ -300,6 +306,8 @@ void register_scene_types() { GDREGISTER_CLASS(SubViewport); GDREGISTER_CLASS(ViewportTexture); GDREGISTER_CLASS(HTTPRequest); + GDREGISTER_CLASS(MultiplayerSpawner); + GDREGISTER_CLASS(MultiplayerSynchronizer); GDREGISTER_CLASS(Timer); GDREGISTER_CLASS(CanvasLayer); GDREGISTER_CLASS(CanvasModulate); @@ -353,6 +361,9 @@ void register_scene_types() { GDREGISTER_CLASS(CenterContainer); GDREGISTER_CLASS(ScrollContainer); GDREGISTER_CLASS(PanelContainer); + GDREGISTER_VIRTUAL_CLASS(FlowContainer); + GDREGISTER_CLASS(HFlowContainer); + GDREGISTER_CLASS(VFlowContainer); OS::get_singleton()->yield(); // may take time to init @@ -390,6 +401,7 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(SplitContainer); GDREGISTER_CLASS(HSplitContainer); GDREGISTER_CLASS(VSplitContainer); + GDREGISTER_CLASS(GraphNode); GDREGISTER_CLASS(GraphEdit); @@ -550,11 +562,13 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeResizableBase); GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeGroupBase); GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeConstant); + GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeVectorBase); GDREGISTER_CLASS(VisualShaderNodeComment); GDREGISTER_CLASS(VisualShaderNodeFloatConstant); GDREGISTER_CLASS(VisualShaderNodeIntConstant); GDREGISTER_CLASS(VisualShaderNodeBooleanConstant); GDREGISTER_CLASS(VisualShaderNodeColorConstant); + GDREGISTER_CLASS(VisualShaderNodeVec2Constant); GDREGISTER_CLASS(VisualShaderNodeVec3Constant); GDREGISTER_CLASS(VisualShaderNodeTransformConstant); GDREGISTER_CLASS(VisualShaderNodeFloatOp); @@ -572,8 +586,7 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeDotProduct); GDREGISTER_CLASS(VisualShaderNodeVectorLen); GDREGISTER_CLASS(VisualShaderNodeDeterminant); - GDREGISTER_CLASS(VisualShaderNodeScalarDerivativeFunc); - GDREGISTER_CLASS(VisualShaderNodeVectorDerivativeFunc); + GDREGISTER_CLASS(VisualShaderNodeDerivativeFunc); GDREGISTER_CLASS(VisualShaderNodeClamp); GDREGISTER_CLASS(VisualShaderNodeFaceForward); GDREGISTER_CLASS(VisualShaderNodeOuterProduct); @@ -599,6 +612,7 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeIntUniform); GDREGISTER_CLASS(VisualShaderNodeBooleanUniform); GDREGISTER_CLASS(VisualShaderNodeColorUniform); + GDREGISTER_CLASS(VisualShaderNodeVec2Uniform); GDREGISTER_CLASS(VisualShaderNodeVec3Uniform); GDREGISTER_CLASS(VisualShaderNodeTransformUniform); GDREGISTER_CLASS(VisualShaderNodeTextureUniform); @@ -815,6 +829,8 @@ void register_scene_types() { GDREGISTER_CLASS(Font); GDREGISTER_CLASS(Curve); + GDREGISTER_CLASS(SceneReplicationConfig); + GDREGISTER_CLASS(TextLine); GDREGISTER_CLASS(TextParagraph); @@ -1019,6 +1035,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarStep", "VisualShaderNodeStep"); ClassDB::add_compatibility_class("VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch"); ClassDB::add_compatibility_class("VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarDerivativeFunc", "VisualShaderNodeDerivativeFunc"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorDerivativeFunc", "VisualShaderNodeDerivativeFunc"); ClassDB::add_compatibility_class("World", "World3D"); #endif /* DISABLE_DEPRECATED */ @@ -1041,13 +1059,17 @@ void register_scene_types() { } SceneDebugger::initialize(); + SceneReplicationInterface::make_default(); + SceneRPCInterface::make_default(); + SceneCacheInterface::make_default(); NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE); } void initialize_theme() { - bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + // Allow creating the default theme at a different scale to suit higher/lower base resolutions. + float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String theme_path = GLOBAL_DEF_RST("gui/theme/custom", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); @@ -1063,7 +1085,7 @@ void initialize_theme() { // Always make the default theme to avoid invalid default font/icon/style in the given theme. if (RenderingServer::get_singleton()) { - make_default_theme(default_theme_hidpi, font); + make_default_theme(default_theme_scale, font); } if (!theme_path.is_empty()) { diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 44d3e4af19..b6151bccf4 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2474,34 +2474,38 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol real_t delta = (length - p_keys[next].time) - (length - p_keys[idx].time); real_t from = (length - p_time) - (length - p_keys[idx].time); - if (Math::is_zero_approx(delta)) + if (Math::is_zero_approx(delta)) { c = 0; - else + } else { c = from / delta; + } } else { next = len - 1; real_t delta = p_keys[idx].time + (length - p_keys[next].time); real_t from = (length - p_time) - (length - p_keys[idx].time); - if (Math::is_zero_approx(delta)) + if (Math::is_zero_approx(delta)) { c = 0; - else + } else { c = from / delta; + } } } else { // on loop, in front of last key idx = 0; next = len - 1; real_t endtime = p_keys[idx].time; - if (endtime > length) // may be keys past the end + if (endtime > length) { // may be keys past the end endtime = length; + } real_t delta = p_keys[next].time - endtime; real_t from = p_time - endtime; - if (Math::is_zero_approx(delta)) + if (Math::is_zero_approx(delta)) { c = 0; - else + } else { c = from / delta; + } } } } else { // no loop @@ -2609,7 +2613,7 @@ Variant Animation::value_track_interpolate(int p_track, double p_time) const { void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { - to_time = length * 1.001; //include a little more if at the end + to_time = length + CMP_EPSILON; //include a little more if at the end } int to = _find(vt->values, to_time); @@ -2730,7 +2734,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const template <class T> void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { - to_time = length * 1.01; //include a little more if at the end + to_time = length + CMP_EPSILON; //include a little more if at the end } int to = _find(p_array, to_time); @@ -3081,7 +3085,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { - to_time = length * 1.01; //include a little more if at the end + to_time = length + CMP_EPSILON; //include a little more if at the end } int to = _find(mt->methods, to_time); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 25f169b6a2..c2988c2e8c 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -667,11 +667,13 @@ void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size); + ClassDB::bind_method(D_METHOD("resize", "new_size"), &BitMap::resize); ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data); ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data); ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask); + ClassDB::bind_method(D_METHOD("convert_to_image"), &BitMap::convert_to_image); ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index b97d378e02..a1ec9a2230 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -95,5 +95,5 @@ void BoxShape3D::_bind_methods() { BoxShape3D::BoxShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) { - set_size(Vector3(2, 2, 2)); + set_size(Vector3(1, 1, 1)); } diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index cb8a189116..4d2698d27d 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -84,13 +84,11 @@ real_t CapsuleShape2D::get_height() const { void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Vector2> points = _get_points(); - Vector<Color> col; - col.push_back(p_color); + Vector<Color> col = { p_color }; RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); if (is_collision_outline_enabled()) { + points.push_back(points[0]); RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); - // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. - RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); } } diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h index 967a413da4..4c039ab326 100644 --- a/scene/resources/capsule_shape_3d.h +++ b/scene/resources/capsule_shape_3d.h @@ -35,8 +35,8 @@ class CapsuleShape3D : public Shape3D { GDCLASS(CapsuleShape3D, Shape3D); - float radius = 1.0; - float height = 3.0; + float radius = 0.5; + float height = 2.0; protected: static void _bind_methods(); diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 68ee1be9f9..9c16ac2eed 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -71,18 +71,19 @@ real_t CircleShape2D::get_enclosing_radius() const { void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Vector2> points; + points.resize(24); + const real_t turn_step = Math_TAU / 24.0; for (int i = 0; i < 24; i++) { - points.push_back(Vector2(Math::cos(i * turn_step), Math::sin(i * turn_step)) * get_radius()); + points.write[i] = Vector2(Math::cos(i * turn_step), Math::sin(i * turn_step)) * get_radius(); } - Vector<Color> col; - col.push_back(p_color); + Vector<Color> col = { p_color }; RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + points.push_back(points[0]); RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); - // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. - RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); } } diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index d2cd76b796..6485c1ac77 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -661,8 +661,8 @@ void Curve2D::_bake() const { baked_cache_dirty = false; if (points.size() == 0) { - baked_point_cache.resize(0); - baked_dist_cache.resize(0); + baked_point_cache.clear(); + baked_dist_cache.clear(); return; } @@ -1164,10 +1164,10 @@ void Curve3D::_bake() const { baked_cache_dirty = false; if (points.size() == 0) { - baked_point_cache.resize(0); - baked_tilt_cache.resize(0); - baked_up_vector_cache.resize(0); - baked_dist_cache.resize(0); + baked_point_cache.clear(); + baked_tilt_cache.clear(); + baked_up_vector_cache.clear(); + baked_dist_cache.clear(); return; } @@ -1183,7 +1183,7 @@ void Curve3D::_bake() const { baked_up_vector_cache.resize(1); baked_up_vector_cache.set(0, Vector3(0, 1, 0)); } else { - baked_up_vector_cache.resize(0); + baked_up_vector_cache.clear(); } return; diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h index 0211f2b08f..65427423c8 100644 --- a/scene/resources/cylinder_shape_3d.h +++ b/scene/resources/cylinder_shape_3d.h @@ -35,7 +35,7 @@ class CylinderShape3D : public Shape3D { GDCLASS(CylinderShape3D, Shape3D); - float radius = 1.0; + float radius = 0.5; float height = 2.0; protected: diff --git a/scene/resources/default_theme/SCsub b/scene/resources/default_theme/SCsub index 3667ab7c14..f27bd9144e 100644 --- a/scene/resources/default_theme/SCsub +++ b/scene/resources/default_theme/SCsub @@ -4,6 +4,7 @@ Import("env") from platform_methods import run_in_subprocess import default_theme_builders +import default_theme_icons_builders env.add_source_files(env.scene_sources, "*.cpp") @@ -13,3 +14,19 @@ env.CommandNoCache( "#thirdparty/fonts/OpenSans_SemiBold.ttf", run_in_subprocess(default_theme_builders.make_fonts_header), ) + +env["BUILDERS"]["MakeDefaultThemeIconsBuilder"] = Builder( + action=env.Run( + default_theme_icons_builders.make_default_theme_icons_action, "Generating default project theme icons header." + ), + suffix=".h", + src_suffix=".svg", +) + +# Default theme icons +icon_sources = Glob("*.svg") + +env.Alias( + "default_theme_icons", + [env.MakeDefaultThemeIconsBuilder("#scene/resources/default_theme/default_theme_icons.gen.h", icon_sources)], +) diff --git a/scene/resources/default_theme/add.svg b/scene/resources/default_theme/add.svg new file mode 100644 index 0000000000..6884a07aa0 --- /dev/null +++ b/scene/resources/default_theme/add.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6z" fill="#b2b2b2" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/arrow_down.png b/scene/resources/default_theme/arrow_down.png Binary files differdeleted file mode 100644 index bfb87a4761..0000000000 --- a/scene/resources/default_theme/arrow_down.png +++ /dev/null diff --git a/scene/resources/default_theme/arrow_down.svg b/scene/resources/default_theme/arrow_down.svg new file mode 100644 index 0000000000..16cc00fa8f --- /dev/null +++ b/scene/resources/default_theme/arrow_down.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m5 7 3 3 3-3" fill="none" stroke="#b2b2b2" stroke-opacity=".45" stroke-width="2"/></svg> diff --git a/scene/resources/default_theme/arrow_left.png b/scene/resources/default_theme/arrow_left.png Binary files differdeleted file mode 100644 index 4163059dd3..0000000000 --- a/scene/resources/default_theme/arrow_left.png +++ /dev/null diff --git a/scene/resources/default_theme/arrow_left.svg b/scene/resources/default_theme/arrow_left.svg new file mode 100644 index 0000000000..7dbf01e186 --- /dev/null +++ b/scene/resources/default_theme/arrow_left.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m9 11-3-3 3-3" fill="none" stroke="#b2b2b2" stroke-opacity=".45" stroke-width="2"/></svg> diff --git a/scene/resources/default_theme/arrow_right.png b/scene/resources/default_theme/arrow_right.png Binary files differdeleted file mode 100644 index 1e4c8e5529..0000000000 --- a/scene/resources/default_theme/arrow_right.png +++ /dev/null diff --git a/scene/resources/default_theme/arrow_right.svg b/scene/resources/default_theme/arrow_right.svg new file mode 100644 index 0000000000..b031f12ec0 --- /dev/null +++ b/scene/resources/default_theme/arrow_right.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m6 11 3-3-3-3" fill="none" stroke="#b2b2b2" stroke-opacity=".45" stroke-width="2"/></svg> diff --git a/scene/resources/default_theme/bar_arrow.png b/scene/resources/default_theme/bar_arrow.png Binary files differdeleted file mode 100644 index 7cf146b8da..0000000000 --- a/scene/resources/default_theme/bar_arrow.png +++ /dev/null diff --git a/scene/resources/default_theme/bookmark.png b/scene/resources/default_theme/bookmark.png Binary files differdeleted file mode 100644 index 9718cf53b6..0000000000 --- a/scene/resources/default_theme/bookmark.png +++ /dev/null diff --git a/scene/resources/default_theme/bookmark.svg b/scene/resources/default_theme/bookmark.svg new file mode 100644 index 0000000000..0b50c2b034 --- /dev/null +++ b/scene/resources/default_theme/bookmark.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#fefffe" fill-opacity=".85"><path d="m14.505 1.476h-12.995v13.049l6.491-5.185 6.504 5.185z"/><path d="m15.018 1.476c0-.25-.23-.452-.514-.452h-12.994c-.284 0-.513.202-.513.452v13.049c0 .178.119.34.306.413.185.071.402.041.552-.079l6.146-4.909 6.158 4.909c.151.12.367.15.553.079.187-.073.306-.235.306-.413zm-.514 0h-12.994v13.049l6.491-5.185 6.503 5.185z"/></g></svg> diff --git a/scene/resources/default_theme/breakpoint.svg b/scene/resources/default_theme/breakpoint.svg new file mode 100644 index 0000000000..9b18b276d8 --- /dev/null +++ b/scene/resources/default_theme/breakpoint.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8c0 3.84-3.16 7-7 7s-7-3.16-7-7 3.16-7 7-7 7 3.16 7 7" fill="#ff5d5d" fill-opacity=".5" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png Binary files differdeleted file mode 100644 index 708748dfe9..0000000000 --- a/scene/resources/default_theme/button_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/button_focus.png b/scene/resources/default_theme/button_focus.png Binary files differdeleted file mode 100644 index 70e16b953b..0000000000 --- a/scene/resources/default_theme/button_focus.png +++ /dev/null diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png Binary files differdeleted file mode 100644 index ff2258281e..0000000000 --- a/scene/resources/default_theme/button_hover.png +++ /dev/null diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png Binary files differdeleted file mode 100644 index c189b61b89..0000000000 --- a/scene/resources/default_theme/button_normal.png +++ /dev/null diff --git a/scene/resources/default_theme/button_pressed.png b/scene/resources/default_theme/button_pressed.png Binary files differdeleted file mode 100644 index 19a7e237aa..0000000000 --- a/scene/resources/default_theme/button_pressed.png +++ /dev/null diff --git a/scene/resources/default_theme/checked.png b/scene/resources/default_theme/checked.png Binary files differdeleted file mode 100644 index bde031b6a2..0000000000 --- a/scene/resources/default_theme/checked.png +++ /dev/null diff --git a/scene/resources/default_theme/checked.svg b/scene/resources/default_theme/checked.svg new file mode 100644 index 0000000000..6c3bc8f210 --- /dev/null +++ b/scene/resources/default_theme/checked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#fff" fill-opacity=".75" stroke-width="1.16667"/><path d="m11.500773 3.7343508-5.6117507 5.6117502-1.7045017-1.6814543-1.4992276 1.4992276 3.2037293 3.1806817 7.1109777-7.1109775z" fill="#1a1a1a" stroke-width="1.06023"/></svg> diff --git a/scene/resources/default_theme/checked_disabled.png b/scene/resources/default_theme/checked_disabled.png Binary files differdeleted file mode 100644 index 70549e2edc..0000000000 --- a/scene/resources/default_theme/checked_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/checked_disabled.svg b/scene/resources/default_theme/checked_disabled.svg new file mode 100644 index 0000000000..109c4dc129 --- /dev/null +++ b/scene/resources/default_theme/checked_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#fff" fill-opacity=".37" stroke-width="1.16667"/><path d="m11.500773 3.7343508-5.6117507 5.6117502-1.7045017-1.6814543-1.4992276 1.4992276 3.2037293 3.1806817 7.1109777-7.1109775z" fill="#1a1a1a" fill-opacity=".5" stroke-width="1.06023"/></svg> diff --git a/scene/resources/default_theme/checker_bg.png b/scene/resources/default_theme/checker_bg.png Binary files differdeleted file mode 100644 index 3eff2f0e08..0000000000 --- a/scene/resources/default_theme/checker_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/close.png b/scene/resources/default_theme/close.png Binary files differdeleted file mode 100644 index 4d4ac4a551..0000000000 --- a/scene/resources/default_theme/close.png +++ /dev/null diff --git a/scene/resources/default_theme/close.svg b/scene/resources/default_theme/close.svg new file mode 100644 index 0000000000..c26cca06c3 --- /dev/null +++ b/scene/resources/default_theme/close.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5.3020979-5-4.6979021 5-2-2 5-5z" fill="#fff" fill-opacity=".75"/></svg> diff --git a/scene/resources/default_theme/close_hl.png b/scene/resources/default_theme/close_hl.png Binary files differdeleted file mode 100644 index 4d4ac4a551..0000000000 --- a/scene/resources/default_theme/close_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/close_hl.svg b/scene/resources/default_theme/close_hl.svg new file mode 100644 index 0000000000..ec44ba6d24 --- /dev/null +++ b/scene/resources/default_theme/close_hl.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5.3020979-5-4.6979021 5-2-2 5-5z" fill="#fff"/></svg> diff --git a/scene/resources/default_theme/color_picker_bar_arrow.svg b/scene/resources/default_theme/color_picker_bar_arrow.svg new file mode 100644 index 0000000000..5043da0761 --- /dev/null +++ b/scene/resources/default_theme/color_picker_bar_arrow.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 20" xmlns="http://www.w3.org/2000/svg"><path d="m3.564 15.218h8.872l-4.436-4.436z" fill="#b2b2b2" fill-rule="nonzero" stroke="#b2b2b2"/></svg> diff --git a/scene/resources/default_theme/color_picker_cursor.svg b/scene/resources/default_theme/color_picker_cursor.svg new file mode 100644 index 0000000000..88ee3f55ce --- /dev/null +++ b/scene/resources/default_theme/color_picker_cursor.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 1a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#fff"/><path d="m8 3a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 5-5 5 5 0 0 0 -5-5zm-.0605469 1a4 4 0 0 1 .0605469 0 4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 3.9394531-4z"/></svg> diff --git a/scene/resources/default_theme/color_picker_hue.png b/scene/resources/default_theme/color_picker_hue.png Binary files differdeleted file mode 100644 index 7b46f03cb4..0000000000 --- a/scene/resources/default_theme/color_picker_hue.png +++ /dev/null diff --git a/scene/resources/default_theme/color_picker_hue.svg b/scene/resources/default_theme/color_picker_hue.svg new file mode 100644 index 0000000000..ff75d5eb9e --- /dev/null +++ b/scene/resources/default_theme/color_picker_hue.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 1 256" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientTransform="matrix(0 256 -256 0 0 0)" gradientUnits="userSpaceOnUse" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#f00"/><stop offset=".04" stop-color="#ff4000"/><stop offset=".08" stop-color="#ff8000"/><stop offset=".17" stop-color="#ff0"/><stop offset=".25" stop-color="#80ff00"/><stop offset=".33" stop-color="#0f0"/><stop offset=".42" stop-color="#00ff80"/><stop offset=".5" stop-color="#0ff"/><stop offset=".58" stop-color="#0080ff"/><stop offset=".63" stop-color="#0040ff"/><stop offset=".67" stop-color="#00f"/><stop offset=".75" stop-color="#8000ff"/><stop offset=".83" stop-color="#f0f"/><stop offset=".92" stop-color="#ff0080"/><stop offset="1" stop-color="#f00"/></linearGradient><path d="m0 0h1v256h-1z" fill="url(#a)"/></svg> diff --git a/scene/resources/default_theme/color_picker_overbright.svg b/scene/resources/default_theme/color_picker_overbright.svg new file mode 100644 index 0000000000..f618980d51 --- /dev/null +++ b/scene/resources/default_theme/color_picker_overbright.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m.5.5v10l10-10z" fill="#fff" stroke="#000"/><path d="m0 12 12-12h-1.714286l-10.285714 10.285714z" fill="#000003" stroke-width="2"/></svg> diff --git a/scene/resources/default_theme/color_picker_pipette.svg b/scene/resources/default_theme/color_picker_pipette.svg new file mode 100644 index 0000000000..5213a6e1bc --- /dev/null +++ b/scene/resources/default_theme/color_picker_pipette.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.108 0-2 .892-2 2v2h-1v2h1v5c.001.712.383 1.372 1 1.729v1.271h2v-1.27c.618-.356.999-1.017 1-1.73v-5h1v-2h-1v-2c0-1.108-.892-2-2-2zm-1 6h2v5c0 .549-.451 1-1 1s-1-.451-1-1z" fill="#b2b2b2" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/color_picker_sample.png b/scene/resources/default_theme/color_picker_sample.png Binary files differdeleted file mode 100644 index e6ec28d307..0000000000 --- a/scene/resources/default_theme/color_picker_sample.png +++ /dev/null diff --git a/scene/resources/default_theme/color_picker_sample.svg b/scene/resources/default_theme/color_picker_sample.svg new file mode 100644 index 0000000000..140ac20a99 --- /dev/null +++ b/scene/resources/default_theme/color_picker_sample.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 256 20" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m0 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m5 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m80 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m85 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m159.978 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m164.978 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m39.991 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m44.991 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m119.99 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m124.99 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m199.968 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m204.968 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m9.98 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m14.98 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m89.98 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m94.98 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m169.957 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m174.957 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m49.97 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m54.97 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m129.97 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m134.97 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m209.948 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m214.948 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m19.995 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m24.995 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m99.995 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m104.995 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m179.973 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m184.973 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m59.986 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m64.986 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m139.986 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m144.986 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m219.964 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m224.964 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m30.011 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m35.011 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m110.011 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m115.011 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m189.989 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m194.989 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m70.001 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m75.001 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m150.001 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m155.001 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m229.979 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m234.979 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m240.017 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m245.017 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m249.996 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m254.996 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m249.996 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m254.996 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m240.017 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m245.017 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m0 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m5 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m80 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m85 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m159.978 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m164.978 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m39.991 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m44.991 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m119.99 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m124.99 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m199.968 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m204.968 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m9.98 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m14.98 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m89.98 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m94.98 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m169.957 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m174.957 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m49.97 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m54.97 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m129.97 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m134.97 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m209.948 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m214.948 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m19.995 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m24.995 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m99.995 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m104.995 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m179.973 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m184.973 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m59.986 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m64.986 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m139.986 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m144.986 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m219.964 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m224.964 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m30.011 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m35.011 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m110.011 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m115.011 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m189.989 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m194.989 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m70.001 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m75.001 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m150.001 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m155.001 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m229.979 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m234.979 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/></g></svg> diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 61cd834867..670b141080 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -32,49 +32,22 @@ #include "core/os/os.h" #include "default_font.gen.h" +#include "default_theme_icons.gen.h" #include "scene/resources/font.h" #include "scene/resources/theme.h" #include "servers/text_server.h" -#include "theme_data.h" -typedef Map<const void *, Ref<ImageTexture>> TexCacheMap; +#include "modules/modules_enabled.gen.h" // For svg. +#ifdef MODULE_SVG_ENABLED +#include "modules/svg/image_loader_svg.h" +#endif -static TexCacheMap *tex_cache; static float scale = 1.0; -template <class T> -static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { - Ref<ImageTexture> texture; +static const int default_margin = 4; +static const int default_corner_radius = 3; - if (tex_cache->has(p_src)) { - texture = (*tex_cache)[p_src]; - } else { - texture = Ref<ImageTexture>(memnew(ImageTexture)); - Ref<Image> img = memnew(Image(p_src)); - const Size2 orig_size = img->get_size(); - img->convert(Image::FORMAT_RGBA8); - img->resize(orig_size.x * scale, orig_size.y * scale); - - texture->create_from_image(img); - (*tex_cache)[p_src] = texture; - } - - Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); - style->set_texture(texture); - style->set_margin_size(SIDE_LEFT, p_left * scale); - style->set_margin_size(SIDE_RIGHT, p_right * scale); - style->set_margin_size(SIDE_BOTTOM, p_bottom * scale); - style->set_margin_size(SIDE_TOP, p_top * scale); - style->set_default_margin(SIDE_LEFT, p_margin_left * scale); - style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(SIDE_TOP, p_margin_top * scale); - style->set_draw_center(p_draw_center); - - return style; -} - -static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { +static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); style->set_default_margin(SIDE_LEFT, p_margin_left * scale); @@ -82,10 +55,18 @@ static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); style->set_default_margin(SIDE_TOP, p_margin_top * scale); + style->set_corner_radius_all(p_corner_radius); + style->set_anti_aliased(true); + // Adjust level of detail based on the corners' effective sizes. + style->set_corner_detail(MIN(Math::ceil(1.5 * p_corner_radius), 6) * scale); + + style->set_draw_center(p_draw_center); + style->set_border_width_all(p_border_width); + return style; } -static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_bottom) { +static Ref<StyleBoxFlat> sb_expand(Ref<StyleBoxFlat> p_sbox, float p_left, float p_top, float p_right, float p_bottom) { p_sbox->set_expand_margin_size(SIDE_LEFT, p_left * scale); p_sbox->set_expand_margin_size(SIDE_TOP, p_top * scale); p_sbox->set_expand_margin_size(SIDE_RIGHT, p_right * scale); @@ -93,36 +74,22 @@ static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, return p_sbox; } -template <class T> -static Ref<Texture2D> make_icon(T p_src) { - Ref<ImageTexture> texture(memnew(ImageTexture)); - Ref<Image> img = memnew(Image(p_src)); - const Size2 orig_size = img->get_size(); - img->convert(Image::FORMAT_RGBA8); - img->resize(orig_size.x * scale, orig_size.y * scale); - texture->create_from_image(img); - - return texture; -} - -static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, bool p_flip_x = false) { - if (!p_flip_y && !p_flip_x) { - return p_texture; - } - - Ref<ImageTexture> texture(memnew(ImageTexture)); - Ref<Image> img = p_texture->get_image(); - img = img->duplicate(); - - if (p_flip_y) { - img->flip_y(); - } - if (p_flip_x) { - img->flip_x(); - } - - texture->create_from_image(img); - return texture; +// See also `editor_generate_icon()` in `editor/editor_themes.cpp`. +static Ref<ImageTexture> generate_icon(int p_index) { + Ref<ImageTexture> icon = memnew(ImageTexture); + Ref<Image> img = memnew(Image); + +#ifdef MODULE_SVG_ENABLED + // Upsample icon generation only if the scale isn't an integer multiplier. + // Generating upsampled icons is slower, and the benefit is hardly visible + // with integer scales. + const bool upsample = !Math::is_equal_approx(Math::round(scale), scale); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false); +#endif + icon->create_from_image(img); + + return icon; } static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { @@ -136,48 +103,60 @@ static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margi return style; } -void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &large_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) { +void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) { scale = p_scale; - tex_cache = memnew(TexCacheMap); - - // Font Colors - - Color control_font_color = Color(0.88, 0.88, 0.88); - Color control_font_lower_color = Color(0.63, 0.63, 0.63); - Color control_font_low_color = Color(0.69, 0.69, 0.69); - Color control_font_hover_color = Color(0.94, 0.94, 0.94); - Color control_font_focus_color = Color(0.94, 0.94, 0.94); - Color control_font_disabled_color = Color(0.9, 0.9, 0.9, 0.2); - Color control_font_pressed_color = Color(1, 1, 1); - - Color control_selection_color = Color(0.49, 0.49, 0.49); + // Font colors + const Color control_font_color = Color(0.875, 0.875, 0.875); + const Color control_font_low_color = Color(0.7, 0.7, 0.7); + const Color control_font_lower_color = Color(0.65, 0.65, 0.65); + const Color control_font_hover_color = Color(0.95, 0.95, 0.95); + const Color control_font_focus_color = Color(0.95, 0.95, 0.95); + const Color control_font_disabled_color = control_font_color * Color(1, 1, 1, 0.5); + const Color control_font_placeholder_color = Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.6f); + const Color control_font_pressed_color = Color(1, 1, 1); + const Color control_selection_color = Color(0.5, 0.5, 0.5); + + // StyleBox colors + const Color style_normal_color = Color(0.1, 0.1, 0.1, 0.6); + const Color style_hover_color = Color(0.225, 0.225, 0.225, 0.6); + const Color style_pressed_color = Color(0, 0, 0, 0.6); + const Color style_disabled_color = Color(0.1, 0.1, 0.1, 0.3); + const Color style_focus_color = Color(1, 1, 1, 0.75); + const Color style_popup_color = Color(0.25, 0.25, 0.25, 1); + const Color style_popup_border_color = Color(0.175, 0.175, 0.175, 1); + const Color style_popup_hover_color = Color(0.4, 0.4, 0.4, 1); + const Color style_selected_color = Color(1, 1, 1, 0.3); + // Don't use a color too bright to keep the percentage readable. + const Color style_progress_color = Color(1, 1, 1, 0.4); + const Color style_separator_color = Color(0.5, 0.5, 0.5); + + // Convert the generated icon sources to a dictionary for easier access. + // Unlike the editor icons, there is no central repository of icons in the Theme resource itself to keep it tidy. + Dictionary icons; + for (int i = 0; i < default_theme_icons_count; i++) { + icons[default_theme_icons_names[i]] = generate_icon(i); + } // Panel - - theme->set_stylebox("panel", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0)); - theme->set_stylebox("panel_fg", "Panel", make_stylebox(panel_bg_png, 0, 0, 0, 0)); - - // Focus - - Ref<StyleBoxTexture> focus = make_stylebox(focus_png, 5, 5, 5, 5); - for (int i = 0; i < 4; i++) { - focus->set_expand_margin_size(Side(i), 1 * scale); - } + theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + theme->set_stylebox("panel_fg", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); // Button - Ref<StyleBox> sb_button_normal = sb_expand(make_stylebox(button_normal_png, 4, 4, 4, 4, 6, 3, 6, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_button_pressed = sb_expand(make_stylebox(button_pressed_png, 4, 4, 4, 4, 6, 3, 6, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_button_hover = sb_expand(make_stylebox(button_hover_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); - Ref<StyleBox> sb_button_disabled = sb_expand(make_stylebox(button_disabled_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); - Ref<StyleBox> sb_button_focus = sb_expand(make_stylebox(button_focus_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); + const Ref<StyleBoxFlat> button_normal = make_flat_stylebox(style_normal_color); + const Ref<StyleBoxFlat> button_hover = make_flat_stylebox(style_hover_color); + const Ref<StyleBoxFlat> button_pressed = make_flat_stylebox(style_pressed_color); + const Ref<StyleBoxFlat> button_disabled = make_flat_stylebox(style_disabled_color); + Ref<StyleBoxFlat> focus = make_flat_stylebox(style_focus_color, default_margin, default_margin, default_margin, default_margin, default_corner_radius, false, 2); + // Make the focus outline appear to be flush with the buttons it's focusing. + focus->set_expand_margin_size_all(2 * scale); - theme->set_stylebox("normal", "Button", sb_button_normal); - theme->set_stylebox("pressed", "Button", sb_button_pressed); - theme->set_stylebox("hover", "Button", sb_button_hover); - theme->set_stylebox("disabled", "Button", sb_button_disabled); - theme->set_stylebox("focus", "Button", sb_button_focus); + theme->set_stylebox("normal", "Button", button_normal); + theme->set_stylebox("hover", "Button", button_hover); + theme->set_stylebox("pressed", "Button", button_pressed); + theme->set_stylebox("disabled", "Button", button_disabled); + theme->set_stylebox("focus", "Button", focus); theme->set_font("font", "Button", Ref<Font>()); theme->set_font_size("font_size", "Button", -1); @@ -217,31 +196,29 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("underline_spacing", "LinkButton", 2 * scale); // OptionButton + theme->set_stylebox("focus", "OptionButton", focus); - Ref<StyleBox> sb_optbutton_focus = sb_expand(make_stylebox(button_focus_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2); - theme->set_stylebox("focus", "OptionButton", sb_optbutton_focus); - - Ref<StyleBox> sb_optbutton_normal = sb_expand(make_stylebox(option_button_normal_png, 4, 4, 21, 4, 6, 3, 9, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_pressed = sb_expand(make_stylebox(option_button_pressed_png, 4, 4, 21, 4, 6, 3, 9, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_hover = sb_expand(make_stylebox(option_button_hover_png, 4, 4, 21, 4, 6, 2, 9, 2), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_disabled = sb_expand(make_stylebox(option_button_disabled_png, 4, 4, 21, 4, 6, 2, 9, 2), 2, 2, 2, 2); + Ref<StyleBox> sb_optbutton_normal = make_flat_stylebox(style_normal_color, 2 * default_margin, default_margin, 21, default_margin); + Ref<StyleBox> sb_optbutton_hover = make_flat_stylebox(style_hover_color, 2 * default_margin, default_margin, 21, default_margin); + Ref<StyleBox> sb_optbutton_pressed = make_flat_stylebox(style_pressed_color, 2 * default_margin, default_margin, 21, default_margin); + Ref<StyleBox> sb_optbutton_disabled = make_flat_stylebox(style_disabled_color, 2 * default_margin, default_margin, 21, default_margin); theme->set_stylebox("normal", "OptionButton", sb_optbutton_normal); - theme->set_stylebox("pressed", "OptionButton", sb_optbutton_pressed); theme->set_stylebox("hover", "OptionButton", sb_optbutton_hover); + theme->set_stylebox("pressed", "OptionButton", sb_optbutton_pressed); theme->set_stylebox("disabled", "OptionButton", sb_optbutton_disabled); - Ref<StyleBox> sb_optbutton_normal_mirrored = sb_expand(make_stylebox(option_button_normal_mirrored_png, 21, 4, 4, 4, 9, 3, 6, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_pressed_mirrored = sb_expand(make_stylebox(option_button_pressed_mirrored_png, 21, 4, 4, 4, 9, 3, 6, 3), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_hover_mirrored = sb_expand(make_stylebox(option_button_hover_mirrored_png, 21, 4, 4, 4, 9, 2, 6, 2), 2, 2, 2, 2); - Ref<StyleBox> sb_optbutton_disabled_mirrored = sb_expand(make_stylebox(option_button_disabled_mirrored_png, 21, 4, 4, 4, 9, 2, 6, 2), 2, 2, 2, 2); + Ref<StyleBox> sb_optbutton_normal_mirrored = make_flat_stylebox(style_normal_color, 21, default_margin, 2 * default_margin, default_margin); + Ref<StyleBox> sb_optbutton_hover_mirrored = make_flat_stylebox(style_hover_color, 21, default_margin, 2 * default_margin, default_margin); + Ref<StyleBox> sb_optbutton_pressed_mirrored = make_flat_stylebox(style_pressed_color, 21, default_margin, 2 * default_margin, default_margin); + Ref<StyleBox> sb_optbutton_disabled_mirrored = make_flat_stylebox(style_disabled_color, 21, default_margin, 2 * default_margin, default_margin); theme->set_stylebox("normal_mirrored", "OptionButton", sb_optbutton_normal_mirrored); - theme->set_stylebox("pressed_mirrored", "OptionButton", sb_optbutton_pressed_mirrored); theme->set_stylebox("hover_mirrored", "OptionButton", sb_optbutton_hover_mirrored); + theme->set_stylebox("pressed_mirrored", "OptionButton", sb_optbutton_pressed_mirrored); theme->set_stylebox("disabled_mirrored", "OptionButton", sb_optbutton_disabled_mirrored); - theme->set_icon("arrow", "OptionButton", make_icon(option_arrow_png)); + theme->set_icon("arrow", "OptionButton", icons["option_button_arrow"]); theme->set_font("font", "OptionButton", Ref<Font>()); theme->set_font_size("font_size", "OptionButton", -1); @@ -254,16 +231,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1)); theme->set_constant("hseparation", "OptionButton", 2 * scale); - theme->set_constant("arrow_margin", "OptionButton", 2 * scale); + theme->set_constant("arrow_margin", "OptionButton", 4 * scale); theme->set_constant("outline_size", "OptionButton", 0); // MenuButton - theme->set_stylebox("normal", "MenuButton", sb_button_normal); - theme->set_stylebox("pressed", "MenuButton", sb_button_pressed); - theme->set_stylebox("hover", "MenuButton", sb_button_hover); - theme->set_stylebox("disabled", "MenuButton", sb_button_disabled); - theme->set_stylebox("focus", "MenuButton", sb_button_focus); + theme->set_stylebox("normal", "MenuButton", button_normal); + theme->set_stylebox("pressed", "MenuButton", button_pressed); + theme->set_stylebox("hover", "MenuButton", button_hover); + theme->set_stylebox("disabled", "MenuButton", button_disabled); + theme->set_stylebox("focus", "MenuButton", focus); theme->set_font("font", "MenuButton", Ref<Font>()); theme->set_font_size("font_size", "MenuButton", -1); @@ -298,14 +275,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("hover_pressed", "CheckBox", cbx_empty); theme->set_stylebox("focus", "CheckBox", cbx_focus); - theme->set_icon("checked", "CheckBox", make_icon(checked_png)); - theme->set_icon("checked_disabled", "CheckBox", make_icon(checked_disabled_png)); - theme->set_icon("unchecked", "CheckBox", make_icon(unchecked_png)); - theme->set_icon("unchecked_disabled", "CheckBox", make_icon(unchecked_disabled_png)); - theme->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png)); - theme->set_icon("radio_checked_disabled", "CheckBox", make_icon(radio_checked_disabled_png)); - theme->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png)); - theme->set_icon("radio_unchecked_disabled", "CheckBox", make_icon(radio_unchecked_disabled_png)); + theme->set_icon("checked", "CheckBox", icons["checked"]); + theme->set_icon("checked_disabled", "CheckBox", icons["checked"]); + theme->set_icon("unchecked", "CheckBox", icons["unchecked"]); + theme->set_icon("unchecked_disabled", "CheckBox", icons["unchecked"]); + theme->set_icon("radio_checked", "CheckBox", icons["radio_checked"]); + theme->set_icon("radio_checked_disabled", "CheckBox", icons["radio_checked"]); + theme->set_icon("radio_unchecked", "CheckBox", icons["radio_unchecked"]); + theme->set_icon("radio_unchecked_disabled", "CheckBox", icons["radio_unchecked"]); theme->set_font("font", "CheckBox", Ref<Font>()); theme->set_font_size("font_size", "CheckBox", -1); @@ -337,15 +314,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("hover_pressed", "CheckButton", cb_empty); theme->set_stylebox("focus", "CheckButton", focus); - theme->set_icon("on", "CheckButton", make_icon(toggle_on_png)); - theme->set_icon("on_disabled", "CheckButton", make_icon(toggle_on_disabled_png)); - theme->set_icon("off", "CheckButton", make_icon(toggle_off_png)); - theme->set_icon("off_disabled", "CheckButton", make_icon(toggle_off_disabled_png)); + theme->set_icon("on", "CheckButton", icons["toggle_on"]); + theme->set_icon("on_disabled", "CheckButton", icons["toggle_on_disabled"]); + theme->set_icon("off", "CheckButton", icons["toggle_off"]); + theme->set_icon("off_disabled", "CheckButton", icons["toggle_off_disabled"]); - theme->set_icon("on_mirrored", "CheckButton", make_icon(toggle_on_mirrored_png)); - theme->set_icon("on_disabled_mirrored", "CheckButton", make_icon(toggle_on_disabled_mirrored_png)); - theme->set_icon("off_mirrored", "CheckButton", make_icon(toggle_off_mirrored_png)); - theme->set_icon("off_disabled_mirrored", "CheckButton", make_icon(toggle_off_disabled_mirrored_png)); + theme->set_icon("on_mirrored", "CheckButton", icons["toggle_on_mirrored"]); + theme->set_icon("on_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]); + theme->set_icon("off_mirrored", "CheckButton", icons["toggle_off_mirrored"]); + theme->set_icon("off_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]); theme->set_font("font", "CheckButton", Ref<Font>()); theme->set_font_size("font_size", "CheckButton", -1); @@ -389,16 +366,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // LineEdit - theme->set_stylebox("normal", "LineEdit", make_stylebox(line_edit_png, 5, 5, 5, 5)); + Ref<StyleBoxFlat> style_line_edit = make_flat_stylebox(style_normal_color); + // Add a line at the bottom to make LineEdits distinguishable from Buttons. + style_line_edit->set_border_width(SIDE_BOTTOM, 2); + style_line_edit->set_border_color(style_pressed_color); + theme->set_stylebox("normal", "LineEdit", style_line_edit); + theme->set_stylebox("focus", "LineEdit", focus); - theme->set_stylebox("read_only", "LineEdit", make_stylebox(line_edit_disabled_png, 6, 6, 6, 6)); + + Ref<StyleBoxFlat> style_line_edit_read_only = make_flat_stylebox(style_disabled_color); + // Add a line at the bottom to make LineEdits distinguishable from Buttons. + style_line_edit_read_only->set_border_width(SIDE_BOTTOM, 2); + style_line_edit_read_only->set_border_color(style_pressed_color * Color(1, 1, 1, 0.5)); + theme->set_stylebox("read_only", "LineEdit", style_line_edit_read_only); theme->set_font("font", "LineEdit", Ref<Font>()); theme->set_font_size("font_size", "LineEdit", -1); theme->set_color("font_color", "LineEdit", control_font_color); - theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0)); - theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_selected_color", "LineEdit", control_font_pressed_color); + theme->set_color("font_uneditable_color", "LineEdit", control_font_disabled_color); + theme->set_color("font_placeholder_color", "LineEdit", control_font_placeholder_color); theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1)); theme->set_color("caret_color", "LineEdit", control_font_hover_color); theme->set_color("selection_color", "LineEdit", control_selection_color); @@ -409,12 +397,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("outline_size", "LineEdit", 0); theme->set_constant("caret_width", "LineEdit", 1); - theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png)); + theme->set_icon("clear", "LineEdit", icons["line_edit_clear"]); // ProgressBar - theme->set_stylebox("bg", "ProgressBar", make_stylebox(progress_bar_png, 4, 4, 4, 4, 0, 0, 0, 0)); - theme->set_stylebox("fg", "ProgressBar", make_stylebox(progress_fill_png, 6, 6, 6, 6, 2, 1, 2, 1)); + theme->set_stylebox("bg", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6)); + theme->set_stylebox("fg", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6)); theme->set_font("font", "ProgressBar", Ref<Font>()); theme->set_font_size("font_size", "ProgressBar", -1); @@ -427,26 +415,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // TextEdit - theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + theme->set_stylebox("normal", "TextEdit", style_line_edit); theme->set_stylebox("focus", "TextEdit", focus); - theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0)); + theme->set_stylebox("read_only", "TextEdit", style_line_edit_read_only); - theme->set_icon("tab", "TextEdit", make_icon(tab_png)); - theme->set_icon("space", "TextEdit", make_icon(space_png)); + theme->set_icon("tab", "TextEdit", icons["text_edit_tab"]); + theme->set_icon("space", "TextEdit", icons["text_edit_space"]); theme->set_font("font", "TextEdit", Ref<Font>()); theme->set_font_size("font_size", "TextEdit", -1); theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0)); theme->set_color("font_color", "TextEdit", control_font_color); - theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0)); - theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_selected_color", "TextEdit", control_font_pressed_color); + theme->set_color("font_readonly_color", "TextEdit", control_font_disabled_color); + theme->set_color("font_placeholder_color", "TextEdit", control_font_placeholder_color); theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1)); theme->set_color("selection_color", "TextEdit", control_selection_color); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0)); - theme->set_color("word_highlighted_color", "TextEdit", Color(0.8, 0.9, 0.9, 0.15)); + theme->set_color("word_highlighted_color", "TextEdit", Color(0.5, 0.5, 0.5, 0.25)); theme->set_color("search_result_color", "TextEdit", Color(0.3, 0.3, 0.3)); theme->set_color("search_result_border_color", "TextEdit", Color(0.3, 0.3, 0.3, 0.4)); @@ -456,19 +445,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CodeEdit - theme->set_stylebox("normal", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); + theme->set_stylebox("normal", "CodeEdit", style_line_edit); theme->set_stylebox("focus", "CodeEdit", focus); - theme->set_stylebox("read_only", "CodeEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0)); - theme->set_stylebox("completion", "CodeEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0)); - - theme->set_icon("tab", "CodeEdit", make_icon(tab_png)); - theme->set_icon("space", "CodeEdit", make_icon(space_png)); - theme->set_icon("breakpoint", "CodeEdit", make_icon(graph_port_png)); - theme->set_icon("bookmark", "CodeEdit", make_icon(bookmark_png)); - theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png)); - theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png)); - theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png)); - theme->set_icon("folded_eol_icon", "CodeEdit", make_icon(ellipsis_png)); + theme->set_stylebox("read_only", "CodeEdit", style_line_edit_read_only); + theme->set_stylebox("completion", "CodeEdit", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + + theme->set_icon("tab", "CodeEdit", icons["text_edit_tab"]); + theme->set_icon("space", "CodeEdit", icons["text_edit_space"]); + theme->set_icon("breakpoint", "CodeEdit", icons["breakpoint"]); + theme->set_icon("bookmark", "CodeEdit", icons["bookmark"]); + theme->set_icon("executing_line", "CodeEdit", icons["arrow_right"]); + theme->set_icon("can_fold", "CodeEdit", icons["arrow_down"]); + theme->set_icon("folded", "CodeEdit", icons["arrow_right"]); + theme->set_icon("folded_eol_icon", "CodeEdit", icons["text_edit_ellipsis"]); theme->set_font("font", "CodeEdit", Ref<Font>()); theme->set_font_size("font_size", "CodeEdit", -1); @@ -482,6 +471,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "CodeEdit", control_font_color); theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0)); theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_placeholder_color", "CodeEdit", control_font_placeholder_color); theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1)); theme->set_color("selection_color", "CodeEdit", control_selection_color); theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8)); @@ -506,13 +496,18 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Texture2D> empty_icon = memnew(ImageTexture); + const Ref<StyleBoxFlat> style_scrollbar = make_flat_stylebox(style_normal_color, 4, 4, 4, 4, 10); + Ref<StyleBoxFlat> style_scrollbar_grabber = make_flat_stylebox(style_progress_color, 4, 4, 4, 4, 10); + Ref<StyleBoxFlat> style_scrollbar_grabber_highlight = make_flat_stylebox(style_focus_color, 4, 4, 4, 4, 10); + Ref<StyleBoxFlat> style_scrollbar_grabber_pressed = make_flat_stylebox(style_focus_color * Color(0.75, 0.75, 0.75), 4, 4, 4, 4, 10); + // HScrollBar - theme->set_stylebox("scroll", "HScrollBar", make_stylebox(scroll_bg_png, 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("scroll_focus", "HScrollBar", make_stylebox(scroll_bg_png, 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("grabber", "HScrollBar", make_stylebox(scroll_grabber_png, 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_highlight", "HScrollBar", make_stylebox(scroll_grabber_hl_png, 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_pressed", "HScrollBar", make_stylebox(scroll_grabber_pressed_png, 5, 5, 5, 5, 2, 2, 2, 2)); + theme->set_stylebox("scroll", "HScrollBar", style_scrollbar); + theme->set_stylebox("scroll_focus", "HScrollBar", focus); + theme->set_stylebox("grabber", "HScrollBar", style_scrollbar_grabber); + theme->set_stylebox("grabber_highlight", "HScrollBar", style_scrollbar_grabber_highlight); + theme->set_stylebox("grabber_pressed", "HScrollBar", style_scrollbar_grabber_pressed); theme->set_icon("increment", "HScrollBar", empty_icon); theme->set_icon("increment_highlight", "HScrollBar", empty_icon); @@ -523,11 +518,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // VScrollBar - theme->set_stylebox("scroll", "VScrollBar", make_stylebox(scroll_bg_png, 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("scroll_focus", "VScrollBar", make_stylebox(scroll_bg_png, 5, 5, 5, 5, 0, 0, 0, 0)); - theme->set_stylebox("grabber", "VScrollBar", make_stylebox(scroll_grabber_png, 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_highlight", "VScrollBar", make_stylebox(scroll_grabber_hl_png, 5, 5, 5, 5, 2, 2, 2, 2)); - theme->set_stylebox("grabber_pressed", "VScrollBar", make_stylebox(scroll_grabber_pressed_png, 5, 5, 5, 5, 2, 2, 2, 2)); + theme->set_stylebox("scroll", "VScrollBar", style_scrollbar); + theme->set_stylebox("scroll_focus", "VScrollBar", focus); + theme->set_stylebox("grabber", "VScrollBar", style_scrollbar_grabber); + theme->set_stylebox("grabber_highlight", "VScrollBar", style_scrollbar_grabber_highlight); + theme->set_stylebox("grabber_pressed", "VScrollBar", style_scrollbar_grabber_pressed); theme->set_icon("increment", "VScrollBar", empty_icon); theme->set_icon("increment_highlight", "VScrollBar", empty_icon); @@ -536,31 +531,35 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("decrement_highlight", "VScrollBar", empty_icon); theme->set_icon("decrement_pressed", "VScrollBar", empty_icon); + const Ref<StyleBoxFlat> style_slider = make_flat_stylebox(style_normal_color, 4, 4, 4, 4, 4); + const Ref<StyleBoxFlat> style_slider_grabber = make_flat_stylebox(style_progress_color, 4, 4, 4, 4, 4); + const Ref<StyleBoxFlat> style_slider_grabber_highlight = make_flat_stylebox(style_focus_color, 4, 4, 4, 4, 4); + // HSlider - theme->set_stylebox("slider", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); - theme->set_stylebox("grabber_area", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); - theme->set_stylebox("grabber_area_highlight", "HSlider", make_stylebox(hslider_bg_png, 4, 4, 4, 4)); + theme->set_stylebox("slider", "HSlider", style_slider); + theme->set_stylebox("grabber_area", "HSlider", style_slider_grabber); + theme->set_stylebox("grabber_area_highlight", "HSlider", style_slider_grabber_highlight); - theme->set_icon("grabber", "HSlider", make_icon(hslider_grabber_png)); - theme->set_icon("grabber_highlight", "HSlider", make_icon(hslider_grabber_hl_png)); - theme->set_icon("grabber_disabled", "HSlider", make_icon(hslider_grabber_disabled_png)); - theme->set_icon("tick", "HSlider", make_icon(hslider_tick_png)); + theme->set_icon("grabber", "HSlider", icons["slider_grabber"]); + theme->set_icon("grabber_highlight", "HSlider", icons["slider_grabber_hl"]); + theme->set_icon("grabber_disabled", "HSlider", icons["slider_grabber_disabled"]); + theme->set_icon("tick", "HSlider", icons["hslider_tick"]); // VSlider - theme->set_stylebox("slider", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); - theme->set_stylebox("grabber_area", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); - theme->set_stylebox("grabber_area_highlight", "VSlider", make_stylebox(vslider_bg_png, 4, 4, 4, 4)); + theme->set_stylebox("slider", "VSlider", style_slider); + theme->set_stylebox("grabber_area", "VSlider", style_slider_grabber); + theme->set_stylebox("grabber_area_highlight", "VSlider", style_slider_grabber_highlight); - theme->set_icon("grabber", "VSlider", make_icon(vslider_grabber_png)); - theme->set_icon("grabber_highlight", "VSlider", make_icon(vslider_grabber_hl_png)); - theme->set_icon("grabber_disabled", "VSlider", make_icon(vslider_grabber_disabled_png)); - theme->set_icon("tick", "VSlider", make_icon(vslider_tick_png)); + theme->set_icon("grabber", "VSlider", icons["slider_grabber"]); + theme->set_icon("grabber_highlight", "VSlider", icons["slider_grabber_hl"]); + theme->set_icon("grabber_disabled", "VSlider", icons["slider_grabber_disabled"]); + theme->set_icon("tick", "VSlider", icons["vslider_tick"]); // SpinBox - theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png)); + theme->set_icon("updown", "SpinBox", icons["updown"]); // ScrollContainer @@ -570,67 +569,88 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Window - theme->set_stylebox("embedded_border", "Window", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6)); + theme->set_stylebox("embedded_border", "Window", sb_expand(make_flat_stylebox(style_popup_color, 10, 28, 10, 8), 8, 32, 8, 6)); theme->set_constant("scaleborder_size", "Window", 4 * scale); - theme->set_font("title_font", "Window", large_font); + theme->set_font("title_font", "Window", Ref<Font>()); theme->set_font_size("title_font_size", "Window", -1); - - theme->set_color("title_color", "Window", Color(0, 0, 0)); + theme->set_color("title_color", "Window", control_font_color); theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1)); - theme->set_constant("title_outline_size", "Window", 0); - theme->set_constant("title_height", "Window", 20 * scale); + theme->set_constant("title_height", "Window", 36 * scale); theme->set_constant("resize_margin", "Window", 4 * scale); - theme->set_icon("close", "Window", make_icon(close_png)); - theme->set_icon("close_pressed", "Window", make_icon(close_hl_png)); + theme->set_icon("close", "Window", icons["close"]); + theme->set_icon("close_pressed", "Window", icons["close_hl"]); theme->set_constant("close_h_ofs", "Window", 18 * scale); - theme->set_constant("close_v_ofs", "Window", 18 * scale); + theme->set_constant("close_v_ofs", "Window", 24 * scale); + + // Dialogs + + theme->set_constant("margin", "Dialogs", 8 * scale); + theme->set_constant("button_margin", "Dialogs", 32 * scale); // AcceptDialog - theme->set_stylebox("panel", "AcceptDialog", make_stylebox(dialog_bg_png, 0, 0, 0, 0)); + theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0)); // File Dialog - theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png)); - theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png)); - theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png)); - theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png)); - theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png)); + theme->set_icon("parent_folder", "FileDialog", icons["folder_up"]); + theme->set_icon("back_folder", "FileDialog", icons["arrow_left"]); + theme->set_icon("forward_folder", "FileDialog", icons["arrow_right"]); + theme->set_icon("reload", "FileDialog", icons["reload"]); + theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]); + theme->set_icon("folder", "FileDialog", icons["folder"]); + theme->set_icon("file", "FileDialog", icons["file"]); + theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1)); + theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1)); + theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7)); // Popup - Ref<StyleBoxTexture> style_pp = sb_expand(make_stylebox(popup_bg_png, 5, 5, 5, 5, 4, 4, 4, 4), 2, 2, 2, 2); - - Ref<StyleBoxTexture> selected = make_stylebox(selection_png, 6, 6, 6, 6); - for (int i = 0; i < 4; i++) { - selected->set_expand_margin_size(Side(i), 2 * scale); - } - - theme->set_stylebox("panel", "PopupPanel", style_pp); + theme->set_stylebox("panel", "PopupPanel", make_flat_stylebox(style_normal_color)); // 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); + theme->set_stylebox("panel", "PopupDialog", make_flat_stylebox(style_normal_color)); // PopupMenu - 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)); - theme->set_stylebox("labeled_separator_left", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0)); - theme->set_stylebox("labeled_separator_right", "PopupMenu", make_stylebox(vseparator_png, 0, 0, 0, 0)); - - theme->set_icon("checked", "PopupMenu", make_icon(checked_png)); - theme->set_icon("unchecked", "PopupMenu", make_icon(unchecked_png)); - theme->set_icon("radio_checked", "PopupMenu", make_icon(radio_checked_png)); - theme->set_icon("radio_unchecked", "PopupMenu", make_icon(radio_unchecked_png)); - theme->set_icon("submenu", "PopupMenu", make_icon(submenu_png)); - theme->set_icon("submenu_mirrored", "PopupMenu", make_icon(submenu_mirrored_png)); + Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine); + separator_horizontal->set_thickness(Math::round(scale)); + separator_horizontal->set_color(style_separator_color); + separator_horizontal->set_default_margin(SIDE_LEFT, default_margin); + separator_horizontal->set_default_margin(SIDE_TOP, 0); + separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin); + separator_horizontal->set_default_margin(SIDE_BOTTOM, 0); + Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate(); + separator_vertical->set_vertical(true); + separator_vertical->set_default_margin(SIDE_LEFT, 0); + separator_vertical->set_default_margin(SIDE_TOP, default_margin); + separator_vertical->set_default_margin(SIDE_RIGHT, 0); + separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin); + + // Always display a border for PopupMenus so they can be distinguished from their background. + Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color); + style_popup_panel->set_border_width_all(2); + style_popup_panel->set_border_color(style_popup_border_color); + Ref<StyleBoxFlat> style_popup_panel_disabled = style_popup_panel->duplicate(); + style_popup_panel_disabled->set_bg_color(style_disabled_color); + + theme->set_stylebox("panel", "PopupMenu", style_popup_panel); + theme->set_stylebox("panel_disabled", "PopupMenu", style_popup_panel_disabled); + theme->set_stylebox("hover", "PopupMenu", make_flat_stylebox(style_popup_hover_color)); + theme->set_stylebox("separator", "PopupMenu", separator_horizontal); + theme->set_stylebox("labeled_separator_left", "PopupMenu", separator_horizontal); + theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal); + + theme->set_icon("checked", "PopupMenu", icons["checked"]); + theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]); + theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]); + theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]); + theme->set_icon("submenu", "PopupMenu", icons["arrow_right"]); + theme->set_icon("submenu_mirrored", "PopupMenu", icons["arrow_left"]); theme->set_font("font", "PopupMenu", Ref<Font>()); theme->set_font_size("font_size", "PopupMenu", -1); @@ -649,65 +669,63 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("item_end_padding", "PopupMenu", 2 * scale); // GraphNode - - Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 6); - Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 6); - Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 6); - Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 6); - Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png, 4, 4, 4, 4, 6, 4, 4, 4); - Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png, 4, 4, 4, 4, 6, 4, 4, 4); - Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 6); - Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 6); - - //graphsb->set_expand_margin_size(SIDE_LEFT,10); - //graphsb->set_expand_margin_size(SIDE_RIGHT,10); - theme->set_stylebox("frame", "GraphNode", graphsb); - theme->set_stylebox("selectedframe", "GraphNode", graphsbselected); - theme->set_stylebox("defaultframe", "GraphNode", graphsbdefault); - theme->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus); - theme->set_stylebox("comment", "GraphNode", graphsbcomment); - theme->set_stylebox("commentfocus", "GraphNode", graphsbcommentselected); - theme->set_stylebox("breakpoint", "GraphNode", graph_bpoint); - theme->set_stylebox("position", "GraphNode", graph_position); - theme->set_constant("separation", "GraphNode", 1 * scale); - theme->set_icon("port", "GraphNode", make_icon(graph_port_png)); - theme->set_icon("close", "GraphNode", make_icon(graph_node_close_png)); - theme->set_icon("resizer", "GraphNode", make_icon(window_resizer_png)); + Ref<StyleBoxFlat> graphnode_normal = make_flat_stylebox(style_normal_color, 18, 42, 18, 12); + graphnode_normal->set_border_width(SIDE_TOP, 30); + graphnode_normal->set_border_color(Color(0.325, 0.325, 0.325, 0.6)); + Ref<StyleBoxFlat> graphnode_selected = graphnode_normal->duplicate(); + graphnode_selected->set_border_color(Color(0.625, 0.625, 0.625, 0.6)); + Ref<StyleBoxFlat> graphnode_comment_normal = make_flat_stylebox(style_pressed_color, 18, 42, 18, 12, 3, true, 2); + graphnode_comment_normal->set_border_color(style_pressed_color); + Ref<StyleBoxFlat> graphnode_comment_selected = graphnode_comment_normal->duplicate(); + graphnode_comment_selected->set_border_color(style_hover_color); + Ref<StyleBoxFlat> graphnode_breakpoint = make_flat_stylebox(style_pressed_color, 18, 42, 18, 12, 6, true, 4); + graphnode_breakpoint->set_border_color(Color(0.9, 0.29, 0.3)); + Ref<StyleBoxFlat> graphnode_position = make_flat_stylebox(style_pressed_color, 18, 42, 18, 12, 6, true, 4); + graphnode_position->set_border_color(Color(0.98, 0.89, 0.27)); + + theme->set_stylebox("frame", "GraphNode", graphnode_normal); + theme->set_stylebox("selectedframe", "GraphNode", graphnode_selected); + theme->set_stylebox("comment", "GraphNode", graphnode_comment_normal); + theme->set_stylebox("commentfocus", "GraphNode", graphnode_comment_selected); + theme->set_stylebox("breakpoint", "GraphNode", graphnode_breakpoint); + theme->set_stylebox("position", "GraphNode", graphnode_position); + + theme->set_icon("port", "GraphNode", icons["graph_port"]); + theme->set_icon("close", "GraphNode", icons["close"]); + theme->set_icon("resizer", "GraphNode", icons["resizer_se"]); theme->set_font("title_font", "GraphNode", Ref<Font>()); - theme->set_color("title_color", "GraphNode", Color(0, 0, 0, 1)); - theme->set_color("close_color", "GraphNode", Color(0, 0, 0, 1)); - theme->set_color("resizer_color", "GraphNode", Color(0, 0, 0, 1)); - theme->set_constant("title_offset", "GraphNode", 20 * scale); - theme->set_constant("close_offset", "GraphNode", 18 * scale); - theme->set_constant("port_offset", "GraphNode", 3 * scale); + theme->set_color("title_color", "GraphNode", control_font_color); + theme->set_color("close_color", "GraphNode", control_font_color); + theme->set_color("resizer_color", "GraphNode", control_font_color); + theme->set_constant("separation", "GraphNode", 2 * scale); + theme->set_constant("title_offset", "GraphNode", 26 * scale); + theme->set_constant("close_offset", "GraphNode", 22 * scale); + theme->set_constant("port_offset", "GraphNode", 0); // Tree - Ref<StyleBoxTexture> tree_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 0, 8, 0); - Ref<StyleBoxTexture> tree_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 0, 8, 0); - - theme->set_stylebox("bg", "Tree", make_stylebox(tree_bg_png, 4, 4, 4, 5)); + theme->set_stylebox("bg", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); theme->set_stylebox("bg_focus", "Tree", focus); - theme->set_stylebox("selected", "Tree", tree_selected_oof); - theme->set_stylebox("selected_focus", "Tree", tree_selected); + theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color)); + theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color)); theme->set_stylebox("cursor", "Tree", focus); theme->set_stylebox("cursor_unfocused", "Tree", focus); - theme->set_stylebox("button_pressed", "Tree", make_stylebox(button_pressed_png, 4, 4, 4, 4)); - theme->set_stylebox("title_button_normal", "Tree", make_stylebox(tree_title_png, 4, 4, 4, 4)); - theme->set_stylebox("title_button_pressed", "Tree", make_stylebox(tree_title_pressed_png, 4, 4, 4, 4)); - theme->set_stylebox("title_button_hover", "Tree", make_stylebox(tree_title_png, 4, 4, 4, 4)); - theme->set_stylebox("custom_button", "Tree", sb_button_normal); - theme->set_stylebox("custom_button_pressed", "Tree", sb_button_pressed); - theme->set_stylebox("custom_button_hover", "Tree", sb_button_hover); - - theme->set_icon("checked", "Tree", make_icon(checked_png)); - theme->set_icon("unchecked", "Tree", make_icon(unchecked_png)); - theme->set_icon("indeterminate", "Tree", make_icon(indeterminate_png)); - theme->set_icon("updown", "Tree", make_icon(updown_png)); - theme->set_icon("select_arrow", "Tree", make_icon(dropdown_png)); - theme->set_icon("arrow", "Tree", make_icon(arrow_down_png)); - theme->set_icon("arrow_collapsed", "Tree", make_icon(arrow_right_png)); - theme->set_icon("arrow_collapsed_mirrored", "Tree", make_icon(arrow_left_png)); + theme->set_stylebox("button_pressed", "Tree", button_pressed); + theme->set_stylebox("title_button_normal", "Tree", make_flat_stylebox(style_pressed_color, 4, 4, 4, 4)); + theme->set_stylebox("title_button_pressed", "Tree", make_flat_stylebox(style_hover_color, 4, 4, 4, 4)); + theme->set_stylebox("title_button_hover", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 4)); + theme->set_stylebox("custom_button", "Tree", button_normal); + theme->set_stylebox("custom_button_pressed", "Tree", button_pressed); + theme->set_stylebox("custom_button_hover", "Tree", button_hover); + + theme->set_icon("checked", "Tree", icons["checked"]); + theme->set_icon("unchecked", "Tree", icons["unchecked"]); + theme->set_icon("indeterminate", "Tree", icons["indeterminate"]); + theme->set_icon("updown", "Tree", icons["updown"]); + theme->set_icon("select_arrow", "Tree", icons["option_button_arrow"]); + theme->set_icon("arrow", "Tree", icons["arrow_down"]); + theme->set_icon("arrow_collapsed", "Tree", icons["arrow_right"]); + theme->set_icon("arrow_collapsed_mirrored", "Tree", icons["arrow_left"]); theme->set_font("title_button_font", "Tree", Ref<Font>()); theme->set_font("font", "Tree", Ref<Font>()); @@ -717,7 +735,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color", "Tree", control_font_low_color); theme->set_color("font_selected_color", "Tree", control_font_pressed_color); theme->set_color("font_outline_color", "Tree", Color(1, 1, 1)); - theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1)); + theme->set_color("guide_color", "Tree", Color(0.7, 0.7, 0.7, 0.25)); theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27)); @@ -726,7 +744,7 @@ 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("item_margin", "Tree", 12 * scale); + theme->set_constant("item_margin", "Tree", 16 * scale); theme->set_constant("button_margin", "Tree", 4 * scale); theme->set_constant("draw_relationship_lines", "Tree", 0); theme->set_constant("relationship_line_width", "Tree", 1); @@ -740,10 +758,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ItemList - Ref<StyleBoxTexture> item_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 2, 8, 2); - Ref<StyleBoxTexture> item_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 2, 8, 2); - - theme->set_stylebox("bg", "ItemList", make_stylebox(tree_bg_png, 4, 4, 4, 5)); + theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color)); theme->set_stylebox("bg_focus", "ItemList", focus); theme->set_constant("hseparation", "ItemList", 4); theme->set_constant("vseparation", "ItemList", 2); @@ -757,8 +772,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_selected_color", "ItemList", control_font_pressed_color); theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1)); theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1)); - theme->set_stylebox("selected", "ItemList", item_selected_oof); - theme->set_stylebox("selected_focus", "ItemList", item_selected); + theme->set_stylebox("selected", "ItemList", make_flat_stylebox(style_selected_color)); + theme->set_stylebox("selected_focus", "ItemList", make_flat_stylebox(style_selected_color)); theme->set_stylebox("cursor", "ItemList", focus); theme->set_stylebox("cursor_unfocused", "ItemList", focus); @@ -766,22 +781,28 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // TabContainer - Ref<StyleBoxTexture> tc_sb = sb_expand(make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 4, 4, 4, 4), 3, 3, 3, 3); - - tc_sb->set_expand_margin_size(SIDE_TOP, 2 * scale); - tc_sb->set_default_margin(SIDE_TOP, 8 * scale); - - theme->set_stylebox("tab_selected", "TabContainer", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); - theme->set_stylebox("tab_unselected", "TabContainer", sb_expand(make_stylebox(tab_behind_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 0)); - theme->set_stylebox("tab_disabled", "TabContainer", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 0)); - theme->set_stylebox("panel", "TabContainer", tc_sb); - - theme->set_icon("increment", "TabContainer", make_icon(scroll_button_right_png)); - theme->set_icon("increment_highlight", "TabContainer", make_icon(scroll_button_right_hl_png)); - theme->set_icon("decrement", "TabContainer", make_icon(scroll_button_left_png)); - theme->set_icon("decrement_highlight", "TabContainer", make_icon(scroll_button_left_hl_png)); - theme->set_icon("menu", "TabContainer", make_icon(tab_menu_png)); - theme->set_icon("menu_highlight", "TabContainer", make_icon(tab_menu_hl_png)); + Ref<StyleBoxFlat> style_tab_selected = make_flat_stylebox(style_normal_color, 10, 4, 10, 4, 0); + style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * scale)); + style_tab_selected->set_border_color(style_focus_color); + Ref<StyleBoxFlat> style_tab_unselected = make_flat_stylebox(style_pressed_color, 10, 4, 10, 4, 0); + // Add some spacing between unselected tabs to make them easier to distinguish from each other. + style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(scale)); + style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(scale)); + style_tab_unselected->set_border_color(style_popup_border_color); + Ref<StyleBoxFlat> style_tab_disabled = style_tab_unselected->duplicate(); + style_tab_disabled->set_bg_color(style_disabled_color); + + theme->set_stylebox("tab_selected", "TabContainer", style_tab_selected); + theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected); + theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled); + theme->set_stylebox("panel", "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + + theme->set_icon("increment", "TabContainer", icons["scroll_button_right"]); + theme->set_icon("increment_highlight", "TabContainer", icons["scroll_button_right_hl"]); + theme->set_icon("decrement", "TabContainer", icons["scroll_button_left"]); + theme->set_icon("decrement_highlight", "TabContainer", icons["scroll_button_left_hl"]); + theme->set_icon("menu", "TabContainer", icons["tabs_menu"]); + theme->set_icon("menu_highlight", "TabContainer", icons["tabs_menu_hl"]); theme->set_font("font", "TabContainer", Ref<Font>()); theme->set_font_size("font_size", "TabContainer", -1); @@ -797,17 +818,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // TabBar - theme->set_stylebox("tab_selected", "TabBar", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); - theme->set_stylebox("tab_unselected", "TabBar", sb_expand(make_stylebox(tab_behind_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 0)); - theme->set_stylebox("tab_disabled", "TabBar", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 0)); - theme->set_stylebox("close_bg_pressed", "TabBar", make_stylebox(button_pressed_png, 4, 4, 4, 4)); - theme->set_stylebox("close_bg_highlight", "TabBar", make_stylebox(button_normal_png, 4, 4, 4, 4)); + theme->set_stylebox("tab_selected", "TabBar", style_tab_selected); + theme->set_stylebox("tab_unselected", "TabBar", style_tab_unselected); + theme->set_stylebox("tab_disabled", "TabBar", style_tab_disabled); + theme->set_stylebox("button_pressed", "TabBar", button_pressed); + theme->set_stylebox("button_highlight", "TabBar", button_normal); - theme->set_icon("increment", "TabBar", make_icon(scroll_button_right_png)); - theme->set_icon("increment_highlight", "TabBar", make_icon(scroll_button_right_hl_png)); - theme->set_icon("decrement", "TabBar", make_icon(scroll_button_left_png)); - theme->set_icon("decrement_highlight", "TabBar", make_icon(scroll_button_left_hl_png)); - theme->set_icon("close", "TabBar", make_icon(tab_close_png)); + theme->set_icon("increment", "TabBar", icons["scroll_button_right"]); + theme->set_icon("increment_highlight", "TabBar", icons["scroll_button_right_hl"]); + theme->set_icon("decrement", "TabBar", icons["scroll_button_left"]); + theme->set_icon("decrement_highlight", "TabBar", icons["scroll_button_left_hl"]); + theme->set_icon("close", "TabBar", icons["close"]); theme->set_font("font", "TabBar", Ref<Font>()); theme->set_font_size("font_size", "TabBar", -1); @@ -822,29 +843,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Separators - theme->set_stylebox("separator", "HSeparator", make_stylebox(vseparator_png, 3, 3, 3, 3)); - theme->set_stylebox("separator", "VSeparator", make_stylebox(hseparator_png, 3, 3, 3, 3)); + theme->set_stylebox("separator", "HSeparator", separator_horizontal); + theme->set_stylebox("separator", "VSeparator", separator_vertical); - theme->set_icon("close", "Icons", make_icon(icon_close_png)); + theme->set_icon("close", "Icons", icons["close"]); theme->set_font("normal", "Fonts", Ref<Font>()); - theme->set_font("large", "Fonts", large_font); + theme->set_font("large", "Fonts", Ref<Font>()); theme->set_constant("separation", "HSeparator", 4 * scale); theme->set_constant("separation", "VSeparator", 4 * scale); - // Dialogs - - theme->set_constant("margin", "Dialogs", 8 * scale); - theme->set_constant("button_margin", "Dialogs", 32 * scale); - - // FileDialog - - theme->set_icon("folder", "FileDialog", make_icon(icon_folder_png)); - theme->set_icon("file", "FileDialog", make_icon(icon_file_png)); - theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1)); - theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1)); - theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7)); - // ColorPicker theme->set_constant("margin", "ColorPicker", 4 * scale); @@ -853,23 +861,23 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("h_width", "ColorPicker", 30 * scale); theme->set_constant("label_width", "ColorPicker", 10 * scale); - theme->set_icon("screen_picker", "ColorPicker", make_icon(icon_color_pick_png)); - theme->set_icon("add_preset", "ColorPicker", make_icon(icon_add_png)); - 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("sample_bg", "ColorPicker", make_icon(mini_checkerboard_png)); - theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png)); - theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png)); - theme->set_icon("picker_cursor", "ColorPicker", make_icon(picker_cursor_png)); + theme->set_icon("screen_picker", "ColorPicker", icons["color_picker_pipette"]); + theme->set_icon("add_preset", "ColorPicker", icons["add"]); + theme->set_icon("color_hue", "ColorPicker", icons["color_picker_hue"]); + theme->set_icon("color_sample", "ColorPicker", icons["color_picker_sample"]); + theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]); + theme->set_icon("overbright_indicator", "ColorPicker", icons["color_picker_overbright"]); + theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]); + theme->set_icon("picker_cursor", "ColorPicker", icons["color_picker_cursor"]); // ColorPickerButton - theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png)); - theme->set_stylebox("normal", "ColorPickerButton", sb_button_normal); - theme->set_stylebox("pressed", "ColorPickerButton", sb_button_pressed); - theme->set_stylebox("hover", "ColorPickerButton", sb_button_hover); - theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled); - theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus); + theme->set_icon("bg", "ColorPickerButton", icons["mini_checkerboard"]); + theme->set_stylebox("normal", "ColorPickerButton", button_normal); + theme->set_stylebox("pressed", "ColorPickerButton", button_pressed); + theme->set_stylebox("hover", "ColorPickerButton", button_hover); + theme->set_stylebox("disabled", "ColorPickerButton", button_disabled); + theme->set_stylebox("focus", "ColorPickerButton", focus); theme->set_font("font", "ColorPickerButton", Ref<Font>()); theme->set_font_size("font_size", "ColorPickerButton", -1); @@ -892,24 +900,20 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const preset_sb->set_anti_aliased(false); theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb); - theme->set_icon("preset_bg", "ColorPresetButton", make_icon(mini_checkerboard_png)); - theme->set_icon("overbright_indicator", "ColorPresetButton", make_icon(overbright_indicator_png)); - - // TooltipPanel + theme->set_icon("preset_bg", "ColorPresetButton", icons["mini_checkerboard"]); + theme->set_icon("overbright_indicator", "ColorPresetButton", icons["color_picker_overbright"]); - Ref<StyleBoxTexture> style_tt = make_stylebox(tooltip_bg_png, 4, 4, 4, 4); - for (int i = 0; i < 4; i++) { - style_tt->set_expand_margin_size((Side)i, 4 * scale); - } + // TooltipPanel + TooltipLabel - theme->set_stylebox("panel", "TooltipPanel", style_tt); + theme->set_stylebox("panel", "TooltipPanel", + make_flat_stylebox(Color(0, 0, 0, 0.5), 2 * default_margin, 0.5 * default_margin, 2 * default_margin, 0.5 * default_margin)); theme->set_font("font", "TooltipLabel", Ref<Font>()); theme->set_font_size("font_size", "TooltipLabel", -1); - theme->set_color("font_color", "TooltipLabel", Color(0, 0, 0)); - theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0.1)); - theme->set_color("font_outline_color", "TooltipLabel", Color(1, 1, 1)); + theme->set_color("font_color", "TooltipLabel", control_font_color); + theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0)); + theme->set_color("font_outline_color", "TooltipLabel", Color(0, 0, 0, 0)); theme->set_constant("shadow_offset_x", "TooltipLabel", 1); theme->set_constant("shadow_offset_y", "TooltipLabel", 1); @@ -956,11 +960,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Containers - theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1)); - theme->set_stylebox("bg", "HSplitContainer", make_stylebox(hsplit_bg_png, 1, 1, 1, 1)); - - theme->set_icon("grabber", "VSplitContainer", make_icon(vsplitter_png)); - theme->set_icon("grabber", "HSplitContainer", make_icon(hsplitter_png)); + theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]); + theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]); theme->set_constant("separation", "HBoxContainer", 4 * scale); theme->set_constant("separation", "VBoxContainer", 4 * scale); @@ -974,17 +975,20 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("separation", "VSplitContainer", 12 * scale); theme->set_constant("autohide", "HSplitContainer", 1 * scale); theme->set_constant("autohide", "VSplitContainer", 1 * scale); - - Ref<StyleBoxTexture> sb_pc = make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 7, 7, 7, 7); - theme->set_stylebox("panel", "PanelContainer", sb_pc); - - theme->set_icon("minus", "GraphEdit", make_icon(icon_zoom_less_png)); - theme->set_icon("reset", "GraphEdit", make_icon(icon_zoom_reset_png)); - theme->set_icon("more", "GraphEdit", make_icon(icon_zoom_more_png)); - theme->set_icon("snap", "GraphEdit", make_icon(icon_snap_grid_png)); - theme->set_icon("minimap", "GraphEdit", make_icon(icon_grid_minimap_png)); - theme->set_icon("layout", "GraphEdit", make_icon(icon_grid_layout_png)); - theme->set_stylebox("bg", "GraphEdit", make_stylebox(tree_bg_png, 4, 4, 4, 5)); + theme->set_constant("hseparation", "HFlowContainer", 4 * scale); + theme->set_constant("vseparation", "HFlowContainer", 4 * scale); + theme->set_constant("hseparation", "VFlowContainer", 4 * scale); + theme->set_constant("vseparation", "VFlowContainer", 4 * scale); + + theme->set_stylebox("panel", "PanelContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + + theme->set_icon("minus", "GraphEdit", icons["zoom_less"]); + theme->set_icon("reset", "GraphEdit", icons["zoom_reset"]); + theme->set_icon("more", "GraphEdit", icons["zoom_more"]); + theme->set_icon("snap", "GraphEdit", icons["grid_snap"]); + theme->set_icon("minimap", "GraphEdit", icons["grid_minimap"]); + theme->set_icon("layout", "GraphEdit", icons["grid_layout"]); + theme->set_stylebox("bg", "GraphEdit", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); theme->set_color("grid_minor", "GraphEdit", Color(1, 1, 1, 0.05)); theme->set_color("grid_major", "GraphEdit", Color(1, 1, 1, 0.2)); theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3)); @@ -999,33 +1003,30 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale); theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); - Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0); + Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0); style_minimap_camera->set_border_color(Color(0.65, 0.65, 0.65, 0.45)); style_minimap_camera->set_border_width_all(1); theme->set_stylebox("camera", "GraphEditMinimap", style_minimap_camera); - Ref<StyleBoxFlat> style_minimap_node = make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0); - style_minimap_node->set_corner_radius_all(2); - theme->set_stylebox("node", "GraphEditMinimap", style_minimap_node); + theme->set_stylebox("node", "GraphEditMinimap", make_flat_stylebox(Color(1, 1, 1), 0, 0, 0, 0, 2)); - Ref<Texture2D> resizer_icon = make_icon(window_resizer_png); - theme->set_icon("resizer", "GraphEditMinimap", flip_icon(resizer_icon, true, true)); + theme->set_icon("resizer", "GraphEditMinimap", icons["resizer_nw"]); theme->set_color("resizer_color", "GraphEditMinimap", Color(1, 1, 1, 0.85)); // Theme - default_icon = make_icon(error_icon_png); - default_style = make_stylebox(error_icon_png, 2, 2, 2, 2); - - memdelete(tex_cache); + default_icon = icons["error_icon"]; + // Same color as the error icon. + default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2); } -void make_default_theme(bool p_hidpi, Ref<Font> p_font) { +void make_default_theme(float p_scale, Ref<Font> p_font) { Ref<Theme> t; t.instantiate(); Ref<StyleBox> default_style; Ref<Texture2D> default_icon; Ref<Font> default_font; + float default_scale = CLAMP(p_scale, 0.5, 8.0); if (p_font.is_valid()) { // Use the custom font defined in the Project Settings. @@ -1045,21 +1046,14 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { default_font = dynamic_font; } - Ref<Font> large_font = default_font; - - float default_scale = 1.0; - if (p_hidpi) { - default_scale = 2.0; - } - - fill_default_theme(t, default_font, large_font, default_icon, default_style, default_scale); + fill_default_theme(t, default_font, default_icon, default_style, default_scale); Theme::set_default(t); Theme::set_fallback_base_scale(default_scale); Theme::set_fallback_icon(default_icon); Theme::set_fallback_style(default_style); Theme::set_fallback_font(default_font); - Theme::set_fallback_font_size(default_font_size); + Theme::set_fallback_font_size(default_font_size * default_scale); } void clear_default_theme() { diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index e6d7b31b3e..3016517824 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -35,8 +35,8 @@ const int default_font_size = 16; -void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &large_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); -void make_default_theme(bool p_hidpi, Ref<Font> p_font); +void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); +void make_default_theme(float p_scale, Ref<Font> p_font); void clear_default_theme(); #endif diff --git a/scene/resources/default_theme/default_theme_icons_builders.py b/scene/resources/default_theme/default_theme_icons_builders.py new file mode 100644 index 0000000000..4dd5819a23 --- /dev/null +++ b/scene/resources/default_theme/default_theme_icons_builders.py @@ -0,0 +1,78 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" + +import os +from io import StringIO +from platform_methods import subprocess_main + + +# See also `editor/icons/editor_icons_builders.py`. +def make_default_theme_icons_action(target, source, env): + + dst = target[0] + svg_icons = source + + icons_string = StringIO() + + for f in svg_icons: + + fname = str(f) + + icons_string.write('\t"') + + with open(fname, "rb") as svgf: + b = svgf.read(1) + while len(b) == 1: + icons_string.write("\\" + str(hex(ord(b)))[1:]) + b = svgf.read(1) + + icons_string.write('"') + if fname != svg_icons[-1]: + icons_string.write(",") + icons_string.write("\n") + + s = StringIO() + s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n\n") + s.write('#include "modules/modules_enabled.gen.h"\n\n') + s.write("#ifndef _DEFAULT_THEME_ICONS_H\n") + s.write("#define _DEFAULT_THEME_ICONS_H\n") + s.write("static const int default_theme_icons_count = {};\n\n".format(len(svg_icons))) + s.write("#ifdef MODULE_SVG_ENABLED\n") + s.write("static const char *default_theme_icons_sources[] = {\n") + s.write(icons_string.getvalue()) + s.write("};\n") + s.write("#endif // MODULE_SVG_ENABLED\n\n") + s.write("static const char *default_theme_icons_names[] = {\n") + + index = 0 + for f in svg_icons: + + fname = str(f) + + # Trim the `.svg` extension from the string. + icon_name = os.path.basename(fname)[:-4] + + s.write('\t"{0}"'.format(icon_name)) + + if fname != svg_icons[-1]: + s.write(",") + s.write("\n") + + index += 1 + + s.write("};\n") + + s.write("#endif\n") + + with open(dst, "w") as f: + f.write(s.getvalue()) + + s.close() + icons_string.close() + + +if __name__ == "__main__": + subprocess_main(globals()) diff --git a/scene/resources/default_theme/dialog_bg.png b/scene/resources/default_theme/dialog_bg.png Binary files differdeleted file mode 100644 index a23a10b48a..0000000000 --- a/scene/resources/default_theme/dialog_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/dropdown.png b/scene/resources/default_theme/dropdown.png Binary files differdeleted file mode 100644 index b5d9ffbbb4..0000000000 --- a/scene/resources/default_theme/dropdown.png +++ /dev/null diff --git a/scene/resources/default_theme/ellipsis.png b/scene/resources/default_theme/ellipsis.png Binary files differdeleted file mode 100644 index c949e2c95b..0000000000 --- a/scene/resources/default_theme/ellipsis.png +++ /dev/null diff --git a/scene/resources/default_theme/error_icon.png b/scene/resources/default_theme/error_icon.png Binary files differdeleted file mode 100644 index 30336b91a4..0000000000 --- a/scene/resources/default_theme/error_icon.png +++ /dev/null diff --git a/scene/resources/default_theme/error_icon.svg b/scene/resources/default_theme/error_icon.svg new file mode 100644 index 0000000000..2f5099aa29 --- /dev/null +++ b/scene/resources/default_theme/error_icon.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1v8.5859l1.293-1.293a1.0001 1.0001 0 0 1 .69141-.29102 1.0001 1.0001 0 0 1 .72266.29102l2.293 2.293 2.293-2.293a1.0001 1.0001 0 0 1 1.4141 0l2.293 2.293 1-1v-3.5859h-5v-5h-7zm8 0v4h4zm-6 9.4141-2 2v2.5859h12v-2.5859l-.29297.29297a1.0001 1.0001 0 0 1 -1.4141 0l-2.293-2.293-2.293 2.293a1.0001 1.0001 0 0 1 -1.4141 0l-2.293-2.293z" fill="#ff5d5d" transform="translate(0 -.000017)"/></svg> diff --git a/scene/resources/default_theme/error_icon.xpm b/scene/resources/default_theme/error_icon.xpm deleted file mode 100644 index 666a60338d..0000000000 --- a/scene/resources/default_theme/error_icon.xpm +++ /dev/null @@ -1,38 +0,0 @@ -/* XPM */ -static const char * error_icon_xpm[] = { -"32 32 3 1", -" c None", -". c #FF00FF", -"+ c #000000", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"....++++.+++..+++...++..+++.....", -"....+....+..+.+..+.+..+.+..+....", -"....+....+..+.+..+.+..+.+..+....", -"....+++..+++..+++..+..+.+++.....", -"....+....+..+.+..+.+..+.+..+....", -"....+....+..+.+..+.+..+.+..+....", -"....++++.+..+.+..+..++..+..+....", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................", -"................................"}; diff --git a/scene/resources/default_theme/file.svg b/scene/resources/default_theme/file.svg new file mode 100644 index 0000000000..974644c5da --- /dev/null +++ b/scene/resources/default_theme/file.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1v14h12v-9h-5v-5zm8 0v4h4z" fill="#b2b2b2" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png Binary files differdeleted file mode 100644 index f51ea89e8f..0000000000 --- a/scene/resources/default_theme/focus.png +++ /dev/null diff --git a/scene/resources/default_theme/folder.svg b/scene/resources/default_theme/folder.svg new file mode 100644 index 0000000000..ca4c8c9c70 --- /dev/null +++ b/scene/resources/default_theme/folder.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2c-.549 0-1 .451-1 1v10c0 .549.451 1 1 1h12c.549 0 1-.451 1-1v-7c0-.549-.451-1-1-1h-4c-.549 0-1-.451-1-1v-1c0-.549-.451-1-1-1z" fill="#b2b2b2" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/folder_up.svg b/scene/resources/default_theme/folder_up.svg new file mode 100644 index 0000000000..aaf5693d38 --- /dev/null +++ b/scene/resources/default_theme/folder_up.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m3 8c.003.26.107.509.291.693.388.388 1.026.388 1.414 0l2.293-2.293v4.586c0 .553.448 1 1 1s1-.447 1-1v-4.586l2.293 2.293c.388.388 1.026.388 1.414 0 .388-.387.388-1.026 0-1.414l-4-4c-.388-.387-1.026-.387-1.414 0l-4 4c-.19.191-.295.451-.291.721z" fill="#b2b2b2" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png Binary files differdeleted file mode 100644 index d4b4dd3c1f..0000000000 --- a/scene/resources/default_theme/graph_node.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_breakpoint.png b/scene/resources/default_theme/graph_node_breakpoint.png Binary files differdeleted file mode 100644 index e18c6f42e1..0000000000 --- a/scene/resources/default_theme/graph_node_breakpoint.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png Binary files differdeleted file mode 100644 index 5c962ae1c6..0000000000 --- a/scene/resources/default_theme/graph_node_close.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_comment.png b/scene/resources/default_theme/graph_node_comment.png Binary files differdeleted file mode 100644 index cdec1d1eac..0000000000 --- a/scene/resources/default_theme/graph_node_comment.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_comment_focus.png b/scene/resources/default_theme/graph_node_comment_focus.png Binary files differdeleted file mode 100644 index 472a6b6f53..0000000000 --- a/scene/resources/default_theme/graph_node_comment_focus.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png Binary files differdeleted file mode 100644 index 359bbdc205..0000000000 --- a/scene/resources/default_theme/graph_node_default.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png Binary files differdeleted file mode 100644 index 204dd16ac0..0000000000 --- a/scene/resources/default_theme/graph_node_default_focus.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_position.png b/scene/resources/default_theme/graph_node_position.png Binary files differdeleted file mode 100644 index 24c2759be6..0000000000 --- a/scene/resources/default_theme/graph_node_position.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differdeleted file mode 100644 index c52d88586b..0000000000 --- a/scene/resources/default_theme/graph_node_selected.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differdeleted file mode 100644 index 358934f4d8..0000000000 --- a/scene/resources/default_theme/graph_port.png +++ /dev/null diff --git a/scene/resources/default_theme/graph_port.svg b/scene/resources/default_theme/graph_port.svg new file mode 100644 index 0000000000..423819ea68 --- /dev/null +++ b/scene/resources/default_theme/graph_port.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m10 5c0 2.743-2.257 5-5 5s-5-2.257-5-5 2.257-5 5-5 5 2.257 5 5" fill="#fff"/><path d="m8.667 5c0 2.011-1.656 3.667-3.667 3.667s-3.667-1.656-3.667-3.667 1.656-3.667 3.667-3.667 3.667 1.656 3.667 3.667" fill="#b2b2b2" fill-opacity=".65"/></g></svg> diff --git a/scene/resources/default_theme/grid_layout.svg b/scene/resources/default_theme/grid_layout.svg new file mode 100644 index 0000000000..d5cafca687 --- /dev/null +++ b/scene/resources/default_theme/grid_layout.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke-width="1.3"><g stroke="#fefffe"><path d="m1.87 6.541h2.917v2.917h-2.917z"/><path d="m6.536 6.541h2.917v2.917h-2.917z"/><path d="m11.202 6.541h2.917v2.917h-2.917z"/></g><g stroke="#e0e0e0" stroke-opacity=".65"><path d="m5.432 1.112-1.95 1.95 1.95 1.95" stroke-linejoin="miter" stroke-miterlimit="10"/><path d="m3.482 3.062h9.386"/><path d="m10.731 11.112 1.95 1.95-1.95 1.95" stroke-linejoin="miter" stroke-miterlimit="10"/><path d="m3.294 13.062h9.387"/></g></g></svg> diff --git a/scene/resources/default_theme/grid_minimap.svg b/scene/resources/default_theme/grid_minimap.svg new file mode 100644 index 0000000000..a7e5150bc3 --- /dev/null +++ b/scene/resources/default_theme/grid_minimap.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m14 2.199v2.615l-2.625 1.313v-2.615zm-12 4.065 2.625 1.312v2.551l-2.625-1.313zm12 0v2.55l-2.625 1.313v-2.551zm-8 1.455h4v2.64h-4zm-4 2.56 2.625 1.313v2.521l-2.625-1.312zm12 0v2.522l-2.625 1.312v-2.521zm-8 1.455h4v2.641h-4zm1.701-8.109h2.299v2.734h-4.156s-.749.647-.875.641c-.131-.007-1.51-1.456-1.51-1.456l-1.459-.73v-2.615l.068.034s.027-.457.063-.676c.034-.212.197-.592.197-.592l-1.049-.524c-.079-.04-.167-.062-.256-.066-.354-.013-.648.27-.648.625v12c0 .237.134.453.346.559l4 2c.086.043.182.066.279.066h6c.097 0 .193-.023.279-.066l4-2c.212-.106.346-.322.346-.559v-12c0-.464-.489-.766-.904-.559l-3.869 1.934h-2.971s.033.417.016.625c-.03.346-.196.625-.196.625z" fill="#b2b2b2" fill-opacity=".65"/><path d="m5 6s-2.219-2.162-2.219-3.243c0-1.08 0-2.607 2.219-2.607s2.219 1.527 2.219 2.607c0 1.081-2.219 3.243-2.219 3.243z" fill="#fefffe"/></g></svg> diff --git a/scene/resources/default_theme/grid_snap.svg b/scene/resources/default_theme/grid_snap.svg new file mode 100644 index 0000000000..633c85fe79 --- /dev/null +++ b/scene/resources/default_theme/grid_snap.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m3 0v3h-3v2h3v4h-3v2h3v3h2v-9h9v-2h-3v-3h-2v3h-4v-3zm4 13v2h2v-2zm6 0v2h2v-2z" fill="#b2b2b2" fill-opacity=".65"/><path d="m11 7c-2.194 0-4 1.806-4 4v2h2v-2c0-1.097.903-2 2-2s2 .903 2 2v2h2v-2c0-2.194-1.806-4-4-4z" fill="#fefffe"/></g></svg> diff --git a/scene/resources/default_theme/hseparator.png b/scene/resources/default_theme/hseparator.png Binary files differdeleted file mode 100644 index d4fd71ace5..0000000000 --- a/scene/resources/default_theme/hseparator.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png Binary files differdeleted file mode 100644 index b402bd370d..0000000000 --- a/scene/resources/default_theme/hslider_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_grabber.png b/scene/resources/default_theme/hslider_grabber.png Binary files differdeleted file mode 100644 index d273b491ee..0000000000 --- a/scene/resources/default_theme/hslider_grabber.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_grabber_disabled.png b/scene/resources/default_theme/hslider_grabber_disabled.png Binary files differdeleted file mode 100644 index dddd1a468e..0000000000 --- a/scene/resources/default_theme/hslider_grabber_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_grabber_hl.png b/scene/resources/default_theme/hslider_grabber_hl.png Binary files differdeleted file mode 100644 index e3defb3610..0000000000 --- a/scene/resources/default_theme/hslider_grabber_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_tick.png b/scene/resources/default_theme/hslider_tick.png Binary files differdeleted file mode 100644 index 1ba19c37a1..0000000000 --- a/scene/resources/default_theme/hslider_tick.png +++ /dev/null diff --git a/scene/resources/default_theme/hslider_tick.svg b/scene/resources/default_theme/hslider_tick.svg new file mode 100644 index 0000000000..a97d05b9e8 --- /dev/null +++ b/scene/resources/default_theme/hslider_tick.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 4 15.999999" width="4" xmlns="http://www.w3.org/2000/svg"><path d="m1 0h2v16h-2z" fill="#fff" fill-opacity=".25" stroke-width=".285079"/></svg> diff --git a/scene/resources/default_theme/hsplit_bg.png b/scene/resources/default_theme/hsplit_bg.png Binary files differdeleted file mode 100644 index a5749f6d5c..0000000000 --- a/scene/resources/default_theme/hsplit_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/hsplitter.png b/scene/resources/default_theme/hsplitter.png Binary files differdeleted file mode 100644 index 2287753c9d..0000000000 --- a/scene/resources/default_theme/hsplitter.png +++ /dev/null diff --git a/scene/resources/default_theme/hsplitter.svg b/scene/resources/default_theme/hsplitter.svg new file mode 100644 index 0000000000..effc6996cc --- /dev/null +++ b/scene/resources/default_theme/hsplitter.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" viewBox="0 0 8 48" xmlns="http://www.w3.org/2000/svg"><path d="m4 4.012v39.976" fill="none" stroke="#808080" stroke-opacity=".65" stroke-width="1.7"/></svg> diff --git a/scene/resources/default_theme/icon_add.png b/scene/resources/default_theme/icon_add.png Binary files differdeleted file mode 100644 index eccb69b363..0000000000 --- a/scene/resources/default_theme/icon_add.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_close.png b/scene/resources/default_theme/icon_close.png Binary files differdeleted file mode 100644 index 4d4ac4a551..0000000000 --- a/scene/resources/default_theme/icon_close.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_color_pick.png b/scene/resources/default_theme/icon_color_pick.png Binary files differdeleted file mode 100644 index 46953febb8..0000000000 --- a/scene/resources/default_theme/icon_color_pick.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_file.png b/scene/resources/default_theme/icon_file.png Binary files differdeleted file mode 100644 index bb4c361a8d..0000000000 --- a/scene/resources/default_theme/icon_file.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_folder.png b/scene/resources/default_theme/icon_folder.png Binary files differdeleted file mode 100644 index d1b308e88d..0000000000 --- a/scene/resources/default_theme/icon_folder.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_grid_layout.png b/scene/resources/default_theme/icon_grid_layout.png Binary files differdeleted file mode 100644 index a249252a79..0000000000 --- a/scene/resources/default_theme/icon_grid_layout.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_grid_minimap.png b/scene/resources/default_theme/icon_grid_minimap.png Binary files differdeleted file mode 100644 index 00a6179d5e..0000000000 --- a/scene/resources/default_theme/icon_grid_minimap.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_parent_folder.png b/scene/resources/default_theme/icon_parent_folder.png Binary files differdeleted file mode 100644 index 35d218722e..0000000000 --- a/scene/resources/default_theme/icon_parent_folder.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_reload.png b/scene/resources/default_theme/icon_reload.png Binary files differdeleted file mode 100644 index bec5f3f4f9..0000000000 --- a/scene/resources/default_theme/icon_reload.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_snap_grid.png b/scene/resources/default_theme/icon_snap_grid.png Binary files differdeleted file mode 100644 index 0680317d86..0000000000 --- a/scene/resources/default_theme/icon_snap_grid.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_visibility.png b/scene/resources/default_theme/icon_visibility.png Binary files differdeleted file mode 100644 index b2df8cbdb8..0000000000 --- a/scene/resources/default_theme/icon_visibility.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_zoom_less.png b/scene/resources/default_theme/icon_zoom_less.png Binary files differdeleted file mode 100644 index 03119c60ca..0000000000 --- a/scene/resources/default_theme/icon_zoom_less.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_zoom_more.png b/scene/resources/default_theme/icon_zoom_more.png Binary files differdeleted file mode 100644 index 31467ec3de..0000000000 --- a/scene/resources/default_theme/icon_zoom_more.png +++ /dev/null diff --git a/scene/resources/default_theme/icon_zoom_reset.png b/scene/resources/default_theme/icon_zoom_reset.png Binary files differdeleted file mode 100644 index cac68c09fa..0000000000 --- a/scene/resources/default_theme/icon_zoom_reset.png +++ /dev/null diff --git a/scene/resources/default_theme/indeterminate.png b/scene/resources/default_theme/indeterminate.png Binary files differdeleted file mode 100644 index 28a457b251..0000000000 --- a/scene/resources/default_theme/indeterminate.png +++ /dev/null diff --git a/scene/resources/default_theme/indeterminate.svg b/scene/resources/default_theme/indeterminate.svg new file mode 100644 index 0000000000..2a742e1475 --- /dev/null +++ b/scene/resources/default_theme/indeterminate.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#fff" fill-opacity=".75" stroke-width="1.16667"/><path d="m3 7h10v2h-10z" fill="#1a1a1a" stroke-linecap="square" stroke-opacity=".75" stroke-width="2"/></svg> diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png Binary files differdeleted file mode 100644 index 2b0c506f34..0000000000 --- a/scene/resources/default_theme/line_edit.png +++ /dev/null diff --git a/scene/resources/default_theme/line_edit_clear.png b/scene/resources/default_theme/line_edit_clear.png Binary files differdeleted file mode 100644 index af2775a132..0000000000 --- a/scene/resources/default_theme/line_edit_clear.png +++ /dev/null diff --git a/scene/resources/default_theme/line_edit_clear.svg b/scene/resources/default_theme/line_edit_clear.svg new file mode 100644 index 0000000000..3709c43410 --- /dev/null +++ b/scene/resources/default_theme/line_edit_clear.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m1 3 2-2 5 5 5-5 2 2-5 5 5 5-2 2-5.302-5-4.698 5-2-2 5-5z" fill="#fff" fill-opacity=".75" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/line_edit_disabled.png b/scene/resources/default_theme/line_edit_disabled.png Binary files differdeleted file mode 100644 index 69d78febd9..0000000000 --- a/scene/resources/default_theme/line_edit_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py deleted file mode 100755 index efad3b2815..0000000000 --- a/scene/resources/default_theme/make_header.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -import glob -import os - -enc = "utf-8" - -# Change to the directory where the script is located, -# so that the script can be run from any location -os.chdir(os.path.dirname(os.path.realpath(__file__))) - -# Generate include files - -f = open("theme_data.h", "wb") - -f.write(b"// THIS FILE HAS BEEN AUTOGENERATED, DON'T EDIT!!\n") - -# Generate png image block -f.write(b"\n// png image block\n") - -pixmaps = glob.glob("*.png") -pixmaps.sort() - -for x in pixmaps: - - var_str = x[:-4] + "_png" - - s = "\nstatic const unsigned char " + var_str + "[] = {\n\t" - f.write(s.encode(enc)) - - pngf = open(x, "rb") - - b = pngf.read(1) - while len(b) == 1: - f.write(hex(ord(b)).encode(enc)) - b = pngf.read(1) - if len(b) == 1: - f.write(b", ") - - f.write(b"\n};\n") - pngf.close() - -# Generate shaders block -f.write(b"\n// shaders block\n") - -shaders = glob.glob("*.gsl") -shaders.sort() - -for x in shaders: - - var_str = x[:-4] + "_shader_code" - - s = "\nstatic const char *" + var_str + " = \n" - f.write(s.encode(enc)) - - sf = open(x, "rb") - - b = sf.readline() - while b != "": - if b.endswith("\r\n"): - b = b[:-2] - if b.endswith("\n"): - b = b[:-1] - s = ' "' + b - f.write(s.encode(enc)) - b = sf.readline() - if b != "": - f.write(b'"\n') - - f.write(b'";\n') - sf.close() - -f.close() diff --git a/scene/resources/default_theme/mini_checkerboard.png b/scene/resources/default_theme/mini_checkerboard.png Binary files differdeleted file mode 100644 index d8279bda80..0000000000 --- a/scene/resources/default_theme/mini_checkerboard.png +++ /dev/null diff --git a/scene/resources/default_theme/mini_checkerboard.svg b/scene/resources/default_theme/mini_checkerboard.svg new file mode 100644 index 0000000000..0ae6a855bd --- /dev/null +++ b/scene/resources/default_theme/mini_checkerboard.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="1.9994"><path d="m0 0v8h8v-8zm8 8v8h8v-8z" fill="#e0e0e0"/><path d="m8 0v8h8v-8zm0 8h-8v8h8z" fill="#fff"/></g></svg> diff --git a/scene/resources/default_theme/option_arrow.png b/scene/resources/default_theme/option_arrow.png Binary files differdeleted file mode 100644 index 40590fd60a..0000000000 --- a/scene/resources/default_theme/option_arrow.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_arrow.svg b/scene/resources/default_theme/option_button_arrow.svg new file mode 100644 index 0000000000..1a33668708 --- /dev/null +++ b/scene/resources/default_theme/option_button_arrow.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="m10 3c-.264.01-.514.117-.697.307l-3.293 3.293-3.293-3.293c-.189-.194-.447-.303-.717-.303-.897 0-1.34 1.091-.697 1.717l4 4c.39.39 1.023.39 1.414 0l4-4c.657-.632.195-1.742-.717-1.721z" fill="#b2b2b2" fill-opacity=".85" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png Binary files differdeleted file mode 100644 index 1961b673cd..0000000000 --- a/scene/resources/default_theme/option_button_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_disabled_mirrored.png b/scene/resources/default_theme/option_button_disabled_mirrored.png Binary files differdeleted file mode 100644 index 9d149a35ca..0000000000 --- a/scene/resources/default_theme/option_button_disabled_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_hover.png b/scene/resources/default_theme/option_button_hover.png Binary files differdeleted file mode 100644 index 826fe1c9ca..0000000000 --- a/scene/resources/default_theme/option_button_hover.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_hover_mirrored.png b/scene/resources/default_theme/option_button_hover_mirrored.png Binary files differdeleted file mode 100644 index d49c165645..0000000000 --- a/scene/resources/default_theme/option_button_hover_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png Binary files differdeleted file mode 100644 index 43fc29e958..0000000000 --- a/scene/resources/default_theme/option_button_normal.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_normal_mirrored.png b/scene/resources/default_theme/option_button_normal_mirrored.png Binary files differdeleted file mode 100644 index feec848f33..0000000000 --- a/scene/resources/default_theme/option_button_normal_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_pressed.png b/scene/resources/default_theme/option_button_pressed.png Binary files differdeleted file mode 100644 index 68796f9d85..0000000000 --- a/scene/resources/default_theme/option_button_pressed.png +++ /dev/null diff --git a/scene/resources/default_theme/option_button_pressed_mirrored.png b/scene/resources/default_theme/option_button_pressed_mirrored.png Binary files differdeleted file mode 100644 index 94cabb18d6..0000000000 --- a/scene/resources/default_theme/option_button_pressed_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/overbright_indicator.png b/scene/resources/default_theme/overbright_indicator.png Binary files differdeleted file mode 100644 index e13f15dd02..0000000000 --- a/scene/resources/default_theme/overbright_indicator.png +++ /dev/null diff --git a/scene/resources/default_theme/panel_bg.png b/scene/resources/default_theme/panel_bg.png Binary files differdeleted file mode 100644 index b496e2177e..0000000000 --- a/scene/resources/default_theme/panel_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/picker_cursor.png b/scene/resources/default_theme/picker_cursor.png Binary files differdeleted file mode 100644 index 2f403492d2..0000000000 --- a/scene/resources/default_theme/picker_cursor.png +++ /dev/null diff --git a/scene/resources/default_theme/popup_bg.png b/scene/resources/default_theme/popup_bg.png Binary files differdeleted file mode 100644 index 023029f936..0000000000 --- a/scene/resources/default_theme/popup_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/popup_bg_disabled.png b/scene/resources/default_theme/popup_bg_disabled.png Binary files differdeleted file mode 100644 index 8eab5f27bc..0000000000 --- a/scene/resources/default_theme/popup_bg_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png Binary files differdeleted file mode 100644 index 442084049d..0000000000 --- a/scene/resources/default_theme/popup_window.png +++ /dev/null diff --git a/scene/resources/default_theme/progress_bar.png b/scene/resources/default_theme/progress_bar.png Binary files differdeleted file mode 100644 index 057557e567..0000000000 --- a/scene/resources/default_theme/progress_bar.png +++ /dev/null diff --git a/scene/resources/default_theme/progress_fill.png b/scene/resources/default_theme/progress_fill.png Binary files differdeleted file mode 100644 index e39bb2a021..0000000000 --- a/scene/resources/default_theme/progress_fill.png +++ /dev/null diff --git a/scene/resources/default_theme/radio_checked.png b/scene/resources/default_theme/radio_checked.png Binary files differdeleted file mode 100644 index 0ce575c15f..0000000000 --- a/scene/resources/default_theme/radio_checked.png +++ /dev/null diff --git a/scene/resources/default_theme/radio_checked.svg b/scene/resources/default_theme/radio_checked.svg new file mode 100644 index 0000000000..73d1c8e34a --- /dev/null +++ b/scene/resources/default_theme/radio_checked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#fff" fill-opacity=".75" stroke-width="2.33333"/><path d="m12 8a4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4" fill="#1a1a1a" stroke-width="1.33333"/></svg> diff --git a/scene/resources/default_theme/radio_checked_disabled.png b/scene/resources/default_theme/radio_checked_disabled.png Binary files differdeleted file mode 100644 index 72f08ecb96..0000000000 --- a/scene/resources/default_theme/radio_checked_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/radio_checked_disabled.svg b/scene/resources/default_theme/radio_checked_disabled.svg new file mode 100644 index 0000000000..ef5eff8d97 --- /dev/null +++ b/scene/resources/default_theme/radio_checked_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#fff" fill-opacity=".37" stroke-width="2.33333"/><path d="m12 8a4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 4-4 4 4 0 0 1 4 4" fill="#1a1a1a" fill-opacity=".5" stroke-width="1.33333"/></svg> diff --git a/scene/resources/default_theme/radio_unchecked.png b/scene/resources/default_theme/radio_unchecked.png Binary files differdeleted file mode 100644 index fe5bcf6ab1..0000000000 --- a/scene/resources/default_theme/radio_unchecked.png +++ /dev/null diff --git a/scene/resources/default_theme/radio_unchecked.svg b/scene/resources/default_theme/radio_unchecked.svg new file mode 100644 index 0000000000..5429855db5 --- /dev/null +++ b/scene/resources/default_theme/radio_unchecked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#1a1a1a" fill-opacity=".5" stroke-width="2.33333"/></svg> diff --git a/scene/resources/default_theme/radio_unchecked_disabled.png b/scene/resources/default_theme/radio_unchecked_disabled.png Binary files differdeleted file mode 100644 index a8f4c1b555..0000000000 --- a/scene/resources/default_theme/radio_unchecked_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/radio_unchecked_disabled.svg b/scene/resources/default_theme/radio_unchecked_disabled.svg new file mode 100644 index 0000000000..1e827d9374 --- /dev/null +++ b/scene/resources/default_theme/radio_unchecked_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#1a1a1a" fill-opacity=".25" stroke-width="2.33333"/></svg> diff --git a/scene/resources/default_theme/reload.svg b/scene/resources/default_theme/reload.svg new file mode 100644 index 0000000000..66809f8374 --- /dev/null +++ b/scene/resources/default_theme/reload.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#b2b2b2" fill-rule="nonzero"><path d="m8.987 2c-3.292 0-6 2.708-6 6h2c0-2.194 1.806-4 4-4s4 1.806 4 4-1.806 4-4 4v2c3.291 0 6-2.708 6-6s-2.709-6-6-6z"/><path d="m7.013 7.989-1.5 2-1.5 2-1.5-2-1.5-2z"/></g></svg> diff --git a/scene/resources/default_theme/resizer_nw.svg b/scene/resources/default_theme/resizer_nw.svg new file mode 100644 index 0000000000..92e25c3be2 --- /dev/null +++ b/scene/resources/default_theme/resizer_nw.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".65"><path d="m4 12c.552 0 1-.448 1-1v-6h6c.552 0 1-.448 1-1s-.448-1-1-1h-7c-.552 0-1 .448-1 1v7c0 .552.448 1 1 1z" fill="#fefffe" fill-rule="nonzero"/><circle cx="7.5" cy="7.5" fill="#b2b2b2" r="1.479"/></g></svg> diff --git a/scene/resources/default_theme/resizer_se.svg b/scene/resources/default_theme/resizer_se.svg new file mode 100644 index 0000000000..2d492e976e --- /dev/null +++ b/scene/resources/default_theme/resizer_se.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".65"><path d="m11 3c-.552 0-1 .448-1 1v6h-6c-.552 0-1 .448-1 1s.448 1 1 1h7c.552 0 1-.448 1-1v-7c0-.552-.448-1-1-1z" fill="#fefffe" fill-rule="nonzero"/><circle cx="7.5" cy="7.5" fill="#b2b2b2" r="1.479"/></g></svg> diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png Binary files differdeleted file mode 100644 index fb151a48b1..0000000000 --- a/scene/resources/default_theme/scroll_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_button_left.png b/scene/resources/default_theme/scroll_button_left.png Binary files differdeleted file mode 100644 index e430cb4673..0000000000 --- a/scene/resources/default_theme/scroll_button_left.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_button_left.svg b/scene/resources/default_theme/scroll_button_left.svg new file mode 100644 index 0000000000..947b417a00 --- /dev/null +++ b/scene/resources/default_theme/scroll_button_left.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fefffe" fill-opacity=".75" r="6"/><path d="m9.014 4c-.27-.004-.53.102-.721.293l-3 3c-.388.388-.388 1.026 0 1.414l3 3c.388.388 1.026.388 1.414 0s.388-1.026 0-1.414l-2.293-2.293 2.293-2.293c.388-.388.388-1.026 0-1.414-.184-.184-.433-.289-.693-.293z" fill="#1a1a1a" fill-opacity=".65"/></svg> diff --git a/scene/resources/default_theme/scroll_button_left_hl.png b/scene/resources/default_theme/scroll_button_left_hl.png Binary files differdeleted file mode 100644 index 2a6ef17a34..0000000000 --- a/scene/resources/default_theme/scroll_button_left_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_button_left_hl.svg b/scene/resources/default_theme/scroll_button_left_hl.svg new file mode 100644 index 0000000000..fa092c861a --- /dev/null +++ b/scene/resources/default_theme/scroll_button_left_hl.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fefffe" r="6"/><path d="m9.014 4c-.27-.004-.53.102-.721.293l-3 3c-.388.388-.388 1.026 0 1.414l3 3c.388.388 1.026.388 1.414 0s.388-1.026 0-1.414l-2.293-2.293 2.293-2.293c.388-.388.388-1.026 0-1.414-.184-.184-.433-.289-.693-.293z" fill="#1a1a1a"/></svg> diff --git a/scene/resources/default_theme/scroll_button_right.png b/scene/resources/default_theme/scroll_button_right.png Binary files differdeleted file mode 100644 index 4f61687aa4..0000000000 --- a/scene/resources/default_theme/scroll_button_right.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_button_right.svg b/scene/resources/default_theme/scroll_button_right.svg new file mode 100644 index 0000000000..84619e7aa9 --- /dev/null +++ b/scene/resources/default_theme/scroll_button_right.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fefffe" fill-opacity=".75" r="6"/><path d="m6.986 4c.27-.004.53.102.721.293l3 3c.388.388.388 1.026 0 1.414l-3 3c-.388.388-1.026.388-1.414 0s-.388-1.026 0-1.414l2.293-2.293-2.293-2.293c-.388-.388-.388-1.026 0-1.414.184-.184.433-.289.693-.293z" fill="#1a1a1a" fill-opacity=".65"/></svg> diff --git a/scene/resources/default_theme/scroll_button_right_hl.png b/scene/resources/default_theme/scroll_button_right_hl.png Binary files differdeleted file mode 100644 index 10e2722509..0000000000 --- a/scene/resources/default_theme/scroll_button_right_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_button_right_hl.svg b/scene/resources/default_theme/scroll_button_right_hl.svg new file mode 100644 index 0000000000..601f98c0d5 --- /dev/null +++ b/scene/resources/default_theme/scroll_button_right_hl.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#fefffe" r="6"/><path d="m6.986 4c.27-.004.53.102.721.293l3 3c.388.388.388 1.026 0 1.414l-3 3c-.388.388-1.026.388-1.414 0s-.388-1.026 0-1.414l2.293-2.293-2.293-2.293c-.388-.388-.388-1.026 0-1.414.184-.184.433-.289.693-.293z" fill="#1a1a1a"/></svg> diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png Binary files differdeleted file mode 100644 index 732725a28f..0000000000 --- a/scene/resources/default_theme/scroll_grabber.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png Binary files differdeleted file mode 100644 index 21ee486e0b..0000000000 --- a/scene/resources/default_theme/scroll_grabber_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/scroll_grabber_pressed.png b/scene/resources/default_theme/scroll_grabber_pressed.png Binary files differdeleted file mode 100644 index f4886158fa..0000000000 --- a/scene/resources/default_theme/scroll_grabber_pressed.png +++ /dev/null diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png Binary files differdeleted file mode 100644 index 7d1c985b35..0000000000 --- a/scene/resources/default_theme/selection.png +++ /dev/null diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png Binary files differdeleted file mode 100644 index 2da0538389..0000000000 --- a/scene/resources/default_theme/selection_oof.png +++ /dev/null diff --git a/scene/resources/default_theme/slider_grabber.svg b/scene/resources/default_theme/slider_grabber.svg new file mode 100644 index 0000000000..0813830134 --- /dev/null +++ b/scene/resources/default_theme/slider_grabber.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#fefefe" fill-opacity=".75" stroke-width="2.33333"/></svg> diff --git a/scene/resources/default_theme/slider_grabber_disabled.svg b/scene/resources/default_theme/slider_grabber_disabled.svg new file mode 100644 index 0000000000..659c2e9e14 --- /dev/null +++ b/scene/resources/default_theme/slider_grabber_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#fefefe" fill-opacity=".37" stroke-width="2.33333"/></svg> diff --git a/scene/resources/default_theme/slider_grabber_hl.svg b/scene/resources/default_theme/slider_grabber_hl.svg new file mode 100644 index 0000000000..d7d0594d67 --- /dev/null +++ b/scene/resources/default_theme/slider_grabber_hl.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8a7 7 0 0 1 -7 7 7 7 0 0 1 -7-7 7 7 0 0 1 7-7 7 7 0 0 1 7 7" fill="#fefefe" fill-opacity=".997951" stroke-width="2.33333"/></svg> diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png Binary files differdeleted file mode 100644 index 3c66316074..0000000000 --- a/scene/resources/default_theme/space.png +++ /dev/null diff --git a/scene/resources/default_theme/spinbox_updown.png b/scene/resources/default_theme/spinbox_updown.png Binary files differdeleted file mode 100644 index 74fab19f34..0000000000 --- a/scene/resources/default_theme/spinbox_updown.png +++ /dev/null diff --git a/scene/resources/default_theme/submenu.png b/scene/resources/default_theme/submenu.png Binary files differdeleted file mode 100644 index 8f7de446d4..0000000000 --- a/scene/resources/default_theme/submenu.png +++ /dev/null diff --git a/scene/resources/default_theme/submenu_mirrored.png b/scene/resources/default_theme/submenu_mirrored.png Binary files differdeleted file mode 100644 index 1142b9ba9f..0000000000 --- a/scene/resources/default_theme/submenu_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/tab.png b/scene/resources/default_theme/tab.png Binary files differdeleted file mode 100644 index 895daa65e2..0000000000 --- a/scene/resources/default_theme/tab.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png Binary files differdeleted file mode 100644 index 2803d9db65..0000000000 --- a/scene/resources/default_theme/tab_behind.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_close.png b/scene/resources/default_theme/tab_close.png Binary files differdeleted file mode 100644 index af2775a132..0000000000 --- a/scene/resources/default_theme/tab_close.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png Binary files differdeleted file mode 100644 index c189b61b89..0000000000 --- a/scene/resources/default_theme/tab_container_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png Binary files differdeleted file mode 100644 index ce2b9b0925..0000000000 --- a/scene/resources/default_theme/tab_current.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_disabled.png b/scene/resources/default_theme/tab_disabled.png Binary files differdeleted file mode 100644 index a7c04effa3..0000000000 --- a/scene/resources/default_theme/tab_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_menu.png b/scene/resources/default_theme/tab_menu.png Binary files differdeleted file mode 100644 index fa4421a28a..0000000000 --- a/scene/resources/default_theme/tab_menu.png +++ /dev/null diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png Binary files differdeleted file mode 100644 index fa4421a28a..0000000000 --- a/scene/resources/default_theme/tab_menu_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/tabs_menu.svg b/scene/resources/default_theme/tabs_menu.svg new file mode 100644 index 0000000000..4670a5deae --- /dev/null +++ b/scene/resources/default_theme/tabs_menu.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 0c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2zm0 6c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2zm0 6c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2z" fill="#b2b2b2" fill-opacity=".45" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/tabs_menu_hl.svg b/scene/resources/default_theme/tabs_menu_hl.svg new file mode 100644 index 0000000000..4ea54a2fda --- /dev/null +++ b/scene/resources/default_theme/tabs_menu_hl.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 0c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2zm0 6c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2zm0 6c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2z" fill="#fefffe" fill-opacity=".65" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/text_edit_ellipsis.svg b/scene/resources/default_theme/text_edit_ellipsis.svg new file mode 100644 index 0000000000..026a1fcba7 --- /dev/null +++ b/scene/resources/default_theme/text_edit_ellipsis.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 14 8" xmlns="http://www.w3.org/2000/svg"><path d="m3.859 0c-2.138 0-3.859 1.721-3.859 3.859v.282c0 2.138 1.721 3.859 3.859 3.859h6.282c2.138 0 3.859-1.721 3.859-3.859v-.282c0-2.138-1.721-3.859-3.859-3.859zm-.859 3c.549 0 1 .451 1 1s-.451 1-1 1-1-.451-1-1 .451-1 1-1zm4 0c.549 0 1 .451 1 1s-.451 1-1 1-1-.451-1-1 .451-1 1-1zm4 0c.549 0 1 .451 1 1s-.451 1-1 1-1-.451-1-1 .451-1 1-1z" fill="#fefffe" fill-opacity=".25" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/text_edit_space.svg b/scene/resources/default_theme/text_edit_space.svg new file mode 100644 index 0000000000..b2b1dd4676 --- /dev/null +++ b/scene/resources/default_theme/text_edit_space.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="4" fill="#b2b2b2" fill-opacity=".25" r="1.5"/></svg> diff --git a/scene/resources/default_theme/text_edit_tab.svg b/scene/resources/default_theme/text_edit_tab.svg new file mode 100644 index 0000000000..1968afb1e7 --- /dev/null +++ b/scene/resources/default_theme/text_edit_tab.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"><path d="m6 0v8h2v-8zm-5.014.002c-.26.003-.509.108-.693.291-.388.388-.388 1.026 0 1.414l2.293 2.293-2.293 2.293c-.388.388-.388 1.026 0 1.414s1.026.388 1.414 0l3-3c.388-.388.388-1.026 0-1.414l-3-3c-.191-.19-.451-.295-.721-.291z" fill="#b2b2b2" fill-opacity=".25" fill-rule="nonzero"/></svg> diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h deleted file mode 100644 index 1cec50eab4..0000000000 --- a/scene/resources/default_theme/theme_data.h +++ /dev/null @@ -1,517 +0,0 @@ -// THIS FILE HAS BEEN AUTOGENERATED, DON'T EDIT!! - -// png image block - -static const unsigned char arrow_down_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x34, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x32, 0x78, 0xf0, 0x1f, 0x15, 0x52, 0x20, 0xf1, 0x30, 0xee, 0xc1, 0x17, 0xb8, 0xf0, 0xb7, 0x87, 0x69, 0x48, 0xb6, 0xdc, 0xd7, 0xb8, 0x7f, 0x9, 0x2c, 0x7c, 0xfd, 0xb1, 0x2e, 0x9a, 0x3, 0x5e, 0x70, 0x3f, 0x9c, 0xff, 0x70, 0xfe, 0xb, 0x6e, 0x6, 0xea, 0x3, 0x0, 0xfb, 0x81, 0x48, 0xb8, 0x4d, 0xe4, 0x75, 0xd9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char arrow_left_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0xa0, 0x0, 0xdc, 0x4f, 0x78, 0xf0, 0xff, 0xc1, 0xff, 0x7, 0xff, 0x21, 0x3c, 0x46, 0x98, 0xf0, 0x43, 0xed, 0xff, 0x27, 0x19, 0xb8, 0x19, 0x18, 0x18, 0x18, 0x14, 0x18, 0x19, 0x18, 0x18, 0x18, 0x98, 0x20, 0xc2, 0x2f, 0xb8, 0xff, 0xaf, 0x82, 0x8, 0xc3, 0x0, 0x54, 0xe2, 0xe7, 0x14, 0x6, 0x2d, 0x54, 0x83, 0x99, 0x70, 0xd9, 0x8, 0x95, 0x60, 0xcf, 0x61, 0xb8, 0x86, 0x55, 0x42, 0xe2, 0x2b, 0x63, 0x18, 0xc3, 0x57, 0xac, 0x46, 0xc9, 0x5f, 0xfd, 0x9f, 0x43, 0x89, 0x67, 0x19, 0x18, 0x0, 0xf4, 0x30, 0x14, 0x49, 0xef, 0xe6, 0x74, 0x60, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char arrow_right_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char bar_arrow_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x14, 0x8, 0x4, 0x0, 0x0, 0x0, 0x2e, 0x6b, 0x75, 0xfc, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0xe, 0xc0, 0x1, 0x6a, 0xd6, 0x89, 0x9, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0xfc, 0xcf, 0x80, 0x1f, 0x30, 0x8e, 0x20, 0x5, 0x8c, 0x38, 0x24, 0xff, 0x53, 0x5f, 0xc1, 0xb, 0xee, 0x9f, 0x53, 0x18, 0x18, 0xd8, 0x73, 0x24, 0xbe, 0x62, 0x55, 0x70, 0x5f, 0x83, 0x61, 0x15, 0xa3, 0x2e, 0x3, 0x3, 0xc3, 0xd, 0xe6, 0x30, 0xd9, 0xcb, 0x18, 0xa, 0x1e, 0xc6, 0xfd, 0x9f, 0xc6, 0xc0, 0xd, 0x35, 0xea, 0x3b, 0x63, 0x81, 0xfc, 0x2c, 0x14, 0x5, 0xf, 0x2a, 0x18, 0xda, 0xd1, 0x1c, 0x50, 0xa9, 0xd0, 0x1, 0x57, 0xf0, 0x10, 0x53, 0x9a, 0x81, 0x81, 0x81, 0xa1, 0x52, 0xbe, 0x83, 0x81, 0x81, 0xf1, 0x3f, 0x2e, 0x69, 0xa8, 0x12, 0x3a, 0x4, 0x14, 0x0, 0x7b, 0xda, 0x34, 0x1, 0xbb, 0xb5, 0x3e, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char bookmark_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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x93, 0x31, 0xa, 0xc0, 0x30, 0xc, 0x3, 0xa5, 0xd0, 0xff, 0x7f, 0x59, 0x1d, 0x8a, 0x42, 0x8, 0x9, 0x95, 0xc9, 0xd2, 0xa1, 0x9a, 0x8c, 0xf1, 0xdd, 0x62, 0x1b, 0x38, 0xc, 0x87, 0x5a, 0x5, 0xae, 0x79, 0xde, 0x2, 0x1, 0x80, 0x94, 0x39, 0x48, 0x76, 0x49, 0x17, 0xa4, 0xf0, 0x24, 0x61, 0x2b, 0x51, 0x8b, 0xfc, 0x82, 0xcf, 0xb, 0x48, 0x7a, 0xdf, 0x75, 0x81, 0xf, 0xe5, 0x29, 0xf7, 0x92, 0x6b, 0x3, 0x1a, 0x1e, 0xda, 0x7c, 0x3d, 0x77, 0x21, 0x7b, 0xa8, 0x74, 0x2e, 0xcb, 0xd, 0xc8, 0x75, 0x13, 0x28, 0x9, 0xed, 0xc2, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char button_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, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char button_focus_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, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x62, 0xed, 0x5e, 0xfc, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0x84, 0x4c, 0x42, 0x43, 0x9d, 0x15, 0x81, 0x8c, 0xf4, 0xce, 0x99, 0x33, 0x67, 0x94, 0x1, 0x19, 0xab, 0x41, 0xc2, 0xbb, 0x80, 0x38, 0x6, 0xc4, 0x38, 0xa, 0xc4, 0x91, 0x20, 0xc6, 0x54, 0x3c, 0xc, 0xb8, 0x62, 0x98, 0x76, 0x29, 0x20, 0xce, 0xdd, 0x39, 0x73, 0xe6, 0x3c, 0x90, 0x81, 0x62, 0x10, 0x2b, 0x30, 0x1, 0x0, 0xec, 0xe0, 0x11, 0x6d, 0xb5, 0xe0, 0x8c, 0x99, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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, 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[] = { - 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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 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, 0xe0, 0x7, 0x1c, 0xc, 0x14, 0x2b, 0xf9, 0x77, 0x52, 0x64, 0x0, 0x0, 0x1, 0x92, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x8d, 0x93, 0x4d, 0x4e, 0x1b, 0x41, 0x10, 0x85, 0xbf, 0xea, 0xaa, 0x1e, 0x20, 0x83, 0xf9, 0x9, 0x36, 0xb2, 0x85, 0x72, 0x84, 0x8, 0x65, 0x11, 0xe5, 0xc, 0x9c, 0x80, 0x73, 0x10, 0xee, 0xc1, 0x41, 0x38, 0x1, 0xab, 0xec, 0xa3, 0x2c, 0x2, 0x8a, 0xe0, 0x2, 0x51, 0xc2, 0x48, 0x46, 0x42, 0x64, 0xc6, 0x91, 0x21, 0xf4, 0x74, 0x16, 0x2e, 0xb0, 0x71, 0x2, 0xf2, 0x93, 0x9e, 0xba, 0x16, 0xdd, 0xaf, 0x5e, 0xa9, 0x5f, 0x9, 0x60, 0x40, 0x1, 0x2c, 0x1, 0xcb, 0x5e, 0x2b, 0x10, 0x78, 0x8a, 0x16, 0x48, 0xc0, 0x1d, 0x30, 0x6, 0x6e, 0x81, 0x3b, 0xf3, 0x87, 0x25, 0xb0, 0x9, 0xac, 0x7b, 0xbd, 0xc, 0x88, 0x13, 0x20, 0x3b, 0xc7, 0xc0, 0x8, 0xb8, 0x1, 0xae, 0x81, 0x91, 0xf9, 0xe5, 0xad, 0x77, 0xbb, 0x1f, 0xf6, 0x7b, 0xdd, 0xfe, 0x41, 0x4a, 0x69, 0x2d, 0x93, 0xf9, 0x1f, 0x4, 0x41, 0x55, 0x7f, 0xd, 0xaf, 0xaa, 0xa3, 0xaf, 0x67, 0x9f, 0x8f, 0x81, 0x64, 0xde, 0xb1, 0xbb, 0xdd, 0x1b, 0x7c, 0xac, 0x9b, 0x9b, 0xce, 0xd9, 0xb7, 0x2f, 0xfc, 0xf3, 0x5e, 0xa6, 0xe5, 0xee, 0xdb, 0xf7, 0x6b, 0xdb, 0xbd, 0xc1, 0x21, 0xf0, 0x9, 0x18, 0x5, 0x60, 0x5, 0xd8, 0x48, 0x6d, 0xdb, 0x39, 0xbf, 0x38, 0xc5, 0x34, 0x62, 0x36, 0x47, 0x9d, 0xf2, 0xfc, 0xe2, 0x94, 0xd4, 0xb6, 0x1d, 0x60, 0x3, 0x58, 0x31, 0x20, 0x2, 0x65, 0x40, 0x88, 0x31, 0x92, 0xbd, 0xbb, 0x8, 0xe4, 0x3c, 0x39, 0x67, 0x91, 0x33, 0x84, 0x89, 0xa5, 0x12, 0x88, 0xf, 0x3f, 0x10, 0x45, 0x5, 0xb3, 0xc8, 0x73, 0x10, 0x11, 0xb2, 0xab, 0x8b, 0xa, 0xde, 0xb8, 0x30, 0x9f, 0xb0, 0x8, 0xa2, 0xc4, 0x58, 0xb0, 0x8, 0x82, 0x28, 0xde, 0x58, 0xcc, 0xff, 0x5c, 0x45, 0x64, 0x61, 0x1, 0x99, 0xcc, 0xa5, 0x80, 0x4e, 0x5, 0xc2, 0xcb, 0x2, 0xe2, 0x41, 0x10, 0x40, 0xc2, 0x53, 0x81, 0xc, 0xa8, 0x8a, 0x52, 0x2c, 0xe8, 0x40, 0x27, 0x23, 0x28, 0x90, 0xcd, 0xe3, 0x79, 0x1b, 0x34, 0x50, 0x14, 0x4b, 0xf0, 0x4c, 0x88, 0x66, 0xbd, 0x4, 0xd, 0x78, 0x94, 0x93, 0x79, 0x3c, 0x9b, 0x18, 0x63, 0x7a, 0xbd, 0xb9, 0xa5, 0xcd, 0xa8, 0x7e, 0xb4, 0x3a, 0x2f, 0x15, 0x10, 0xca, 0x72, 0x95, 0x18, 0x8b, 0x4, 0x34, 0xc0, 0xd8, 0x80, 0x1a, 0x18, 0x56, 0xd5, 0xcf, 0x93, 0x41, 0x7f, 0x67, 0xaf, 0xb3, 0xba, 0x1e, 0x5e, 0x8a, 0xb2, 0x99, 0xb5, 0x97, 0xd5, 0x8f, 0x13, 0x60, 0x8, 0xd4, 0x2, 0x74, 0x9d, 0x6f, 0x80, 0xbe, 0x2f, 0x55, 0xe9, 0x26, 0xc2, 0xcc, 0x26, 0x66, 0x5f, 0xa4, 0x6b, 0xa0, 0x2, 0xbe, 0x3, 0x57, 0xe6, 0x56, 0x1e, 0x66, 0x1a, 0x2, 0xaf, 0x3c, 0x24, 0x36, 0x67, 0xe0, 0x1e, 0xf8, 0x3, 0xfc, 0xf6, 0x6d, 0xac, 0x81, 0xe6, 0x2f, 0x7c, 0x22, 0x6d, 0x74, 0x25, 0xb, 0xb3, 0xa2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char checked_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, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x73, 0x72, 0x7b, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x82, 0x80, 0x8a, 0x90, 0x90, 0x93, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x93, 0x93, 0x95, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x7d, 0x7d, 0x7f, 0x58, 0x58, 0x5b, 0xa4, 0xa4, 0xa4, 0x9e, 0x9e, 0xa0, 0x9e, 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x93, 0x93, 0x94, 0x8f, 0x8f, 0x8f, 0x86, 0x86, 0x88, 0x85, 0x85, 0x86, 0x82, 0x82, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x7c, 0x7e, 0x7a, 0x7a, 0x7d, 0x78, 0x78, 0x7b, 0x71, 0x71, 0x74, 0x68, 0x68, 0x6c, 0x66, 0x66, 0x6a, 0x65, 0x65, 0x68, 0x63, 0x63, 0x66, 0x5f, 0x5f, 0x63, 0x5c, 0x5c, 0x60, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x59, 0x59, 0x5c, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x10, 0x13, 0xbb, 0xf, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xb4, 0xdd, 0xfa, 0xfa, 0xfb, 0xfb, 0x5b, 0xd1, 0xf1, 0xe6, 0x0, 0x0, 0x0, 0x96, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x5d, 0x8f, 0xc9, 0x12, 0x82, 0x30, 0x14, 0x4, 0x87, 0x18, 0x50, 0x51, 0x44, 0x25, 0x42, 0x4, 0x77, 0xc4, 0x8d, 0x97, 0x0, 0xf9, 0xff, 0x8f, 0xb3, 0x88, 0xa4, 0x4a, 0xed, 0x63, 0x5f, 0xa6, 0x7, 0xf8, 0x7, 0x1e, 0xe3, 0x7e, 0x60, 0x19, 0x4f, 0x46, 0x1e, 0x0, 0x36, 0x8d, 0x4c, 0x67, 0x59, 0x65, 0x33, 0x6, 0x80, 0x47, 0xad, 0x56, 0x3d, 0xb7, 0x3c, 0x5d, 0x70, 0x0, 0xbe, 0xd1, 0x44, 0x65, 0x4d, 0x94, 0xc8, 0xc2, 0xf8, 0x0, 0x82, 0x4e, 0x91, 0x94, 0x15, 0x5d, 0xd2, 0xec, 0xde, 0x5, 0x83, 0x38, 0xc8, 0xe3, 0x63, 0x23, 0xce, 0xca, 0x9, 0x7a, 0x6e, 0xf3, 0x93, 0x48, 0x1a, 0x27, 0x14, 0x35, 0x3b, 0xb9, 0x5e, 0x56, 0xe4, 0x84, 0x22, 0xba, 0xa, 0x51, 0xd0, 0xb7, 0xa8, 0xcb, 0xfd, 0xcb, 0x9, 0x3b, 0xfb, 0x41, 0xdb, 0x59, 0x17, 0xa6, 0x94, 0x6e, 0xe3, 0x3e, 0x8c, 0x85, 0xf1, 0x90, 0x6e, 0xe6, 0x21, 0xfb, 0x39, 0xe7, 0x73, 0xe6, 0xfd, 0x5f, 0x7, 0xde, 0xc3, 0xb5, 0x16, 0x87, 0xb0, 0x9e, 0x42, 0x46, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char checker_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char close_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, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char close_hl_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, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x47, 0x29, 0xbc, 0x83, 0x0, 0x0, 0x0, 0x3c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xd5, 0x21, 0x11, 0x0, 0x30, 0xc, 0x4, 0xc1, 0xfa, 0x57, 0x53, 0x87, 0xed, 0x4, 0x45, 0xc4, 0xed, 0xa3, 0xc3, 0x4b, 0xfe, 0xbc, 0xd9, 0x9d, 0x35, 0x2b, 0xe, 0x0, 0x0, 0x0, 0x80, 0xed, 0x66, 0xc5, 0x1, 0x0, 0x0, 0x0, 0xe0, 0x6, 0x1, 0x0, 0x0, 0x90, 0x6, 0x70, 0x83, 0x0, 0x0, 0x0, 0x28, 0x3, 0x7c, 0x54, 0x93, 0xd6, 0xf1, 0xd1, 0x16, 0x8a, 0x17, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char dialog_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x26, 0x8, 0x3, 0x0, 0x0, 0x0, 0xf7, 0x10, 0x9b, 0xa4, 0x0, 0x0, 0x2, 0xf5, 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, 0xb5, 0x95, 0x6d, 0x72, 0xe4, 0x28, 0xc, 0x86, 0xff, 0x73, 0x8a, 0x3d, 0x2, 0xfa, 0x42, 0x70, 0x1c, 0xc, 0xa6, 0x6a, 0x6f, 0xb0, 0xc7, 0x9f, 0x17, 0xec, 0x38, 0xd9, 0x4c, 0x57, 0xda, 0x49, 0xcf, 0x40, 0xb5, 0xa5, 0x92, 0x5, 0x12, 0x3c, 0x92, 0x3b, 0xec, 0xff, 0xfd, 0x3b, 0xc2, 0x3f, 0x18, 0xa4, 0x39, 0x6, 0x35, 0xcf, 0xa9, 0xa4, 0x14, 0x31, 0xb4, 0x68, 0xe1, 0xa, 0x25, 0xc7, 0xf7, 0xb1, 0x9f, 0xf2, 0xb0, 0x51, 0xd4, 0xf5, 0x5c, 0xa3, 0xe8, 0xf9, 0x8e, 0x22, 0x85, 0x8f, 0x2f, 0x2e, 0x8d, 0x21, 0x5, 0x52, 0xe, 0xa3, 0xbf, 0x2d, 0x90, 0xd3, 0xfe, 0xe6, 0x9f, 0x2e, 0x89, 0x8d, 0x1e, 0xbc, 0x20, 0xfb, 0xb4, 0x40, 0xae, 0x30, 0xfc, 0x31, 0xb0, 0xd7, 0xd3, 0xce, 0x91, 0xff, 0x97, 0x91, 0x7a, 0xb4, 0xf8, 0x71, 0xe4, 0xf7, 0xdf, 0x18, 0x3d, 0x8f, 0xb1, 0x1f, 0xa7, 0xab, 0x9a, 0x70, 0xd, 0xe9, 0x38, 0xd4, 0x11, 0x22, 0xbc, 0x6d, 0x3, 0xc7, 0xd, 0x5b, 0xc9, 0x5a, 0x96, 0x30, 0x1d, 0x3f, 0x83, 0xee, 0x6b, 0x16, 0xcc, 0x1c, 0x6b, 0x6c, 0xa4, 0xb1, 0xc7, 0x16, 0x37, 0xcc, 0x46, 0x85, 0x98, 0x24, 0xe, 0x52, 0xea, 0x81, 0x2a, 0xd, 0xda, 0xa9, 0x43, 0x36, 0x6a, 0xc8, 0x51, 0x79, 0x67, 0x87, 0x64, 0x6e, 0x2c, 0xcb, 0x96, 0xc5, 0xb9, 0x70, 0x93, 0x28, 0x24, 0x3a, 0x27, 0xd, 0x76, 0x29, 0xd2, 0x25, 0xb, 0x4b, 0xe3, 0x5d, 0x44, 0x34, 0x8, 0x5f, 0xb9, 0xd0, 0x8a, 0x5b, 0x56, 0xbc, 0x46, 0x19, 0x91, 0x3b, 0xc1, 0x95, 0x9, 0x9b, 0x11, 0x96, 0x7c, 0x39, 0xc3, 0x33, 0x87, 0x3b, 0x73, 0x8c, 0x16, 0x71, 0x47, 0x44, 0x38, 0x3d, 0x9d, 0x75, 0x81, 0xbc, 0x98, 0x27, 0x7, 0x9a, 0xd7, 0x28, 0xf3, 0x9, 0x37, 0x0, 0xa1, 0x71, 0x72, 0xb3, 0x75, 0xc1, 0x6f, 0xf3, 0x1a, 0xe1, 0x3, 0x58, 0x1, 0x41, 0x5b, 0xd7, 0x9c, 0x71, 0xc0, 0x1a, 0xb7, 0x63, 0x8b, 0xcd, 0xe8, 0xbd, 0xb6, 0x64, 0x15, 0x80, 0xc0, 0xcf, 0x20, 0x8f, 0xfa, 0x22, 0xef, 0x93, 0x1a, 0xaf, 0x2a, 0x51, 0xc4, 0x36, 0x24, 0x43, 0x2, 0x4, 0x31, 0x91, 0x18, 0x25, 0x8a, 0xce, 0xec, 0x44, 0x2a, 0x9c, 0x1, 0xa8, 0x22, 0x73, 0x16, 0xe5, 0xd, 0x4, 0xc8, 0x8c, 0x3b, 0x92, 0x64, 0x15, 0x49, 0x60, 0x93, 0x51, 0x47, 0x88, 0x8d, 0x35, 0x4e, 0xcb, 0x97, 0x8d, 0xf, 0x3b, 0x5a, 0x5, 0x7c, 0x4c, 0x92, 0x38, 0xd8, 0x14, 0xa9, 0x80, 0xa5, 0x6a, 0xa8, 0x1f, 0xd7, 0x8c, 0x1a, 0xaa, 0x26, 0xa6, 0x66, 0x96, 0xcc, 0x2d, 0x5b, 0xb1, 0x1a, 0x92, 0x24, 0x4d, 0x96, 0x52, 0xf2, 0x34, 0x7b, 0xae, 0xba, 0xb8, 0xba, 0x79, 0x72, 0xf7, 0xec, 0xc5, 0x6b, 0x96, 0xac, 0xd9, 0x72, 0xca, 0x9e, 0x73, 0x2e, 0xb9, 0x16, 0x2e, 0x82, 0x96, 0xb4, 0x92, 0x8a, 0x97, 0x5c, 0x4a, 0xa9, 0x15, 0x31, 0xab, 0x86, 0x6a, 0x15, 0xab, 0x2b, 0x3c, 0x6a, 0xdd, 0x78, 0x93, 0x4d, 0x37, 0xdb, 0xd2, 0xe6, 0x5b, 0xde, 0xca, 0x56, 0x1b, 0xca, 0xa7, 0x69, 0xb3, 0x96, 0x9a, 0xb7, 0xdc, 0x4a, 0xab, 0x9d, 0xbb, 0x74, 0xed, 0xd6, 0x53, 0xf7, 0x9e, 0x7b, 0xe9, 0x75, 0xa7, 0x1d, 0xa5, 0x14, 0x76, 0xdd, 0x6d, 0x4f, 0xbb, 0xef, 0x79, 0x2f, 0x7b, 0x1d, 0xa8, 0xb5, 0x21, 0x43, 0x87, 0x8d, 0x34, 0x7c, 0xe4, 0x51, 0x46, 0xbd, 0xa8, 0xd1, 0xd9, 0xb6, 0x9f, 0xe7, 0x37, 0xa8, 0xd1, 0x49, 0x8d, 0x17, 0xa9, 0xe9, 0xe7, 0x17, 0x35, 0x58, 0xdd, 0xe7, 0x46, 0x6b, 0xb, 0x9a, 0xdf, 0x19, 0x9b, 0xcc, 0x40, 0x8c, 0x95, 0x40, 0xdc, 0x27, 0x1, 0x14, 0x34, 0x4f, 0x66, 0x31, 0x93, 0x2a, 0x4f, 0x72, 0x93, 0x59, 0x2c, 0x8c, 0xae, 0x30, 0x46, 0x92, 0x36, 0xd9, 0x74, 0x8a, 0x35, 0x50, 0x2, 0x42, 0xdd, 0x89, 0x6d, 0xd0, 0xc5, 0xee, 0x9d, 0xdc, 0x6d, 0x6e, 0x1, 0x77, 0xfd, 0x8c, 0x1b, 0xdf, 0x21, 0x17, 0x26, 0xba, 0x3f, 0x40, 0x8e, 0xc3, 0x2e, 0x9f, 0xb8, 0x3d, 0xa0, 0xd6, 0xe7, 0x97, 0xb0, 0x2d, 0x62, 0x47, 0x17, 0xce, 0x3b, 0x8d, 0x82, 0xee, 0x83, 0x6f, 0xe5, 0x5c, 0x79, 0x53, 0x50, 0x5b, 0x5a, 0x7e, 0x55, 0xfe, 0x85, 0x8d, 0x68, 0x9, 0x1c, 0xe2, 0x67, 0x32, 0x3c, 0x7c, 0xa1, 0x6b, 0xe7, 0xf4, 0x1d, 0x25, 0xdc, 0x70, 0x42, 0xce, 0x65, 0x85, 0xb0, 0x2f, 0x94, 0x70, 0xc7, 0xe9, 0x37, 0xe5, 0x41, 0xd2, 0xe1, 0x47, 0xe7, 0x78, 0x90, 0x74, 0x40, 0x91, 0x8a, 0xa6, 0x74, 0x1a, 0x5b, 0xa7, 0x72, 0x86, 0xfe, 0xa6, 0x39, 0xdc, 0x72, 0x47, 0x97, 0x1b, 0xa1, 0xbf, 0xf0, 0x3f, 0x8c, 0xe, 0x7d, 0xa8, 0x84, 0x2f, 0xde, 0x7d, 0xad, 0x90, 0x1a, 0xdb, 0xc, 0xb1, 0x2d, 0x25, 0x5c, 0xda, 0x8b, 0x4a, 0x38, 0xb3, 0x2e, 0x15, 0xa7, 0x39, 0x8c, 0x38, 0x53, 0xeb, 0x67, 0xe8, 0xfb, 0xe6, 0x70, 0xdb, 0xfd, 0x49, 0xa9, 0x86, 0x17, 0xa9, 0x5f, 0x5c, 0xc2, 0x8b, 0xd4, 0x2f, 0x73, 0x78, 0x4e, 0xdd, 0x6e, 0xc9, 0x70, 0xd7, 0xf1, 0x59, 0x3d, 0x84, 0x17, 0xca, 0x88, 0x3e, 0xca, 0xf0, 0xd9, 0xf0, 0x53, 0xf9, 0xe7, 0x36, 0xf2, 0x81, 0x8f, 0x7b, 0x81, 0xf2, 0xb, 0x12, 0xea, 0xac, 0x15, 0x79, 0x70, 0x44, 0x63, 0x0, 0x0, 0x1, 0x68, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xe8, 0xe5, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x22, 0x0, 0x0, 0x0, 0x1a, 0x19, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x21, 0x17, 0x16, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1b, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1e, 0x1c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x0, 0x0, 0x0, 0x20, 0x20, 0x25, 0x20, 0x1d, 0x25, 0x20, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x20, 0x1d, 0x1a, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30, 0x38, 0xe8, 0xe5, 0xf1, 0xe5, 0xe2, 0xeb, 0xe3, 0xe1, 0xe8, 0xe1, 0xdf, 0xe7, 0xe0, 0xde, 0xe6, 0xdf, 0xdd, 0xe5, 0xde, 0xdc, 0xe4, 0xdd, 0xdb, 0xe3, 0xdc, 0xda, 0xe2, 0xda, 0xd8, 0xe0, 0xd9, 0xd7, 0xdf, 0xd7, 0xd6, 0xdf, 0xd6, 0xd4, 0xdd, 0xd5, 0xd3, 0xdc, 0xd4, 0xd1, 0xdb, 0xd3, 0xd0, 0xda, 0xd1, 0xce, 0xd8, 0xd0, 0xcd, 0xd7, 0xcf, 0xcd, 0xd7, 0xe2, 0xdf, 0xeb, 0x48, 0x46, 0x51, 0x42, 0x40, 0x4b, 0x40, 0x3e, 0x48, 0x40, 0x3d, 0x48, 0x48, 0x45, 0x50, 0x42, 0x3f, 0x4a, 0x3f, 0x3d, 0x48, 0x47, 0x44, 0x50, 0x41, 0x3f, 0x4a, 0x3f, 0x3d, 0x47, 0x41, 0x3e, 0x49, 0x3f, 0x3c, 0x47, 0x46, 0x43, 0x4f, 0x3e, 0x3c, 0x46, 0x40, 0x3e, 0x49, 0x3d, 0x3b, 0x46, 0x45, 0x43, 0x4e, 0x3d, 0x3b, 0x45, 0x44, 0x42, 0x4d, 0x3d, 0x3a, 0x45, 0x3e, 0x3c, 0x47, 0x3c, 0x3a, 0x44, 0x43, 0x42, 0x4c, 0x43, 0x40, 0x4c, 0x3e, 0x3b, 0x46, 0x3b, 0x39, 0x43, 0x43, 0x3f, 0x4c, 0x43, 0x3f, 0x4b, 0x3a, 0x38, 0x42, 0x42, 0x3e, 0x4b, 0x42, 0x3e, 0x49, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3f, 0x3e, 0x48, 0x39, 0x37, 0x40, 0x38, 0x36, 0x40, 0x3e, 0x3d, 0x48, 0x38, 0x36, 0x3f, 0x3e, 0x3d, 0x47, 0x3a, 0x38, 0x41, 0x38, 0x35, 0x3f, 0x37, 0x35, 0x3e, 0x39, 0x36, 0x40, 0x37, 0x34, 0x3e, 0x3d, 0x3a, 0x46, 0x36, 0x34, 0x3d, 0x3d, 0x3a, 0x44, 0x37, 0x35, 0x3f, 0x35, 0x33, 0x3c, 0x6b, 0xff, 0x8f, 0xb1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x88, 0x5, 0x1d, 0x48, 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, 0xe5, 0x7, 0x1b, 0x17, 0x11, 0x18, 0xe6, 0xb9, 0x22, 0xac, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0xf4, 0x64, 0xc0, 0x6, 0x98, 0x18, 0x68, 0x27, 0xcc, 0xc2, 0x88, 0x5d, 0x98, 0x99, 0x24, 0x61, 0x26, 0x52, 0x84, 0x71, 0xb9, 0x84, 0x89, 0x76, 0xc2, 0xb8, 0xac, 0x64, 0x21, 0x49, 0x35, 0x33, 0x15, 0x54, 0xe3, 0xa, 0x6f, 0x26, 0x6a, 0xa8, 0x26, 0xc9, 0x4a, 0xaa, 0x44, 0x3, 0x89, 0x89, 0x8d, 0x99, 0xee, 0xe9, 0x1b, 0x87, 0x30, 0x0, 0x20, 0x4, 0x0, 0xed, 0x48, 0xa7, 0x26, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char dropdown_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x2, 0x60, 0x16, 0x98, 0x78, 0x67, 0x8, 0x81, 0x6f, 0x4d, 0xde, 0x9a, 0x0, 0x5, 0xde, 0x3a, 0x3d, 0xfc, 0x8f, 0x80, 0xaf, 0xba, 0x18, 0xde, 0x29, 0x2, 0x19, 0xbf, 0x61, 0x2, 0x6f, 0x62, 0x18, 0x3e, 0xb0, 0xbd, 0x97, 0x4, 0x32, 0xff, 0x80, 0xb9, 0xb1, 0x20, 0x93, 0xc0, 0x42, 0x8, 0x2e, 0x54, 0xe8, 0x9d, 0xdc, 0x9b, 0x54, 0x10, 0xb, 0x21, 0xc4, 0x4, 0x63, 0x1, 0x0, 0x86, 0x1f, 0x3b, 0x1e, 0x92, 0x22, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char ellipsis_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc9, 0x11, 0xce, 0xcc, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x78, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x95, 0xd1, 0x31, 0xa, 0xc2, 0x50, 0x10, 0x4, 0xd0, 0xb7, 0x1f, 0xf, 0x60, 0x67, 0xa, 0xf, 0x12, 0x6f, 0x60, 0xe9, 0x51, 0x5, 0x3d, 0x44, 0xee, 0x61, 0xa1, 0xa5, 0xf6, 0x81, 0xb5, 0xc8, 0x47, 0x82, 0x84, 0x4f, 0xb2, 0xdd, 0xb0, 0x33, 0xb3, 0xb3, 0x4c, 0x40, 0x66, 0xee, 0x71, 0xc2, 0x1, 0x3b, 0xcb, 0x33, 0xe2, 0x85, 0x21, 0x22, 0xde, 0x51, 0x45, 0x97, 0x86, 0x60, 0xc9, 0xe0, 0x5a, 0xea, 0xa5, 0xb5, 0x22, 0x95, 0xdb, 0x97, 0x1a, 0xf, 0x6e, 0xb8, 0xcf, 0x8, 0x2d, 0xdc, 0x95, 0xd9, 0x22, 0xfe, 0x9c, 0x9b, 0x38, 0x32, 0xf3, 0x8c, 0xe3, 0x86, 0xa8, 0xf0, 0x28, 0x18, 0x4c, 0xf, 0xaf, 0x9d, 0x11, 0x43, 0xf0, 0xab, 0xa3, 0x47, 0xa7, 0x5d, 0xc7, 0xd3, 0x54, 0xc7, 0xe7, 0xb, 0xb9, 0xce, 0x1f, 0xc6, 0x2d, 0x99, 0x55, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 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, 0xe0, 0x8, 0x17, 0xd, 0x5, 0x12, 0xa1, 0x38, 0x83, 0x9b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x2, 0x74, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x97, 0x3d, 0x6f, 0xd3, 0x60, 0x10, 0xc7, 0x7f, 0x17, 0x9b, 0x26, 0x25, 0x22, 0xad, 0xa, 0x8, 0xf1, 0x52, 0x75, 0x0, 0x16, 0x24, 0x90, 0x2a, 0x96, 0x7c, 0x1, 0x6, 0xc4, 0xce, 0xc4, 0x17, 0x0, 0x31, 0xb0, 0x30, 0x0, 0x23, 0x82, 0x85, 0x5, 0x9, 0x4, 0x5f, 0x80, 0x89, 0x1d, 0x31, 0xf0, 0x5, 0x58, 0x50, 0x25, 0x50, 0x59, 0x80, 0xa1, 0xe2, 0xad, 0x28, 0x34, 0x4a, 0x3, 0x25, 0x76, 0xea, 0xe7, 0x39, 0x6, 0x3f, 0x76, 0x6d, 0xc7, 0x49, 0x5f, 0xd8, 0x90, 0x6f, 0xb1, 0xf5, 0xe4, 0xb9, 0xdf, 0xdd, 0xfd, 0xef, 0x22, 0xf9, 0x84, 0x2d, 0x13, 0xa0, 0x6, 0x78, 0xee, 0x29, 0xe4, 0x4d, 0x1, 0xb, 0x18, 0xf7, 0x54, 0x32, 0x97, 0x6a, 0xc0, 0x7e, 0x60, 0xe, 0x38, 0xc, 0xb4, 0x80, 0x7d, 0x5, 0xc0, 0x26, 0xd0, 0x7, 0x3a, 0x40, 0x17, 0xf8, 0x3, 0xd8, 0x24, 0x6a, 0x13, 0x38, 0x35, 0x73, 0x60, 0xf6, 0x6a, 0xa3, 0xde, 0xb8, 0x38, 0x35, 0x55, 0x3f, 0x41, 0x89, 0xd, 0x87, 0xe1, 0x97, 0x20, 0xc, 0x5e, 0xae, 0xff, 0xea, 0x3d, 0x5, 0x3e, 0x2, 0x1b, 0xe2, 0x22, 0x2d, 0xcc, 0xcd, 0x1e, 0x7c, 0x78, 0x72, 0xe1, 0xf4, 0xa5, 0x7b, 0xb7, 0x1f, 0x7c, 0x9e, 0x6e, 0x35, 0xca, 0xfc, 0x19, 0xf4, 0x3, 0xee, 0xdc, 0xbf, 0x39, 0xff, 0x69, 0xe5, 0xc3, 0x8b, 0x6e, 0x6f, 0xed, 0x6, 0xb0, 0x22, 0x40, 0x3, 0x58, 0x3c, 0x7a, 0xe4, 0xf8, 0xab, 0x67, 0x4f, 0x9e, 0x77, 0xa3, 0xc8, 0x12, 0xd, 0xa3, 0x52, 0x80, 0x3f, 0xe5, 0xe3, 0xfb, 0x35, 0xae, 0x5c, 0xbb, 0x3c, 0xf7, 0xfd, 0xc7, 0xd7, 0xb, 0xc0, 0x92, 0xef, 0x74, 0x68, 0xfa, 0x9e, 0xdf, 0x1c, 0xfc, 0xe, 0xbb, 0x88, 0xc6, 0x47, 0xa, 0x2a, 0x59, 0x85, 0x95, 0x61, 0xb8, 0xc9, 0x30, 0x4, 0xdf, 0xf3, 0x9b, 0xae, 0x6c, 0x49, 0x0, 0x1e, 0x80, 0x51, 0x1b, 0xfb, 0xc7, 0x2, 0xc7, 0x5a, 0x3b, 0x88, 0x66, 0xcf, 0x63, 0xf3, 0x12, 0x80, 0x26, 0xbf, 0xa8, 0xb5, 0xa8, 0xa, 0x88, 0x22, 0x8, 0x8a, 0x22, 0x2a, 0x19, 0x37, 0x1d, 0xe9, 0xad, 0x9f, 0x6b, 0xb4, 0x55, 0x14, 0x5, 0x55, 0x44, 0xe2, 0x32, 0x6c, 0xe2, 0x24, 0x71, 0x18, 0x9d, 0x4, 0xb0, 0x6a, 0xd3, 0x1b, 0x2a, 0xe9, 0x4b, 0xfc, 0xae, 0xe4, 0x45, 0x19, 0x9f, 0x81, 0x2b, 0xdb, 0x15, 0xa6, 0xa2, 0x19, 0x2d, 0xec, 0x8, 0x24, 0x7, 0x30, 0xd6, 0x16, 0xf8, 0x82, 0xa8, 0xc6, 0x45, 0x68, 0x52, 0xbf, 0x4e, 0xce, 0x60, 0xeb, 0x42, 0x5c, 0xb4, 0x66, 0x9c, 0x6c, 0xc9, 0x1f, 0xa4, 0x0, 0xb0, 0x39, 0xc5, 0xc9, 0xa1, 0x28, 0x89, 0x5f, 0x14, 0xd1, 0x5a, 0x37, 0x32, 0x89, 0xf2, 0x82, 0xc6, 0x3, 0xe0, 0xda, 0xa, 0x22, 0x3a, 0xa9, 0xb, 0x9a, 0x26, 0xaa, 0xf1, 0x41, 0x9a, 0x42, 0x2, 0xb2, 0xb2, 0x6d, 0x6, 0x5b, 0xa3, 0xab, 0x23, 0xd5, 0x48, 0x32, 0x92, 0xe3, 0x33, 0x10, 0x37, 0xb7, 0x2a, 0xea, 0xee, 0x4a, 0x2a, 0x42, 0xe, 0x5a, 0x2a, 0xa2, 0x51, 0x37, 0x40, 0x85, 0x48, 0x96, 0xb4, 0x23, 0xdb, 0x88, 0x68, 0x5c, 0xc4, 0xcc, 0x3c, 0x14, 0xa7, 0x6f, 0xa2, 0x6, 0xaa, 0xb1, 0x7c, 0xd9, 0x30, 0xaa, 0x79, 0xc7, 0x49, 0x93, 0x78, 0xf7, 0xd1, 0xad, 0x79, 0x76, 0x69, 0x29, 0x20, 0xda, 0x34, 0x2c, 0x9e, 0x3d, 0xff, 0x7a, 0x27, 0x4e, 0x4b, 0xef, 0xde, 0xb4, 0x4b, 0x33, 0x58, 0xef, 0xf7, 0x76, 0x9b, 0x0, 0x35, 0xfe, 0xd1, 0x2a, 0x40, 0x5, 0xa8, 0x0, 0x15, 0xa0, 0x2, 0x54, 0x80, 0xa, 0xf0, 0x5f, 0x2, 0xa4, 0xe4, 0x13, 0x78, 0xd7, 0x19, 0xd8, 0x3d, 0xf8, 0xda, 0x4, 0x60, 0x81, 0xc0, 0x18, 0x13, 0xda, 0x68, 0x7, 0x5e, 0x11, 0x18, 0x63, 0x42, 0x20, 0x0, 0x6c, 0xcd, 0xad, 0xb2, 0x6b, 0x41, 0x38, 0x58, 0xee, 0x74, 0x57, 0xdb, 0x93, 0x20, 0x36, 0x82, 0x4e, 0x77, 0xb5, 0x1d, 0x84, 0x83, 0x65, 0x60, 0xd, 0x30, 0xc9, 0xe6, 0x3a, 0x3, 0x9c, 0x6b, 0x35, 0x67, 0x1f, 0x37, 0xea, 0xd3, 0x67, 0x3c, 0xcf, 0x2b, 0x15, 0xd7, 0x18, 0x63, 0x83, 0x70, 0xf0, 0xbe, 0xbf, 0xd1, 0xbb, 0xe, 0xbc, 0x5, 0xd6, 0x25, 0xb3, 0xc2, 0xb5, 0x80, 0x63, 0xc0, 0x21, 0xa0, 0x3e, 0x66, 0xf9, 0xe, 0x81, 0x9f, 0xc0, 0x37, 0xb7, 0x47, 0x1b, 0x29, 0x8, 0xea, 0x27, 0xfb, 0xe0, 0x98, 0x2a, 0xd4, 0x95, 0x1c, 0xed, 0x51, 0xf8, 0x51, 0xfb, 0xb, 0x1, 0xbe, 0x20, 0x9f, 0x90, 0x81, 0x17, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_breakpoint_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, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0xe7, 0x2c, 0xf4, 0xe7, 0x2c, 0xec, 0x5a, 0x6b, 0x42, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_close_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0x90, 0xb5, 0x1, 0xc0, 0x30, 0x10, 0x3, 0x55, 0x1a, 0xbe, 0xc, 0x6e, 0xe6, 0xb5, 0xc3, 0x34, 0x4b, 0x98, 0xcc, 0xee, 0x7c, 0x4f, 0x92, 0x0, 0x70, 0x45, 0x19, 0x8c, 0x47, 0x19, 0x57, 0x37, 0x66, 0x1b, 0x6b, 0x74, 0x89, 0x32, 0xd6, 0xb0, 0xed, 0x2c, 0x51, 0xca, 0x6b, 0xb6, 0xb3, 0x41, 0x94, 0x0, 0xfe, 0x9f, 0x2c, 0x0, 0xa3, 0x64, 0x61, 0xa3, 0x6f, 0x66, 0xbd, 0xc6, 0x7f, 0xe9, 0x86, 0x3b, 0x5b, 0x34, 0x76, 0xa, 0xcf, 0xad, 0xe0, 0xaa, 0xbf, 0xa4, 0x4f, 0x5a, 0xa, 0x6d, 0x25, 0xba, 0x14, 0x37, 0x18, 0x8b, 0xe4, 0x0, 0x6f, 0xe9, 0x37, 0x83, 0x22, 0x73, 0x83, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_comment_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, 0x0, 0x78, 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, 0xf, 0xd, 0x10, 0x17, 0x14, 0x18, 0x1d, 0x1a, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x10, 0x13, 0x35, 0x2f, 0x38, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0x19, 0x17, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x24, 0x1e, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x85, 0xbb, 0x9b, 0xdf, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xff, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0xff, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0xff, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0x31, 0x64, 0xfe, 0xeb, 0x0, 0x0, 0x0, 0x8d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xc8, 0x35, 0x62, 0x3, 0x41, 0x14, 0x4, 0xd1, 0xee, 0x21, 0x33, 0x33, 0xdb, 0xf7, 0xbf, 0x93, 0x99, 0x49, 0xcc, 0xd2, 0x7c, 0x2d, 0x53, 0xa6, 0x58, 0x5b, 0x59, 0x3d, 0x2, 0xc, 0x3, 0x20, 0x61, 0x20, 0x5c, 0x9, 0xc6, 0x74, 0x11, 0x20, 0x2c, 0x86, 0xbd, 0xec, 0x63, 0xa1, 0xd9, 0xa7, 0x47, 0x9a, 0x92, 0x7f, 0xda, 0x83, 0xa1, 0xcd, 0x60, 0xb2, 0xfa, 0xc7, 0x33, 0xf6, 0xb, 0xb0, 0x2e, 0xb4, 0xce, 0x2e, 0x17, 0x20, 0x2f, 0x82, 0x5d, 0x66, 0x2f, 0xb2, 0x20, 0xd4, 0x50, 0xc3, 0x19, 0x59, 0x1, 0xe3, 0xb, 0xa0, 0xa6, 0x34, 0xe7, 0x9c, 0x65, 0xa0, 0xe5, 0x9d, 0x7b, 0x3b, 0xe4, 0x38, 0x79, 0x27, 0xd2, 0xa2, 0xbb, 0x22, 0xd9, 0x8b, 0x7e, 0x43, 0x44, 0x5e, 0x8, 0x75, 0x67, 0x66, 0x1f, 0x3b, 0x0, 0x5a, 0x67, 0x7a, 0xfa, 0xe0, 0x9, 0xb8, 0x99, 0x3a, 0x44, 0xd8, 0xaf, 0xd7, 0x63, 0x10, 0x95, 0xe6, 0x1e, 0x57, 0xc1, 0x90, 0xf7, 0xdc, 0x9d, 0x9f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_comment_focus_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, 0x0, 0x6f, 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, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x5f, 0x8c, 0x8b, 0xc7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0xb1, 0x1b, 0xa4, 0x4f, 0x0, 0x0, 0x0, 0x90, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xca, 0xb5, 0x75, 0xc4, 0x50, 0x0, 0x5, 0xd1, 0xf7, 0x49, 0xcc, 0xcc, 0xdc, 0x7f, 0x8b, 0x2b, 0xe6, 0xc8, 0xb1, 0x75, 0xc3, 0x39, 0x3, 0x80, 0x50, 0xc6, 0xc5, 0x84, 0x33, 0x4a, 0x30, 0x91, 0x64, 0x45, 0xd5, 0xf4, 0x89, 0xa6, 0x2a, 0xb2, 0x4, 0x48, 0x86, 0x69, 0xd9, 0xce, 0xc2, 0xb6, 0x4c, 0x43, 0x82, 0xeb, 0xf9, 0x4e, 0xb0, 0x71, 0x7c, 0xcf, 0x5, 0xf, 0xa3, 0xe0, 0x10, 0x85, 0x1c, 0x22, 0x76, 0xce, 0xe0, 0xc4, 0x2, 0x49, 0x7a, 0xd, 0x69, 0x2, 0xa1, 0xff, 0xb3, 0x70, 0xda, 0x42, 0x76, 0xf8, 0x73, 0xf8, 0xc2, 0x17, 0x92, 0xf4, 0x19, 0xf2, 0x6b, 0xc8, 0x13, 0xf0, 0xa2, 0x3c, 0x43, 0x59, 0x70, 0xb8, 0x55, 0x7d, 0x2c, 0x4e, 0x5d, 0xb9, 0x90, 0x9a, 0xb6, 0xeb, 0x9d, 0x45, 0xdf, 0xb5, 0x8d, 0x4, 0xd0, 0x66, 0x68, 0xf5, 0x74, 0xa2, 0xb7, 0x43, 0x43, 0x31, 0x91, 0x98, 0x48, 0x16, 0x82, 0x49, 0x78, 0x1b, 0x1, 0xf, 0xa7, 0x50, 0x68, 0x35, 0xb8, 0x84, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_default_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, 0x36, 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, 0x16, 0x12, 0x19, 0xe, 0xb, 0x10, 0xe, 0xb, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x24, 0x1e, 0x27, 0x16, 0x12, 0x19, 0x76, 0x9, 0xd2, 0x13, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x46, 0x47, 0x3f, 0x2b, 0x11, 0x3, 0xfd, 0xd3, 0xcd, 0x2a, 0x73, 0x45, 0xf8, 0x3d, 0x3f, 0x57, 0xda, 0x84, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x64, 0x2, 0x2, 0x46, 0x8, 0xc9, 0xcc, 0xc2, 0xca, 0xc6, 0xc0, 0x8f, 0x4, 0xd8, 0x39, 0x98, 0x59, 0x19, 0x50, 0x80, 0x0, 0x27, 0x17, 0x3, 0x2a, 0x10, 0xe4, 0x46, 0x13, 0xe0, 0x67, 0x1a, 0x18, 0x1, 0x1e, 0x34, 0x1, 0x5e, 0x3e, 0xc, 0xa7, 0x63, 0x78, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x4d, 0x2, 0xf2, 0xa2, 0x23, 0x3b, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_default_focus_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, 0x8a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x81, 0xff, 0x8c, 0xff, 0x99, 0xff, 0xb3, 0x2, 0x21, 0x3b, 0x4, 0x82, 0xd8, 0x40, 0x11, 0x46, 0x88, 0xa4, 0xf8, 0x7f, 0x49, 0x20, 0x14, 0xff, 0x2f, 0xa, 0x84, 0x8, 0xb6, 0xe0, 0x7f, 0x6e, 0xa0, 0x22, 0x90, 0x92, 0x92, 0xff, 0xd8, 0x60, 0xe5, 0x9b, 0xb6, 0x15, 0xff, 0x79, 0xc1, 0x4a, 0xb0, 0x83, 0x17, 0xc2, 0x29, 0xff, 0x1b, 0xe, 0x1, 0x4d, 0x61, 0xc6, 0xa1, 0x80, 0x5b, 0xf9, 0xf, 0x63, 0xe9, 0x77, 0xa0, 0x45, 0xac, 0xc, 0x38, 0x0, 0xd8, 0x72, 0xa0, 0x5b, 0xd8, 0xf1, 0x2b, 0x10, 0x27, 0xa4, 0x40, 0x92, 0x7c, 0x5, 0x8, 0x2b, 0xc8, 0x77, 0xe4, 0xb, 0xe1, 0xd2, 0x6f, 0x78, 0xbc, 0xf9, 0x87, 0x17, 0x18, 0x50, 0x7, 0x40, 0x1, 0x85, 0x23, 0xa8, 0x4b, 0xbf, 0x3, 0xc3, 0x91, 0x1f, 0x14, 0xd4, 0x78, 0x23, 0xb, 0x2d, 0xa0, 0xff, 0xb3, 0x23, 0x20, 0x22, 0xba, 0x1, 0x39, 0x96, 0x8a, 0xa5, 0x9b, 0x88, 0xa3, 0x56, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char graph_node_position_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, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0x3f, 0x2c, 0xf4, 0x3f, 0x2c, 0x1c, 0x3e, 0x10, 0xcd, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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, 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[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x64, 0x60, 0x60, 0xc2, 0x40, 0x8c, 0xc, 0x0, 0x0, 0xc7, 0x0, 0xf, 0xf5, 0x92, 0x2f, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hslider_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, 0x4b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x57, 0x2e, 0xcb, 0x70, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x68, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x1a, 0x96, 0x95, 0x6b, 0xe2, 0xd5, 0x49, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x4f, 0x83, 0x11, 0x3, 0x1, 0x10, 0xcc, 0x39, 0xef, 0xfe, 0xb, 0x7d, 0xdb, 0xc6, 0x8e, 0x8e, 0xb, 0xf8, 0x9d, 0x70, 0x1d, 0x9c, 0x46, 0x2d, 0xcc, 0x18, 0xea, 0x11, 0x80, 0xda, 0xb7, 0x36, 0xe, 0xf2, 0xbe, 0x2f, 0x80, 0x1c, 0xb0, 0xe5, 0xa2, 0x1f, 0xa5, 0xc0, 0xea, 0x12, 0x2c, 0x4, 0x75, 0x52, 0x80, 0x38, 0x46, 0x2b, 0x65, 0x9d, 0xa7, 0x97, 0xc1, 0xf5, 0x25, 0x82, 0x7a, 0x47, 0x4a, 0x83, 0xac, 0x93, 0x33, 0x8f, 0x83, 0xaa, 0xb2, 0xb4, 0xb8, 0x18, 0xbb, 0x58, 0xff, 0x4e, 0xdb, 0x1, 0xc3, 0xf1, 0x34, 0x3b, 0x7e, 0xbc, 0xb3, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hslider_grabber_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, 0xf3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x96, 0x96, 0xd7, 0x79, 0x70, 0xc6, 0xfb, 0x19, 0xef, 0x3b, 0xf, 0xa6, 0xe5, 0x31, 0x88, 0xa1, 0x2b, 0xe1, 0x4d, 0xcb, 0x9b, 0xf4, 0xa2, 0xef, 0x7f, 0x3b, 0x10, 0xf6, 0xfd, 0x9f, 0xf4, 0x2, 0xa8, 0x84, 0x17, 0x55, 0x81, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0x81, 0xb0, 0x5, 0xa8, 0xa4, 0xf3, 0x20, 0xd0, 0x22, 0x14, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x50, 0x12, 0xc, 0x81, 0xa6, 0xcc, 0x78, 0xf, 0x74, 0xb, 0xa, 0xd0, 0x98, 0xf6, 0x1, 0x59, 0xc1, 0xd4, 0xf, 0xc, 0x1a, 0xa8, 0xa, 0x94, 0xfa, 0x6f, 0x77, 0xc1, 0x15, 0x74, 0xfc, 0xef, 0xbb, 0xc7, 0xa0, 0x82, 0xaa, 0x40, 0xbc, 0x71, 0x7d, 0x3f, 0x5c, 0x41, 0xef, 0xff, 0xde, 0xa3, 0xc, 0x52, 0xa8, 0xa, 0xb8, 0x82, 0x52, 0xa7, 0xfd, 0x69, 0x5, 0x4b, 0xb7, 0xfe, 0x9f, 0xf6, 0xcf, 0x37, 0x85, 0x81, 0x7, 0x2d, 0x1c, 0x14, 0xd, 0xfb, 0x1f, 0x74, 0x82, 0x15, 0x74, 0xfe, 0x9f, 0xf8, 0x80, 0x45, 0x83, 0x81, 0x9, 0x55, 0x1, 0x23, 0x83, 0x48, 0xc5, 0x9c, 0xc9, 0xff, 0x5b, 0x81, 0x70, 0xf2, 0xff, 0x92, 0xa9, 0xc, 0xc2, 0x98, 0x41, 0xcd, 0xca, 0xa3, 0x33, 0xe1, 0x76, 0xcf, 0xff, 0x9e, 0xff, 0x13, 0xef, 0xf0, 0xe8, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0xb, 0xff, 0x39, 0x5f, 0xe6, 0x7c, 0x77, 0x8, 0x45, 0xd8, 0x8f, 0x61, 0x4d, 0x51, 0x71, 0x55, 0x2d, 0x83, 0x18, 0x90, 0x85, 0x3, 0xb0, 0x30, 0x70, 0x3, 0x75, 0xb3, 0x20, 0xb, 0x1, 0x0, 0x86, 0xe, 0x79, 0x54, 0x16, 0xbe, 0x69, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hslider_grabber_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, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x66, 0x9c, 0xe7, 0x7a, 0xd0, 0xe7, 0xbd, 0xcf, 0x7b, 0xd7, 0x83, 0xc6, 0x79, 0xc, 0x62, 0xe8, 0x4a, 0x78, 0x8d, 0xf3, 0x3c, 0x5f, 0xb8, 0xff, 0x77, 0x1, 0x42, 0xf7, 0xff, 0x9e, 0x2f, 0x80, 0x4a, 0x78, 0x51, 0x15, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x81, 0x40, 0x25, 0xae, 0x7, 0x81, 0x16, 0xa1, 0x0, 0x75, 0x9f, 0xf7, 0x2e, 0x30, 0x5, 0x40, 0x53, 0x7c, 0xde, 0x3, 0xdd, 0x82, 0x2, 0x34, 0xbc, 0x3f, 0x20, 0x2b, 0xf0, 0xfe, 0xc0, 0xa0, 0x81, 0xaa, 0x40, 0xc9, 0xe3, 0xb6, 0x2b, 0x92, 0x2, 0xf7, 0x7b, 0xc, 0x2a, 0xa8, 0xa, 0xc4, 0x1d, 0xd7, 0x7b, 0x20, 0xb9, 0xc1, 0xfd, 0x28, 0x83, 0x14, 0xaa, 0x2, 0x2e, 0xcd, 0x54, 0xef, 0x3f, 0xce, 0x60, 0x69, 0xe7, 0xff, 0xde, 0xff, 0xd4, 0x53, 0x18, 0x78, 0xd0, 0xc2, 0x41, 0xd0, 0xd0, 0xe3, 0x1, 0xc4, 0x12, 0xd7, 0xff, 0x9e, 0xf, 0x98, 0x34, 0x18, 0x98, 0x50, 0x15, 0x30, 0x32, 0x88, 0xd8, 0xcc, 0xf1, 0xfa, 0xef, 0xc, 0x84, 0x5e, 0xff, 0xad, 0xa6, 0x32, 0x8, 0x63, 0x6, 0x35, 0x2b, 0x9b, 0x8e, 0xc7, 0x6d, 0xb7, 0xff, 0x6e, 0xff, 0x3d, 0xef, 0xb0, 0xe9, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0x19, 0x7f, 0xbf, 0x2f, 0x7e, 0xdf, 0x15, 0x42, 0x11, 0xf6, 0x63, 0x58, 0x63, 0x59, 0x6c, 0x5b, 0xcb, 0x20, 0x6, 0x64, 0xe1, 0x0, 0x2c, 0xc, 0xdc, 0x40, 0xdd, 0x2c, 0xc8, 0x42, 0x0, 0x4, 0x5c, 0x63, 0x9b, 0xfc, 0xae, 0x1b, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hslider_grabber_hl_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, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x83, 0x83, 0x60, 0xaf, 0xb1, 0x65, 0xbb, 0xca, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x63, 0xb7, 0xc8, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x61, 0xb3, 0xbc, 0x60, 0xb1, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x63, 0xb4, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x69, 0x69, 0x5e, 0xb1, 0xcd, 0x5e, 0xb0, 0xcd, 0x36, 0x63, 0x63, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x60, 0xb2, 0xbd, 0x62, 0xb3, 0xbf, 0x3, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x9b, 0x9a, 0x52, 0x96, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x62, 0xb4, 0xbd, 0x63, 0xb7, 0xbf, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x51, 0x93, 0x92, 0x56, 0x9d, 0x9c, 0x0, 0x0, 0x0, 0x54, 0xa2, 0xc8, 0x4c, 0x94, 0xc2, 0x48, 0x8e, 0xc0, 0x47, 0x8c, 0xbf, 0x4b, 0x93, 0xc2, 0x4b, 0x92, 0xc2, 0x4f, 0x98, 0xc4, 0x4d, 0x96, 0xc3, 0x55, 0xa3, 0xc8, 0x53, 0x9f, 0xc7, 0x49, 0x8f, 0xc0, 0x4e, 0x97, 0xc4, 0x5a, 0xab, 0xcb, 0x5a, 0xac, 0xcc, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0xd4, 0xd, 0x1d, 0x1c, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xd, 0x1c, 0x27, 0x16, 0x6e, 0xc1, 0xef, 0xe8, 0x28, 0xf0, 0xf0, 0x22, 0xdb, 0xde, 0x24, 0x17, 0xaf, 0xc5, 0x1a, 0xa, 0x65, 0xfc, 0xfe, 0x64, 0xc, 0x31, 0xe0, 0xe0, 0x28, 0x2, 0x1, 0x14, 0x9c, 0x95, 0x13, 0x5, 0x2c, 0xdb, 0xdc, 0xb, 0x4f, 0xf4, 0xf7, 0x55, 0x73, 0x7d, 0x4, 0x28, 0xf1, 0xfd, 0xa1, 0x0, 0x0, 0x0, 0x7d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcc, 0x81, 0x6, 0xc3, 0x40, 0x10, 0x84, 0xe1, 0xdd, 0x9d, 0xd9, 0x3d, 0x40, 0x1f, 0xa1, 0x0, 0xd1, 0xbe, 0xff, 0xbb, 0x94, 0x10, 0x29, 0x40, 0x1a, 0x40, 0x9, 0xa, 0xbd, 0x34, 0x7b, 0x39, 0xfa, 0x63, 0xf0, 0x61, 0x4c, 0xfe, 0xfa, 0x81, 0x1a, 0x48, 0x98, 0x36, 0x50, 0x66, 0xda, 0x40, 0x71, 0xab, 0x41, 0x3b, 0xc, 0x56, 0x1b, 0x3a, 0xd4, 0x8e, 0x4d, 0x8, 0x40, 0x6a, 0x64, 0x24, 0x0, 0xb6, 0x83, 0xa1, 0x1, 0x79, 0x0, 0x79, 0xc2, 0x54, 0x44, 0xca, 0x14, 0x91, 0xb0, 0xba, 0xef, 0xa7, 0xee, 0x9e, 0x70, 0x8d, 0xd0, 0x52, 0x2c, 0xe2, 0x99, 0x30, 0x93, 0xb, 0x7d, 0x81, 0x4a, 0x82, 0x8c, 0xc0, 0xba, 0xfa, 0x7b, 0x3c, 0x41, 0xb6, 0xd, 0x78, 0x84, 0x74, 0x98, 0x2f, 0x9f, 0xd7, 0x7d, 0x96, 0xbd, 0x2f, 0xa5, 0x6b, 0x13, 0xc4, 0x35, 0x90, 0x18, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hslider_tick_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xc3, 0x98, 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x38, 0x55, 0x5f, 0x8c, 0xac, 0xb8, 0x81, 0xa2, 0xad, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x8d, 0x8d, 0x8d, 0x82, 0x82, 0x82, 0x4e, 0x4e, 0x4e, 0xc9, 0xf6, 0x7, 0x31, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x31, 0x79, 0x79, 0x1c, 0x7e, 0xed, 0x4b, 0xf4, 0x0, 0x0, 0x0, 0x20, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x9, 0x60, 0x60, 0xb, 0x60, 0x60, 0xf, 0x60, 0x60, 0x6d, 0x60, 0x60, 0x14, 0x60, 0xc0, 0x4, 0x4c, 0x2, 0xc, 0xcc, 0x2, 0x70, 0x65, 0x0, 0x46, 0x9d, 0x2, 0xbe, 0xb7, 0xdf, 0x14, 0x38, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char hsplit_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, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 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 -}; - -static const unsigned char hsplitter_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x40, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6f, 0x69, 0x56, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x1a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x80, 0x5, 0xa9, 0x10, 0xcc, 0x90, 0x6a, 0xd, 0xc6, 0x70, 0x80, 0x4b, 0xcd, 0xa8, 0x9a, 0x51, 0x35, 0x0, 0x78, 0xd5, 0x34, 0xa1, 0x54, 0x8c, 0xd5, 0x84, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_add_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, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xff, 0xe0, 0xff, 0xd0, 0x52, 0x80, 0x10, 0xc4, 0xd, 0x9, 0x2a, 0x18, 0x26, 0xe1, 0x40, 0x18, 0x0, 0x0, 0x5b, 0x26, 0x61, 0x4d, 0xc9, 0xc1, 0x48, 0x81, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_close_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, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_color_pick_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, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x9d, 0x8e, 0x35, 0x82, 0x2, 0x41, 0x10, 0x45, 0x3b, 0xda, 0x3d, 0xca, 0xba, 0x44, 0x2b, 0x70, 0x9, 0xdc, 0xe1, 0x20, 0xe8, 0x91, 0x90, 0x78, 0x6e, 0x40, 0x4c, 0x82, 0x74, 0xff, 0xc2, 0x9d, 0x18, 0xa7, 0x6, 0x77, 0x7b, 0x23, 0x2d, 0xaf, 0x4c, 0xdc, 0xc, 0xbd, 0x65, 0x1e, 0x84, 0x80, 0x19, 0x55, 0x34, 0x60, 0x3e, 0xd0, 0xea, 0x17, 0x3d, 0x4a, 0xc8, 0x80, 0x1a, 0x60, 0xc2, 0x4f, 0xfd, 0x30, 0xe0, 0x1b, 0x2d, 0x16, 0xab, 0xa7, 0x2c, 0xe, 0x41, 0x68, 0xa5, 0xb9, 0xca, 0x91, 0x16, 0x2e, 0x54, 0xe0, 0x59, 0x54, 0x91, 0xfe, 0xa3, 0x3a, 0xff, 0xce, 0xab, 0x5b, 0xf, 0xa0, 0x4, 0x8f, 0x7b, 0x4c, 0xd3, 0x1b, 0xca, 0x32, 0xcc, 0x55, 0x7a, 0xf4, 0x76, 0x42, 0x2b, 0x97, 0x3e, 0xae, 0xfa, 0xdd, 0xd2, 0xd2, 0x8e, 0x72, 0xe1, 0x83, 0xaf, 0x9f, 0xa9, 0x28, 0x7d, 0x5b, 0xe2, 0x2a, 0xd, 0xc3, 0xa2, 0x78, 0xfe, 0x7d, 0x51, 0xfc, 0x0, 0x8a, 0x41, 0xcb, 0x3d, 0xb2, 0xae, 0x1c, 0xd3, 0xc, 0xa5, 0x30, 0x81, 0xc6, 0xda, 0x29, 0x8e, 0x83, 0x34, 0x25, 0x29, 0x4a, 0x46, 0x71, 0x1f, 0x33, 0xbe, 0x51, 0x89, 0xaf, 0x78, 0xe3, 0x97, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_file_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, 0x2, 0x3, 0x0, 0x0, 0x0, 0x62, 0x9d, 0x17, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0x42, 0xf, 0xc7, 0x49, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x88, 0x95, 0xf0, 0xc6, 0x2a, 0x0, 0x0, 0x0, 0x21, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x0, 0x1, 0xae, 0x55, 0x2d, 0x20, 0xa2, 0x13, 0x44, 0x74, 0x39, 0x80, 0x88, 0x9, 0x40, 0xa2, 0x1, 0xc4, 0x5d, 0xb5, 0x80, 0x68, 0x2, 0x4, 0x0, 0x95, 0x34, 0x18, 0xe4, 0x5e, 0x46, 0xf7, 0x27, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_folder_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, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_grid_layout_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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x5, 0x52, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x22, 0xef, 0xbb, 0xbf, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x57, 0x35, 0x4d, 0x30, 0x4d, 0x70, 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, 0x7a, 0x4e, 0x54, 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x22, 0x3f, 0x3e, 0xa, 0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, 0x4d, 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x35, 0x2e, 0x30, 0x22, 0x3e, 0xa, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64, 0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x31, 0x2e, 0x31, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x65, 0x78, 0x69, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x78, 0x69, 0x66, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x6d, 0x70, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x6d, 0x6d, 0x2f, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x73, 0x54, 0x79, 0x70, 0x65, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x23, 0x22, 0xa, 0x20, 0x20, 0x20, 0x65, 0x78, 0x69, 0x66, 0x3a, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x58, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x36, 0x22, 0xa, 0x20, 0x20, 0x20, 0x65, 0x78, 0x69, 0x66, 0x3a, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x59, 0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x36, 0x22, 0xa, 0x20, 0x20, 0x20, 0x65, 0x78, 0x69, 0x66, 0x3a, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x3d, 0x22, 0x31, 0x22, 0xa, 0x20, 0x20, 0x20, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x57, 0x69, 0x64, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x36, 0x22, 0xa, 0x20, 0x20, 0x20, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3d, 0x22, 0x31, 0x36, 0x22, 0xa, 0x20, 0x20, 0x20, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x6e, 0x69, 0x74, 0x3d, 0x22, 0x32, 0x22, 0xa, 0x20, 0x20, 0x20, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x58, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x37, 0x32, 0x2e, 0x30, 0x22, 0xa, 0x20, 0x20, 0x20, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x59, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x37, 0x32, 0x2e, 0x30, 0x22, 0xa, 0x20, 0x20, 0x20, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x3d, 0x22, 0x33, 0x22, 0xa, 0x20, 0x20, 0x20, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x68, 0x6f, 0x70, 0x3a, 0x49, 0x43, 0x43, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x3d, 0x22, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x22, 0xa, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x70, 0x3a, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x44, 0x61, 0x74, 0x65, 0x3d, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x38, 0x2d, 0x31, 0x35, 0x54, 0x30, 0x39, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x30, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x22, 0xa, 0x20, 0x20, 0x20, 0x78, 0x6d, 0x70, 0x3a, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x44, 0x61, 0x74, 0x65, 0x3d, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x38, 0x2d, 0x31, 0x35, 0x54, 0x30, 0x39, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x30, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x22, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x3c, 0x64, 0x63, 0x3a, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x78, 0x6d, 0x6c, 0x3a, 0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x22, 0x78, 0x2d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x22, 0x3e, 0x47, 0x72, 0x69, 0x64, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x41, 0x6c, 0x74, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x64, 0x63, 0x3a, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x3c, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x53, 0x65, 0x71, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x6c, 0x69, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x41, 0x66, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x20, 0x44, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x20, 0x31, 0x2e, 0x39, 0x2e, 0x31, 0x22, 0xa, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x77, 0x68, 0x65, 0x6e, 0x3d, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2d, 0x30, 0x38, 0x2d, 0x31, 0x35, 0x54, 0x30, 0x39, 0x3a, 0x34, 0x31, 0x3a, 0x34, 0x30, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x22, 0x2f, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x53, 0x65, 0x71, 0x3e, 0xa, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x3e, 0xa, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0xa, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0xa, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0xa, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x22, 0x72, 0x22, 0x3f, 0x3e, 0x10, 0xfa, 0x51, 0xae, 0x0, 0x0, 0x1, 0x82, 0x69, 0x43, 0x43, 0x50, 0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2e, 0x31, 0x0, 0x0, 0x28, 0x91, 0x75, 0x91, 0xbf, 0x4b, 0x42, 0x51, 0x14, 0xc7, 0x3f, 0x5a, 0xa1, 0x94, 0x61, 0x50, 0x43, 0x43, 0x83, 0x84, 0x45, 0x83, 0x85, 0x15, 0x84, 0x2d, 0xd, 0x4a, 0xbf, 0xa0, 0x1a, 0xd4, 0x20, 0xab, 0x45, 0x9f, 0xbf, 0x2, 0xb5, 0xc7, 0x7b, 0x4a, 0x48, 0x6b, 0xd0, 0x2a, 0x14, 0x44, 0x2d, 0xfd, 0x1a, 0xea, 0x2f, 0xa8, 0x35, 0x68, 0xe, 0x82, 0xa2, 0x8, 0xa2, 0x2d, 0x68, 0x2e, 0x6a, 0xa9, 0x78, 0x9d, 0xa7, 0x82, 0x11, 0x79, 0x2e, 0xe7, 0x9e, 0xcf, 0xfd, 0xde, 0x7b, 0xe, 0xf7, 0x9e, 0xb, 0xd6, 0x70, 0x46, 0xc9, 0xea, 0x8d, 0x5e, 0xc8, 0xe6, 0xf2, 0x5a, 0x70, 0xd2, 0xef, 0x5a, 0x88, 0x2c, 0xba, 0x6c, 0xcf, 0xd8, 0x71, 0x62, 0xa3, 0xf, 0x5f, 0x54, 0xd1, 0xd5, 0xd9, 0xd0, 0x44, 0x98, 0xba, 0xf6, 0x71, 0x87, 0xc5, 0x8c, 0x37, 0xfd, 0x66, 0xad, 0xfa, 0xe7, 0xfe, 0xb5, 0x96, 0x78, 0x42, 0x57, 0xc0, 0x62, 0x17, 0x1e, 0x53, 0x54, 0x2d, 0x2f, 0x3c, 0x25, 0x3c, 0xb3, 0x96, 0x57, 0x4d, 0xde, 0x16, 0xee, 0x50, 0xd2, 0xd1, 0xb8, 0xf0, 0xa9, 0xb0, 0x47, 0x93, 0xb, 0xa, 0xdf, 0x9a, 0x7a, 0xac, 0xc2, 0x2f, 0x26, 0xa7, 0x2a, 0xfc, 0x65, 0xb2, 0x16, 0xe, 0x6, 0xc0, 0xda, 0x26, 0xec, 0x4a, 0xfd, 0xe2, 0xd8, 0x2f, 0x56, 0xd2, 0x5a, 0x56, 0x58, 0x5e, 0x8e, 0x3b, 0x9b, 0x29, 0x28, 0xd5, 0xfb, 0x98, 0x2f, 0x71, 0x24, 0x72, 0xf3, 0x21, 0x89, 0xdd, 0xe2, 0x5d, 0xe8, 0x4, 0x99, 0xc4, 0x8f, 0x8b, 0x69, 0xc6, 0x9, 0x30, 0xc2, 0x20, 0xa3, 0x32, 0x8f, 0xd0, 0xcf, 0x10, 0x3, 0xb2, 0xa2, 0x4e, 0xbe, 0xb7, 0x9c, 0x3f, 0xc7, 0xaa, 0xe4, 0x2a, 0x32, 0xab, 0x14, 0xd1, 0x58, 0x21, 0x45, 0x9a, 0x3c, 0x1e, 0x51, 0xb, 0x52, 0x3d, 0x21, 0x31, 0x29, 0x7a, 0x42, 0x46, 0x86, 0xa2, 0xd9, 0xff, 0xbf, 0x7d, 0xd5, 0x93, 0xc3, 0x43, 0x95, 0xea, 0xe, 0x3f, 0x34, 0x3d, 0x19, 0xc6, 0x5b, 0xf, 0xd8, 0xb6, 0xe0, 0xbb, 0x64, 0x18, 0x9f, 0x87, 0x86, 0xf1, 0x7d, 0x4, 0xd, 0x8f, 0x70, 0x91, 0xab, 0xe5, 0xaf, 0x1e, 0x80, 0xef, 0x5d, 0xf4, 0x52, 0x4d, 0x73, 0xef, 0x83, 0x73, 0x3, 0xce, 0x2e, 0x6b, 0x5a, 0x6c, 0x7, 0xce, 0x37, 0xa1, 0xf3, 0x41, 0x8d, 0x6a, 0xd1, 0xb2, 0xd4, 0x20, 0x6e, 0x4d, 0x26, 0xe1, 0xf5, 0x4, 0x5a, 0x23, 0xd0, 0x7e, 0xd, 0xcd, 0x4b, 0x95, 0x9e, 0x55, 0xf7, 0x39, 0xbe, 0x87, 0xf0, 0xba, 0x7c, 0xd5, 0x15, 0xec, 0xee, 0x41, 0xaf, 0x9c, 0x77, 0x2e, 0xff, 0x0, 0xa6, 0xc4, 0x68, 0x3, 0x1f, 0xd7, 0x32, 0xd8, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x1, 0x40, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x9d, 0xd2, 0xbd, 0x4a, 0x5d, 0x41, 0x14, 0x86, 0xe1, 0xe7, 0x84, 0xa3, 0x51, 0x22, 0x82, 0x41, 0x8c, 0x12, 0x2, 0xeb, 0x1a, 0x2c, 0x84, 0x4, 0x52, 0x88, 0xb1, 0xd2, 0x26, 0x76, 0x62, 0x67, 0xeb, 0xd, 0x78, 0x19, 0x56, 0x69, 0x82, 0x62, 0x67, 0x25, 0x82, 0x60, 0x97, 0xc2, 0x52, 0x8, 0x24, 0x95, 0x16, 0xa9, 0x6, 0x8c, 0x18, 0xb5, 0x30, 0x88, 0xa7, 0x90, 0x88, 0x5a, 0xec, 0x39, 0x66, 0xd8, 0x7a, 0x54, 0x5c, 0xb0, 0xd8, 0xcc, 0xbb, 0xe7, 0xfb, 0x58, 0x3f, 0xd3, 0x50, 0x8b, 0x94, 0xd2, 0x6b, 0xcc, 0x60, 0x25, 0x22, 0xae, 0xea, 0xff, 0xeb, 0xd1, 0xbc, 0x47, 0xfc, 0xd, 0xbd, 0x58, 0x7e, 0x4c, 0xc, 0x8d, 0x42, 0x3c, 0x82, 0x9f, 0xe8, 0xc1, 0x26, 0xce, 0x3b, 0x68, 0xae, 0xf1, 0x25, 0x22, 0x76, 0xeb, 0x15, 0xf4, 0xa3, 0xf, 0x97, 0x18, 0xce, 0xdf, 0x4e, 0x6, 0xfd, 0x77, 0x2a, 0xc8, 0x55, 0x4, 0xb6, 0xf1, 0x1b, 0x1f, 0x23, 0xe2, 0xfa, 0x49, 0x2d, 0xa4, 0x94, 0x7a, 0x30, 0x98, 0xd9, 0x5b, 0x4c, 0x63, 0x49, 0x35, 0xb, 0x68, 0xe1, 0x2f, 0x46, 0xf0, 0x22, 0xb3, 0x93, 0x88, 0xb8, 0x68, 0x1f, 0x36, 0xb0, 0x9f, 0x73, 0x7, 0x87, 0xf8, 0x53, 0xb0, 0x23, 0x2c, 0xe0, 0xa0, 0x60, 0xeb, 0xa, 0xb7, 0x1, 0xac, 0x60, 0x34, 0x5f, 0x1a, 0x52, 0xcd, 0x67, 0x16, 0x73, 0xe8, 0xca, 0x6c, 0x3f, 0xdf, 0x59, 0xcd, 0x9a, 0x5b, 0x83, 0x67, 0x47, 0x7b, 0xb, 0xa7, 0x98, 0xcf, 0x9, 0xc7, 0xaa, 0x2d, 0xac, 0xe5, 0xf3, 0xbf, 0xcc, 0xde, 0xe1, 0x47, 0x66, 0x5b, 0xa5, 0xc1, 0x67, 0xff, 0x87, 0x78, 0xa5, 0x9a, 0xc1, 0x1a, 0x5e, 0x65, 0xd6, 0xc2, 0x24, 0x3e, 0xe4, 0x36, 0xe0, 0x84, 0xda, 0x1a, 0x1f, 0x8a, 0x94, 0xd2, 0x6, 0xc6, 0x30, 0x1e, 0x11, 0xbf, 0xda, 0xbc, 0x7c, 0x89, 0xc3, 0x58, 0x44, 0x77, 0x7, 0x8f, 0x2e, 0x4c, 0xa9, 0x1e, 0xd1, 0xa7, 0x88, 0xd8, 0x29, 0x5b, 0xa0, 0x7a, 0xc2, 0xf1, 0x80, 0x41, 0x23, 0xe7, 0x4b, 0xbc, 0x79, 0x6a, 0xe5, 0x65, 0xb, 0x5f, 0x53, 0x4a, 0x67, 0x29, 0xa5, 0xf7, 0x25, 0x6f, 0x76, 0x12, 0xdc, 0x13, 0x7b, 0x98, 0x88, 0x88, 0xef, 0x25, 0xbc, 0x1, 0x6c, 0x4d, 0x56, 0x9e, 0x2a, 0x4e, 0x48, 0xae, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_grid_minimap_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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0x2, 0xd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x75, 0x93, 0x31, 0x68, 0x14, 0x51, 0x10, 0x86, 0xbf, 0xd9, 0xd, 0xbb, 0xde, 0x76, 0x82, 0x21, 0xf8, 0xe0, 0xbc, 0x5d, 0x8b, 0x80, 0x69, 0x6c, 0xd2, 0x5a, 0x6a, 0x91, 0xc3, 0xd2, 0x46, 0x22, 0x8, 0x9, 0x89, 0x70, 0x85, 0x10, 0x41, 0xd, 0x24, 0x45, 0xb0, 0xb, 0x68, 0x11, 0x14, 0x24, 0x10, 0x22, 0x62, 0x21, 0x41, 0xe, 0x4b, 0x21, 0xa4, 0xb7, 0x49, 0x17, 0xb1, 0x8, 0xb9, 0xdd, 0xc7, 0x86, 0x33, 0x21, 0xe1, 0x3a, 0x8f, 0x64, 0x61, 0x6f, 0x2c, 0xbc, 0x3b, 0x36, 0xb9, 0xdc, 0xc0, 0x2b, 0xde, 0xcc, 0xfc, 0xf3, 0xff, 0xfc, 0xcc, 0x48, 0xa3, 0xd1, 0x78, 0x20, 0x22, 0x13, 0xbe, 0xef, 0xaf, 0xdf, 0xac, 0xd7, 0x1f, 0xe1, 0x38, 0xd3, 0xa8, 0x2a, 0xf0, 0x45, 0x6a, 0xb5, 0xcf, 0x5c, 0x11, 0xcd, 0x66, 0x33, 0x38, 0x3f, 0x3f, 0x9f, 0x13, 0x91, 0x7d, 0xb1, 0xd6, 0x6e, 0xaa, 0xea, 0xd3, 0xe0, 0xe8, 0xe8, 0xde, 0xe8, 0xee, 0xee, 0x37, 0xc0, 0xe9, 0xf6, 0x75, 0xf0, 0xfd, 0x9, 0x99, 0x9d, 0x6d, 0x15, 0x81, 0x59, 0x96, 0x3d, 0x3, 0x5e, 0x2, 0x63, 0x22, 0xf2, 0x69, 0xa4, 0x57, 0x1c, 0xdd, 0xdb, 0xfb, 0x5b, 0x0, 0x3, 0x38, 0x67, 0x41, 0x30, 0x11, 0xc7, 0xf1, 0x13, 0x0, 0x11, 0x71, 0xb2, 0x2c, 0x7b, 0xd8, 0xad, 0xad, 0x2, 0x6f, 0xb9, 0x0, 0x38, 0x3c, 0xfc, 0x5, 0x9c, 0xf6, 0xff, 0x22, 0x27, 0x27, 0xe3, 0xe3, 0x7f, 0xa, 0x3, 0x67, 0x45, 0xe4, 0xbb, 0xe7, 0x79, 0xb7, 0xc3, 0x30, 0x7c, 0xd7, 0x67, 0xe9, 0xe3, 0x67, 0x66, 0x5c, 0x60, 0x1, 0x50, 0x40, 0x51, 0x7d, 0x71, 0x6b, 0x72, 0xf2, 0x20, 0x8a, 0xa2, 0xf9, 0x28, 0x8a, 0xe6, 0x1, 0x3a, 0x9d, 0xce, 0x4f, 0x63, 0x4c, 0x3b, 0x4d, 0xd3, 0xd2, 0xc0, 0x80, 0x3c, 0xcf, 0xf, 0x92, 0xa9, 0xa9, 0x31, 0x60, 0x5, 0x58, 0x91, 0x5a, 0xed, 0xc7, 0x15, 0xfe, 0x95, 0xac, 0xb5, 0xcf, 0xf3, 0x3c, 0x3f, 0xe8, 0x25, 0x46, 0xa, 0xc5, 0xd, 0x11, 0x59, 0xb3, 0xd5, 0xea, 0x1b, 0xa0, 0x95, 0x54, 0xab, 0x5b, 0x97, 0xd1, 0x22, 0xb2, 0xa6, 0xaa, 0x6d, 0x60, 0xd, 0x58, 0xba, 0xa0, 0x20, 0xc, 0xc3, 0x65, 0xd7, 0x75, 0x23, 0xe0, 0x2e, 0xb0, 0x1, 0x5c, 0xbf, 0xf4, 0x0, 0xbe, 0xba, 0xae, 0x1b, 0x85, 0x61, 0xb8, 0x3c, 0xa0, 0x20, 0x4d, 0xd3, 0x52, 0xb9, 0x5c, 0x6e, 0xc5, 0x71, 0xbc, 0x23, 0x22, 0xd3, 0x61, 0x18, 0xde, 0x2f, 0xb2, 0x27, 0x49, 0xa2, 0xaa, 0xba, 0x53, 0x2e, 0x97, 0x5b, 0x69, 0x9a, 0x96, 0xf2, 0x3c, 0x1f, 0xf0, 0xc0, 0x5a, 0x6b, 0x5f, 0x1, 0x25, 0x86, 0x84, 0xe3, 0x38, 0x9e, 0xb5, 0x76, 0x2e, 0xcf, 0xf3, 0xfd, 0x1, 0x5, 0x22, 0xb2, 0xa1, 0xaa, 0x4b, 0x22, 0x72, 0xad, 0xcb, 0x38, 0xe0, 0x81, 0xaa, 0x7e, 0x0, 0xce, 0x44, 0xe4, 0xbd, 0xaa, 0xbe, 0xbe, 0xa0, 0xa0, 0x52, 0xa9, 0x2c, 0x7a, 0x9e, 0x17, 0x1, 0x3d, 0xe0, 0x55, 0x1e, 0x6c, 0x79, 0x9e, 0x17, 0x55, 0x2a, 0x95, 0xc5, 0x1, 0x5, 0xcd, 0x66, 0x33, 0x30, 0xc6, 0x9c, 0xc6, 0x71, 0xbc, 0x2d, 0x22, 0x8f, 0x87, 0x78, 0xb0, 0x6d, 0x8c, 0x39, 0xed, 0xae, 0x74, 0xdf, 0x83, 0x3a, 0x70, 0x9c, 0x65, 0x59, 0x23, 0x49, 0x92, 0x5, 0x11, 0x9, 0x86, 0x79, 0x20, 0x22, 0x41, 0x92, 0x24, 0xb, 0x59, 0x96, 0x35, 0x80, 0x63, 0xa0, 0x2e, 0x3d, 0xf6, 0xc2, 0x91, 0xdc, 0x0, 0x5c, 0x55, 0x5d, 0xbf, 0x4, 0x9e, 0x3, 0x72, 0xfe, 0xaf, 0xfb, 0xaa, 0xe7, 0x79, 0x1f, 0x8d, 0x31, 0x6d, 0x29, 0x36, 0xf5, 0xce, 0x14, 0xb8, 0x33, 0x44, 0xc4, 0x6f, 0xdf, 0xf7, 0xd7, 0x8d, 0x31, 0xed, 0x5e, 0xe2, 0x1f, 0xb, 0x5c, 0xe2, 0xcb, 0xd, 0x9b, 0x69, 0xcb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_parent_folder_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, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_reload_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, 0xb1, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x50, 0x35, 0xba, 0xc2, 0x40, 0x10, 0x7e, 0xcd, 0x33, 0x5c, 0xca, 0x1c, 0x21, 0x87, 0xc1, 0xa9, 0xd3, 0x23, 0x47, 0xca, 0x69, 0xb0, 0x6, 0x77, 0xdb, 0xfd, 0x17, 0x2f, 0x91, 0x3e, 0xee, 0xd2, 0xc1, 0x4e, 0xb5, 0xdf, 0xcc, 0xaf, 0x5f, 0x9f, 0x7c, 0xdb, 0x5f, 0xda, 0x44, 0x17, 0x2f, 0x75, 0xba, 0xa4, 0xb1, 0xfd, 0xf5, 0xad, 0x8f, 0x1c, 0x86, 0x90, 0x5c, 0x33, 0x38, 0x72, 0x1e, 0xb4, 0xbe, 0x66, 0x28, 0xad, 0xe2, 0xab, 0x38, 0xcd, 0x63, 0xa9, 0x9d, 0xb8, 0x58, 0x68, 0x53, 0x5b, 0x1f, 0x33, 0xd6, 0x9f, 0xa5, 0xc1, 0x20, 0x91, 0xba, 0x7d, 0x80, 0x1e, 0x24, 0x94, 0xdc, 0x92, 0xa4, 0x2, 0x9, 0x1d, 0xe7, 0xe0, 0x9, 0x69, 0x15, 0xf7, 0x58, 0x4e, 0x40, 0xc2, 0xc3, 0x58, 0x8a, 0xb6, 0x31, 0xd1, 0x39, 0xd8, 0x27, 0xed, 0x83, 0x5b, 0x14, 0x33, 0x7d, 0x3d, 0xbb, 0x45, 0x5d, 0x12, 0x55, 0x97, 0x4, 0xe3, 0xb5, 0xf4, 0x8c, 0x77, 0xd6, 0xa7, 0x2c, 0x3b, 0x78, 0x4c, 0x52, 0x81, 0xa, 0x8e, 0x3a, 0xa9, 0x6a, 0x6b, 0xc, 0xe6, 0x3f, 0xa1, 0x8d, 0x86, 0x16, 0xe5, 0x39, 0x78, 0xa2, 0x4d, 0xea, 0xe, 0xfa, 0xdd, 0xa7, 0x0, 0x90, 0x4f, 0x8b, 0xd0, 0xe1, 0x9e, 0x1b, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_snap_grid_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, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf3, 0xf3, 0xf3, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x85, 0x85, 0xff, 0x83, 0x83, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x80, 0x80, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0xff, 0xff, 0xa, 0xa5, 0x43, 0x1, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xff, 0x1d, 0xac, 0xf2, 0xaf, 0x27, 0xed, 0xff, 0xee, 0xb4, 0x1b, 0x1c, 0xb6, 0xaa, 0xf1, 0x50, 0xa6, 0xdd, 0x5f, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x2, 0x40, 0x23, 0xd3, 0x60, 0x0, 0x40, 0xc, 0x3, 0xaf, 0x76, 0x93, 0xfd, 0x97, 0x7d, 0x9b, 0x55, 0x70, 0x12, 0x62, 0xaf, 0x68, 0x0, 0xc4, 0xe9, 0x3c, 0x1, 0x67, 0xf7, 0x17, 0x20, 0x95, 0xd6, 0xc6, 0xee, 0x80, 0x74, 0xde, 0x7b, 0x1f, 0x24, 0xb0, 0x64, 0x29, 0x1f, 0x53, 0x2e, 0xbe, 0x6e, 0x80, 0xf6, 0x19, 0x90, 0x9e, 0x36, 0x8b, 0xf7, 0xc0, 0x5c, 0xdf, 0x0, 0x66, 0x60, 0xae, 0xf3, 0xb9, 0x1, 0xfb, 0xe9, 0x1, 0xa6, 0x26, 0x1, 0xcd, 0x30, 0x66, 0x63, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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[] = { - 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, 0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x31, 0xe0, 0xc1, 0x7f, 0x3c, 0x90, 0xb0, 0x82, 0x11, 0x2, 0x0, 0xbf, 0x57, 0x36, 0x25, 0x52, 0x24, 0x7b, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_zoom_more_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, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xf, 0x84, 0x43, 0x4a, 0x1, 0x42, 0x10, 0xf, 0x24, 0xa8, 0x60, 0x78, 0x84, 0x3, 0x61, 0x0, 0x0, 0xca, 0x3a, 0x6d, 0x8d, 0x50, 0x1e, 0x9a, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char icon_zoom_reset_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, 0x33, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0xa, 0x3c, 0xc, 0x7b, 0xf0, 0xff, 0xc1, 0x7f, 0x9c, 0x22, 0xcf, 0x44, 0x1e, 0xbc, 0x84, 0x72, 0xb1, 0x8b, 0x3c, 0x58, 0x5, 0xe4, 0x40, 0xb8, 0x38, 0x45, 0x18, 0x60, 0x5c, 0x84, 0x30, 0x59, 0xa, 0xa0, 0x80, 0x6e, 0xa, 0x86, 0x92, 0x2f, 0x8, 0x3, 0x0, 0x69, 0xc8, 0x86, 0x87, 0x72, 0xca, 0x85, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char indeterminate_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, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xfe, 0xfe, 0xfe, 0x98, 0x4d, 0x2d, 0x9a, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1c, 0x77, 0x5e, 0x7f, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x85, 0xcf, 0xc1, 0x12, 0x80, 0x20, 0x8, 0x45, 0xd1, 0x4, 0x14, 0xd, 0xc5, 0xfa, 0xff, 0x9f, 0x8d, 0x9c, 0x6c, 0x9a, 0xb4, 0xe9, 0x2e, 0xcf, 0x42, 0x9e, 0xcb, 0x32, 0xe4, 0x0, 0xc9, 0xb7, 0x8, 0xc1, 0x19, 0x40, 0x60, 0xc9, 0x2d, 0xe1, 0x0, 0x6, 0xc8, 0x45, 0x6b, 0x4b, 0xb, 0xa3, 0x1, 0x89, 0x6e, 0x57, 0x2a, 0x64, 0xe0, 0x73, 0xed, 0x50, 0xb3, 0x9f, 0xc3, 0x7e, 0xf7, 0x5, 0x7f, 0x6f, 0xc, 0x67, 0x9f, 0xc3, 0xe2, 0x39, 0xc, 0x52, 0xec, 0xd3, 0xd7, 0x4, 0xb3, 0xcf, 0xbd, 0x3a, 0x0, 0xa0, 0xa2, 0x8, 0xbc, 0xf6, 0x84, 0x3a, 0x9d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char line_edit_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char line_edit_clear_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, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char line_edit_disabled_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, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char mini_checkerboard_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, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x98, 0xa0, 0xbd, 0x0, 0x0, 0x0, 0x17, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0x0, 0x5, 0xff, 0xa1, 0x60, 0xa0, 0x4, 0x60, 0xc, 0x98, 0xc4, 0x0, 0x9, 0x0, 0x0, 0x44, 0x81, 0xef, 0x81, 0xc1, 0x26, 0x8e, 0x8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char option_arrow_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0xdc, 0x4f, 0xb8, 0x9f, 0x80, 0x45, 0xf8, 0xa1, 0xf6, 0x83, 0x2f, 0xf, 0xbe, 0x3c, 0xd4, 0x46, 0x13, 0x7e, 0xc1, 0xfd, 0xe0, 0xea, 0x83, 0xff, 0x40, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xfa, 0xf9, 0x40, 0x41, 0x30, 0x7c, 0x38, 0x9f, 0x81, 0x12, 0x80, 0x69, 0x14, 0x61, 0xcb, 0x11, 0xce, 0xc5, 0xe5, 0x41, 0xc2, 0x0, 0x0, 0x95, 0x48, 0x37, 0x91, 0x1f, 0xec, 0x77, 0x5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char option_button_disabled_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, 0x2f, 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, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xd3, 0xa7, 0xd4, 0x88, 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, 0xec, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x8e, 0x5, 0x4e, 0x0, 0x31, 0x10, 0x45, 0xff, 0xef, 0x56, 0xc2, 0xe2, 0xee, 0x4e, 0x3c, 0xc8, 0xd, 0xb8, 0x38, 0xa7, 0xc0, 0xdd, 0xdd, 0x5d, 0xbb, 0x94, 0x4c, 0xd2, 0xc1, 0xdf, 0x4a, 0x47, 0x5e, 0x27, 0xc3, 0xc, 0x80, 0x64, 0x24, 0xb8, 0xc7, 0x4f, 0x2c, 0x6b, 0xd5, 0x90, 0xff, 0xdd, 0x23, 0x7e, 0xc1, 0xa2, 0xb6, 0x64, 0xad, 0x26, 0x82, 0xc6, 0xef, 0x45, 0xbc, 0xe3, 0x1, 0x2c, 0x69, 0x9b, 0xc8, 0x7f, 0x5, 0x36, 0x1e, 0x41, 0x84, 0xd6, 0x4, 0x25, 0x90, 0xb7, 0x39, 0x6c, 0x4c, 0x2f, 0xbe, 0x68, 0xdf, 0x13, 0xa1, 0x9e, 0xc8, 0xa4, 0xb7, 0xe7, 0x47, 0x93, 0x63, 0x1b, 0xf9, 0xdc, 0x8, 0x88, 0x60, 0xbf, 0x4, 0xff, 0xd2, 0x56, 0x93, 0xe3, 0xb7, 0xb2, 0xf6, 0x2c, 0x36, 0x1, 0x16, 0xf4, 0x5f, 0x42, 0xc4, 0x17, 0x8f, 0xb5, 0xc0, 0xa5, 0x8, 0x30, 0x5f, 0xc2, 0x5d, 0xcf, 0xc9, 0xd, 0x74, 0x87, 0x8b, 0x5e, 0x56, 0x22, 0x24, 0xf7, 0x6d, 0xc2, 0xd1, 0x80, 0x26, 0x27, 0x5d, 0x5b, 0x67, 0x7d, 0x2f, 0x80, 0x4d, 0xc9, 0x7f, 0x9, 0x63, 0xa7, 0x61, 0x23, 0xc7, 0x74, 0x3d, 0xf, 0xae, 0x41, 0x84, 0x6f, 0x13, 0xe6, 0x26, 0xfa, 0x36, 0x46, 0x73, 0xbc, 0xba, 0x3b, 0xd6, 0xca, 0x8, 0xd0, 0xd6, 0x36, 0x4e, 0x35, 0xeb, 0xad, 0xd7, 0xb0, 0x60, 0x72, 0xdc, 0xda, 0x9c, 0x2, 0x67, 0x76, 0x64, 0x82, 0x99, 0x9b, 0xb6, 0x80, 0xb0, 0x7e, 0x8d, 0xf6, 0x5a, 0xdd, 0xe1, 0xb5, 0xba, 0xba, 0xb1, 0x0, 0xcd, 0xc7, 0x50, 0x23, 0xeb, 0xfb, 0x7f, 0xb4, 0xc8, 0x22, 0x18, 0xdd, 0x0, 0xd5, 0xec, 0x4e, 0x53, 0xc6, 0x18, 0x44, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char option_button_disabled_mirrored_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, 0x2f, 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, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x5a, 0x5a, 0x5a, 0x3e, 0x3e, 0x3e, 0x2a, 0x2a, 0x30, 0x59, 0x59, 0x59, 0x22, 0x22, 0x27, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x4a, 0x4a, 0x4a, 0x36, 0x36, 0x36, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x62, 0x62, 0x62, 0x56, 0x56, 0x56, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x54, 0x54, 0x54, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x3a, 0x3a, 0x3a, 0x49, 0x49, 0x49, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x47, 0x47, 0x47, 0x39, 0x39, 0x39, 0x46, 0x46, 0x46, 0xda, 0x9d, 0x96, 0x5c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0xf, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0xef, 0x50, 0x45, 0x4b, 0x6d, 0xe, 0x95, 0xa6, 0xa5, 0x40, 0xab, 0x15, 0x5, 0xdc, 0xc0, 0x8a, 0xa, 0xb8, 0xa1, 0xef, 0xff, 0xc, 0x86, 0x90, 0x30, 0xc, 0x17, 0xfa, 0x5d, 0x26, 0xff, 0x4c, 0x4e, 0x12, 0x41, 0x98, 0x32, 0x33, 0x1b, 0x98, 0x9b, 0x17, 0x83, 0x84, 0x18, 0xa, 0x47, 0xa2, 0xb1, 0xe9, 0x7d, 0x21, 0x16, 0x58, 0x58, 0x5c, 0x5a, 0x96, 0x24, 0x29, 0x9e, 0x48, 0xa6, 0xd2, 0x2b, 0x51, 0xb2, 0xb4, 0xba, 0x96, 0xc9, 0xca, 0x87, 0x47, 0x8c, 0x9c, 0xc9, 0x1d, 0x9f, 0x30, 0xeb, 0x1b, 0xe9, 0x8, 0x9, 0x36, 0x15, 0x25, 0xaf, 0x9e, 0x6a, 0x8c, 0x8a, 0xa0, 0xa0, 0x8f, 0x9c, 0x15, 0xb7, 0x52, 0x61, 0x12, 0xa8, 0x6, 0x56, 0x4d, 0x2b, 0xcb, 0x98, 0xb8, 0xc4, 0x3, 0x5d, 0x2f, 0x24, 0x43, 0xc3, 0xc0, 0x6, 0xcd, 0x2a, 0xcb, 0x4c, 0xe, 0x4a, 0x95, 0x2a, 0x57, 0x49, 0x88, 0x24, 0x70, 0xc, 0x70, 0xcf, 0xcb, 0x17, 0x8c, 0x5, 0x8e, 0x77, 0xc9, 0x79, 0xf1, 0x20, 0x9, 0x80, 0x4, 0xd6, 0x64, 0x50, 0xbb, 0xe2, 0x6a, 0xd2, 0x30, 0xc0, 0xd7, 0xf5, 0x89, 0x19, 0xb4, 0x46, 0xbe, 0x79, 0xc3, 0x35, 0x69, 0x80, 0x6e, 0x15, 0xb8, 0x33, 0xef, 0x99, 0x7, 0x84, 0x5a, 0x6d, 0xae, 0x45, 0x8f, 0xb0, 0x1f, 0xed, 0x86, 0x3f, 0xbe, 0xa6, 0x6f, 0x3f, 0x75, 0x9e, 0xb9, 0xe, 0x1d, 0xd2, 0x78, 0x79, 0xed, 0x62, 0xf0, 0x19, 0xdc, 0xeb, 0x17, 0xdf, 0xb8, 0x77, 0x7a, 0xcd, 0xed, 0x8f, 0xcf, 0x5e, 0xb7, 0x8e, 0x19, 0xe5, 0xab, 0x3f, 0xf8, 0x66, 0xda, 0x3b, 0xf4, 0xa1, 0x76, 0xf7, 0x90, 0xe3, 0x8e, 0x67, 0x70, 0x1, 0xbc, 0x9f, 0x91, 0xc1, 0xfe, 0x1, 0x7d, 0xea, 0x7f, 0x3f, 0xeb, 0xef, 0xef, 0xfe, 0x5, 0xd6, 0xe3, 0x56, 0x89, 0xd8, 0x62, 0xb6, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char option_button_hover_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, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xd3, 0x26, 0x54, 0x35, 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, 0xe5, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x91, 0x43, 0x62, 0xc5, 0x60, 0x18, 0x45, 0xef, 0x8d, 0x51, 0xdb, 0xee, 0x46, 0xca, 0x6d, 0x77, 0x58, 0xce, 0x6b, 0xdb, 0x7c, 0x8a, 0xad, 0xea, 0x44, 0x1f, 0x4e, 0x92, 0x1f, 0x4c, 0x0, 0xe0, 0x9, 0x61, 0xf0, 0x89, 0x32, 0x12, 0xcd, 0xd4, 0x8, 0xef, 0x1f, 0x35, 0x54, 0xa0, 0x68, 0x1a, 0x34, 0x89, 0x8, 0x86, 0xa4, 0xd, 0x57, 0xb4, 0xdf, 0x79, 0x5, 0x89, 0x94, 0xba, 0xf9, 0xb3, 0xc0, 0xce, 0xeb, 0xf0, 0x17, 0x1c, 0xab, 0x11, 0x9, 0x1a, 0xf9, 0x96, 0x84, 0x5d, 0x5e, 0x43, 0x15, 0x7, 0x2e, 0x42, 0x41, 0x51, 0xd3, 0xbe, 0x67, 0xd5, 0x6b, 0x42, 0x3a, 0x38, 0x9b, 0xf5, 0x2e, 0x20, 0xfa, 0x5, 0x33, 0x41, 0x69, 0xf4, 0xeb, 0x49, 0x6c, 0x19, 0xe6, 0xbd, 0xdd, 0xd, 0x48, 0xa0, 0x92, 0xb, 0x36, 0x72, 0x6a, 0x26, 0xf0, 0x14, 0xa, 0x10, 0x72, 0xe1, 0x7d, 0xf4, 0xf6, 0x35, 0x1b, 0xc3, 0xe3, 0x18, 0x9d, 0x50, 0xf0, 0xe4, 0xc2, 0x17, 0xae, 0x27, 0xd3, 0xe4, 0x6e, 0xe8, 0xf8, 0x7e, 0xbc, 0x1, 0x48, 0x9e, 0x57, 0xf8, 0xc5, 0xfc, 0xbd, 0x7a, 0x98, 0xc4, 0x94, 0x47, 0xbf, 0xe4, 0xce, 0x48, 0x8, 0x6e, 0x69, 0x91, 0x63, 0x47, 0x73, 0x49, 0xbc, 0x77, 0x3e, 0xd7, 0x4b, 0x3b, 0x12, 0x36, 0x16, 0xb3, 0x85, 0x6a, 0x68, 0xce, 0x39, 0x62, 0xc6, 0xba, 0x3d, 0x8d, 0xe7, 0x91, 0x20, 0xac, 0xad, 0xa6, 0xc2, 0xe, 0x6, 0xcc, 0x74, 0xc, 0x2d, 0xe7, 0xf9, 0x55, 0x2, 0x28, 0x94, 0x37, 0xab, 0xee, 0xa1, 0xcc, 0xbf, 0xdb, 0xed, 0x3, 0x70, 0xe6, 0x4f, 0x4a, 0xc3, 0xed, 0xed, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char option_button_hover_mirrored_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, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x5f, 0x5a, 0x6c, 0x42, 0x40, 0x4b, 0x2a, 0x2a, 0x30, 0x5f, 0x5a, 0x6b, 0x22, 0x22, 0x27, 0x56, 0x53, 0x64, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x57, 0x53, 0x63, 0x3e, 0x3c, 0x47, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x67, 0x63, 0x76, 0x5a, 0x56, 0x67, 0x5b, 0x57, 0x68, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x5a, 0x56, 0x65, 0x48, 0x45, 0x51, 0x49, 0x46, 0x52, 0x4d, 0x4a, 0x57, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x5b, 0x57, 0x66, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x54, 0x50, 0x5f, 0x43, 0x40, 0x4c, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x53, 0x4f, 0x5f, 0x42, 0x3f, 0x4c, 0x43, 0x3f, 0x4d, 0x47, 0x43, 0x51, 0x5f, 0x5a, 0x6c, 0x53, 0x4f, 0x5e, 0x53, 0x50, 0x5f, 0x68, 0x6, 0xa3, 0x65, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x15, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0x8b, 0xb, 0x54, 0x51, 0x4b, 0x6d, 0x8f, 0x60, 0xd3, 0x62, 0xc1, 0x56, 0x11, 0x5, 0xdc, 0xd0, 0x5a, 0x14, 0x70, 0x5f, 0xdf, 0xff, 0x1, 0xc, 0x69, 0xc2, 0x30, 0x5c, 0xe8, 0x77, 0x99, 0xfc, 0x33, 0x39, 0x49, 0x38, 0x6e, 0xc8, 0xc8, 0xa8, 0x6f, 0x6c, 0x9c, 0xf7, 0x63, 0x7c, 0x20, 0x18, 0xa, 0x47, 0x86, 0xf7, 0xb9, 0x88, 0x6f, 0x62, 0x72, 0x6a, 0x5a, 0x10, 0x84, 0x68, 0x2c, 0x9e, 0x48, 0xce, 0x84, 0xf1, 0xd2, 0xec, 0x5c, 0x3a, 0x23, 0x6e, 0x6c, 0x52, 0x62, 0x3a, 0xbb, 0xb5, 0xed, 0xd9, 0x99, 0x5f, 0x48, 0x86, 0x70, 0xb0, 0x28, 0x49, 0x39, 0x79, 0x57, 0xa1, 0x64, 0x15, 0xf6, 0xf2, 0x9e, 0xc2, 0xfe, 0x52, 0x22, 0x88, 0x3, 0x59, 0x43, 0xb2, 0x6e, 0x64, 0x28, 0x1d, 0x15, 0x59, 0x90, 0x2f, 0x1c, 0xc4, 0x3, 0xbd, 0xc0, 0x4, 0xc5, 0x28, 0x89, 0x54, 0x16, 0x8a, 0xe5, 0x43, 0xa6, 0x1c, 0xe3, 0x71, 0x60, 0x69, 0x60, 0x1f, 0x95, 0x8e, 0x29, 0x3, 0xac, 0xca, 0x9, 0x53, 0x89, 0xfa, 0x71, 0x0, 0x38, 0x30, 0x6, 0x83, 0xea, 0x29, 0x53, 0x15, 0x7a, 0x1, 0x3a, 0xab, 0xd, 0xcc, 0xa0, 0xd4, 0x73, 0x8d, 0x73, 0xa6, 0x41, 0x2, 0xf5, 0x42, 0x82, 0x4b, 0xfd, 0x8a, 0xba, 0x56, 0xd5, 0xe6, 0xd, 0xd3, 0x24, 0x47, 0x98, 0xb7, 0x66, 0xdd, 0xe9, 0x5f, 0xd3, 0x31, 0xef, 0xdc, 0x16, 0xe3, 0x92, 0x21, 0xb5, 0xfb, 0x87, 0x36, 0x2, 0x87, 0x42, 0x9d, 0xee, 0xe3, 0x13, 0xd5, 0x72, 0xc9, 0x35, 0x97, 0x9f, 0x5f, 0x3a, 0xed, 0x1a, 0xa2, 0xa4, 0xd7, 0xee, 0xdb, 0xbb, 0xe7, 0xe3, 0x33, 0x45, 0x1e, 0x6a, 0x65, 0x55, 0xb5, 0xec, 0xfe, 0xc, 0x36, 0xc0, 0xd7, 0xb7, 0xe7, 0x67, 0x6d, 0x9d, 0x3c, 0xf5, 0xbf, 0x9f, 0xf5, 0xf7, 0x77, 0xff, 0x2, 0xa7, 0xc5, 0x58, 0xc8, 0x6e, 0x59, 0x8, 0x3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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_normal_mirrored_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, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x56, 0x53, 0x61, 0x3c, 0x3a, 0x45, 0x2a, 0x2a, 0x30, 0x56, 0x52, 0x60, 0x22, 0x22, 0x27, 0x47, 0x44, 0x52, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x47, 0x44, 0x50, 0x33, 0x31, 0x3a, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x5d, 0x5a, 0x6a, 0x51, 0x4f, 0x5d, 0x52, 0x50, 0x5d, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x51, 0x4e, 0x5b, 0x41, 0x3e, 0x49, 0x42, 0x3e, 0x4a, 0x46, 0x42, 0x4e, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x50, 0x4e, 0x5a, 0x40, 0x3e, 0x48, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x47, 0x43, 0x50, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x44, 0x41, 0x4e, 0x36, 0x34, 0x3e, 0x4e, 0x4b, 0x58, 0x44, 0x41, 0x4c, 0x44, 0x42, 0x4d, 0x7d, 0x2e, 0xcf, 0xc5, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x13, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0xe1, 0x2a, 0x5a, 0x56, 0x97, 0xb2, 0xb9, 0x8b, 0xb, 0x54, 0x51, 0x4b, 0x6d, 0xf, 0x68, 0xd3, 0xa2, 0x5, 0x5b, 0x40, 0x14, 0x70, 0x3, 0x2b, 0x2a, 0xe0, 0xbe, 0xbd, 0xff, 0x3, 0x18, 0xd2, 0x84, 0x61, 0xb8, 0xd0, 0xef, 0x32, 0xf9, 0x67, 0x72, 0x92, 0x70, 0xdc, 0x88, 0xb1, 0x71, 0xcf, 0xc4, 0x24, 0xef, 0xc5, 0x78, 0x9f, 0x3f, 0x10, 0xc, 0x8d, 0xee, 0x73, 0x21, 0xcf, 0xd4, 0xf4, 0xcc, 0xac, 0x20, 0x8, 0xe1, 0x48, 0x34, 0x16, 0x9f, 0xb, 0xe2, 0xa5, 0xf9, 0x85, 0x64, 0x4a, 0xdc, 0xda, 0xa6, 0xc4, 0x64, 0x7a, 0x67, 0xd7, 0xb5, 0xb7, 0xb8, 0x14, 0xf, 0xe0, 0x60, 0x59, 0x92, 0x32, 0xf2, 0xbe, 0x42, 0xc9, 0x2a, 0x64, 0x73, 0xae, 0x83, 0xc3, 0x95, 0x98, 0x1f, 0x7, 0xb2, 0x86, 0x64, 0xdd, 0x48, 0x51, 0x3a, 0xca, 0x1f, 0x1d, 0x53, 0xb9, 0x6c, 0xd4, 0xd7, 0xf, 0x4c, 0x50, 0x8c, 0x82, 0x48, 0xa5, 0x21, 0x5f, 0x3c, 0x61, 0x8a, 0x11, 0x1e, 0x7, 0x96, 0x6, 0x76, 0xa9, 0x50, 0xa6, 0xc, 0xb0, 0x2a, 0xa7, 0x4c, 0x25, 0xec, 0xc5, 0x1, 0xe0, 0xc0, 0x18, 0xe, 0xaa, 0x67, 0x4c, 0x55, 0xe8, 0x7, 0xe8, 0xbc, 0x36, 0x34, 0x83, 0x52, 0xcf, 0x34, 0x2e, 0x98, 0x6, 0x9, 0xd4, 0x4b, 0x9, 0xae, 0xf4, 0x6b, 0xea, 0x46, 0x55, 0x9b, 0x2d, 0xa6, 0x49, 0x8e, 0x30, 0x6f, 0xcd, 0xba, 0x33, 0xb8, 0xa6, 0x63, 0xde, 0xb5, 0xef, 0x99, 0x36, 0x19, 0x52, 0x7b, 0x78, 0xec, 0x20, 0x70, 0x28, 0xd4, 0xed, 0x3d, 0x3d, 0x33, 0x2f, 0xe4, 0x9a, 0xab, 0xaf, 0x6f, 0xdd, 0x4e, 0xd, 0x51, 0xd2, 0x7b, 0xef, 0xe3, 0x93, 0x6a, 0x25, 0xc8, 0x43, 0xad, 0xad, 0xab, 0x96, 0x3d, 0x98, 0xc1, 0x6, 0xf8, 0xfa, 0x76, 0xfd, 0x6c, 0x6c, 0x92, 0xa7, 0xfe, 0xf7, 0xb3, 0xfe, 0xfe, 0xee, 0x5f, 0xa1, 0x5f, 0x59, 0xbd, 0x75, 0x41, 0x2b, 0xf8, 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 option_button_pressed_mirrored_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, 0x2d, 0x2d, 0x34, 0x2b, 0x2b, 0x31, 0x46, 0x43, 0x4f, 0x31, 0x2f, 0x38, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x50, 0x22, 0x22, 0x27, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x29, 0x24, 0x24, 0x28, 0x56, 0x52, 0x60, 0x3c, 0x3a, 0x45, 0x2a, 0x2a, 0x30, 0x2c, 0x2c, 0x32, 0x2d, 0x2d, 0x34, 0x2e, 0x2e, 0x35, 0x2f, 0x2f, 0x36, 0x2a, 0x2a, 0x31, 0x4c, 0x49, 0x56, 0x42, 0x40, 0x4b, 0x43, 0x40, 0x4c, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2b, 0x27, 0x27, 0x2d, 0x28, 0x28, 0x2e, 0x29, 0x29, 0x2f, 0x24, 0x24, 0x28, 0x26, 0x26, 0x2b, 0x44, 0x41, 0x4c, 0x36, 0x34, 0x3d, 0x3a, 0x38, 0x41, 0x22, 0x22, 0x26, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x26, 0x26, 0x2c, 0x44, 0x41, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4e, 0x22, 0x22, 0x27, 0x2d, 0x2d, 0x33, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x27, 0x27, 0x2b, 0x29, 0x29, 0x2e, 0x2c, 0x2c, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x20, 0x20, 0x25, 0x24, 0x24, 0x29, 0x24, 0x24, 0x2a, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x20, 0x20, 0x23, 0x29, 0x29, 0x2d, 0x2b, 0x2b, 0x30, 0x28, 0x28, 0x2d, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x1e, 0x1e, 0x22, 0x27, 0x27, 0x2c, 0x22, 0x22, 0x28, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x1d, 0x1d, 0x21, 0x20, 0x20, 0x24, 0x23, 0x23, 0x27, 0x21, 0x21, 0x25, 0x21, 0x21, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x3f, 0x3d, 0x48, 0x50, 0x4d, 0x5a, 0x1e, 0x1e, 0x21, 0x1f, 0x1f, 0x23, 0x1f, 0x1f, 0x24, 0x50, 0x4e, 0x5a, 0x40, 0x3e, 0x48, 0x41, 0x3e, 0x49, 0x45, 0x42, 0x4d, 0x5d, 0x59, 0x69, 0x51, 0x4e, 0x5b, 0x52, 0x4e, 0x5c, 0x49, 0x7e, 0x80, 0x9, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2, 0x7, 0xd, 0x16, 0x1d, 0x22, 0x24, 0x1f, 0x19, 0x11, 0xa, 0x4, 0x1b, 0x2d, 0x3a, 0x43, 0x48, 0x47, 0x46, 0x3f, 0x34, 0x25, 0x15, 0x49, 0xe6, 0xef, 0x77, 0xe6, 0xef, 0xe7, 0xef, 0x4a, 0xe4, 0xef, 0x77, 0x7e, 0xb9, 0x59, 0x66, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x1, 0x14, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x3, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x40, 0xc0, 0xc6, 0xc1, 0xc9, 0xc5, 0xcd, 0x83, 0x2e, 0xcf, 0xc0, 0xc3, 0xcc, 0xcb, 0xc7, 0x2f, 0x20, 0x28, 0x28, 0x28, 0x24, 0x2c, 0x22, 0x2a, 0x26, 0xce, 0xd, 0x14, 0x92, 0x90, 0x54, 0x51, 0x55, 0x53, 0xd7, 0x80, 0x2, 0x35, 0x15, 0x4d, 0x2d, 0x6d, 0x8, 0xd0, 0x91, 0x92, 0x16, 0xe3, 0x2, 0x2a, 0x90, 0xd1, 0xd5, 0xd5, 0xd3, 0x37, 0x30, 0x84, 0x2, 0x7d, 0x23, 0x63, 0x13, 0x53, 0x28, 0x30, 0x93, 0x15, 0xe5, 0x4, 0x2a, 0xd0, 0x37, 0xb7, 0xd0, 0xb7, 0xb4, 0x52, 0x85, 0x2, 0x4b, 0xb, 0x6b, 0x1b, 0x5b, 0x18, 0xb0, 0x13, 0xe1, 0x0, 0x29, 0xb0, 0x37, 0x36, 0xb4, 0x72, 0x50, 0x83, 0x2, 0x4d, 0x63, 0x6b, 0x47, 0x27, 0x18, 0x70, 0x14, 0x66, 0x3, 0x2a, 0x70, 0x36, 0x37, 0x76, 0x71, 0x75, 0x70, 0x83, 0x2, 0x2b, 0x63, 0x67, 0x77, 0xf, 0x18, 0x70, 0x17, 0x62, 0x7, 0x2a, 0x30, 0x6, 0x2a, 0xb0, 0x42, 0x56, 0xe0, 0xe9, 0x5, 0x3, 0x9e, 0x82, 0x20, 0x5, 0x16, 0xde, 0x3e, 0x48, 0x6e, 0x30, 0xf4, 0xd5, 0xf3, 0xf3, 0x87, 0x1, 0x3f, 0xb0, 0x2, 0xa3, 0x0, 0x5d, 0xe3, 0x40, 0xcb, 0x20, 0x28, 0x8, 0x36, 0x32, 0xa, 0x9, 0x85, 0x81, 0x10, 0xb0, 0x15, 0xf6, 0x61, 0xf6, 0xbe, 0xe1, 0x70, 0x6f, 0x86, 0xdb, 0x47, 0x44, 0x46, 0xc1, 0x40, 0x24, 0xd8, 0x91, 0xe6, 0xd1, 0x31, 0xb1, 0x16, 0xc6, 0xe1, 0x50, 0x60, 0x11, 0x17, 0x9f, 0x90, 0x8, 0x5, 0x49, 0xc9, 0x60, 0x6f, 0xca, 0xa5, 0xa4, 0xc6, 0xc5, 0xfa, 0x58, 0x40, 0x81, 0x6e, 0x5a, 0x7c, 0x7a, 0x6, 0x4, 0x64, 0x66, 0xc9, 0x83, 0x3, 0x4a, 0x41, 0xd1, 0xc8, 0xd9, 0x5, 0xee, 0x6, 0x17, 0x63, 0xe3, 0xec, 0x1c, 0x8, 0xc8, 0x55, 0x52, 0x6, 0x7, 0x35, 0xc1, 0xc8, 0xc2, 0x1f, 0xdd, 0x0, 0xa5, 0xe, 0x59, 0xe5, 0x7f, 0xe9, 0xa4, 0x40, 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, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0xcd, 0x4b, 0xe, 0x80, 0x20, 0xc, 0x45, 0xd1, 0x9b, 0xea, 0xbe, 0x40, 0x97, 0x87, 0x8b, 0xae, 0x13, 0x34, 0x88, 0x1f, 0xa, 0x9d, 0xf8, 0x92, 0xe, 0xcf, 0x2d, 0x80, 0xda, 0x4f, 0x14, 0x26, 0x5, 0x49, 0x14, 0x53, 0xcb, 0x42, 0x58, 0xe, 0xbc, 0x51, 0xcd, 0x85, 0x9b, 0x81, 0x16, 0xfe, 0xc, 0x58, 0xf0, 0x6b, 0xc0, 0x8a, 0x1f, 0x3, 0x3d, 0xf8, 0x16, 0xe8, 0xc5, 0x97, 0x40, 0x81, 0x53, 0x9b, 0x55, 0x81, 0x91, 0xcf, 0x67, 0x20, 0xc6, 0x75, 0xe8, 0x73, 0x9e, 0xc, 0x7f, 0xce, 0x73, 0x61, 0x80, 0xd9, 0x83, 0x7f, 0xb0, 0x1d, 0xec, 0x30, 0xf0, 0x78, 0x5a, 0x7, 0xa8, 0x21, 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 -}; - -static const unsigned char picker_cursor_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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 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, 0xb9, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0x8f, 0x3d, 0x8a, 0xc2, 0x50, 0x18, 0x45, 0xcf, 0x6b, 0x92, 0x2a, 0x19, 0xd4, 0xa4, 0x72, 0x47, 0x3, 0x42, 0xc0, 0x9f, 0x55, 0x44, 0x17, 0x24, 0x88, 0xee, 0x24, 0x53, 0x4d, 0x7e, 0xa, 0xbf, 0x94, 0xd6, 0x71, 0x5, 0xf2, 0x5e, 0x7f, 0x2d, 0xa2, 0xa2, 0xe0, 0x29, 0xef, 0xb9, 0xcd, 0x1, 0x40, 0xb1, 0x76, 0x6a, 0x14, 0x14, 0xd4, 0x68, 0xab, 0x98, 0x11, 0xcd, 0xd5, 0xef, 0x9b, 0xac, 0x27, 0x10, 0x32, 0x3b, 0xb4, 0x32, 0xcd, 0xc7, 0x77, 0xff, 0xfb, 0xc7, 0xc0, 0x92, 0x84, 0x84, 0x82, 0xcb, 0xa2, 0x92, 0x29, 0x46, 0xbb, 0x7d, 0xc3, 0xc0, 0x94, 0x27, 0x13, 0x86, 0x63, 0xa7, 0x12, 0xb5, 0x59, 0xcf, 0x8a, 0x77, 0xd6, 0xb9, 0xa9, 0x46, 0xde, 0x5, 0x92, 0xf, 0x91, 0x3a, 0x2f, 0xff, 0x4d, 0xfc, 0x38, 0xaf, 0x1b, 0x6a, 0x33, 0xa3, 0xf8, 0x10, 0x9b, 0xfc, 0xac, 0x1a, 0x6d, 0xf, 0x2d, 0x17, 0x26, 0xaf, 0x79, 0xc6, 0xf5, 0xd4, 0xa9, 0x44, 0xb1, 0x6c, 0x51, 0x31, 0xb0, 0x26, 0x25, 0x65, 0xc3, 0xb5, 0xa8, 0x64, 0x8a, 0xc6, 0x40, 0x3b, 0x76, 0xb9, 0xb9, 0xe0, 0x42, 0x7e, 0x3e, 0x75, 0x8f, 0x40, 0x0, 0x45, 0x2a, 0x55, 0xcb, 0xcb, 0xeb, 0x5f, 0xa5, 0x22, 0x80, 0x3b, 0xa0, 0x2c, 0x6c, 0xa1, 0x40, 0x2f, 0xda, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char popup_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, 0xa2, 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, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x36, 0xc6, 0xc8, 0x93, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8f, 0x35, 0x82, 0xc3, 0x0, 0xc, 0x4, 0x77, 0x24, 0x85, 0xba, 0xe3, 0xff, 0xff, 0xee, 0xca, 0x74, 0x41, 0xdb, 0x32, 0xf3, 0x94, 0x82, 0x85, 0x10, 0x1d, 0x92, 0xb2, 0x3, 0x8e, 0x95, 0x77, 0x93, 0x6c, 0x28, 0xed, 0x15, 0x54, 0x67, 0xa6, 0x41, 0x3e, 0x8, 0x9c, 0xc3, 0xf4, 0xf2, 0xf6, 0x2a, 0x80, 0xf8, 0x44, 0x2d, 0x79, 0x2d, 0x20, 0xe0, 0x2, 0xa8, 0xc3, 0x2e, 0x6f, 0xc, 0x9e, 0x4c, 0x3c, 0x21, 0x4, 0xd8, 0xf0, 0x2, 0x28, 0x24, 0xcd, 0x3, 0xa9, 0x19, 0x64, 0xce, 0x83, 0x4c, 0x45, 0xe6, 0x69, 0x1a, 0xd8, 0xe9, 0x99, 0x96, 0x7f, 0x77, 0x37, 0x59, 0x83, 0xcc, 0xef, 0x7f, 0x89, 0x1f, 0x8e, 0xbf, 0x95, 0xd3, 0x1d, 0xf0, 0xff, 0x7a, 0x63, 0x7e, 0x86, 0xcb, 0x73, 0x8c, 0x5e, 0xee, 0xca, 0xb1, 0xad, 0x5f, 0x3, 0xaf, 0xdb, 0x49, 0x94, 0x4b, 0x90, 0x40, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char popup_bg_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x67, 0x7a, 0x85, 0x66, 0x7a, 0x86, 0x68, 0x7b, 0x86, 0x57, 0x51, 0x51, 0x4c, 0x42, 0x40, 0x4d, 0x43, 0x41, 0x56, 0x4c, 0x4b, 0x4d, 0x44, 0x41, 0x4e, 0x44, 0x42, 0x4f, 0x45, 0x43, 0x67, 0x7b, 0x87, 0x4f, 0x44, 0x43, 0x50, 0x45, 0x44, 0x52, 0x46, 0x44, 0x51, 0x46, 0x45, 0x4b, 0x40, 0x3f, 0x51, 0x47, 0x45, 0x52, 0x48, 0x46, 0x53, 0x48, 0x47, 0x4b, 0x41, 0x3f, 0x54, 0x49, 0x46, 0x55, 0x4a, 0x47, 0x55, 0x49, 0x47, 0x68, 0x7c, 0x88, 0x4a, 0x40, 0x3e, 0x55, 0x4b, 0x49, 0x56, 0x4d, 0x4b, 0x53, 0x49, 0x47, 0x50, 0x46, 0x44, 0x4a, 0x41, 0x3e, 0x48, 0x3e, 0x3c, 0x4b, 0x42, 0x3f, 0x49, 0x3f, 0x3d, 0x46, 0x3d, 0x3c, 0x47, 0x3d, 0x3b, 0x47, 0x3e, 0x3b, 0x49, 0x40, 0x3d, 0x45, 0x3c, 0x3b, 0x46, 0x3c, 0x3a, 0xdd, 0x63, 0x56, 0x8d, 0x0, 0x0, 0x0, 0xad, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2d, 0x88, 0x35, 0x42, 0x4, 0x0, 0xc, 0x4, 0x77, 0x93, 0x9c, 0xbb, 0xf4, 0xc8, 0xff, 0xdf, 0x84, 0xb5, 0xb8, 0x5b, 0x84, 0x0, 0x37, 0xc5, 0xca, 0x10, 0xd, 0xc9, 0xce, 0xaa, 0xea, 0x24, 0x40, 0xca, 0x41, 0x64, 0x2b, 0x5, 0x87, 0x34, 0xa8, 0x88, 0x54, 0xef, 0x82, 0x80, 0x89, 0x34, 0x36, 0x96, 0xe0, 0x14, 0xa4, 0x12, 0xa6, 0x24, 0x18, 0xe1, 0xa8, 0x50, 0x59, 0x7c, 0x73, 0x30, 0x50, 0x55, 0x4a, 0x31, 0xd7, 0xb4, 0x89, 0xa1, 0x51, 0xb2, 0x9c, 0x1, 0x2c, 0x4, 0x83, 0x15, 0x12, 0x30, 0xab, 0xe9, 0x5a, 0x1, 0xb4, 0x40, 0xa1, 0x29, 0xbe, 0x75, 0xe, 0x5a, 0x70, 0xbe, 0x2a, 0xff, 0x12, 0xf1, 0xef, 0x1b, 0x5f, 0x8d, 0x5b, 0x68, 0xd, 0xdc, 0xe3, 0xf1, 0x71, 0x16, 0x3e, 0x5b, 0xc8, 0x33, 0xa9, 0xc7, 0xbc, 0x7f, 0xa4, 0x22, 0x6a, 0xb5, 0x90, 0xcb, 0xb2, 0x1a, 0x25, 0x67, 0x8b, 0x8f, 0x6f, 0xf8, 0x64, 0xa8, 0x35, 0x7a, 0x25, 0xa8, 0xa7, 0x1, 0x38, 0xc, 0xcc, 0xab, 0x4c, 0x5, 0xea, 0xe3, 0x76, 0x2f, 0x54, 0x93, 0xf3, 0xf, 0x4f, 0x10, 0x8d, 0x4c, 0x16, 0x9d, 0xcf, 0x1f, 0xd1, 0xf9, 0x3, 0x34, 0xc8, 0x4a, 0xb4, 0x1d, 0xb, 0xcd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char popup_window_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x48, 0x8, 0x3, 0x0, 0x0, 0x0, 0xb7, 0x21, 0x97, 0x38, 0x0, 0x0, 0x1, 0x71, 0x69, 0x43, 0x43, 0x50, 0x69, 0x63, 0x63, 0x0, 0x0, 0x28, 0x91, 0x75, 0x91, 0x3d, 0x4b, 0xc3, 0x50, 0x14, 0x86, 0xdf, 0xb6, 0x96, 0x8a, 0xad, 0x74, 0xd0, 0x41, 0xa4, 0x43, 0x86, 0x2a, 0xe, 0x2d, 0x14, 0x5, 0x71, 0xd4, 0x3a, 0x74, 0x29, 0x52, 0x6a, 0x5, 0xab, 0x2e, 0xc9, 0x6d, 0xd2, 0xa, 0x49, 0x1a, 0x6e, 0x52, 0xa4, 0xb8, 0xa, 0x2e, 0xe, 0x5, 0x7, 0xd1, 0xc5, 0xaf, 0xc1, 0x7f, 0xa0, 0xab, 0xe0, 0xaa, 0x20, 0x8, 0x8a, 0x20, 0xe2, 0xe2, 0x1f, 0xf0, 0x6b, 0x91, 0x12, 0xcf, 0x6d, 0xa, 0x2d, 0xd2, 0x9e, 0x70, 0x73, 0x1e, 0xde, 0x7b, 0xde, 0xc3, 0xbd, 0xe7, 0x2, 0xfe, 0xac, 0xce, 0xc, 0x7b, 0x20, 0x5, 0x18, 0xa6, 0xc3, 0xf3, 0x99, 0xb4, 0xb4, 0x5a, 0x5c, 0x93, 0x42, 0xef, 0x8, 0x21, 0x6, 0x1f, 0x82, 0x8, 0xcb, 0xcc, 0xb6, 0x16, 0x72, 0xb9, 0x2c, 0xfa, 0xc6, 0xcf, 0x23, 0x55, 0x52, 0x3c, 0x24, 0x45, 0xaf, 0xfe, 0x75, 0x3d, 0x23, 0x5c, 0x52, 0x6d, 0x6, 0xf8, 0x6, 0x89, 0x67, 0x99, 0xc5, 0x1d, 0xe2, 0x79, 0xe2, 0xec, 0x96, 0x63, 0x9, 0xde, 0x23, 0x1e, 0x65, 0x15, 0xb9, 0x44, 0x7c, 0x42, 0x9c, 0xe0, 0x74, 0x40, 0xe2, 0x5b, 0xa1, 0x2b, 0x1e, 0xbf, 0x9, 0x2e, 0x7b, 0xfc, 0x25, 0x98, 0x17, 0xf2, 0x8b, 0x80, 0x5f, 0xf4, 0x94, 0xca, 0x5d, 0xac, 0x74, 0x31, 0xab, 0x70, 0x83, 0x78, 0x8a, 0x38, 0x6e, 0xe8, 0x35, 0xd6, 0x3e, 0x8f, 0xb8, 0x49, 0x44, 0x35, 0x57, 0x96, 0x29, 0x8f, 0xd3, 0x8a, 0xc1, 0x46, 0x1e, 0x19, 0xa4, 0x21, 0x41, 0x41, 0xd, 0x9b, 0xd0, 0xe1, 0x20, 0x49, 0xd9, 0xa4, 0x99, 0xf5, 0xf6, 0xa5, 0x5a, 0xbe, 0x25, 0x54, 0xc9, 0xc3, 0xe8, 0x6f, 0xa1, 0xe, 0x4e, 0x8e, 0x32, 0x2a, 0xe4, 0x4d, 0x90, 0x5a, 0xa3, 0xae, 0x2a, 0x65, 0x8d, 0x74, 0x95, 0x3e, 0x1d, 0x75, 0x31, 0xf7, 0xff, 0xf3, 0xb4, 0xb5, 0x99, 0x69, 0xaf, 0x7b, 0x24, 0xd, 0x4, 0x5f, 0x5d, 0xf7, 0x73, 0x2, 0x8, 0xed, 0x3, 0xcd, 0x86, 0xeb, 0xfe, 0x9e, 0xba, 0x6e, 0xf3, 0xc, 0x8, 0xbc, 0x0, 0xd7, 0x66, 0xc7, 0x5f, 0xa5, 0x39, 0xcd, 0x7d, 0x93, 0xde, 0xe8, 0x68, 0xf1, 0x63, 0x20, 0xba, 0x3, 0x5c, 0xde, 0x74, 0x34, 0xe5, 0x0, 0xb8, 0xda, 0x5, 0xc6, 0x9e, 0x2d, 0x99, 0xcb, 0x2d, 0x29, 0x40, 0xcb, 0xaf, 0x69, 0xc0, 0xc7, 0x5, 0x30, 0x5c, 0x4, 0x46, 0xee, 0x81, 0xa1, 0x75, 0x6f, 0x56, 0xed, 0x7d, 0x9c, 0x3f, 0x1, 0x85, 0x6d, 0x7a, 0xa2, 0x3b, 0xe0, 0xf0, 0x8, 0x98, 0xa4, 0xfa, 0xe8, 0xc6, 0x1f, 0x7b, 0xde, 0x67, 0xcd, 0xda, 0x7, 0x3a, 0xfb, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x0, 0xa8, 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, 0xe8, 0xe5, 0xf1, 0x20, 0x1e, 0x23, 0x21, 0x1f, 0x24, 0x21, 0x1f, 0x24, 0x22, 0x20, 0x25, 0x1d, 0x1a, 0x20, 0x1d, 0x1d, 0x20, 0x1d, 0x1d, 0x22, 0x20, 0x1d, 0x22, 0x20, 0x1d, 0x25, 0x20, 0x20, 0x25, 0x22, 0x20, 0x25, 0xcf, 0xcd, 0xd7, 0xd0, 0xcd, 0xd7, 0xd1, 0xce, 0xd8, 0xd3, 0xd0, 0xda, 0xd4, 0xd1, 0xdb, 0xd5, 0xd3, 0xdc, 0xd6, 0xd4, 0xdd, 0xd7, 0xd6, 0xdf, 0xd9, 0xd7, 0xdf, 0xda, 0xd8, 0xe0, 0xdc, 0xda, 0xe2, 0xdd, 0xdb, 0xe3, 0xde, 0xdc, 0xe4, 0xdf, 0xdd, 0xe5, 0xe0, 0xde, 0xe6, 0xe1, 0xdf, 0xe7, 0xe2, 0xdf, 0xeb, 0xe3, 0xe1, 0xe8, 0xe5, 0xe2, 0xeb, 0xe8, 0xe5, 0xf1, 0xe8, 0x4e, 0x48, 0xd9, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0x9, 0xc, 0xf, 0x15, 0x1d, 0x20, 0x22, 0x25, 0x30, 0x3a, 0x44, 0x52, 0x57, 0x59, 0x5b, 0x5e, 0x60, 0x7e, 0x92, 0x9e, 0x9f, 0xa1, 0xa2, 0xb8, 0xba, 0xbd, 0xbf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf5, 0xb3, 0x97, 0xfb, 0x0, 0x0, 0x0, 0xea, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x96, 0x31, 0xe, 0x83, 0x30, 0xc, 0x45, 0x6d, 0x93, 0xc2, 0xda, 0xb5, 0x13, 0xf7, 0x3f, 0x4a, 0xef, 0xd0, 0xa5, 0xc7, 0x28, 0x10, 0xff, 0xe, 0x4, 0x35, 0x88, 0xc6, 0x25, 0x48, 0x34, 0x2a, 0x6a, 0x16, 0x86, 0x3c, 0x7d, 0xbe, 0xfd, 0x49, 0x30, 0x51, 0xe1, 0xc5, 0xe1, 0xc1, 0xc2, 0xcc, 0xbc, 0xd8, 0x6, 0x0, 0x5, 0x22, 0x94, 0xa5, 0x72, 0xc2, 0x22, 0xb, 0x54, 0x15, 0x3a, 0x78, 0x5, 0x11, 0x91, 0x1b, 0xd1, 0xea, 0xd4, 0xf0, 0x1b, 0x59, 0x0, 0xc0, 0x83, 0x10, 0xa1, 0xe2, 0x9a, 0xba, 0x4d, 0x58, 0xbc, 0x13, 0x54, 0x23, 0x55, 0xe1, 0x36, 0x38, 0x5a, 0x14, 0xd3, 0xde, 0x64, 0x7c, 0x59, 0x40, 0x99, 0xc9, 0x27, 0x54, 0xdd, 0xe4, 0x4b, 0x26, 0x55, 0xa3, 0x49, 0x73, 0x55, 0x61, 0xc2, 0x3a, 0x94, 0xc8, 0x42, 0x27, 0x27, 0xaf, 0xc6, 0x7c, 0x4a, 0xcb, 0x85, 0xaa, 0xea, 0x34, 0x5a, 0xf7, 0xcc, 0xd8, 0xa0, 0x7a, 0x5c, 0x34, 0x23, 0x82, 0x1d, 0xd2, 0xda, 0x11, 0x3d, 0xaf, 0x45, 0xdd, 0x35, 0x89, 0x5c, 0x6, 0x1f, 0x9d, 0x2, 0xfb, 0xaa, 0x98, 0x1d, 0x98, 0x2, 0x68, 0x13, 0x32, 0x90, 0xf5, 0xd7, 0xdb, 0x6, 0xd4, 0x8, 0x0, 0xf4, 0xd, 0x3, 0xc5, 0xcb, 0xfa, 0xa5, 0xe, 0x1c, 0x34, 0xad, 0xff, 0xe7, 0x72, 0x44, 0x14, 0x40, 0x97, 0x46, 0x3a, 0x8c, 0x63, 0xcd, 0x9e, 0x69, 0x41, 0x2d, 0x34, 0x6c, 0xe6, 0xa3, 0xb0, 0x50, 0x64, 0xab, 0x86, 0x3f, 0x82, 0xb3, 0xc6, 0xc7, 0x7e, 0x88, 0x66, 0x42, 0x78, 0x82, 0x31, 0x94, 0x22, 0x77, 0xd4, 0x2d, 0xbe, 0x9e, 0x25, 0x9d, 0x7b, 0xb0, 0x59, 0x6d, 0x9f, 0xd7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char progress_bar_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, 0x0, 0x30, 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, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0x43, 0x65, 0x7d, 0x95, 0x0, 0x0, 0x0, 0xc, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xb7, 0x4a, 0xbe, 0x33, 0x0, 0x0, 0x0, 0x35, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x9f, 0xe, 0x66, 0xb4, 0x33, 0x7a, 0xb4, 0x1b, 0x0, 0x19, 0x7f, 0x3b, 0x28, 0x64, 0xc0, 0xd, 0x84, 0x5b, 0x1, 0xb7, 0x14, 0xee, 0xc, 0x0, 0xcf, 0x9d, 0x26, 0xff, 0xba, 0xcb, 0x90, 0x39, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char progress_fill_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, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x4c, 0xc0, 0xc1, 0xc2, 0xf8, 0xa5, 0xfa, 0x7f, 0x8, 0x34, 0x7e, 0xe9, 0x60, 0x81, 0xa1, 0xc0, 0xf8, 0xa5, 0xca, 0x17, 0x85, 0xff, 0x10, 0xa8, 0xf2, 0xc5, 0xf8, 0x25, 0x86, 0x2, 0x75, 0xa0, 0x4, 0x1c, 0x2, 0x4d, 0xa1, 0xbf, 0x2, 0x4c, 0x47, 0x12, 0xf6, 0xe6, 0x20, 0x2, 0x0, 0x78, 0x21, 0x45, 0x61, 0x7f, 0xe2, 0xad, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char radio_checked_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, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char radio_checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x83, 0xac, 0xe9, 0xaf, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x20, 0xe, 0xf0, 0x8, 0x2, 0x1, 0xf, 0x9c, 0x2b, 0x2c, 0x8, 0x5, 0xc2, 0x50, 0x1, 0xb0, 0x34, 0x58, 0x11, 0x5c, 0xbd, 0x10, 0x3f, 0x10, 0x8, 0xc1, 0x74, 0x1, 0x65, 0xf8, 0xc1, 0x0, 0xa6, 0x4, 0x28, 0x1, 0x11, 0xe0, 0xc1, 0x2d, 0x80, 0xa6, 0x5, 0xc3, 0x50, 0xc, 0x6b, 0x31, 0x1d, 0x86, 0xe1, 0x74, 0xfc, 0x0, 0x0, 0x1b, 0xc, 0x7, 0xb9, 0xa, 0x5e, 0x2e, 0x12, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char radio_unchecked_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, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char radio_unchecked_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x54, 0x54, 0x54, 0xad, 0xad, 0xad, 0x80, 0x80, 0x81, 0x64, 0x64, 0x64, 0xf4, 0x17, 0x36, 0x28, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1b, 0xfc, 0xf6, 0x4, 0xd4, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x7d, 0x8d, 0xb1, 0x11, 0x80, 0x40, 0xc, 0xc3, 0x94, 0xd, 0x12, 0x60, 0x1, 0xc4, 0x4, 0xb0, 0x1, 0xfb, 0x2f, 0x45, 0xe5, 0x3b, 0xaa, 0x57, 0xe5, 0xc2, 0xb6, 0x20, 0xc0, 0xcc, 0xc, 0x40, 0xed, 0x7a, 0x37, 0x70, 0xa8, 0xbe, 0x50, 0x9b, 0xea, 0xd9, 0xd4, 0xa3, 0x7a, 0x35, 0xa5, 0xaa, 0xeb, 0x90, 0x72, 0xe6, 0x39, 0xfc, 0x2b, 0x22, 0xd, 0x1f, 0xe7, 0x64, 0xa, 0x5d, 0x6c, 0xfe, 0xc1, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_bg_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, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_button_left_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, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x2e, 0x28, 0xa3, 0x7b, 0xf7, 0x6e, 0x8, 0xa3, 0xe7, 0xcc, 0x19, 0xa8, 0x14, 0x9c, 0xd1, 0x7b, 0x17, 0xa6, 0xfd, 0x1d, 0x86, 0x81, 0x60, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0xcc, 0x4e, 0x3f, 0xd1, 0x4, 0x90, 0xbf, 0x60, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_button_left_hl_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, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0x58, 0xf9, 0x63, 0x6a, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x42, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x9e, 0x3d, 0x10, 0x46, 0xf7, 0xee, 0xdb, 0x10, 0x46, 0xef, 0xdd, 0xbb, 0x50, 0xa9, 0x77, 0xef, 0xa0, 0x8c, 0xfe, 0x7f, 0x30, 0xed, 0xff, 0x81, 0xc, 0x4c, 0x93, 0x11, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfe, 0x97, 0x40, 0xa0, 0xa6, 0x84, 0xb1, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_button_right_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, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x18, 0x33, 0x61, 0x8c, 0x59, 0x2b, 0xa0, 0x8c, 0x5d, 0xab, 0xa0, 0x8c, 0xdd, 0xbb, 0x77, 0x40, 0x18, 0x67, 0xce, 0x9c, 0x80, 0x31, 0xa0, 0x52, 0x77, 0x6f, 0x40, 0x19, 0xef, 0x30, 0xc, 0x84, 0x30, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfd, 0x36, 0x40, 0x93, 0xf1, 0x83, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_button_right_hl_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, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0x2e, 0x3d, 0xb1, 0x1e, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xc8, 0x31, 0x16, 0x2, 0x20, 0x10, 0x43, 0xc1, 0xe4, 0x83, 0xdc, 0xff, 0xb8, 0x88, 0xf, 0x57, 0xb, 0x8b, 0x80, 0x53, 0xe, 0xf2, 0x23, 0x18, 0xc6, 0x68, 0x61, 0x74, 0xca, 0xa, 0x2e, 0x74, 0xf9, 0x85, 0xfd, 0x17, 0x5c, 0x81, 0xfb, 0x11, 0x2a, 0xaa, 0x65, 0x80, 0x20, 0xc3, 0x5f, 0xaf, 0x2b, 0x96, 0xce, 0x78, 0xea, 0x88, 0x39, 0x95, 0x91, 0x70, 0x29, 0x94, 0xd9, 0x6b, 0x87, 0xf5, 0xfe, 0x0, 0xc6, 0xa7, 0x1b, 0x66, 0x7b, 0x42, 0xf1, 0x14, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char scroll_grabber_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, 0x5d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0x59, 0x61, 0x5b, 0x59, 0x61, 0x5a, 0x58, 0x60, 0x59, 0x57, 0x5f, 0x5a, 0x58, 0x60, 0x5a, 0x58, 0x60, 0x57, 0x56, 0x5e, 0x58, 0x56, 0x5e, 0x56, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x55, 0x53, 0x5b, 0x55, 0x53, 0x5b, 0x54, 0x53, 0x5b, 0x55, 0x54, 0x5c, 0x54, 0x52, 0x5a, 0x55, 0x53, 0x5b, 0x5a, 0x58, 0x60, 0x56, 0x54, 0x5c, 0x54, 0x53, 0x5a, 0x55, 0x53, 0x5b, 0x53, 0x51, 0x59, 0x52, 0x51, 0x59, 0x52, 0x50, 0x58, 0x51, 0x50, 0x58, 0x51, 0x4f, 0x57, 0x50, 0x4e, 0x56, 0x4f, 0x4d, 0x55, 0x50, 0x4f, 0x57, 0x54, 0x52, 0x5a, 0xae, 0x55, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2c, 0xb8, 0xf4, 0x2e, 0xf2, 0xb8, 0xf4, 0xf5, 0xf4, 0xf5, 0xb8, 0x2f, 0xf2, 0x2e, 0xb8, 0xf4, 0xb8, 0x66, 0xf6, 0xf7, 0x12, 0x0, 0x0, 0x0, 0x48, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x64, 0xc7, 0xb1, 0x11, 0x80, 0x40, 0x8, 0x45, 0x41, 0xff, 0x83, 0x2, 0xe, 0xfb, 0x2f, 0x13, 0xe2, 0xf3, 0x6, 0x12, 0x1d, 0x37, 0x5b, 0xae, 0x97, 0x5f, 0x84, 0xdd, 0x68, 0xe2, 0x1e, 0x41, 0xb8, 0x77, 0x58, 0x6, 0xb6, 0xe8, 0x88, 0xd1, 0xe1, 0x93, 0xad, 0x63, 0xab, 0xa3, 0x3a, 0xa3, 0x26, 0xa9, 0x4a, 0x52, 0xf9, 0xc, 0x62, 0xcf, 0xa7, 0x8f, 0x1f, 0x1e, 0xbd, 0xff, 0x84, 0xee, 0x2, 0x0, 0x54, 0x76, 0x10, 0x19, 0x1e, 0xd7, 0x1d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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[] = { - 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, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x3a, 0xd8, 0xcf, 0xb2, 0xc1, 0x7d, 0xc3, 0x14, 0x20, 0x74, 0xdf, 0xcf, 0x82, 0x22, 0xb1, 0xc1, 0x7d, 0xfd, 0x2e, 0x8, 0xdc, 0xe0, 0x8e, 0x2a, 0x31, 0x5, 0x2e, 0x31, 0x85, 0x90, 0x4, 0xa6, 0x51, 0xb8, 0x2d, 0xa7, 0x36, 0x0, 0x0, 0x7b, 0xcd, 0x2b, 0x75, 0x45, 0x5e, 0xf8, 0x88, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char selection_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, 0x0, 0x2d, 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, 0xfd, 0xfb, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf6, 0xff, 0xf6, 0xf4, 0xff, 0x15, 0x15, 0x17, 0xff, 0x70, 0xc0, 0x21, 0x0, 0x0, 0x0, 0xe, 0x74, 0x52, 0x4e, 0x53, 0x6, 0xf, 0x16, 0x18, 0x2a, 0x3b, 0x40, 0x3c, 0x6, 0x3d, 0x44, 0x3e, 0x31, 0x25, 0x8, 0x3d, 0x16, 0xb4, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x6, 0x2, 0x23, 0x1, 0x6, 0x91, 0xb0, 0x34, 0x20, 0x48, 0x75, 0x64, 0x50, 0xef, 0x5c, 0x5, 0x4, 0x33, 0x8a, 0x18, 0xcc, 0xf6, 0xdc, 0x5, 0x82, 0xd3, 0xc9, 0xc, 0x66, 0x6b, 0x41, 0x8c, 0x5b, 0x94, 0x33, 0x60, 0x6, 0xc2, 0xad, 0x80, 0x5b, 0xa, 0x73, 0x6, 0x0, 0x45, 0x34, 0x48, 0x41, 0xa3, 0xc5, 0x91, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char selection_oof_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, 0x0, 0x2d, 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, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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[] = { - 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, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char submenu_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0xc0, 0xf0, 0xe0, 0x3f, 0x8, 0xde, 0x4f, 0x60, 0x0, 0x3, 0xb8, 0xc0, 0x83, 0x2f, 0xf, 0xb5, 0xe1, 0x2, 0x50, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xc0, 0xff, 0x87, 0xf3, 0x31, 0x4, 0x30, 0xb5, 0x60, 0x1a, 0x8a, 0x61, 0x2d, 0x0, 0xa6, 0x55, 0x4f, 0xb1, 0x91, 0xd6, 0xa7, 0xae, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char submenu_mirrored_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcb, 0xa1, 0x11, 0x83, 0x40, 0x14, 0x45, 0xd1, 0xb3, 0x6b, 0x10, 0x34, 0x10, 0x47, 0x34, 0xf4, 0x13, 0x9d, 0x2, 0x28, 0x87, 0x2a, 0xe8, 0x84, 0x2, 0x82, 0x65, 0x71, 0x69, 0x0, 0x11, 0xf5, 0x11, 0x4c, 0x66, 0xd8, 0xe7, 0xee, 0x99, 0x79, 0x80, 0xed, 0x5d, 0xa2, 0x44, 0x9, 0x12, 0xec, 0x43, 0x2c, 0x5a, 0x78, 0xa6, 0xcc, 0xb7, 0x8d, 0xf9, 0x4a, 0xc8, 0xfc, 0x26, 0x3d, 0x37, 0xa8, 0x97, 0x69, 0x46, 0x6b, 0x5, 0x8f, 0x23, 0xbd, 0x1c, 0xd5, 0xa5, 0xfb, 0xc4, 0xf8, 0x87, 0x13, 0xd2, 0x2f, 0x14, 0x49, 0x6f, 0xb1, 0x11, 0xe1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tab_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, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x19, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0xfe, 0x47, 0xfe, 0x17, 0x1, 0xc2, 0x48, 0xd2, 0x84, 0x10, 0x2, 0x84, 0xb9, 0x98, 0x0, 0x0, 0xbf, 0x67, 0x1d, 0x5, 0x89, 0x9b, 0x48, 0x90, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tab_behind_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, 0x57, 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, 0x30, 0x2e, 0x36, 0x43, 0x40, 0x4d, 0x0, 0x0, 0x0, 0x43, 0x40, 0x4c, 0x3e, 0x3c, 0x47, 0x3e, 0x3b, 0x46, 0x31, 0x2f, 0x38, 0x2d, 0x2b, 0x33, 0x3f, 0x3c, 0x47, 0x91, 0xf8, 0xc4, 0xb2, 0x0, 0x0, 0x0, 0x18, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0xc, 0x4, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x77, 0xf3, 0x7, 0xef, 0xd3, 0x51, 0x5e, 0xca, 0x0, 0x0, 0x0, 0x5a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0x8c, 0x35, 0x2, 0x80, 0x30, 0x10, 0x4, 0x6f, 0x73, 0xc4, 0x53, 0xf3, 0xff, 0x3f, 0xe2, 0xee, 0x4e, 0x9d, 0xe9, 0x56, 0x41, 0xd8, 0xa1, 0x69, 0x7, 0xd0, 0x43, 0x72, 0x19, 0x3d, 0x37, 0x10, 0x6c, 0x1f, 0x8d, 0x6a, 0x0, 0x2b, 0x25, 0xc1, 0x20, 0xa2, 0x69, 0x98, 0xba, 0xb6, 0x45, 0x9a, 0x2b, 0xbd, 0xe9, 0xd5, 0x69, 0xda, 0x0, 0xa9, 0x94, 0x9f, 0x68, 0x7, 0xc5, 0xd2, 0x50, 0x4a, 0x69, 0x71, 0x18, 0x63, 0xb3, 0x18, 0x7a, 0x71, 0x2e, 0xa3, 0xfd, 0x1b, 0xff, 0xc9, 0xff, 0x34, 0x86, 0x31, 0x3, 0x12, 0xb2, 0x4c, 0x6a, 0xfb, 0x60, 0xc7, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tab_close_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, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -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, 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, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x1, 0x71, 0x69, 0x43, 0x43, 0x50, 0x69, 0x63, 0x63, 0x0, 0x0, 0x28, 0x91, 0x75, 0x91, 0x3d, 0x4b, 0xc3, 0x50, 0x14, 0x86, 0xdf, 0xb6, 0x8a, 0xa2, 0x91, 0xe, 0x15, 0x11, 0x71, 0xc8, 0x50, 0xc5, 0xa1, 0x85, 0xa2, 0x20, 0x8e, 0x5a, 0x87, 0x2e, 0x45, 0x4a, 0xad, 0x60, 0xd5, 0x25, 0xb9, 0x4d, 0x5a, 0x21, 0x49, 0xc3, 0x4d, 0x8a, 0x14, 0x57, 0xc1, 0xc5, 0xa1, 0xe0, 0x20, 0xba, 0xf8, 0x35, 0xf8, 0xf, 0x74, 0x15, 0x5c, 0x15, 0x4, 0x41, 0x11, 0x44, 0x9c, 0xfc, 0x1, 0x7e, 0x2d, 0x52, 0xe2, 0xb9, 0x4d, 0xa1, 0x45, 0xda, 0x13, 0x6e, 0xce, 0xc3, 0x7b, 0xcf, 0x7b, 0xb8, 0xf7, 0x5c, 0x20, 0x98, 0x36, 0x98, 0xe9, 0xf4, 0x24, 0x0, 0xd3, 0x72, 0x79, 0x36, 0x95, 0x94, 0x57, 0xf3, 0x6b, 0x72, 0xdf, 0x3b, 0x2, 0x90, 0x30, 0x82, 0x8, 0x24, 0x85, 0x39, 0xf6, 0x42, 0x26, 0x93, 0x46, 0xd7, 0xf8, 0x79, 0xa4, 0x6a, 0x8a, 0x87, 0xb8, 0xe8, 0xd5, 0xbd, 0xae, 0x63, 0xc, 0x16, 0x34, 0x87, 0x1, 0x81, 0x7e, 0xe2, 0x59, 0x66, 0x73, 0x97, 0x78, 0x9e, 0x38, 0xbd, 0xe5, 0xda, 0x82, 0xf7, 0x88, 0x87, 0x59, 0x49, 0x29, 0x10, 0x9f, 0x10, 0xc7, 0x38, 0x1d, 0x90, 0xf8, 0x56, 0xe8, 0xaa, 0xcf, 0x6f, 0x82, 0x8b, 0x3e, 0x7f, 0x9, 0xe6, 0xb9, 0xec, 0x22, 0x10, 0x14, 0x3d, 0xe5, 0x62, 0x1b, 0xab, 0x6d, 0xcc, 0x4a, 0xdc, 0x24, 0x9e, 0x22, 0x8e, 0x9a, 0x46, 0x85, 0x35, 0xcf, 0x23, 0x6e, 0x22, 0x69, 0xd6, 0xca, 0x32, 0xe5, 0x31, 0x5a, 0xe3, 0x70, 0x90, 0x45, 0xa, 0x49, 0xc8, 0x50, 0x51, 0xc1, 0x26, 0xc, 0xb8, 0x88, 0x53, 0xb6, 0x68, 0x66, 0x9d, 0x7d, 0x89, 0x86, 0x6f, 0x9, 0x65, 0xf2, 0x30, 0xfa, 0xdb, 0xa8, 0x82, 0x93, 0xa3, 0x88, 0x12, 0x79, 0x63, 0xa4, 0x56, 0xa8, 0xab, 0x46, 0x59, 0x27, 0x5d, 0xa3, 0xcf, 0x40, 0x55, 0xcc, 0xfd, 0xff, 0x3c, 0x1d, 0x7d, 0x66, 0xda, 0xef, 0x2e, 0x25, 0x81, 0xde, 0x57, 0xcf, 0xfb, 0x9c, 0x0, 0xfa, 0xf6, 0x81, 0x7a, 0xcd, 0xf3, 0x7e, 0x4f, 0x3d, 0xaf, 0x7e, 0x6, 0x84, 0x5e, 0x80, 0x6b, 0xab, 0xe5, 0x2f, 0xd3, 0x9c, 0xe6, 0xbe, 0x49, 0xaf, 0xb5, 0xb4, 0xe8, 0x31, 0x10, 0xde, 0x1, 0x2e, 0x6f, 0x5a, 0x9a, 0x7a, 0x0, 0x5c, 0xed, 0x2, 0xa3, 0xcf, 0xb6, 0xc2, 0x95, 0x86, 0x14, 0xa2, 0x15, 0xd4, 0x75, 0xe0, 0xe3, 0x2, 0x18, 0xca, 0x3, 0x91, 0x7b, 0x60, 0x60, 0xdd, 0x9f, 0x55, 0x73, 0x1f, 0xe7, 0x4f, 0x40, 0x6e, 0x9b, 0x9e, 0xe8, 0xe, 0x38, 0x3c, 0x2, 0x26, 0xa9, 0x3e, 0xbc, 0xf1, 0x7, 0x9c, 0x2f, 0x67, 0xdc, 0x46, 0x9a, 0x3c, 0x4e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x12, 0x0, 0x0, 0xb, 0x12, 0x1, 0xd2, 0xdd, 0x7e, 0xfc, 0x0, 0x0, 0x1, 0x27, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x9d, 0x93, 0x41, 0x4e, 0xc3, 0x30, 0x10, 0x45, 0xc7, 0xee, 0xd0, 0x82, 0x58, 0xd4, 0x6b, 0x28, 0xdc, 0x4, 0xc1, 0x92, 0x35, 0xa7, 0xe9, 0x11, 0x38, 0xd, 0x6b, 0x36, 0x2c, 0x10, 0x3b, 0xee, 0xc0, 0x6, 0x95, 0x1d, 0x6a, 0x83, 0x54, 0x4, 0xad, 0x1d, 0xf, 0x7f, 0xf0, 0x4, 0xb5, 0x52, 0x11, 0xe, 0x3f, 0x7a, 0x91, 0x93, 0x7c, 0xff, 0x78, 0x9c, 0x89, 0x23, 0x22, 0x6, 0x43, 0x30, 0x2, 0xfb, 0x36, 0x1e, 0x0, 0x4f, 0xdb, 0xca, 0xa0, 0x5, 0x6b, 0xf0, 0x9, 0x56, 0x3a, 0xee, 0x26, 0x1f, 0x82, 0x0, 0xc6, 0x36, 0xd6, 0x30, 0x67, 0xa8, 0xc4, 0xd0, 0x49, 0xef, 0xe0, 0xd, 0x34, 0x64, 0x6f, 0x57, 0x73, 0x38, 0x3f, 0xbb, 0xbc, 0x9a, 0x1c, 0x9f, 0x4e, 0x53, 0x4a, 0x21, 0xb, 0xed, 0x94, 0x47, 0x1c, 0x33, 0x37, 0xb3, 0x97, 0xe7, 0xeb, 0xfb, 0x87, 0xdb, 0x1b, 0xdc, 0x4a, 0x6c, 0xcb, 0x1e, 0x4f, 0x8e, 0x4e, 0xa6, 0x8b, 0xf9, 0x6b, 0x48, 0x31, 0xe1, 0x55, 0xbb, 0x13, 0x1c, 0xe, 0xde, 0xe3, 0xa0, 0x5e, 0x5c, 0xde, 0x81, 0xe5, 0x4f, 0x9, 0xeb, 0x18, 0x43, 0x8c, 0xf1, 0xd7, 0xc9, 0xa5, 0xe, 0x21, 0xf5, 0xa8, 0xd7, 0x4a, 0x1d, 0xb2, 0x6d, 0xd8, 0x28, 0xe7, 0x4c, 0x59, 0x32, 0xfd, 0x25, 0xd, 0x51, 0xaf, 0x95, 0x3e, 0x60, 0xdb, 0x6d, 0x27, 0x59, 0x1f, 0x8, 0xd5, 0x48, 0x8a, 0x4f, 0x37, 0xd8, 0x73, 0x57, 0x5e, 0x2b, 0x6d, 0xd5, 0xa, 0x54, 0xea, 0xed, 0xbe, 0x10, 0x6f, 0xa6, 0x8a, 0xf4, 0x5a, 0x1, 0x6d, 0x6, 0x88, 0x4e, 0xae, 0xe, 0x28, 0xbe, 0xef, 0x93, 0xb7, 0xe, 0x43, 0x68, 0xa2, 0x5a, 0x99, 0x57, 0x3, 0xb2, 0xb7, 0xf6, 0x5c, 0x51, 0xa6, 0x7a, 0x15, 0xaf, 0x76, 0x65, 0xcb, 0x5b, 0x8d, 0xe2, 0x1c, 0xf5, 0x15, 0xdb, 0x8f, 0xd1, 0xfc, 0x23, 0xe0, 0xa0, 0x6b, 0x24, 0xfd, 0xbb, 0x96, 0xa5, 0xd7, 0x7b, 0x5, 0xcc, 0xc1, 0x87, 0xee, 0xc1, 0x2, 0x3c, 0x81, 0xb, 0xa1, 0xba, 0x43, 0xbd, 0xe0, 0x11, 0xcc, 0xbe, 0x0, 0xbe, 0xe0, 0x95, 0x8, 0xaf, 0xb2, 0x52, 0x33, 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, 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[] = { - 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, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tab_menu_hl_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, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_off_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x7a, 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, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x2, 0x29, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x3, 0x93, 0x24, 0x4b, 0x14, 0x85, 0x5f, 0xb9, 0xaa, 0x6d, 0x8e, 0x6d, 0xdb, 0x73, 0x2b, 0xb3, 0xe7, 0xad, 0x6d, 0xab, 0xdd, 0x63, 0xe3, 0xbf, 0x6f, 0x67, 0x65, 0xbb, 0xb4, 0xbb, 0x81, 0xc5, 0x97, 0x11, 0x27, 0x78, 0x4f, 0xea, 0xe2, 0xbf, 0x3f, 0x9, 0x86, 0xe5, 0x38, 0xde, 0x16, 0x8e, 0x63, 0x19, 0xc3, 0x70, 0x96, 0x17, 0x44, 0x49, 0x56, 0x1c, 0x36, 0x28, 0xb2, 0x24, 0xa, 0x3c, 0xab, 0xdf, 0x9d, 0x77, 0xca, 0x2e, 0xb7, 0xc7, 0xeb, 0xf3, 0x7, 0x2c, 0xf1, 0xfb, 0xbc, 0x1e, 0xb7, 0x4b, 0x76, 0xf2, 0x2d, 0xa7, 0x60, 0x83, 0xa1, 0x70, 0x24, 0x1a, 0x8b, 0x27, 0xb6, 0xc1, 0x86, 0xed, 0x44, 0x3c, 0x16, 0x8d, 0x84, 0x43, 0x41, 0xb6, 0x29, 0x3e, 0xd9, 0xd6, 0xde, 0xd1, 0xa9, 0x22, 0x84, 0x31, 0x6, 0xd, 0x4c, 0x40, 0x38, 0x85, 0xd, 0x4d, 0x3a, 0x3b, 0xda, 0xdb, 0x92, 0xd, 0xe, 0x4c, 0x97, 0xd2, 0xdd, 0xa3, 0xa2, 0x9d, 0xff, 0x6f, 0xdd, 0xbe, 0x43, 0xb9, 0x7b, 0x6f, 0x47, 0x73, 0x49, 0x21, 0x93, 0x73, 0xf4, 0x74, 0x2b, 0x5d, 0x4c, 0xfd, 0xfe, 0x92, 0xbb, 0x57, 0xc5, 0xf7, 0x1f, 0x3c, 0x7c, 0xf4, 0x18, 0x8, 0x8f, 0x9f, 0x3c, 0x7d, 0xf6, 0xfc, 0xfe, 0xb, 0xed, 0x24, 0x66, 0x37, 0xe9, 0x75, 0x4b, 0xb5, 0x77, 0x60, 0xfb, 0xfa, 0x7, 0x54, 0xfc, 0xf2, 0xd5, 0x6b, 0x68, 0xe0, 0xcd, 0xdb, 0x97, 0x2f, 0x2c, 0xdf, 0x62, 0xb0, 0xbf, 0xaf, 0x7a, 0x9, 0xbe, 0xcd, 0x33, 0x84, 0xde, 0xbd, 0x7f, 0x2, 0x4d, 0x7c, 0x78, 0xff, 0xf1, 0x31, 0x58, 0x30, 0x34, 0xdc, 0x36, 0x42, 0x8f, 0xc0, 0x8, 0xae, 0x51, 0xf4, 0xe9, 0xf3, 0x17, 0x68, 0xe1, 0xeb, 0xb7, 0x34, 0x58, 0x31, 0xea, 0x12, 0xa8, 0x1, 0x2b, 0xba, 0xc7, 0x50, 0xe6, 0x19, 0xe8, 0xc8, 0x66, 0x80, 0x92, 0xcb, 0x17, 0x8a, 0x25, 0xd8, 0x2d, 0x94, 0xd1, 0x64, 0xf, 0x8, 0xe3, 0x13, 0x93, 0xf4, 0xe, 0x9c, 0xe4, 0x89, 0xe3, 0xfd, 0x3, 0xd0, 0x71, 0xb0, 0xf, 0x94, 0xc3, 0xa3, 0xdc, 0x71, 0x21, 0xb7, 0x4b, 0x2, 0x35, 0xa1, 0x4c, 0xd, 0x4b, 0x1c, 0x35, 0x90, 0xa7, 0x67, 0xf0, 0xc9, 0x29, 0xe8, 0x38, 0x3d, 0xa9, 0x1c, 0x80, 0x4, 0x1d, 0x9d, 0xed, 0x9e, 0x13, 0x3, 0x22, 0x94, 0xed, 0x59, 0x99, 0xa7, 0x6, 0x6d, 0x73, 0x2a, 0xbe, 0x6d, 0xf0, 0x60, 0x8f, 0x6f, 0x13, 0x25, 0x41, 0x65, 0xb9, 0xc8, 0xef, 0x1e, 0x1e, 0x1e, 0xee, 0x69, 0x2, 0x94, 0xf9, 0xb6, 0x8a, 0x81, 0xec, 0x55, 0x2d, 0x4f, 0xb0, 0x47, 0x4e, 0x90, 0xbf, 0xdc, 0x25, 0x91, 0x44, 0x74, 0x27, 0x90, 0x3c, 0xb, 0xc8, 0xf2, 0xd, 0xce, 0xcf, 0x60, 0xaf, 0x58, 0xaa, 0x18, 0xe8, 0xdf, 0x80, 0x15, 0x27, 0x6c, 0x7e, 0x61, 0xb7, 0x78, 0x5e, 0xcc, 0x43, 0xab, 0x1, 0xfd, 0x5, 0x9a, 0x7, 0x8b, 0x36, 0x79, 0xb0, 0x77, 0x76, 0x5, 0x90, 0x2b, 0xed, 0x55, 0x84, 0xb2, 0x18, 0x16, 0x98, 0x5a, 0x26, 0x2e, 0xe1, 0x5f, 0xce, 0x44, 0x5a, 0xb, 0x83, 0x3f, 0x5f, 0xb, 0xcb, 0xb4, 0x16, 0xcc, 0xab, 0xf1, 0x9a, 0xc6, 0xdb, 0x57, 0x23, 0xed, 0x7, 0x2b, 0xab, 0x2a, 0xba, 0x69, 0xed, 0x7, 0xe6, 0x6c, 0xaf, 0xae, 0xd5, 0xfa, 0x1, 0xed, 0x48, 0x8a, 0x7b, 0x7d, 0x3, 0xa5, 0x10, 0x6d, 0x48, 0xb8, 0x2, 0x2a, 0x2f, 0x30, 0xa2, 0x73, 0xdd, 0xad, 0x24, 0x9b, 0x7b, 0x5a, 0x97, 0x14, 0xf6, 0x44, 0x63, 0x53, 0xdb, 0x60, 0xcb, 0xf6, 0x54, 0x2c, 0xea, 0x9, 0x4b, 0x5d, 0x6c, 0x6b, 0x57, 0xee, 0x93, 0x5d, 0x13, 0xc3, 0xb3, 0x9b, 0x1, 0x1b, 0x36, 0x67, 0x87, 0x27, 0x5c, 0x72, 0x1f, 0xcf, 0xe8, 0xa7, 0xca, 0x88, 0x30, 0xb9, 0xd5, 0x66, 0x3f, 0x17, 0xda, 0xb6, 0x26, 0x85, 0x11, 0x96, 0x31, 0x99, 0x4c, 0xfc, 0xf, 0x40, 0x27, 0xd3, 0xbf, 0xc4, 0x77, 0x82, 0xde, 0x40, 0xde, 0x4b, 0x3f, 0xe2, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_off_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0xfc, 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, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0x4e, 0x4e, 0x52, 0x1a, 0x1a, 0x1d, 0x32, 0x32, 0x37, 0x2c, 0x26, 0x2c, 0x26, 0x25, 0x2a, 0x27, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x2f, 0x26, 0x2d, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x5b, 0x5b, 0x5f, 0x84, 0x84, 0x87, 0x77, 0x77, 0x7a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x69, 0x69, 0x6c, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0xb, 0x1b, 0xbb, 0x0, 0x0, 0x0, 0x54, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0xff, 0xff, 0x8, 0x17, 0x35, 0x86, 0xf3, 0xff, 0xff, 0xff, 0xff, 0x7, 0x3a, 0xb4, 0xff, 0xff, 0xff, 0xb9, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x8a, 0xff, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x37, 0xf, 0xff, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xd4, 0x6d, 0x6c, 0xf9, 0x0, 0x0, 0x2, 0x3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x55, 0x85, 0x9a, 0xe2, 0x30, 0x18, 0xbc, 0x7a, 0x8b, 0xbb, 0x7b, 0x2, 0xbb, 0x4d, 0x36, 0xb8, 0x3b, 0xeb, 0xae, 0xef, 0xff, 0x2e, 0x47, 0x48, 0x3f, 0xa0, 0x7a, 0xae, 0x83, 0x56, 0xfe, 0xe9, 0xfc, 0xfe, 0xe9, 0x6f, 0x2, 0xc7, 0xb, 0x82, 0xf8, 0x45, 0x8, 0x2, 0xcf, 0x39, 0x9a, 0xf3, 0xa2, 0x24, 0x2b, 0xaa, 0xe6, 0xfb, 0x2, 0x34, 0x55, 0x91, 0x25, 0x91, 0xb7, 0x3f, 0x5d, 0xf4, 0xab, 0x81, 0x60, 0x28, 0x1c, 0x89, 0xc6, 0x3c, 0x11, 0x8d, 0x84, 0x43, 0xc1, 0x80, 0xea, 0x17, 0x2d, 0x2a, 0xf8, 0x78, 0x22, 0x99, 0x4a, 0x67, 0xb2, 0xb9, 0x7c, 0xe1, 0xb, 0xc8, 0xe7, 0xb2, 0x99, 0x74, 0x2a, 0x99, 0x88, 0xf3, 0x26, 0xfb, 0x62, 0xa9, 0x5c, 0xa9, 0xd6, 0x0, 0x80, 0x10, 0xb2, 0xfb, 0x20, 0x5, 0x80, 0x75, 0xe8, 0x48, 0x52, 0xad, 0x94, 0x4b, 0xc5, 0x23, 0x6, 0xae, 0xa1, 0x9d, 0x9c, 0xd6, 0x80, 0x8e, 0xf0, 0x1e, 0x48, 0xdf, 0xb1, 0xd4, 0x81, 0x8b, 0x8e, 0xd3, 0x13, 0xad, 0xc1, 0x1d, 0xfc, 0x57, 0x82, 0x67, 0x35, 0x48, 0x30, 0x6a, 0xb6, 0x76, 0x97, 0x5b, 0x3a, 0x41, 0x98, 0xb4, 0x77, 0x4a, 0xdc, 0x3c, 0x39, 0xb, 0x2a, 0xfb, 0x38, 0xf0, 0x9d, 0x6e, 0xaf, 0x6, 0x11, 0xea, 0x1f, 0xdf, 0x41, 0x10, 0x6a, 0x7b, 0xc6, 0x62, 0xd0, 0xed, 0xf0, 0x6, 0x81, 0x58, 0xa, 0xd, 0x1, 0xa1, 0xa2, 0x8f, 0xa1, 0x23, 0xd2, 0xf2, 0x62, 0x18, 0x8e, 0x4a, 0x63, 0x26, 0x81, 0x93, 0x2, 0x13, 0xa0, 0xe3, 0xbe, 0xf5, 0xe, 0x82, 0x3d, 0x25, 0x14, 0x26, 0x1, 0x89, 0x11, 0xf0, 0x72, 0x70, 0xba, 0x15, 0x60, 0xbf, 0x3, 0x11, 0xe3, 0xcf, 0x6c, 0xbe, 0x58, 0xa2, 0x42, 0x7f, 0xb1, 0xc5, 0xee, 0x8b, 0x9d, 0x5f, 0xad, 0x37, 0xcc, 0x7, 0x41, 0x9, 0x65, 0x21, 0xbd, 0xd9, 0x8a, 0x3d, 0xe9, 0xf9, 0x7c, 0x46, 0x16, 0xb3, 0x3e, 0x35, 0xa4, 0x5f, 0x6, 0x2e, 0x46, 0x8a, 0xc0, 0x8, 0xd4, 0xcb, 0x2b, 0x88, 0x75, 0x3b, 0x81, 0x8e, 0xd, 0x1, 0xd4, 0x68, 0x8e, 0xfa, 0xe7, 0x94, 0xe0, 0x7c, 0x4f, 0x90, 0xbf, 0x56, 0x45, 0x46, 0x50, 0xba, 0xa9, 0x41, 0xec, 0x10, 0xb0, 0x96, 0x41, 0xd0, 0x3f, 0xdf, 0x7e, 0xe1, 0x79, 0xff, 0xfc, 0xfc, 0x9c, 0x6c, 0xbf, 0xf6, 0x14, 0xb7, 0x25, 0x83, 0x40, 0xd, 0xd7, 0x3c, 0x15, 0x90, 0x9d, 0x2, 0xec, 0xae, 0x40, 0x9, 0xdd, 0x1, 0xef, 0x18, 0xa0, 0x2, 0x59, 0xda, 0x5c, 0xd8, 0xc7, 0x80, 0x97, 0xd7, 0x5f, 0xc8, 0x42, 0x7f, 0x79, 0xbe, 0x9c, 0x17, 0x2c, 0x4, 0xfb, 0x2c, 0xd0, 0x3a, 0xb8, 0xff, 0x42, 0x1d, 0x10, 0x5a, 0x95, 0x33, 0x44, 0xd8, 0x97, 0x81, 0xfb, 0xa4, 0xc4, 0xed, 0x2b, 0xf1, 0x1, 0xfe, 0x40, 0x25, 0xd2, 0x5e, 0x18, 0x7c, 0x7b, 0x2f, 0x3c, 0xd2, 0x5e, 0xf8, 0x72, 0x37, 0x16, 0xbe, 0xdc, 0x8d, 0x6c, 0x1e, 0x3c, 0x3d, 0xd7, 0x40, 0xdb, 0x32, 0xf, 0xbc, 0xec, 0x9f, 0x5f, 0xf6, 0xf3, 0x80, 0x4d, 0x24, 0x2d, 0xf8, 0xfa, 0x6, 0xea, 0x80, 0xd, 0x24, 0x68, 0x0, 0x6c, 0x5f, 0x8e, 0xf6, 0xd5, 0xd7, 0xa0, 0x56, 0x34, 0xcf, 0xb4, 0x86, 0x92, 0xc, 0xa5, 0x33, 0x17, 0xf9, 0xc2, 0x17, 0x91, 0xbf, 0xc8, 0xa4, 0x43, 0x49, 0xa5, 0xc1, 0x5b, 0xa7, 0x72, 0x47, 0xd, 0xac, 0x47, 0xd7, 0xef, 0xb1, 0x2f, 0xe0, 0xfd, 0x7a, 0xb4, 0xe, 0xa8, 0x1d, 0x91, 0xb3, 0x6f, 0x95, 0xb1, 0xb4, 0xf9, 0x28, 0x7d, 0x79, 0x2f, 0x94, 0x3e, 0x36, 0xd2, 0x98, 0xe7, 0x5c, 0x36, 0x93, 0xf8, 0x15, 0xa0, 0x9b, 0xe9, 0xff, 0xc2, 0x67, 0x14, 0xf4, 0xa5, 0xb3, 0x35, 0x5e, 0x63, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_off_disabled_mirrored_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x9c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x1d, 0x1d, 0x21, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x2e, 0x2e, 0x2e, 0x46, 0x46, 0x46, 0x57, 0x57, 0x57, 0x60, 0x60, 0x60, 0x62, 0x62, 0x62, 0x5e, 0x5e, 0x5e, 0x4a, 0x4a, 0x4a, 0x12, 0x12, 0x15, 0x25, 0x27, 0x2d, 0x42, 0x42, 0x42, 0x59, 0x59, 0x59, 0x32, 0x32, 0x32, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x39, 0x39, 0x39, 0x49, 0x49, 0x49, 0x5a, 0x5a, 0x5a, 0x48, 0x48, 0x48, 0x54, 0x54, 0x54, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x1e, 0x1e, 0x22, 0x25, 0x26, 0x2b, 0x3f, 0x3f, 0x3f, 0xe, 0xe, 0x10, 0x2c, 0x2c, 0x2c, 0x58, 0x58, 0x58, 0x5d, 0x5d, 0x5f, 0x80, 0x80, 0x80, 0x79, 0x79, 0x79, 0x40, 0x40, 0x44, 0x32, 0x32, 0x37, 0x41, 0x41, 0x41, 0x1a, 0x1a, 0x1d, 0x6a, 0x6a, 0x6d, 0x52, 0x52, 0x52, 0x3a, 0x3a, 0x3a, 0x5b, 0x5b, 0x5b, 0x2f, 0x2f, 0x2f, 0x50, 0x50, 0x51, 0x13, 0x13, 0x15, 0x2b, 0xcd, 0x4, 0x96, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x1, 0x29, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xdb, 0x76, 0x83, 0x20, 0x10, 0x45, 0x8d, 0xe8, 0x24, 0x98, 0xda, 0x1a, 0x93, 0xda, 0x5b, 0xac, 0xb9, 0x50, 0x14, 0x52, 0x72, 0xfd, 0xff, 0x7f, 0xab, 0x68, 0x49, 0x28, 0x5a, 0x35, 0xf5, 0xa5, 0xf, 0x39, 0xf, 0xb3, 0x96, 0xe3, 0xda, 0x7, 0x98, 0x81, 0xb1, 0xac, 0x9b, 0xfe, 0x97, 0x6, 0x36, 0x72, 0x5c, 0x68, 0x91, 0xeb, 0x20, 0x7b, 0x50, 0xcf, 0xf, 0x5b, 0xe1, 0xb3, 0xc9, 0xb0, 0x6, 0x1f, 0xe1, 0x46, 0xc6, 0x1b, 0xdf, 0xf9, 0xf7, 0xa5, 0x1e, 0x2, 0xf, 0xf0, 0xc8, 0xe4, 0x27, 0x8d, 0xcb, 0x87, 0xd3, 0xd9, 0xf8, 0x31, 0x7a, 0x92, 0x7a, 0xf6, 0x5e, 0x5e, 0xdf, 0xa6, 0xa1, 0x3b, 0x31, 0xc, 0x1a, 0xd7, 0xf, 0xe7, 0xf1, 0xbb, 0xfe, 0x9d, 0xc4, 0xf3, 0x10, 0xff, 0xe4, 0x17, 0x4d, 0xfc, 0x72, 0x15, 0x7b, 0xc6, 0x81, 0xe2, 0xd5, 0x72, 0xa1, 0xf3, 0xeb, 0xc6, 0xf3, 0x93, 0x8f, 0xc4, 0x4c, 0x25, 0x33, 0x2, 0x6b, 0xcd, 0xc0, 0x56, 0x3f, 0x10, 0x4d, 0x33, 0x6, 0x24, 0xcd, 0x55, 0x4, 0x2e, 0x93, 0x9b, 0xa0, 0x6a, 0x1a, 0x6c, 0xe0, 0x53, 0x33, 0x40, 0x2a, 0x2f, 0x28, 0xe2, 0x29, 0x22, 0x12, 0x24, 0x25, 0x9d, 0x6b, 0xbb, 0xab, 0x1a, 0xec, 0xb6, 0x80, 0x34, 0x3, 0x47, 0x6d, 0x40, 0x42, 0x94, 0x11, 0x21, 0xd, 0x84, 0x32, 0xd8, 0x1f, 0xaa, 0x6, 0x87, 0x3d, 0xe8, 0x65, 0x54, 0x3d, 0x24, 0x22, 0xf, 0x47, 0x4a, 0x84, 0x10, 0xbc, 0x8, 0x45, 0xd6, 0x8f, 0xaa, 0x6, 0x91, 0xf, 0x50, 0xd3, 0x44, 0x5e, 0xec, 0xe0, 0x78, 0xfd, 0xe, 0x2e, 0x35, 0x60, 0xc0, 0x33, 0xf3, 0x8, 0x1d, 0x6a, 0x70, 0xee, 0x2, 0xc9, 0x44, 0x46, 0xc1, 0x30, 0xe8, 0xd0, 0x85, 0xcb, 0x3d, 0xe0, 0x4c, 0xd6, 0x92, 0xf1, 0xef, 0xd0, 0xf5, 0x1e, 0xf4, 0xbe, 0x89, 0xfd, 0xdf, 0x42, 0xff, 0xd7, 0x68, 0x9d, 0xae, 0x9b, 0x7, 0xa7, 0xba, 0x89, 0x4, 0x9d, 0x55, 0x37, 0x91, 0xca, 0x99, 0x88, 0xdb, 0x61, 0xfc, 0xeb, 0x4c, 0xbc, 0xe9, 0xaf, 0xfa, 0x2, 0xdc, 0x1a, 0x30, 0x60, 0x4e, 0xef, 0xb8, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_off_mirrored_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0xaa, 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, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x24, 0x24, 0x28, 0x20, 0x20, 0x25, 0x14, 0x14, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x27, 0x10, 0x10, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x19, 0x19, 0x1c, 0x12, 0x12, 0x15, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x11, 0x11, 0x14, 0x1e, 0x1e, 0x22, 0x23, 0x23, 0x27, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x25, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x24, 0x24, 0x27, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x1a, 0x1a, 0x1e, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x26, 0x11, 0x11, 0x13, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x24, 0x24, 0x28, 0x2d, 0x26, 0x2c, 0x51, 0x2c, 0x39, 0x6c, 0x31, 0x42, 0x71, 0x32, 0x44, 0x6e, 0x31, 0x43, 0x63, 0x2f, 0x3f, 0x4d, 0x2b, 0x37, 0x27, 0x25, 0x2a, 0x47, 0x2a, 0x35, 0x68, 0x30, 0x40, 0x52, 0x2c, 0x39, 0x3c, 0x28, 0x31, 0x2e, 0x25, 0x2c, 0x26, 0x25, 0x2a, 0x32, 0x26, 0x2e, 0x4d, 0x2b, 0x38, 0x66, 0x30, 0x40, 0x50, 0x2c, 0x38, 0x5e, 0x2e, 0x3d, 0x38, 0x27, 0x30, 0x35, 0x27, 0x2f, 0x5f, 0x2e, 0x3d, 0x44, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x43, 0x2a, 0x34, 0x2c, 0x26, 0x2c, 0x66, 0x2f, 0x40, 0x37, 0x27, 0x30, 0x36, 0x27, 0x30, 0x64, 0x2f, 0x3f, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x25, 0x25, 0x27, 0xea, 0xac, 0x78, 0x5d, 0x0, 0x0, 0x0, 0x51, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0xfa, 0xe5, 0x98, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xf3, 0x86, 0x7, 0x3a, 0x96, 0xf9, 0xb4, 0x9a, 0xb9, 0xb, 0x28, 0x76, 0xfb, 0x8a, 0xde, 0xf6, 0x82, 0x9b, 0xc6, 0xe6, 0x4c, 0xfe, 0x4f, 0xe9, 0xfb, 0x37, 0x83, 0x9c, 0xf6, 0x77, 0x8b, 0x3b, 0x9c, 0xbb, 0x74, 0xda, 0xf3, 0x87, 0xfb, 0x45, 0x4e, 0x53, 0x5, 0xf, 0x14, 0xc7, 0x22, 0x44, 0x61, 0x0, 0x0, 0x2, 0x45, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0xe7, 0x5f, 0xd3, 0x40, 0x18, 0x26, 0x3b, 0x91, 0x24, 0x65, 0x95, 0xd, 0xd, 0x8e, 0x22, 0x6a, 0x71, 0x2b, 0x82, 0x75, 0xe1, 0x66, 0xa6, 0x97, 0xa0, 0x56, 0x45, 0xa4, 0x2a, 0x2e, 0xdc, 0x76, 0x25, 0x18, 0x84, 0x6, 0x9c, 0xff, 0xb3, 0xb9, 0x26, 0x17, 0xda, 0xa4, 0x49, 0xd4, 0x4f, 0xfa, 0x7c, 0xb8, 0xdf, 0xe5, 0xcd, 0xef, 0x79, 0xee, 0xbd, 0xf7, 0xde, 0xd1, 0xd4, 0xf4, 0xf, 0x1, 0xc3, 0x9, 0x82, 0x8c, 0x4, 0x41, 0xe0, 0x58, 0x43, 0x3a, 0x4e, 0x52, 0x34, 0xc3, 0x72, 0xbb, 0x22, 0xc0, 0xb1, 0xc, 0x4d, 0x91, 0xb8, 0xff, 0x74, 0xb2, 0x99, 0xe5, 0x5, 0x31, 0xd6, 0xd2, 0xda, 0x16, 0x8a, 0xd6, 0x96, 0x98, 0x28, 0xf0, 0x6c, 0x33, 0xe9, 0xf1, 0x2, 0x6f, 0xef, 0x88, 0x77, 0x76, 0x75, 0xf7, 0xf4, 0xf6, 0xc9, 0x11, 0xc8, 0xf4, 0xf5, 0xf, 0xc, 0x76, 0xc6, 0x3b, 0xda, 0xeb, 0x9c, 0xc0, 0x13, 0xd2, 0xd0, 0xee, 0x3d, 0x99, 0x0, 0xe, 0x50, 0x20, 0xec, 0xbd, 0xb5, 0x1, 0x40, 0xdd, 0xbb, 0x6f, 0x48, 0x4a, 0xd4, 0x28, 0x60, 0x49, 0x6e, 0x78, 0xff, 0x48, 0xe0, 0xa1, 0x90, 0xbb, 0x70, 0xeb, 0xf6, 0x1d, 0x1b, 0xd9, 0xbb, 0xf7, 0x16, 0x80, 0x7a, 0x60, 0x98, 0x4b, 0x62, 0x3b, 0xf7, 0x67, 0x84, 0x83, 0xa1, 0xbe, 0xdf, 0x5f, 0x7c, 0xb0, 0xf4, 0x70, 0x39, 0x57, 0xdd, 0xe7, 0x1e, 0x3d, 0x7e, 0xb2, 0xa8, 0xa8, 0x87, 0x4, 0xc6, 0x8d, 0x3, 0x9e, 0x1a, 0x3d, 0x7c, 0x24, 0x94, 0xbf, 0xf2, 0xf4, 0x59, 0xed, 0xf7, 0xf3, 0x17, 0x2b, 0x8a, 0x7a, 0x74, 0x34, 0x85, 0x2e, 0x41, 0x4a, 0xe2, 0xb1, 0x30, 0x7e, 0xee, 0xe5, 0xea, 0xab, 0x7a, 0xcb, 0xf2, 0xea, 0x6b, 0x70, 0x5c, 0x94, 0x48, 0xe7, 0x6, 0x14, 0x7f, 0x22, 0x34, 0xf0, 0x6f, 0xde, 0xbe, 0xf3, 0x9a, 0xde, 0x7f, 0xf8, 0x8, 0x4e, 0xf2, 0x94, 0x73, 0x3, 0x5a, 0x38, 0x85, 0x7e, 0xe4, 0xb, 0xc5, 0x52, 0x59, 0xd6, 0x8a, 0x16, 0xaa, 0x8b, 0xe, 0x8d, 0x6b, 0x9f, 0xfc, 0xa2, 0x4b, 0x6b, 0xe0, 0xb4, 0x40, 0xdb, 0x2, 0x4, 0x23, 0xf6, 0x20, 0xbb, 0xb1, 0x9e, 0xff, 0x5c, 0xcc, 0x6b, 0x90, 0xa8, 0xd9, 0x6c, 0xb, 0x1b, 0x9b, 0x7e, 0x81, 0xcd, 0xd, 0xa5, 0x5f, 0x64, 0x1c, 0x1, 0x76, 0xac, 0x17, 0x39, 0x0, 0x49, 0xeb, 0x15, 0xcd, 0x84, 0x2, 0x26, 0x12, 0xd8, 0xda, 0xf6, 0xb, 0x6c, 0x6f, 0x29, 0x67, 0xc6, 0x58, 0x47, 0x40, 0x1a, 0x47, 0x6f, 0xa8, 0x99, 0xd6, 0xf2, 0xa5, 0xa0, 0x19, 0x86, 0xa1, 0x57, 0x97, 0xaa, 0x35, 0x9b, 0x6b, 0x10, 0xd8, 0xac, 0xa2, 0x8e, 0x4b, 0xc8, 0x83, 0x18, 0x4a, 0x22, 0x1d, 0x7a, 0x50, 0xf8, 0xaa, 0x41, 0xa6, 0x66, 0x44, 0x78, 0xa0, 0xc6, 0x58, 0x37, 0x6, 0x13, 0xc8, 0x6e, 0x56, 0x64, 0xbd, 0x54, 0xf6, 0x8, 0x34, 0x8e, 0x1, 0x38, 0x8b, 0x62, 0x80, 0xd3, 0x69, 0xf7, 0x15, 0xb4, 0x92, 0x59, 0x2a, 0xc8, 0x1e, 0x81, 0xa0, 0x57, 0x48, 0xd3, 0x6e, 0x1e, 0x9c, 0x73, 0x7f, 0xe8, 0x95, 0x6f, 0x56, 0x2c, 0xcb, 0xba, 0xb3, 0x84, 0xe5, 0xc1, 0x79, 0x94, 0x7, 0x7f, 0x97, 0x89, 0xca, 0x5, 0x37, 0x13, 0x61, 0x2d, 0x5c, 0xfc, 0xf3, 0x5a, 0xb8, 0xb4, 0x53, 0xb, 0xbf, 0x51, 0x8d, 0xdf, 0x43, 0xab, 0x11, 0xf6, 0x83, 0xc9, 0xcb, 0xa1, 0x3e, 0xd4, 0xf7, 0x83, 0x1f, 0x40, 0xbd, 0x32, 0x59, 0xd3, 0xf, 0x60, 0x47, 0xe2, 0x84, 0xab, 0xd7, 0x82, 0xc8, 0x76, 0x47, 0x72, 0x9a, 0x92, 0xd5, 0x91, 0x7e, 0x82, 0xeb, 0x37, 0x4, 0x2e, 0x51, 0xdf, 0xd3, 0x92, 0x4c, 0x5c, 0xec, 0xea, 0x9e, 0x18, 0x91, 0x23, 0x91, 0xb9, 0x39, 0x30, 0x28, 0xc6, 0x99, 0xa4, 0xa7, 0x31, 0x63, 0x64, 0x8a, 0xe5, 0xd3, 0x53, 0xd3, 0x33, 0x6d, 0x11, 0x98, 0x99, 0x9e, 0x4a, 0xf3, 0x6c, 0x8a, 0xf4, 0xcd, 0x6, 0xc, 0x9f, 0xa5, 0xe6, 0xe6, 0xa5, 0xe8, 0xb9, 0x20, 0xcd, 0xcf, 0x51, 0xb3, 0x8d, 0x67, 0x8b, 0x35, 0x99, 0xa2, 0x7, 0x93, 0x35, 0x9a, 0x2, 0x26, 0xd3, 0xff, 0x8b, 0x5f, 0x3d, 0xdc, 0x7c, 0xb4, 0x8c, 0xb2, 0xd8, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_on_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x74, 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, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x2, 0x4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x63, 0x83, 0xdc, 0x60, 0x10, 0xc7, 0x1b, 0x3c, 0xc1, 0xda, 0x3e, 0xdb, 0x36, 0xe7, 0x6c, 0xdb, 0xa, 0xcf, 0xc6, 0x7e, 0xf8, 0x2a, 0x6d, 0xb8, 0xac, 0x7b, 0xbf, 0xf7, 0xf3, 0x1f, 0xcf, 0x7c, 0xf8, 0x97, 0xc0, 0x70, 0x82, 0x20, 0xb3, 0x42, 0x10, 0x38, 0x96, 0xd2, 0x1c, 0x27, 0x11, 0x45, 0x33, 0xac, 0x2d, 0xb, 0x2c, 0x43, 0x53, 0x88, 0xc4, 0xad, 0xde, 0x49, 0x3b, 0xe3, 0x70, 0xba, 0xdc, 0x1e, 0xaf, 0x2f, 0x23, 0x5e, 0x8f, 0xdb, 0xe5, 0x74, 0x30, 0x76, 0xd2, 0x14, 0x5, 0xee, 0xf, 0x4, 0x43, 0xe1, 0x48, 0x34, 0x16, 0x87, 0x2c, 0xc4, 0x63, 0xd1, 0x48, 0x38, 0x14, 0xc, 0xf8, 0x71, 0x83, 0x7d, 0xa2, 0xa0, 0xb0, 0xa8, 0x78, 0x4, 0x72, 0x64, 0xa4, 0xb8, 0xa8, 0xb0, 0x20, 0xa1, 0x53, 0xc0, 0x4a, 0xd8, 0xd2, 0xb2, 0x72, 0xc8, 0xc4, 0xe8, 0xd8, 0xf8, 0xc4, 0xa4, 0xc2, 0xd4, 0xf4, 0x28, 0x94, 0x97, 0x95, 0xb2, 0x25, 0x98, 0x96, 0x3f, 0xed, 0xac, 0xc8, 0x18, 0xfb, 0xcc, 0xec, 0xdc, 0xfc, 0xc2, 0xe2, 0xd2, 0x17, 0x96, 0x57, 0x56, 0xd7, 0xd6, 0x37, 0x66, 0xe2, 0x15, 0x4e, 0x5a, 0xad, 0x3, 0x5e, 0x59, 0x55, 0x5d, 0x93, 0xd1, 0x7e, 0x73, 0x6b, 0x1b, 0x74, 0xec, 0xec, 0x6e, 0xce, 0xd4, 0xd4, 0x56, 0x55, 0x7e, 0x4f, 0x82, 0x2c, 0x70, 0xd5, 0x41, 0x6, 0xf6, 0xf6, 0xb7, 0x56, 0xc0, 0xc0, 0xca, 0xd6, 0xc1, 0x5e, 0x5d, 0x7d, 0x41, 0x83, 0x12, 0x2, 0x86, 0x1c, 0x8d, 0x90, 0x89, 0xc3, 0xa3, 0x63, 0x30, 0xb1, 0x33, 0x77, 0x2, 0x8d, 0xe, 0xa4, 0x8, 0xe0, 0x94, 0xb3, 0x9, 0x54, 0x4e, 0xcf, 0x38, 0x5e, 0x0, 0x91, 0x93, 0x40, 0x94, 0x41, 0xe1, 0xfc, 0x2, 0x2c, 0x5c, 0x9e, 0x43, 0x73, 0x4b, 0xab, 0x92, 0x3, 0x41, 0xbb, 0xa2, 0xa0, 0x22, 0x5f, 0x9d, 0x5e, 0x73, 0xa7, 0x22, 0x27, 0x6b, 0x2, 0x37, 0xb7, 0x60, 0xe1, 0xee, 0x6, 0xda, 0xea, 0x69, 0x42, 0x11, 0x60, 0xda, 0x63, 0x5a, 0x0, 0xdc, 0x3d, 0xc0, 0xd5, 0x83, 0xf8, 0xc8, 0x8b, 0xaa, 0xc0, 0xd3, 0x33, 0x58, 0x78, 0x7e, 0x82, 0xf2, 0xe, 0x86, 0x54, 0x4, 0xa, 0x3a, 0xb5, 0x1e, 0x8a, 0x8f, 0x0, 0xf0, 0x72, 0x26, 0xca, 0x2f, 0x8f, 0xaa, 0xc0, 0xc4, 0x22, 0x58, 0x58, 0x9c, 0x0, 0xe8, 0x2a, 0xf8, 0x26, 0xc0, 0xb8, 0xb5, 0x21, 0xba, 0xff, 0x12, 0xc1, 0xd9, 0xeb, 0x67, 0xe3, 0xb7, 0xb3, 0x9c, 0x23, 0xa0, 0x5d, 0x6d, 0xa0, 0xf2, 0xf8, 0x0, 0xf7, 0xbc, 0xf0, 0x59, 0x40, 0xe0, 0x72, 0xad, 0x1, 0x4e, 0xb5, 0xe8, 0xba, 0x20, 0xf2, 0x8f, 0xfc, 0xd9, 0xd7, 0x2, 0x3e, 0xe6, 0xda, 0x5, 0xc, 0x39, 0xba, 0x41, 0xe3, 0xfe, 0x41, 0x2, 0x38, 0x15, 0x0, 0x24, 0x21, 0xf3, 0x1c, 0x74, 0x7, 0x11, 0xf6, 0xd3, 0x93, 0xa8, 0xee, 0x42, 0x6d, 0xfe, 0xbb, 0xd0, 0xa3, 0xed, 0x42, 0xe, 0xdb, 0xb8, 0x61, 0xdc, 0xc6, 0xa4, 0xba, 0x8d, 0xea, 0x3d, 0xe8, 0xed, 0xab, 0xc9, 0xe7, 0x1e, 0xd4, 0xf4, 0xf5, 0xab, 0xf7, 0x40, 0xb9, 0x48, 0xac, 0x73, 0x60, 0x10, 0x72, 0x66, 0x70, 0xc0, 0xc9, 0x26, 0x8c, 0x37, 0xad, 0x84, 0xe, 0xba, 0xc2, 0x91, 0xb6, 0x72, 0xc8, 0x4a, 0x79, 0x5b, 0x24, 0xec, 0xa, 0xd2, 0x25, 0xb8, 0xf9, 0x2a, 0x57, 0x32, 0x8e, 0x96, 0xfa, 0x8e, 0x21, 0x5f, 0x16, 0x86, 0x3a, 0xea, 0x5b, 0x1c, 0x4c, 0x25, 0x89, 0x59, 0xbf, 0x4a, 0x3, 0x6a, 0x1d, 0x2e, 0xc8, 0xfe, 0x17, 0xa, 0x86, 0x5b, 0x51, 0x3, 0x8e, 0xa5, 0xf9, 0x4c, 0x64, 0xe, 0x68, 0x9f, 0xe9, 0xbd, 0xf0, 0x9, 0xb7, 0x71, 0x36, 0xc6, 0x9b, 0x3d, 0x7f, 0x21, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_on_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x53, 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, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x2e, 0x2e, 0x2e, 0x46, 0x46, 0x46, 0x57, 0x57, 0x57, 0x60, 0x60, 0x60, 0x62, 0x62, 0x62, 0x5e, 0x5e, 0x5e, 0x4a, 0x4a, 0x4a, 0x12, 0x12, 0x15, 0x25, 0x27, 0x2d, 0x42, 0x42, 0x42, 0x59, 0x59, 0x59, 0x32, 0x32, 0x32, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x39, 0x39, 0x39, 0x49, 0x49, 0x49, 0x5a, 0x5a, 0x5a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x48, 0x48, 0x48, 0x54, 0x54, 0x54, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x25, 0x26, 0x2b, 0x3f, 0x3f, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x2c, 0x2c, 0x2c, 0x58, 0x58, 0x58, 0x1a, 0x1a, 0x1e, 0x40, 0x40, 0x44, 0x56, 0x56, 0x58, 0x80, 0x80, 0x80, 0x79, 0x79, 0x79, 0x3c, 0x3c, 0x3d, 0x2e, 0x2e, 0x30, 0x27, 0x27, 0x29, 0x64, 0x64, 0x66, 0x41, 0x41, 0x41, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5d, 0x5d, 0x5f, 0x34, 0x34, 0x36, 0x52, 0x52, 0x52, 0x3a, 0x3a, 0x3a, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x32, 0x32, 0x37, 0x42, 0x42, 0x44, 0x6a, 0x6a, 0x6d, 0x5b, 0x5b, 0x5b, 0x2f, 0x2f, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x49, 0x4a, 0x0, 0x0, 0x0, 0x50, 0x50, 0x51, 0x70, 0x70, 0x74, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbd, 0xb, 0x85, 0x35, 0x0, 0x0, 0x0, 0x71, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0xff, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xff, 0x7, 0x3a, 0x96, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb, 0x28, 0x76, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x77, 0xde, 0xff, 0xff, 0x45, 0x5, 0x82, 0xff, 0xff, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x37, 0xf, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x4c, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4e, 0x4f, 0xff, 0x50, 0xff, 0xff, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x49, 0x96, 0x6e, 0xf, 0x0, 0x0, 0x1, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x18, 0x5e, 0x0, 0xd0, 0x5c, 0x39, 0x28, 0x49, 0x12, 0xc0, 0x60, 0xb8, 0xda, 0xdd, 0xcb, 0x31, 0x33, 0xb6, 0x6d, 0xdb, 0x5e, 0xdb, 0xd6, 0xfb, 0x17, 0x4e, 0x7d, 0x37, 0xe6, 0xf9, 0x2b, 0x23, 0x7f, 0x9c, 0x20, 0x28, 0x86, 0xe1, 0xb, 0xc1, 0x30, 0x14, 0x99, 0x6a, 0x8e, 0xe2, 0x4, 0x49, 0xd1, 0xcc, 0xda, 0x2, 0x18, 0x9a, 0x22, 0x9, 0x1c, 0x9d, 0xf4, 0x8e, 0xaf, 0xd3, 0x1b, 0x9b, 0x5b, 0xdb, 0x1c, 0x2e, 0x6f, 0x2e, 0x5c, 0xce, 0xf6, 0xd6, 0xe6, 0x6, 0xbd, 0x8e, 0x8f, 0x45, 0x81, 0xf2, 0x5, 0x42, 0x91, 0x58, 0x22, 0x95, 0xc9, 0x61, 0x1, 0x72, 0x99, 0x54, 0x22, 0x16, 0x9, 0x5, 0x7c, 0x74, 0xc4, 0x5e, 0xa1, 0x54, 0xa9, 0x35, 0x5a, 0x58, 0x12, 0xad, 0x46, 0xad, 0x52, 0x2a, 0x86, 0x14, 0x10, 0x1d, 0xa3, 0x37, 0x18, 0x61, 0x1e, 0x26, 0xb3, 0xc5, 0x6a, 0x63, 0xb1, 0x3b, 0x4c, 0x60, 0x34, 0xe8, 0x19, 0x1d, 0x32, 0xc8, 0x9f, 0xda, 0x74, 0xce, 0x8d, 0xdd, 0xe5, 0xf6, 0x98, 0xbd, 0x3e, 0xff, 0x57, 0x2, 0xa6, 0x60, 0x28, 0xec, 0x76, 0xc9, 0x9d, 0x9b, 0x54, 0xbf, 0xe, 0x68, 0x24, 0x1a, 0x8b, 0xcf, 0xb5, 0x4f, 0x24, 0x53, 0x30, 0x44, 0x3a, 0x99, 0x70, 0xc5, 0x33, 0xd1, 0xc8, 0x8f, 0x24, 0x70, 0xe5, 0x56, 0x16, 0xe6, 0x90, 0xcb, 0x27, 0x4d, 0x63, 0x9, 0x25, 0xf3, 0xb9, 0x6c, 0x41, 0x59, 0x64, 0x43, 0x40, 0x88, 0x8d, 0x12, 0xcc, 0xa3, 0x5c, 0x49, 0xc3, 0x18, 0x69, 0x4f, 0x19, 0x4a, 0x1b, 0x4, 0x2b, 0x80, 0x92, 0x9b, 0x55, 0xe8, 0x53, 0xab, 0x37, 0x9a, 0x2d, 0x68, 0x37, 0x3a, 0xd0, 0xee, 0x2, 0x4b, 0xcf, 0x1, 0x13, 0x38, 0x7a, 0xb0, 0xb3, 0xbb, 0xc7, 0xe6, 0x80, 0x51, 0x5b, 0x52, 0xe8, 0xd3, 0xdd, 0xaf, 0x1d, 0x34, 0x6a, 0xed, 0x46, 0x77, 0x20, 0x70, 0x78, 0x4, 0x13, 0x1c, 0x1d, 0xc2, 0x71, 0x81, 0xc2, 0x58, 0x1, 0xfa, 0x44, 0x36, 0x8, 0xa0, 0x71, 0xa, 0xb0, 0x7f, 0xd6, 0x3e, 0x6f, 0xb6, 0xfb, 0x2, 0x17, 0x97, 0x30, 0xc1, 0xe5, 0x5, 0x18, 0xaf, 0x68, 0x9c, 0x15, 0x50, 0x5e, 0xf, 0x7a, 0xd8, 0x3e, 0x7, 0x80, 0x9b, 0x7a, 0xbb, 0x7b, 0x73, 0xde, 0x17, 0xb0, 0xfa, 0x60, 0x2, 0x9f, 0x15, 0xe0, 0x56, 0xf9, 0x5d, 0x80, 0xde, 0x1e, 0xc, 0xd1, 0xe9, 0xd7, 0x8, 0xea, 0x77, 0xed, 0x2e, 0xdc, 0xd7, 0x97, 0x8e, 0x80, 0xda, 0x3a, 0x86, 0x3e, 0xe7, 0x67, 0x70, 0xda, 0x6c, 0xb5, 0xbb, 0xd0, 0x6a, 0x2c, 0x5b, 0x3, 0x94, 0xdc, 0xad, 0x42, 0x9f, 0x76, 0xf3, 0xbc, 0x59, 0x87, 0xaf, 0xe1, 0x9f, 0x2f, 0xd5, 0x5, 0x76, 0xe, 0x1e, 0x60, 0xc0, 0xe9, 0x59, 0x7, 0xa0, 0xd6, 0x2, 0xe8, 0xb4, 0xe6, 0xcf, 0xc1, 0x83, 0x90, 0x40, 0x7e, 0x79, 0x12, 0xfb, 0xbb, 0x90, 0x59, 0x7d, 0x17, 0x1e, 0xd9, 0x5d, 0xf8, 0xd5, 0x6d, 0xec, 0xdf, 0x83, 0xa7, 0xe7, 0xf8, 0x2a, 0xf7, 0x20, 0xfe, 0xfc, 0xc2, 0xde, 0x83, 0xfe, 0x45, 0x62, 0x36, 0x5f, 0xdf, 0x60, 0x69, 0xde, 0x5e, 0x37, 0x19, 0xc5, 0xe8, 0x4d, 0xd3, 0x51, 0xc2, 0x2d, 0xb1, 0xe4, 0xd8, 0x8, 0xb, 0x31, 0x1e, 0x4b, 0xc4, 0x5b, 0x42, 0x4a, 0x87, 0x8e, 0x5f, 0xe5, 0x8, 0xbd, 0xb1, 0x5b, 0xb8, 0x7a, 0xe7, 0x2d, 0xe0, 0xfd, 0xaa, 0xb0, 0xbb, 0x41, 0x47, 0x70, 0x64, 0xf2, 0xab, 0x14, 0x89, 0xbd, 0xf, 0xe5, 0xe2, 0xbf, 0xa0, 0xfc, 0xd8, 0x23, 0x8a, 0x28, 0x32, 0xe3, 0x33, 0xe1, 0x4b, 0xc0, 0x7e, 0xa6, 0xff, 0x87, 0xcf, 0xb, 0x94, 0xb9, 0x37, 0x3c, 0xc6, 0xd8, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_on_disabled_mirrored_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x93, 0x7f, 0x2b, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x19, 0x19, 0x1c, 0x2b, 0x26, 0x2c, 0x40, 0x40, 0x44, 0x4e, 0x4e, 0x52, 0x1a, 0x1a, 0x1d, 0x32, 0x32, 0x37, 0x2c, 0x26, 0x2c, 0x26, 0x25, 0x2a, 0x27, 0x25, 0x2a, 0x11, 0x11, 0x14, 0x2f, 0x26, 0x2d, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x15, 0x15, 0x18, 0x5b, 0x5b, 0x5f, 0x84, 0x84, 0x87, 0x77, 0x77, 0x7a, 0x69, 0x69, 0x6c, 0x20, 0x20, 0x24, 0x24, 0x24, 0x27, 0x23, 0x23, 0x28, 0x1a, 0x1a, 0x1e, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0xd7, 0x77, 0xc6, 0x92, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x1, 0x35, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xd1, 0x72, 0x83, 0x20, 0x10, 0x45, 0x4d, 0x90, 0xb8, 0x18, 0x96, 0x6c, 0xb5, 0x24, 0x41, 0x68, 0x9b, 0xf4, 0xff, 0x3f, 0xb2, 0x84, 0xb4, 0x8a, 0xa, 0x3a, 0x9d, 0x74, 0xa6, 0x2f, 0xb9, 0xbe, 0x38, 0xca, 0x3d, 0x5c, 0x16, 0xd8, 0xa2, 0x78, 0xea, 0x2f, 0xb5, 0xd9, 0xb2, 0xb2, 0xe4, 0x2b, 0x2a, 0x4b, 0xb6, 0xdd, 0x24, 0xed, 0xbb, 0x8a, 0x1, 0x8, 0x21, 0xee, 0xe3, 0xc4, 0x4d, 0x20, 0x6a, 0x91, 0x84, 0x54, 0xbb, 0xb9, 0x7f, 0xcf, 0x40, 0xa2, 0xea, 0x85, 0x32, 0x50, 0x6a, 0xc8, 0xe4, 0xd8, 0x4f, 0xfd, 0x7, 0x26, 0x48, 0xe1, 0x4b, 0x13, 0x7e, 0x37, 0x92, 0x50, 0x51, 0x1b, 0x92, 0xe4, 0x56, 0x72, 0x18, 0xfb, 0x5f, 0x99, 0x40, 0xd4, 0xf1, 0x8, 0x42, 0x6c, 0x17, 0x6b, 0x71, 0x1c, 0x1, 0x4e, 0x40, 0x21, 0x74, 0x24, 0x89, 0xd4, 0x2c, 0x11, 0x4e, 0xb1, 0xff, 0xc, 0x52, 0xe9, 0xe9, 0x8, 0x52, 0x8b, 0x11, 0xf8, 0x39, 0x2, 0x6c, 0x7d, 0x80, 0xf9, 0x8, 0xa4, 0xe1, 0xd5, 0x74, 0x16, 0xb9, 0xee, 0x5a, 0xae, 0xdd, 0xcf, 0xb7, 0xb7, 0x8, 0xe0, 0x2b, 0x40, 0x73, 0x40, 0x4, 0x75, 0x6, 0xa9, 0x43, 0xdd, 0xb9, 0x8, 0xc0, 0x46, 0x0, 0x25, 0xe7, 0x0, 0xa9, 0xfa, 0x0, 0x9d, 0xe7, 0x1b, 0xd4, 0xce, 0xea, 0x1, 0x50, 0x8e, 0x1, 0x89, 0x82, 0x35, 0x3d, 0x20, 0xb8, 0x94, 0xd1, 0x4e, 0xb9, 0x1, 0xc0, 0x7f, 0x91, 0x80, 0x42, 0x2, 0xe5, 0xcd, 0xd6, 0x24, 0x13, 0xbc, 0xc3, 0x5a, 0xd, 0x90, 0x93, 0xf5, 0x4b, 0xf0, 0x8b, 0x49, 0xd6, 0x60, 0x75, 0x17, 0xb4, 0x75, 0xd6, 0x84, 0x95, 0xb8, 0xe4, 0x2e, 0xac, 0x9f, 0x3, 0xba, 0x9d, 0x4b, 0xf4, 0xb3, 0xb4, 0xfd, 0x4c, 0xf1, 0x39, 0x28, 0x3e, 0xc4, 0x63, 0x27, 0xb1, 0x38, 0x3e, 0x7a, 0x17, 0xb2, 0xb7, 0x31, 0xeb, 0x9f, 0xdc, 0xc6, 0xa2, 0xb8, 0x30, 0x68, 0xa7, 0xfd, 0x60, 0xc1, 0x7f, 0x99, 0x77, 0x94, 0xeb, 0x27, 0xd4, 0x70, 0x6f, 0x48, 0xe2, 0x5b, 0xe0, 0x9f, 0xa4, 0xbf, 0xba, 0x66, 0x7b, 0x22, 0x5f, 0x55, 0xb6, 0x27, 0x3e, 0xf5, 0x8f, 0xfa, 0x2, 0xa0, 0x14, 0x20, 0xeb, 0xde, 0xb1, 0x8c, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char toggle_on_mirrored_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x9b, 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, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x24, 0x24, 0x28, 0x20, 0x20, 0x25, 0x14, 0x14, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x22, 0x22, 0x27, 0x10, 0x10, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x19, 0x19, 0x1c, 0x12, 0x12, 0x15, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1e, 0x1e, 0x22, 0x23, 0x23, 0x27, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1d, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x15, 0x15, 0x18, 0xb, 0xb, 0xd, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x1a, 0x1a, 0x1e, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x11, 0x11, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x25, 0x2c, 0x36, 0x28, 0x4c, 0x6b, 0x29, 0x64, 0x92, 0x2a, 0x68, 0x99, 0x2a, 0x66, 0x95, 0x29, 0x5d, 0x85, 0x27, 0x49, 0x65, 0x25, 0x25, 0x28, 0x25, 0x27, 0x2d, 0x27, 0x44, 0x5c, 0x29, 0x60, 0x8c, 0x27, 0x4d, 0x6b, 0x25, 0x3a, 0x4c, 0x25, 0x2d, 0x38, 0x25, 0x26, 0x2c, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2d, 0x25, 0x30, 0x3e, 0x27, 0x49, 0x66, 0x29, 0x5f, 0x89, 0x27, 0x43, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x58, 0x7f, 0x25, 0x35, 0x45, 0x25, 0x34, 0x43, 0x28, 0x59, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x41, 0x57, 0x27, 0x40, 0x57, 0x25, 0x2b, 0x34, 0x25, 0x34, 0x44, 0x29, 0x5d, 0x87, 0x25, 0x2a, 0x33, 0x27, 0x43, 0x5b, 0x27, 0x4e, 0x6d, 0x27, 0x4d, 0x6c, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x28, 0x56, 0x7b, 0x26, 0x3a, 0x4e, 0x26, 0x3b, 0x4e, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x27, 0x44, 0x5d, 0xa6, 0xa2, 0x25, 0x5b, 0x0, 0x0, 0x0, 0x4c, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0xfa, 0xe5, 0x98, 0x8, 0x17, 0x35, 0x73, 0xd9, 0xf3, 0x86, 0x7, 0x3a, 0x96, 0xf9, 0xb4, 0x9a, 0xb9, 0xb, 0x28, 0x77, 0xfb, 0x8b, 0x5, 0x45, 0xde, 0xf6, 0x82, 0x9b, 0xf, 0x37, 0xc6, 0xe6, 0xe9, 0xfb, 0x4e, 0x50, 0x83, 0x9c, 0x78, 0x8c, 0x3c, 0x9c, 0xbb, 0x74, 0xda, 0x87, 0x53, 0x14, 0xd0, 0x92, 0x4e, 0x2c, 0x0, 0x0, 0x2, 0x35, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0x63, 0x60, 0x18, 0x44, 0x80, 0x91, 0x89, 0x99, 0x99, 0x85, 0x20, 0x60, 0x66, 0x66, 0x62, 0xc4, 0xaa, 0x9d, 0x89, 0x85, 0x95, 0x8d, 0x9d, 0x83, 0x93, 0x8b, 0x0, 0xe0, 0xe4, 0x60, 0x67, 0x63, 0x65, 0x61, 0xc2, 0xb4, 0x9d, 0x85, 0x9b, 0x83, 0x87, 0x97, 0x8f, 0x5f, 0x40, 0x50, 0x8, 0x2f, 0x10, 0x14, 0xe0, 0xe7, 0xe3, 0xe5, 0xe1, 0xe0, 0x66, 0x41, 0x73, 0x5, 0x93, 0xb0, 0x88, 0xa8, 0x98, 0xb8, 0x84, 0xa4, 0x94, 0xb4, 0xf, 0x1, 0xe0, 0x2b, 0x2d, 0x23, 0x2b, 0x27, 0x26, 0x2a, 0x22, 0x8c, 0xe2, 0x8, 0x26, 0x79, 0x5, 0x45, 0x25, 0x65, 0x5f, 0xc, 0xd5, 0x7e, 0xfe, 0x7e, 0x58, 0xd, 0x51, 0x51, 0x55, 0x54, 0x90, 0x47, 0x32, 0x81, 0x51, 0x8d, 0x53, 0x5d, 0x43, 0xd3, 0x27, 0x20, 0x30, 0x28, 0x18, 0x2, 0x42, 0x42, 0xc3, 0x2, 0x20, 0x6, 0x84, 0xe3, 0x70, 0x87, 0x96, 0x3a, 0xa7, 0x1a, 0x23, 0xc2, 0xff, 0xec, 0xbc, 0xda, 0xd2, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x20, 0x90, 0x90, 0x98, 0x94, 0x9c, 0x12, 0x1, 0x36, 0x2, 0x97, 0x4f, 0x74, 0x78, 0xd9, 0xe1, 0xe1, 0xc0, 0xa4, 0xab, 0xa7, 0x6f, 0x10, 0x91, 0x9a, 0x96, 0x8e, 0xac, 0x22, 0x23, 0x33, 0x35, 0x2, 0x6f, 0x58, 0x18, 0xea, 0xe9, 0x42, 0x3d, 0xc1, 0x68, 0xa4, 0x60, 0x6c, 0x92, 0x95, 0x9d, 0x19, 0x8b, 0xaa, 0x22, 0x36, 0x33, 0x27, 0xb, 0x9f, 0x9, 0xa6, 0xc6, 0xa, 0x46, 0x10, 0x27, 0x30, 0xb1, 0xf2, 0x98, 0xf9, 0xe4, 0x26, 0xa7, 0xa3, 0xab, 0xc8, 0xcb, 0x2f, 0xc0, 0x1b, 0x1f, 0xe6, 0x3c, 0xac, 0x10, 0x3, 0x58, 0x2c, 0x2c, 0xad, 0x7c, 0xa, 0x8b, 0x30, 0x55, 0x14, 0x17, 0xc2, 0x99, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x3e, 0x95, 0x65, 0x55, 0x3e, 0x95, 0xd5, 0x30, 0x31, 0x6b, 0x4b, 0xb, 0x88, 0x1f, 0x84, 0xd9, 0x8d, 0x6d, 0x7c, 0x6a, 0x6a, 0x31, 0xd, 0xa8, 0xab, 0x81, 0x33, 0xab, 0xeb, 0x4b, 0x1a, 0xca, 0x4a, 0x2a, 0xcb, 0xaa, 0x91, 0xc, 0xb0, 0x35, 0x66, 0x67, 0x6, 0x1b, 0xa0, 0xc6, 0x61, 0xa7, 0xe9, 0xd3, 0xd8, 0x84, 0x69, 0x40, 0x53, 0x23, 0xdc, 0x1, 0x65, 0xcd, 0x3e, 0x3e, 0xf5, 0x2d, 0x95, 0xad, 0xe5, 0x95, 0x8, 0x3, 0x7c, 0xed, 0x38, 0x58, 0x20, 0x6, 0x28, 0xd8, 0xfb, 0xf8, 0x84, 0x24, 0x60, 0x1a, 0x90, 0x10, 0x2, 0x63, 0x55, 0xb6, 0x2, 0x89, 0xb6, 0xd2, 0xca, 0xea, 0xb6, 0x56, 0x84, 0x1, 0x3e, 0xf6, 0xa, 0x2c, 0xc4, 0xba, 0xa0, 0x19, 0xe4, 0x82, 0xd2, 0x76, 0xa0, 0xe6, 0xf2, 0x52, 0x4c, 0x17, 0x10, 0x13, 0x6, 0xad, 0x2d, 0x3e, 0xcd, 0xe5, 0x15, 0x40, 0x3, 0x2a, 0xca, 0x30, 0xc3, 0x80, 0x98, 0x58, 0xa8, 0x2c, 0x6f, 0x2d, 0x2f, 0x5, 0x7, 0x60, 0x2b, 0x66, 0x2c, 0x30, 0xb1, 0x8a, 0x3a, 0x10, 0x4c, 0x7, 0xcd, 0x2d, 0x55, 0xc0, 0xb0, 0xac, 0xf0, 0xf1, 0xa9, 0xaa, 0x80, 0x9, 0x39, 0x8a, 0x42, 0xd3, 0x1, 0xc5, 0x29, 0x11, 0x94, 0x17, 0x9c, 0x48, 0xcf, 0xb, 0xce, 0xf0, 0xbc, 0x0, 0xcb, 0x8d, 0x1d, 0xa8, 0xb9, 0x31, 0x12, 0xbf, 0x7e, 0xe4, 0xdc, 0x8, 0x2a, 0xf, 0x5c, 0x5c, 0xd, 0xb0, 0x94, 0x7, 0xb8, 0xf5, 0xbb, 0xb9, 0x20, 0x95, 0x7, 0xa0, 0x12, 0x89, 0x93, 0xd7, 0xdd, 0x3, 0x53, 0x9d, 0x5f, 0x38, 0xf6, 0xf2, 0x40, 0xc5, 0x93, 0x97, 0x53, 0x1e, 0xb5, 0x4c, 0x53, 0x63, 0x17, 0xe5, 0x13, 0x97, 0xb0, 0xd1, 0xf4, 0x21, 0x8, 0x7c, 0x6d, 0x65, 0xe5, 0xf8, 0x44, 0xd9, 0xd5, 0xd0, 0xa, 0x66, 0x46, 0x16, 0x5d, 0xe, 0x1e, 0x4b, 0x63, 0x3b, 0x2f, 0x21, 0x2, 0xc0, 0xcb, 0xce, 0xd8, 0x92, 0x87, 0x43, 0x97, 0x5, 0xa3, 0x6e, 0x60, 0x64, 0x32, 0x62, 0xb5, 0xf0, 0x56, 0x20, 0x5c, 0x2f, 0x28, 0x78, 0x5b, 0xb0, 0x1a, 0x61, 0xaf, 0x5b, 0x80, 0x35, 0x13, 0xe1, 0x8a, 0x9, 0x58, 0x35, 0xe1, 0xa8, 0x99, 0x86, 0x2e, 0x0, 0x0, 0x69, 0x2c, 0x6b, 0xc2, 0xf1, 0x2f, 0x53, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tooltip_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 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, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xbc, 0x3, 0x4f, 0xe9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x17, 0x8, 0x76, 0x4d, 0x62, 0x70, 0x7f, 0x7f, 0x6, 0x8, 0xfe, 0x95, 0x30, 0x78, 0xdc, 0x1, 0x31, 0xce, 0xb6, 0x50, 0xc8, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xdc, 0x19, 0x0, 0xcf, 0x24, 0x4d, 0xb3, 0xd0, 0x4d, 0xb9, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tree_bg_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tree_bg_disabled_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, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tree_title_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, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x23, 0x25, 0x4c, 0x4a, 0x4e, 0x1, 0xf9, 0x98, 0x2e, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char tree_title_pressed_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, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x36, 0x34, 0x36, 0x4c, 0x4a, 0x4e, 0x14, 0xd7, 0x5b, 0xf8, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char unchecked_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, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char unchecked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x58, 0x58, 0x5b, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x27, 0xa1, 0xa6, 0x53, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xb4, 0xfa, 0xfa, 0xfb, 0xc7, 0x8b, 0xf6, 0x7e, 0x0, 0x0, 0x0, 0x52, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xb5, 0xcf, 0x31, 0x12, 0xc0, 0x20, 0x8, 0x44, 0xd1, 0x15, 0x50, 0x83, 0x11, 0xe5, 0xfe, 0xa7, 0xcd, 0xe8, 0xc4, 0x22, 0xf4, 0x79, 0xe5, 0x36, 0x7c, 0x80, 0x8, 0x89, 0x58, 0xf2, 0x26, 0x4c, 0x9, 0x0, 0x15, 0xf5, 0xb9, 0xb9, 0x16, 0x2, 0xc0, 0x3a, 0xac, 0x6f, 0x36, 0x94, 0x1, 0x88, 0xdb, 0xfd, 0x32, 0x17, 0x0, 0x79, 0xf6, 0x33, 0xf4, 0x99, 0xff, 0x1a, 0xe2, 0xd9, 0x4f, 0x58, 0x5b, 0x61, 0x54, 0xdb, 0x49, 0xbf, 0xea, 0x4a, 0x8f, 0xcf, 0x45, 0xf, 0x4, 0x40, 0x7, 0x90, 0xb0, 0x7b, 0x47, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char updown_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vseparator_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, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xeb, 0x64, 0x9a, 0x78, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0xf, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x83, 0xac, 0x95, 0xc, 0x48, 0x0, 0x0, 0xe, 0x79, 0x1, 0x14, 0x17, 0x9a, 0x55, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vslider_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, 0x51, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x34, 0x33, 0x3a, 0x2d, 0x2c, 0x32, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x40, 0x3e, 0x4a, 0x20, 0x20, 0x24, 0x34, 0x33, 0x3a, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x27, 0x2d, 0x2c, 0x32, 0x1f, 0x1f, 0x23, 0x30, 0x7, 0x9c, 0xfe, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1a, 0x40, 0x5d, 0x19, 0x28, 0x96, 0xf0, 0xfd, 0x94, 0x95, 0xfc, 0x93, 0xfc, 0xc0, 0x0, 0xb4, 0xa, 0x5f, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2c, 0xc8, 0x83, 0x11, 0x0, 0x30, 0x0, 0xc0, 0xc0, 0xda, 0xf6, 0xfe, 0x8b, 0xd6, 0x39, 0xe6, 0xc1, 0xe, 0x12, 0xca, 0x38, 0x67, 0x82, 0xc0, 0x73, 0xe7, 0xa5, 0xd2, 0xc6, 0x68, 0x2b, 0xbf, 0x40, 0xe1, 0x7c, 0x2e, 0x25, 0xfb, 0x20, 0x3e, 0x30, 0x9d, 0x6b, 0x6b, 0x35, 0x6b, 0xf6, 0x81, 0x9b, 0xd2, 0x76, 0x25, 0xf2, 0x7, 0x28, 0xf5, 0x71, 0x60, 0xf4, 0x84, 0x2e, 0xe0, 0x35, 0x49, 0x29, 0x51, 0x90, 0x80, 0xa8, 0x94, 0x24, 0x33, 0x19, 0x2, 0x18, 0x86, 0xa2, 0x5b, 0x8b, 0xe9, 0x30, 0x4c, 0xa7, 0x63, 0x7a, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x5c, 0xa, 0x6b, 0x4f, 0x78, 0xac, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vslider_grabber_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, 0xbc, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0xd2, 0xf2, 0x3a, 0xf, 0xce, 0x78, 0x3f, 0xed, 0x43, 0xff, 0xed, 0xc6, 0xf5, 0x41, 0xa9, 0x8a, 0x86, 0xc, 0x22, 0xc, 0xac, 0x8, 0x5, 0xbc, 0x69, 0x79, 0x93, 0x5e, 0xf4, 0xfd, 0x6f, 0x7, 0xc2, 0xae, 0xff, 0xfd, 0xff, 0xa7, 0xfd, 0xe9, 0x7f, 0x50, 0x31, 0x87, 0x47, 0x87, 0x81, 0x1b, 0x66, 0x8e, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0xa1, 0xb0, 0xf5, 0x7f, 0xe7, 0xff, 0xc9, 0xff, 0x27, 0xdc, 0xb6, 0xf0, 0x7, 0x9a, 0xc3, 0x2, 0x52, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x54, 0x12, 0xa1, 0xa8, 0xe7, 0xff, 0x9c, 0x2f, 0x45, 0xc5, 0xc, 0xdc, 0xf8, 0x14, 0x7c, 0xaf, 0xaa, 0x65, 0xe0, 0xc1, 0x69, 0xc5, 0xc4, 0x3b, 0xe, 0xa1, 0xc, 0x62, 0xc, 0x2c, 0x68, 0x8e, 0xec, 0xf8, 0xdf, 0xfb, 0x7f, 0xda, 0xbf, 0x89, 0xf, 0x4a, 0xa6, 0xf2, 0xe8, 0x0, 0x75, 0x33, 0xa2, 0x79, 0x73, 0xea, 0x87, 0xbe, 0x7b, 0xbd, 0x47, 0x7d, 0x53, 0x58, 0x34, 0x18, 0x84, 0x19, 0x58, 0xb1, 0x7, 0x94, 0xa, 0x83, 0x14, 0x50, 0x27, 0x13, 0x3, 0x3d, 0x1, 0x0, 0x79, 0xc3, 0x79, 0x54, 0x19, 0x56, 0x3b, 0x28, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vslider_grabber_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, 0x0, 0xb4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0x8c, 0xf3, 0x5c, 0xf, 0xfa, 0xbc, 0xf7, 0xfe, 0xe0, 0x71, 0xdb, 0x71, 0xbd, 0x66, 0xaa, 0xa0, 0x21, 0x83, 0x8, 0x3, 0x2b, 0x42, 0x1, 0xaf, 0x71, 0x9e, 0xe7, 0xb, 0xf7, 0xff, 0x2e, 0x40, 0xe8, 0xfa, 0xdf, 0xe3, 0xbf, 0xf7, 0x1f, 0x8f, 0x7, 0x36, 0x73, 0xd8, 0x74, 0x18, 0xb8, 0x61, 0xe6, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x87, 0xce, 0x40, 0x65, 0x5e, 0xff, 0x3d, 0x6e, 0xcb, 0xf8, 0x3, 0xcd, 0x61, 0x1, 0x29, 0x50, 0xf7, 0x79, 0xef, 0x2, 0x95, 0x44, 0x28, 0x72, 0xfb, 0xef, 0xf7, 0xc5, 0xb2, 0x98, 0x81, 0x1b, 0x9f, 0x82, 0xef, 0xb6, 0xb5, 0xc, 0x3c, 0x38, 0xad, 0xf0, 0xbc, 0xa3, 0x10, 0xca, 0x20, 0xc6, 0xc0, 0x82, 0xec, 0x48, 0x30, 0x74, 0xff, 0xef, 0xfd, 0xcf, 0xf3, 0x81, 0xd5, 0x54, 0x36, 0x1d, 0xa0, 0x6e, 0x46, 0xc, 0x6f, 0xba, 0xdf, 0x73, 0x3f, 0xaa, 0x9e, 0xc2, 0xa4, 0xc1, 0x20, 0xcc, 0xc0, 0x8a, 0x3d, 0xa0, 0x54, 0x18, 0xa4, 0x80, 0x3a, 0x99, 0x18, 0xe8, 0x9, 0x0, 0xf1, 0x9, 0x63, 0x9b, 0x53, 0x7f, 0x6d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vslider_grabber_hl_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, 0x6c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x61, 0xb3, 0xbc, 0x63, 0xb7, 0xc8, 0x65, 0xbb, 0xca, 0x60, 0xaf, 0xb1, 0x55, 0x9b, 0x9a, 0x60, 0xb2, 0xbd, 0x5e, 0xb1, 0xcd, 0x61, 0xb3, 0xc2, 0x62, 0xb4, 0xbd, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x63, 0xb7, 0xbf, 0x52, 0x96, 0x95, 0x62, 0xb3, 0xbf, 0x5e, 0xb0, 0xcd, 0x63, 0xb4, 0xb6, 0x60, 0xb1, 0xbc, 0x63, 0xb7, 0xc7, 0x55, 0xa3, 0xc8, 0x4f, 0x98, 0xc4, 0x4b, 0x93, 0xc2, 0x4c, 0x94, 0xc2, 0x54, 0xa2, 0xc8, 0x5a, 0xab, 0xcb, 0x4e, 0x97, 0xc4, 0x49, 0x8f, 0xc0, 0x47, 0x8c, 0xbf, 0x48, 0x8e, 0xc0, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0x5a, 0xac, 0xcc, 0x53, 0x9f, 0xc7, 0x4d, 0x96, 0xc3, 0x4b, 0x92, 0xc2, 0x7f, 0xcb, 0x5d, 0x16, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0x60, 0x65, 0x61, 0x66, 0x62, 0x44, 0xe2, 0x73, 0x4a, 0x88, 0x8b, 0x89, 0x8a, 0x70, 0xb0, 0xb3, 0xc1, 0xe4, 0x25, 0x64, 0x65, 0x80, 0x40, 0x5a, 0x4a, 0x92, 0xb, 0x22, 0xc0, 0x22, 0x2e, 0x3, 0x1, 0xd2, 0x72, 0xdc, 0x68, 0x2, 0xf2, 0x3c, 0xa8, 0x5a, 0x14, 0x78, 0x11, 0x86, 0x2a, 0x2b, 0x29, 0xa, 0xf0, 0xf3, 0x21, 0x59, 0x2b, 0x2c, 0x24, 0xc8, 0x40, 0x3d, 0x0, 0x0, 0x19, 0x8b, 0x5, 0xfc, 0x96, 0x5c, 0x15, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vslider_tick_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x4, 0x3, 0x0, 0x0, 0x0, 0x75, 0x9a, 0xa2, 0xdf, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x81, 0xa2, 0xad, 0x8c, 0xac, 0xb8, 0x38, 0x55, 0x5f, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x7c, 0xda, 0x48, 0x6d, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x79, 0x79, 0x31, 0x1c, 0x18, 0xed, 0xfe, 0x2b, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x3, 0xd7, 0x44, 0x5, 0x6, 0x6, 0xe6, 0x92, 0x30, 0x86, 0xf2, 0x62, 0x3, 0x20, 0xa3, 0xbd, 0x1c, 0x2e, 0x3, 0x0, 0x3f, 0xce, 0x3, 0xaf, 0xed, 0xed, 0x7c, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char vsplit_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, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 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 -}; - -static const unsigned char vsplitter_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x9, 0xa6, 0x3, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x18, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x1c, 0x2c, 0x48, 0xa5, 0xc, 0x33, 0xa4, 0x5a, 0x53, 0x86, 0x29, 0x7, 0xa3, 0x61, 0x0, 0x0, 0x18, 0x61, 0x34, 0xa1, 0xba, 0xa4, 0x4d, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char window_resizer_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, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0xbc, 0xe0, 0x45, 0x3f, 0x1, 0xe9, 0xec, 0xfe, 0x81, 0x94, 0x86, 0xb1, 0x70, 0x48, 0x23, 0x58, 0x84, 0xa4, 0x7, 0x15, 0x0, 0x0, 0xed, 0x9f, 0x18, 0xe8, 0xcd, 0x91, 0xd8, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -static const unsigned char window_resizer_mirrored_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, 0x1, 0x6f, 0x72, 0x4e, 0x54, 0x1, 0xcf, 0xa2, 0x77, 0x9a, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x44, 0xe0, 0x45, 0x3f, 0x76, 0x71, 0x26, 0x18, 0xa3, 0x19, 0xa7, 0x12, 0x38, 0xc8, 0xee, 0xa7, 0xb1, 0x12, 0x98, 0x4, 0x4e, 0x25, 0x8, 0x9, 0x4a, 0x94, 0xc, 0x10, 0x0, 0x0, 0x9d, 0x84, 0x18, 0x73, 0x33, 0x1c, 0x96, 0xd6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -// shaders block diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png Binary files differdeleted file mode 100644 index 64b51c8c9d..0000000000 --- a/scene/resources/default_theme/toggle_off.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_off.svg b/scene/resources/default_theme/toggle_off.svg new file mode 100644 index 0000000000..95ec679cbe --- /dev/null +++ b/scene/resources/default_theme/toggle_off.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".5" stroke-width=".999997"><rect fill="#1a1a1a" height="14" rx="7.000001" width="30" x="1" y="1"/><circle cx="8" cy="8" fill="#fff" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_off_disabled.png b/scene/resources/default_theme/toggle_off_disabled.png Binary files differdeleted file mode 100644 index 250cd29b66..0000000000 --- a/scene/resources/default_theme/toggle_off_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_off_disabled.svg b/scene/resources/default_theme/toggle_off_disabled.svg new file mode 100644 index 0000000000..c86a678768 --- /dev/null +++ b/scene/resources/default_theme/toggle_off_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".25" stroke-width=".999997"><rect fill="#1a1a1a" height="14" rx="7.000001" width="30" x="1" y="1"/><circle cx="8" cy="8" fill="#fff" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_off_disabled_mirrored.png b/scene/resources/default_theme/toggle_off_disabled_mirrored.png Binary files differdeleted file mode 100644 index 799b63c098..0000000000 --- a/scene/resources/default_theme/toggle_off_disabled_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_off_disabled_mirrored.svg b/scene/resources/default_theme/toggle_off_disabled_mirrored.svg new file mode 100644 index 0000000000..0182dd738e --- /dev/null +++ b/scene/resources/default_theme/toggle_off_disabled_mirrored.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".25" stroke-width=".999997" transform="scale(-1 1)"><rect fill="#1a1a1a" height="14" rx="7.000001" width="30" x="-31" y="1"/><circle cx="-24" cy="8" fill="#fff" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_off_mirrored.png b/scene/resources/default_theme/toggle_off_mirrored.png Binary files differdeleted file mode 100644 index 3487605d58..0000000000 --- a/scene/resources/default_theme/toggle_off_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_off_mirrored.svg b/scene/resources/default_theme/toggle_off_mirrored.svg new file mode 100644 index 0000000000..f61517a4ae --- /dev/null +++ b/scene/resources/default_theme/toggle_off_mirrored.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g fill-opacity=".5" stroke-width=".999997" transform="scale(-1 1)"><rect fill="#1a1a1a" height="14" rx="7.000001" width="30" x="-31" y="1"/><circle cx="-24" cy="8" fill="#fff" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_on.png b/scene/resources/default_theme/toggle_on.png Binary files differdeleted file mode 100644 index f0c699c181..0000000000 --- a/scene/resources/default_theme/toggle_on.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_on.svg b/scene/resources/default_theme/toggle_on.svg new file mode 100644 index 0000000000..7e02602792 --- /dev/null +++ b/scene/resources/default_theme/toggle_on.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g stroke-width=".999997" transform="scale(-1 1)"><rect fill="#fff" fill-opacity=".75" height="14" rx="7.000001" width="30" x="-31" y="1"/><circle cx="-24" cy="8" fill="#1a1a1a" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_on_disabled.png b/scene/resources/default_theme/toggle_on_disabled.png Binary files differdeleted file mode 100644 index b1dacbaf32..0000000000 --- a/scene/resources/default_theme/toggle_on_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_on_disabled.svg b/scene/resources/default_theme/toggle_on_disabled.svg new file mode 100644 index 0000000000..72ce5bb9b2 --- /dev/null +++ b/scene/resources/default_theme/toggle_on_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g stroke-width=".999997" transform="scale(-1 1)"><rect fill="#fff" fill-opacity=".37" height="14" rx="7.000001" width="30" x="-31" y="1"/><circle cx="-24" cy="8" fill="#1a1a1a" fill-opacity=".5" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_on_disabled_mirrored.png b/scene/resources/default_theme/toggle_on_disabled_mirrored.png Binary files differdeleted file mode 100644 index 0758babd4f..0000000000 --- a/scene/resources/default_theme/toggle_on_disabled_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_on_disabled_mirrored.svg b/scene/resources/default_theme/toggle_on_disabled_mirrored.svg new file mode 100644 index 0000000000..340a386def --- /dev/null +++ b/scene/resources/default_theme/toggle_on_disabled_mirrored.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g stroke-width=".999997"><rect fill="#fff" fill-opacity=".37" height="14" rx="7.000001" width="30" x="1" y="1"/><circle cx="8" cy="8" fill="#1a1a1a" fill-opacity=".5" r="5"/></g></svg> diff --git a/scene/resources/default_theme/toggle_on_mirrored.png b/scene/resources/default_theme/toggle_on_mirrored.png Binary files differdeleted file mode 100644 index 3fd953c8e2..0000000000 --- a/scene/resources/default_theme/toggle_on_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/toggle_on_mirrored.svg b/scene/resources/default_theme/toggle_on_mirrored.svg new file mode 100644 index 0000000000..fbc6be2af9 --- /dev/null +++ b/scene/resources/default_theme/toggle_on_mirrored.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 32 15.999999" width="32" xmlns="http://www.w3.org/2000/svg"><g stroke-width=".999997"><rect fill="#fff" fill-opacity=".75" height="14" rx="7.000001" width="30" x="1" y="1"/><circle cx="8" cy="8" fill="#1a1a1a" r="5"/></g></svg> diff --git a/scene/resources/default_theme/tooltip_bg.png b/scene/resources/default_theme/tooltip_bg.png Binary files differdeleted file mode 100644 index 07b7d942ca..0000000000 --- a/scene/resources/default_theme/tooltip_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png Binary files differdeleted file mode 100644 index 2b0c506f34..0000000000 --- a/scene/resources/default_theme/tree_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/tree_bg_disabled.png b/scene/resources/default_theme/tree_bg_disabled.png Binary files differdeleted file mode 100644 index 69d78febd9..0000000000 --- a/scene/resources/default_theme/tree_bg_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/tree_title.png b/scene/resources/default_theme/tree_title.png Binary files differdeleted file mode 100644 index e5f3f49695..0000000000 --- a/scene/resources/default_theme/tree_title.png +++ /dev/null diff --git a/scene/resources/default_theme/tree_title_pressed.png b/scene/resources/default_theme/tree_title_pressed.png Binary files differdeleted file mode 100644 index 35e2bb3008..0000000000 --- a/scene/resources/default_theme/tree_title_pressed.png +++ /dev/null diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png Binary files differdeleted file mode 100644 index 8c818af755..0000000000 --- a/scene/resources/default_theme/unchecked.png +++ /dev/null diff --git a/scene/resources/default_theme/unchecked.svg b/scene/resources/default_theme/unchecked.svg new file mode 100644 index 0000000000..f475108f44 --- /dev/null +++ b/scene/resources/default_theme/unchecked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#1a1a1a" fill-opacity=".5" stroke-width="1.16667"/></svg> diff --git a/scene/resources/default_theme/unchecked_disabled.png b/scene/resources/default_theme/unchecked_disabled.png Binary files differdeleted file mode 100644 index bef9316f58..0000000000 --- a/scene/resources/default_theme/unchecked_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/unchecked_disabled.svg b/scene/resources/default_theme/unchecked_disabled.svg new file mode 100644 index 0000000000..195b85e37f --- /dev/null +++ b/scene/resources/default_theme/unchecked_disabled.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#1a1a1a" fill-opacity=".25" stroke-width="1.16667"/></svg> diff --git a/scene/resources/default_theme/updown.png b/scene/resources/default_theme/updown.png Binary files differdeleted file mode 100644 index 56f81921e8..0000000000 --- a/scene/resources/default_theme/updown.png +++ /dev/null diff --git a/scene/resources/default_theme/updown.svg b/scene/resources/default_theme/updown.svg new file mode 100644 index 0000000000..d6a630740f --- /dev/null +++ b/scene/resources/default_theme/updown.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fff" stroke-opacity=".75" stroke-width="2"><path d="m4 6 4-3.5 4 3.5"/><path d="m12 10-4 3.5-4-3.5"/></g></svg> diff --git a/scene/resources/default_theme/visibility_visible.svg b/scene/resources/default_theme/visibility_visible.svg new file mode 100644 index 0000000000..ac1af8db0a --- /dev/null +++ b/scene/resources/default_theme/visibility_visible.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2c-2.557 0-5.791 1.948-6.955 5.705-.057.186-.059.384-.006.57 1.124 3.936 4.461 5.725 6.961 5.725s5.836-1.789 6.961-5.725c.052-.18.052-.372 0-.552-1.1-3.788-4.407-5.723-6.961-5.723zm0 2c2.194 0 4 1.806 4 4s-1.806 4-4 4-4-1.806-4-4 1.806-4 4-4zm0 2c-1.097 0-2 .903-2 2s.903 2 2 2 2-.903 2-2-.903-2-2-2z" fill="#b2b2b2"/></svg> diff --git a/scene/resources/default_theme/vseparator.png b/scene/resources/default_theme/vseparator.png Binary files differdeleted file mode 100644 index 51e79f3ac5..0000000000 --- a/scene/resources/default_theme/vseparator.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png Binary files differdeleted file mode 100644 index ba3244e3e5..0000000000 --- a/scene/resources/default_theme/vslider_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png Binary files differdeleted file mode 100644 index 6c6bf93e68..0000000000 --- a/scene/resources/default_theme/vslider_grabber.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_grabber_disabled.png b/scene/resources/default_theme/vslider_grabber_disabled.png Binary files differdeleted file mode 100644 index 49cced5055..0000000000 --- a/scene/resources/default_theme/vslider_grabber_disabled.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png Binary files differdeleted file mode 100644 index 28774fdbf8..0000000000 --- a/scene/resources/default_theme/vslider_grabber_hl.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_tick.png b/scene/resources/default_theme/vslider_tick.png Binary files differdeleted file mode 100644 index bde788b563..0000000000 --- a/scene/resources/default_theme/vslider_tick.png +++ /dev/null diff --git a/scene/resources/default_theme/vslider_tick.svg b/scene/resources/default_theme/vslider_tick.svg new file mode 100644 index 0000000000..1365d36aca --- /dev/null +++ b/scene/resources/default_theme/vslider_tick.svg @@ -0,0 +1 @@ +<svg height="4" viewBox="0 0 16 3.9999998" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m-3 0h2v16h-2z" fill="#fff" fill-opacity=".25" stroke-width=".285079" transform="rotate(-90)"/></svg> diff --git a/scene/resources/default_theme/vsplit_bg.png b/scene/resources/default_theme/vsplit_bg.png Binary files differdeleted file mode 100644 index a5749f6d5c..0000000000 --- a/scene/resources/default_theme/vsplit_bg.png +++ /dev/null diff --git a/scene/resources/default_theme/vsplitter.png b/scene/resources/default_theme/vsplitter.png Binary files differdeleted file mode 100644 index dde1f390df..0000000000 --- a/scene/resources/default_theme/vsplitter.png +++ /dev/null diff --git a/scene/resources/default_theme/vsplitter.svg b/scene/resources/default_theme/vsplitter.svg new file mode 100644 index 0000000000..c46d785925 --- /dev/null +++ b/scene/resources/default_theme/vsplitter.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" viewBox="0 0 48 8" xmlns="http://www.w3.org/2000/svg"><path d="m4 4h40" fill="none" stroke="#808080" stroke-opacity=".65" stroke-width="1.7"/></svg> diff --git a/scene/resources/default_theme/window_resizer.png b/scene/resources/default_theme/window_resizer.png Binary files differdeleted file mode 100644 index b06e6f5366..0000000000 --- a/scene/resources/default_theme/window_resizer.png +++ /dev/null diff --git a/scene/resources/default_theme/window_resizer_mirrored.png b/scene/resources/default_theme/window_resizer_mirrored.png Binary files differdeleted file mode 100644 index bbce5f1406..0000000000 --- a/scene/resources/default_theme/window_resizer_mirrored.png +++ /dev/null diff --git a/scene/resources/default_theme/zoom_less.svg b/scene/resources/default_theme/zoom_less.svg new file mode 100644 index 0000000000..a438f7f683 --- /dev/null +++ b/scene/resources/default_theme/zoom_less.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#b2b2b2" fill-opacity=".65" r="8"/><circle cx="8" cy="8" fill="#fefffe" r="7"/><path d="m4 7h8v2h-8z" fill="#010001"/></svg> diff --git a/scene/resources/default_theme/zoom_more.svg b/scene/resources/default_theme/zoom_more.svg new file mode 100644 index 0000000000..192e0ed907 --- /dev/null +++ b/scene/resources/default_theme/zoom_more.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#b2b2b2" fill-opacity=".65" r="8"/><circle cx="8" cy="8" fill="#fefffe" r="7"/><path d="m7 4h2v3h3v2h-3v3h-2v-3h-3v-2h3z" fill="#010001"/></svg> diff --git a/scene/resources/default_theme/zoom_reset.svg b/scene/resources/default_theme/zoom_reset.svg new file mode 100644 index 0000000000..427214cda2 --- /dev/null +++ b/scene/resources/default_theme/zoom_reset.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" fill="#b2b2b2" fill-opacity=".65" r="8"/><circle cx="8" cy="8" fill="#fefffe" r="7"/><path d="m8.016 4.002h.029c.548 0 .999.45 1 .998v7h-2v-5.131l-1.445.963-1.11-1.664 3-2c.156-.103.338-.161.526-.166z" fill="#010001"/></svg> diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 7e71ad8986..b13ae9d016 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -496,13 +496,13 @@ bool Environment::is_sdfgi_enabled() const { return sdfgi_enabled; } -void Environment::set_sdfgi_cascades(SDFGICascades p_cascades) { - ERR_FAIL_INDEX(p_cascades, SDFGI_CASCADES_8 + 1); +void Environment::set_sdfgi_cascades(int p_cascades) { + ERR_FAIL_COND_MSG(p_cascades < 1 || p_cascades > 8, "Invalid number of SDFGI cascades (must be between 1 and 8)."); sdfgi_cascades = p_cascades; _update_sdfgi(); } -Environment::SDFGICascades Environment::get_sdfgi_cascades() const { +int Environment::get_sdfgi_cascades() const { return sdfgi_cascades; } @@ -517,9 +517,7 @@ float Environment::get_sdfgi_min_cell_size() const { void Environment::set_sdfgi_max_distance(float p_distance) { p_distance /= 64.0; - int cc[3] = { 4, 6, 8 }; - int cascades = cc[sdfgi_cascades]; - for (int i = 0; i < cascades; i++) { + for (int i = 0; i < sdfgi_cascades; i++) { p_distance *= 0.5; //halve for each cascade } sdfgi_min_cell_size = p_distance; @@ -529,9 +527,7 @@ void Environment::set_sdfgi_max_distance(float p_distance) { float Environment::get_sdfgi_max_distance() const { float md = sdfgi_min_cell_size; md *= 64.0; - int cc[3] = { 4, 6, 8 }; - int cascades = cc[sdfgi_cascades]; - for (int i = 0; i < cascades; i++) { + for (int i = 0; i < sdfgi_cascades; i++) { md *= 2.0; } return md; @@ -612,7 +608,7 @@ void Environment::_update_sdfgi() { RS::get_singleton()->environment_set_sdfgi( environment, sdfgi_enabled, - RS::EnvironmentSDFGICascades(sdfgi_cascades), + sdfgi_cascades, sdfgi_min_cell_size, RS::EnvironmentSDFGIYScale(sdfgi_y_scale), sdfgi_use_occlusion, @@ -732,6 +728,24 @@ float Environment::get_glow_hdr_luminance_cap() const { return glow_hdr_luminance_cap; } +void Environment::set_glow_map_strength(float p_strength) { + glow_map_strength = p_strength; + _update_glow(); +} + +float Environment::get_glow_map_strength() const { + return glow_map_strength; +} + +void Environment::set_glow_map(Ref<Texture> p_glow_map) { + glow_map = p_glow_map; + _update_glow(); +} + +Ref<Texture> Environment::get_glow_map() const { + return glow_map; +} + void Environment::_update_glow() { Vector<float> normalized_levels; if (glow_normalize_levels) { @@ -747,6 +761,15 @@ void Environment::_update_glow() { normalized_levels = glow_levels; } + float _glow_map_strength = 0.0f; + RID glow_map_rid; + if (glow_map.is_valid()) { + glow_map_rid = glow_map->get_rid(); + _glow_map_strength = glow_map_strength; + } else { + glow_map_rid = RID(); + } + RS::get_singleton()->environment_set_glow( environment, glow_enabled, @@ -758,7 +781,9 @@ void Environment::_update_glow() { RS::EnvironmentGlowBlendMode(glow_blend_mode), glow_hdr_bleed_threshold, glow_hdr_bleed_scale, - glow_hdr_luminance_cap); + glow_hdr_luminance_cap, + _glow_map_strength, + glow_map_rid); } // Fog @@ -1303,7 +1328,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_occlusion"), "set_sdfgi_use_occlusion", "is_sdfgi_using_occlusion"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_read_sky_light"), "set_sdfgi_read_sky_light", "is_sdfgi_reading_sky_light"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_ENUM, "4 Cascades,6 Cascades,8 Cascades"), "set_sdfgi_cascades", "get_sdfgi_cascades"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_RANGE, "1,8,1"), "set_sdfgi_cascades", "get_sdfgi_cascades"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_max_distance", "get_sdfgi_max_distance"); @@ -1336,6 +1361,10 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_glow_hdr_bleed_scale"), &Environment::get_glow_hdr_bleed_scale); ClassDB::bind_method(D_METHOD("set_glow_hdr_luminance_cap", "amount"), &Environment::set_glow_hdr_luminance_cap); ClassDB::bind_method(D_METHOD("get_glow_hdr_luminance_cap"), &Environment::get_glow_hdr_luminance_cap); + ClassDB::bind_method(D_METHOD("set_glow_map_strength", "strength"), &Environment::set_glow_map_strength); + ClassDB::bind_method(D_METHOD("get_glow_map_strength"), &Environment::get_glow_map_strength); + ClassDB::bind_method(D_METHOD("set_glow_map", "mode"), &Environment::set_glow_map); + ClassDB::bind_method(D_METHOD("get_glow_map"), &Environment::get_glow_map); ADD_GROUP("Glow", "glow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "glow_enabled"), "set_glow_enabled", "is_glow_enabled"); @@ -1355,6 +1384,8 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_threshold", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_threshold", "get_glow_hdr_bleed_threshold"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_scale", PROPERTY_HINT_RANGE, "0.0,4.0,0.01"), "set_glow_hdr_bleed_scale", "get_glow_hdr_bleed_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_hdr_luminance_cap", PROPERTY_HINT_RANGE, "0.0,256.0,0.01"), "set_glow_hdr_luminance_cap", "get_glow_hdr_luminance_cap"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "glow_map_strength", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_glow_map_strength", "get_glow_map_strength"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "glow_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_glow_map", "get_glow_map"); // Fog @@ -1480,10 +1511,6 @@ void Environment::_bind_methods() { BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_REPLACE); BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_MIX); - BIND_ENUM_CONSTANT(SDFGI_CASCADES_4); - BIND_ENUM_CONSTANT(SDFGI_CASCADES_6); - BIND_ENUM_CONSTANT(SDFGI_CASCADES_8); - BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_DISABLED); BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_75_PERCENT); BIND_ENUM_CONSTANT(SDFGI_Y_SCALE_50_PERCENT); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 98e755c336..b04723a221 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -70,12 +70,6 @@ public: TONE_MAPPER_ACES, }; - enum SDFGICascades { - SDFGI_CASCADES_4, - SDFGI_CASCADES_6, - SDFGI_CASCADES_8, - }; - enum SDFGIYScale { SDFGI_Y_SCALE_DISABLED, SDFGI_Y_SCALE_75_PERCENT, @@ -153,7 +147,7 @@ private: // SDFGI bool sdfgi_enabled = false; - SDFGICascades sdfgi_cascades = SDFGI_CASCADES_6; + int sdfgi_cascades = 6; float sdfgi_min_cell_size = 0.2; SDFGIYScale sdfgi_y_scale = SDFGI_Y_SCALE_DISABLED; bool sdfgi_use_occlusion = false; @@ -176,6 +170,8 @@ private: float glow_hdr_bleed_threshold = 1.0; float glow_hdr_bleed_scale = 2.0; float glow_hdr_luminance_cap = 12.0; + float glow_map_strength = 0.8f; + Ref<Texture> glow_map; void _update_glow(); // Fog @@ -320,8 +316,8 @@ public: // SDFGI void set_sdfgi_enabled(bool p_enabled); bool is_sdfgi_enabled() const; - void set_sdfgi_cascades(SDFGICascades p_cascades); - SDFGICascades get_sdfgi_cascades() const; + void set_sdfgi_cascades(int p_cascades); + int get_sdfgi_cascades() const; void set_sdfgi_min_cell_size(float p_size); float get_sdfgi_min_cell_size() const; void set_sdfgi_max_distance(float p_distance); @@ -366,6 +362,10 @@ public: float get_glow_hdr_bleed_scale() const; void set_glow_hdr_luminance_cap(float p_amount); float get_glow_hdr_luminance_cap() const; + void set_glow_map_strength(float p_strength); + float get_glow_map_strength() const; + void set_glow_map(Ref<Texture> p_glow_map); + Ref<Texture> get_glow_map() const; // Fog @@ -433,7 +433,6 @@ VARIANT_ENUM_CAST(Environment::BGMode) VARIANT_ENUM_CAST(Environment::AmbientSource) VARIANT_ENUM_CAST(Environment::ReflectionSource) VARIANT_ENUM_CAST(Environment::ToneMapper) -VARIANT_ENUM_CAST(Environment::SDFGICascades) VARIANT_ENUM_CAST(Environment::SDFGIYScale) VARIANT_ENUM_CAST(Environment::GlowBlendMode) diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index d9e0c301de..b512acdd8a 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -30,6 +30,7 @@ #include "font.h" +#include "core/io/image_loader.h" #include "core/io/resource_loader.h" #include "core/string/translation.h" #include "core/templates/hashfuncs.h" @@ -64,6 +65,9 @@ _FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const { } void FontData::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontData::load_bitmap_font); + ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontData::load_dynamic_font); + ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data); ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data); @@ -428,11 +432,766 @@ void FontData::reset_state() { hinting = TextServer::HINTING_LIGHT; msdf_pixel_range = 14; msdf_size = 128; + fixed_size = 0; oversampling = 0.f; } +void FontData::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) { + int w = p_source->get_width(); + int h = p_source->get_height(); + + PackedByteArray imgdata = p_source->get_data(); + const uint8_t *r = imgdata.ptr(); + + PackedByteArray imgdata_r; + imgdata_r.resize(w * h * 2); + uint8_t *wr = imgdata_r.ptrw(); + + PackedByteArray imgdata_g; + imgdata_g.resize(w * h * 2); + uint8_t *wg = imgdata_g.ptrw(); + + PackedByteArray imgdata_b; + imgdata_b.resize(w * h * 2); + uint8_t *wb = imgdata_b.ptrw(); + + PackedByteArray imgdata_a; + imgdata_a.resize(w * h * 2); + uint8_t *wa = imgdata_a.ptrw(); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int ofs_src = (i * w + j) * 4; + int ofs_dst = (i * w + j) * 2; + wr[ofs_dst + 0] = 255; + wr[ofs_dst + 1] = r[ofs_src + 0]; + wg[ofs_dst + 0] = 255; + wg[ofs_dst + 1] = r[ofs_src + 1]; + wb[ofs_dst + 0] = 255; + wb[ofs_dst + 1] = r[ofs_src + 2]; + wa[ofs_dst + 0] = 255; + wa[ofs_dst + 1] = r[ofs_src + 3]; + } + } + Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r); + Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g); + Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b); + Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a); +} + +void FontData::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) { + int w = p_source->get_width(); + int h = p_source->get_height(); + + PackedByteArray imgdata = p_source->get_data(); + const uint8_t *r = imgdata.ptr(); + + PackedByteArray imgdata_r; + imgdata_r.resize(w * h * 2); + uint8_t *wr = imgdata_r.ptrw(); + + PackedByteArray imgdata_g; + imgdata_g.resize(w * h * 2); + uint8_t *wg = imgdata_g.ptrw(); + + PackedByteArray imgdata_b; + imgdata_b.resize(w * h * 2); + uint8_t *wb = imgdata_b.ptrw(); + + PackedByteArray imgdata_a; + imgdata_a.resize(w * h * 2); + uint8_t *wa = imgdata_a.ptrw(); + + PackedByteArray imgdata_ro; + imgdata_ro.resize(w * h * 2); + uint8_t *wro = imgdata_ro.ptrw(); + + PackedByteArray imgdata_go; + imgdata_go.resize(w * h * 2); + uint8_t *wgo = imgdata_go.ptrw(); + + PackedByteArray imgdata_bo; + imgdata_bo.resize(w * h * 2); + uint8_t *wbo = imgdata_bo.ptrw(); + + PackedByteArray imgdata_ao; + imgdata_ao.resize(w * h * 2); + uint8_t *wao = imgdata_ao.ptrw(); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int ofs_src = (i * w + j) * 4; + int ofs_dst = (i * w + j) * 2; + wr[ofs_dst + 0] = 255; + wro[ofs_dst + 0] = 255; + if (r[ofs_src + 0] > 0x0F) { + wr[ofs_dst + 1] = (r[ofs_src + 0] - 0x0F) * 2; + wro[ofs_dst + 1] = 0; + } else { + wr[ofs_dst + 1] = 0; + wro[ofs_dst + 1] = r[ofs_src + 0] * 2; + } + wg[ofs_dst + 0] = 255; + wgo[ofs_dst + 0] = 255; + if (r[ofs_src + 1] > 0x0F) { + wg[ofs_dst + 1] = (r[ofs_src + 1] - 0x0F) * 2; + wgo[ofs_dst + 1] = 0; + } else { + wg[ofs_dst + 1] = 0; + wgo[ofs_dst + 1] = r[ofs_src + 1] * 2; + } + wb[ofs_dst + 0] = 255; + wbo[ofs_dst + 0] = 255; + if (r[ofs_src + 2] > 0x0F) { + wb[ofs_dst + 1] = (r[ofs_src + 2] - 0x0F) * 2; + wbo[ofs_dst + 1] = 0; + } else { + wb[ofs_dst + 1] = 0; + wbo[ofs_dst + 1] = r[ofs_src + 2] * 2; + } + wa[ofs_dst + 0] = 255; + wao[ofs_dst + 0] = 255; + if (r[ofs_src + 3] > 0x0F) { + wa[ofs_dst + 1] = (r[ofs_src + 3] - 0x0F) * 2; + wao[ofs_dst + 1] = 0; + } else { + wa[ofs_dst + 1] = 0; + wao[ofs_dst + 1] = r[ofs_src + 3] * 2; + } + } + } + Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r); + Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g); + Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b); + Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a)); + set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a); + + Ref<Image> img_ro = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ro)); + set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 0, img_ro); + Ref<Image> img_go = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_go)); + set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 1, img_go); + Ref<Image> img_bo = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_bo)); + set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 2, img_bo); + Ref<Image> img_ao = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ao)); + set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao); +} + +void FontData::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) { + int w = p_source->get_width(); + int h = p_source->get_height(); + + PackedByteArray imgdata = p_source->get_data(); + const uint8_t *r = imgdata.ptr(); + + PackedByteArray imgdata_g; + imgdata_g.resize(w * h * 4); + uint8_t *wg = imgdata_g.ptrw(); + + PackedByteArray imgdata_o; + imgdata_o.resize(w * h * 4); + uint8_t *wo = imgdata_o.ptrw(); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int ofs = (i * w + j) * 4; + + if (r[ofs + 0] > 0x7F) { + wg[ofs + 0] = r[ofs + 0]; + wo[ofs + 0] = 0; + } else { + wg[ofs + 0] = 0; + wo[ofs + 0] = r[ofs + 0] * 2; + } + if (r[ofs + 1] > 0x7F) { + wg[ofs + 1] = r[ofs + 1]; + wo[ofs + 1] = 0; + } else { + wg[ofs + 1] = 0; + wo[ofs + 1] = r[ofs + 1] * 2; + } + if (r[ofs + 2] > 0x7F) { + wg[ofs + 2] = r[ofs + 2]; + wo[ofs + 2] = 0; + } else { + wg[ofs + 2] = 0; + wo[ofs + 2] = r[ofs + 2] * 2; + } + if (r[ofs + 3] > 0x7F) { + wg[ofs + 3] = r[ofs + 3]; + wo[ofs + 3] = 0; + } else { + wg[ofs + 3] = 0; + wo[ofs + 3] = r[ofs + 3] * 2; + } + } + } + Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_g)); + set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g); + + Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_o)); + set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o); +} + +void FontData::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) { + int w = p_source->get_width(); + int h = p_source->get_height(); + + PackedByteArray imgdata = p_source->get_data(); + const uint8_t *r = imgdata.ptr(); + + int size = 4; + if (p_source->get_format() == Image::FORMAT_L8) { + size = 1; + p_ch = 0; + } + + PackedByteArray imgdata_g; + imgdata_g.resize(w * h * 2); + uint8_t *wg = imgdata_g.ptrw(); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int ofs_src = (i * w + j) * size; + int ofs_dst = (i * w + j) * 2; + wg[ofs_dst + 0] = 255; + wg[ofs_dst + 1] = r[ofs_src + p_ch]; + } + } + Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); + set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g); +} + +void FontData::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) { + int w = p_source->get_width(); + int h = p_source->get_height(); + + PackedByteArray imgdata = p_source->get_data(); + const uint8_t *r = imgdata.ptr(); + + int size = 4; + if (p_source->get_format() == Image::FORMAT_L8) { + size = 1; + p_ch = 0; + } + + PackedByteArray imgdata_g; + imgdata_g.resize(w * h * 2); + uint8_t *wg = imgdata_g.ptrw(); + + PackedByteArray imgdata_o; + imgdata_o.resize(w * h * 2); + uint8_t *wo = imgdata_o.ptrw(); + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int ofs_src = (i * w + j) * size; + int ofs_dst = (i * w + j) * 2; + wg[ofs_dst + 0] = 255; + wo[ofs_dst + 0] = 255; + if (r[ofs_src + p_ch] > 0x7F) { + wg[ofs_dst + 1] = r[ofs_src + p_ch]; + wo[ofs_dst + 1] = 0; + } else { + wg[ofs_dst + 1] = 0; + wo[ofs_dst + 1] = r[ofs_src + p_ch] * 2; + } + } + } + Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); + set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g); + + Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_o)); + set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o); +} + /*************************************************************************/ +Error FontData::load_bitmap_font(const String &p_path) { + reset_state(); + + antialiased = false; + msdf = false; + force_autohinter = false; + hinting = TextServer::HINTING_NONE; + oversampling = 1.0f; + + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); + if (f == nullptr) { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Cannot open font from file ") + "\"" + p_path + "\"."); + } + + int base_size = 16; + int height = 0; + int ascent = 0; + int outline = 0; + uint32_t st_flags = 0; + String font_name; + + bool packed = false; + uint8_t ch[4] = { 0, 0, 0, 0 }; // RGBA + int first_gl_ch = -1; + int first_ol_ch = -1; + int first_cm_ch = -1; + + unsigned char magic[4]; + f->get_buffer((unsigned char *)&magic, 4); + if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') { + // Binary BMFont file. + ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(TTR("Version %d of BMFont is not supported."), (int)magic[3])); + + uint8_t block_type = f->get_8(); + uint32_t block_size = f->get_32(); + while (!f->eof_reached()) { + uint64_t off = f->get_position(); + switch (block_type) { + case 1: /* info */ { + ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, TTR("Invalid BMFont info block size.")); + base_size = f->get_16(); + uint8_t flags = f->get_8(); + ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); + if (flags & (1 << 3)) { + st_flags |= TextServer::FONT_BOLD; + } + if (flags & (1 << 2)) { + st_flags |= TextServer::FONT_ITALIC; + } + f->get_8(); // non-unicode charset, skip + f->get_16(); // stretch_h, skip + f->get_8(); // aa, skip + f->get_32(); // padding, skip + f->get_16(); // spacing, skip + outline = f->get_8(); + // font name + PackedByteArray name_data; + name_data.resize(block_size - 14); + f->get_buffer(name_data.ptrw(), block_size - 14); + font_name = String::utf8((const char *)name_data.ptr(), block_size - 14); + set_fixed_size(base_size); + } break; + case 2: /* common */ { + ERR_FAIL_COND_V_MSG(block_size != 15, ERR_CANT_CREATE, TTR("Invalid BMFont common block size.")); + height = f->get_16(); + ascent = f->get_16(); + f->get_32(); // scale, skip + f->get_16(); // pages, skip + uint8_t flags = f->get_8(); + packed = (flags & 0x01); + ch[3] = f->get_8(); + ch[0] = f->get_8(); + ch[1] = f->get_8(); + ch[2] = f->get_8(); + for (int i = 0; i < 4; i++) { + if (ch[i] == 0 && first_gl_ch == -1) { + first_gl_ch = i; + } + if (ch[i] == 1 && first_ol_ch == -1) { + first_ol_ch = i; + } + if (ch[i] == 2 && first_cm_ch == -1) { + first_cm_ch = i; + } + } + } break; + case 3: /* pages */ { + int page = 0; + CharString cs; + char32_t c = f->get_8(); + while (!f->eof_reached() && f->get_position() <= off + block_size) { + if (c == '\0') { + String base_dir = p_path.get_base_dir(); + String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length())); + if (RenderingServer::get_singleton() != nullptr) { + Ref<Image> img; + img.instantiate(); + Error err = ImageLoader::load_image(file, img); + ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture: ") + "\"" + file + "\"."); + + if (packed) { + if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_packed_8bit(img, page, base_size); + } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_packed_4bit(img, page, base_size); + } else { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); + } + } else { + if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + set_texture_image(0, Vector2i(base_size, 0), page, img); + } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_rgba_4bit(img, page, base_size); + } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_8bit(img, page, first_gl_ch, base_size, 0); + _convert_mono_8bit(img, page, first_ol_ch, base_size, 1); + } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_4bit(img, page, first_cm_ch, base_size, 1); + } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_8bit(img, page, first_gl_ch, base_size, 0); + } else { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); + } + } + } + page++; + cs = ""; + } else { + cs += c; + } + c = f->get_8(); + } + } break; + case 4: /* chars */ { + int char_count = block_size / 20; + for (int i = 0; i < char_count; i++) { + Vector2 advance; + Vector2 size; + Vector2 offset; + Rect2 uv_rect; + + char32_t idx = f->get_32(); + uv_rect.position.x = (int16_t)f->get_16(); + uv_rect.position.y = (int16_t)f->get_16(); + uv_rect.size.width = (int16_t)f->get_16(); + size.width = uv_rect.size.width; + uv_rect.size.height = (int16_t)f->get_16(); + size.height = uv_rect.size.height; + offset.x = (int16_t)f->get_16(); + offset.y = (int16_t)f->get_16() - ascent; + advance.x = (int16_t)f->get_16(); + if (advance.x < 0) { + advance.x = size.width + 1; + } + + int texture_idx = f->get_8(); + uint8_t channel = f->get_8(); + + ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, TTR("Invalid glyph channel.")); + int ch_off = 0; + switch (channel) { + case 1: + ch_off = 2; + break; // B + case 2: + ch_off = 1; + break; // G + case 4: + ch_off = 0; + break; // R + case 8: + ch_off = 3; + break; // A + default: + ch_off = 0; + break; + } + set_glyph_advance(0, base_size, idx, advance); + set_glyph_offset(0, Vector2i(base_size, 0), idx, offset); + set_glyph_size(0, Vector2i(base_size, 0), idx, size); + set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect); + set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off); + if (outline > 0) { + set_glyph_offset(0, Vector2i(base_size, 1), idx, offset); + set_glyph_size(0, Vector2i(base_size, 1), idx, size); + set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect); + set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off); + } + } + } break; + case 5: /* kerning */ { + int pair_count = block_size / 10; + for (int i = 0; i < pair_count; i++) { + Vector2i kpk; + kpk.x = f->get_32(); + kpk.y = f->get_32(); + set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0)); + } + } break; + default: { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Invalid BMFont block type.")); + } break; + } + f->seek(off + block_size); + block_type = f->get_8(); + block_size = f->get_32(); + } + + } else { + // Text BMFont file. + f->seek(0); + while (true) { + String line = f->get_line(); + + int delimiter = line.find(" "); + String type = line.substr(0, delimiter); + int pos = delimiter + 1; + Map<String, String> keys; + + while (pos < line.size() && line[pos] == ' ') { + pos++; + } + + while (pos < line.size()) { + int eq = line.find("=", pos); + if (eq == -1) { + break; + } + String key = line.substr(pos, eq - pos); + int end = -1; + String value; + if (line[eq + 1] == '"') { + end = line.find("\"", eq + 2); + if (end == -1) { + break; + } + value = line.substr(eq + 2, end - 1 - eq - 1); + pos = end + 1; + } else { + end = line.find(" ", eq + 1); + if (end == -1) { + end = line.size(); + } + value = line.substr(eq + 1, end - eq); + pos = end; + } + + while (pos < line.size() && line[pos] == ' ') { + pos++; + } + + keys[key] = value; + } + + if (type == "info") { + if (keys.has("size")) { + base_size = keys["size"].to_int(); + set_fixed_size(base_size); + } + if (keys.has("outline")) { + outline = keys["outline"].to_int(); + } + if (keys.has("bold")) { + if (keys["bold"].to_int()) { + st_flags |= TextServer::FONT_BOLD; + } + } + if (keys.has("italic")) { + if (keys["italic"].to_int()) { + st_flags |= TextServer::FONT_ITALIC; + } + } + if (keys.has("face")) { + font_name = keys["face"]; + } + ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); + } else if (type == "common") { + if (keys.has("lineHeight")) { + height = keys["lineHeight"].to_int(); + } + if (keys.has("base")) { + ascent = keys["base"].to_int(); + } + if (keys.has("packed")) { + packed = (keys["packed"].to_int() == 1); + } + if (keys.has("alphaChnl")) { + ch[3] = keys["alphaChnl"].to_int(); + } + if (keys.has("redChnl")) { + ch[0] = keys["redChnl"].to_int(); + } + if (keys.has("greenChnl")) { + ch[1] = keys["greenChnl"].to_int(); + } + if (keys.has("blueChnl")) { + ch[2] = keys["blueChnl"].to_int(); + } + for (int i = 0; i < 4; i++) { + if (ch[i] == 0 && first_gl_ch == -1) { + first_gl_ch = i; + } + if (ch[i] == 1 && first_ol_ch == -1) { + first_ol_ch = i; + } + if (ch[i] == 2 && first_cm_ch == -1) { + first_cm_ch = i; + } + } + } else if (type == "page") { + int page = 0; + if (keys.has("id")) { + page = keys["id"].to_int(); + } + if (keys.has("file")) { + String base_dir = p_path.get_base_dir(); + String file = base_dir.plus_file(keys["file"]); + if (RenderingServer::get_singleton() != nullptr) { + Ref<Image> img; + img.instantiate(); + Error err = ImageLoader::load_image(file, img); + ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture: ") + "\"" + file + "\"."); + if (packed) { + if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_packed_8bit(img, page, base_size); + } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_packed_4bit(img, page, base_size); + } else { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); + } + } else { + if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + set_texture_image(0, Vector2i(base_size, 0), page, img); + } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_rgba_4bit(img, page, base_size); + } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_8bit(img, page, first_gl_ch, base_size, 0); + _convert_mono_8bit(img, page, first_ol_ch, base_size, 1); + } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_4bit(img, page, first_cm_ch, base_size, 1); + } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline + outline = 0; + ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); + _convert_mono_8bit(img, page, first_gl_ch, base_size, 0); + } else { + ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); + } + } + } + } + } else if (type == "char") { + char32_t idx = 0; + Vector2 advance; + Vector2 size; + Vector2 offset; + Rect2 uv_rect; + int texture_idx = -1; + uint8_t channel = 15; + + if (keys.has("id")) { + idx = keys["id"].to_int(); + } + if (keys.has("x")) { + uv_rect.position.x = keys["x"].to_int(); + } + if (keys.has("y")) { + uv_rect.position.y = keys["y"].to_int(); + } + if (keys.has("width")) { + uv_rect.size.width = keys["width"].to_int(); + size.width = keys["width"].to_int(); + } + if (keys.has("height")) { + uv_rect.size.height = keys["height"].to_int(); + size.height = keys["height"].to_int(); + } + if (keys.has("xoffset")) { + offset.x = keys["xoffset"].to_int(); + } + if (keys.has("yoffset")) { + offset.y = keys["yoffset"].to_int() - ascent; + } + if (keys.has("page")) { + texture_idx = keys["page"].to_int(); + } + if (keys.has("xadvance")) { + advance.x = keys["xadvance"].to_int(); + } + if (advance.x < 0) { + advance.x = size.width + 1; + } + if (keys.has("chnl")) { + channel = keys["chnl"].to_int(); + } + + ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, TTR("Invalid glyph channel.")); + int ch_off = 0; + switch (channel) { + case 1: + ch_off = 2; + break; // B + case 2: + ch_off = 1; + break; // G + case 4: + ch_off = 0; + break; // R + case 8: + ch_off = 3; + break; // A + default: + ch_off = 0; + break; + } + set_glyph_advance(0, base_size, idx, advance); + set_glyph_offset(0, Vector2i(base_size, 0), idx, offset); + set_glyph_size(0, Vector2i(base_size, 0), idx, size); + set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect); + set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off); + if (outline > 0) { + set_glyph_offset(0, Vector2i(base_size, 1), idx, offset); + set_glyph_size(0, Vector2i(base_size, 1), idx, size); + set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect); + set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off); + } + } else if (type == "kerning") { + Vector2i kpk; + if (keys.has("first")) { + kpk.x = keys["first"].to_int(); + } + if (keys.has("second")) { + kpk.y = keys["second"].to_int(); + } + if (keys.has("amount")) { + set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0)); + } + } + + if (f->eof_reached()) { + break; + } + } + } + + set_font_name(font_name); + set_font_style(st_flags); + set_ascent(0, base_size, ascent); + set_descent(0, base_size, height - ascent); + + return OK; +} + +Error FontData::load_dynamic_font(const String &p_path) { + reset_state(); + + Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); + set_data(data); + + return OK; +} + void FontData::set_data_ptr(const uint8_t *p_data, size_t p_size) { data.clear(); data_ptr = p_data; @@ -1585,8 +2344,9 @@ real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, bool Font::has_char(char32_t p_char) const { for (int i = 0; i < data.size(); i++) { - if (data[i]->has_char(p_char)) + if (data[i]->has_char(p_char)) { return true; + } } return false; } diff --git a/scene/resources/font.h b/scene/resources/font.h index 1b4ecc73ce..93351a3493 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -63,6 +63,12 @@ class FontData : public Resource { _FORCE_INLINE_ void _clear_cache(); _FORCE_INLINE_ void _ensure_rid(int p_cache_index) const; + void _convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz); + void _convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz); + void _convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz); + void _convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol); + void _convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol); + protected: static void _bind_methods(); @@ -73,6 +79,9 @@ protected: virtual void reset_state() override; public: + Error load_bitmap_font(const String &p_path); + Error load_dynamic_font(const String &p_path); + // Font source data. virtual void set_data_ptr(const uint8_t *p_data, size_t p_size); virtual void set_data(const PackedByteArray &p_data); diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index b9469803a0..28afef8638 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -382,7 +382,7 @@ AABB ImmediateMesh::get_aabb() const { if (i == 0) { aabb = surfaces[i].aabb; } else { - aabb.merge(surfaces[i].aabb); + aabb = aabb.merge(surfaces[i].aabb); } } return aabb; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index d2d96b1f06..441e84eccc 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1475,12 +1475,12 @@ void ArrayMesh::add_blend_shape(const StringName &p_name) { StringName name = p_name; - if (blend_shapes.find(name) != -1) { + if (blend_shapes.has(name)) { int count = 2; do { name = String(p_name) + " " + itos(count); count++; - } while (blend_shapes.find(name) != -1); + } while (blend_shapes.has(name)); } blend_shapes.push_back(name); diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index 3db839a1d0..5168bf83eb 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -30,6 +30,8 @@ #include "mesh_library.h" +#include "box_shape_3d.h" + bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name.begins_with("item/")) { @@ -255,12 +257,35 @@ int MeshLibrary::get_last_unused_item_id() const { } void MeshLibrary::_set_item_shapes(int p_item, const Array &p_shapes) { - ERR_FAIL_COND(p_shapes.size() & 1); + Array arr_shapes = p_shapes; + int size = p_shapes.size(); + if (size & 1) { + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + int prev_size = item_map[p_item].shapes.size() * 2; + + if (prev_size < size) { + // Check if last element is a shape. + Ref<Shape3D> shape = arr_shapes[size - 1]; + if (shape.is_null()) { + Ref<BoxShape3D> box_shape; + box_shape.instantiate(); + arr_shapes[size - 1] = box_shape; + } + + // Make sure the added element is a Transform3D. + arr_shapes.push_back(Transform3D()); + size++; + } else { + size--; + arr_shapes.resize(size); + } + } + Vector<ShapeData> shapes; - for (int i = 0; i < p_shapes.size(); i += 2) { + for (int i = 0; i < size; i += 2) { ShapeData sd; - sd.shape = p_shapes[i + 0]; - sd.local_transform = p_shapes[i + 1]; + sd.shape = arr_shapes[i + 0]; + sd.local_transform = arr_shapes[i + 1]; if (sd.shape.is_valid()) { shapes.push_back(sd); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 402e67a0f1..f9a4eba978 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -175,14 +175,12 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { #endif } } else { - Object *obj = nullptr; + //node belongs to this scene and must be created + Object *obj = ClassDB::instantiate(snames[n.type]); - if (ClassDB::is_class_enabled(snames[n.type])) { - //node belongs to this scene and must be created - obj = ClassDB::instantiate(snames[n.type]); - } + node = Object::cast_to<Node>(obj); - if (!Object::cast_to<Node>(obj)) { + if (!node) { if (obj) { memdelete(obj); obj = nullptr; @@ -203,9 +201,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { if (!obj) { obj = memnew(Node); } - } - node = Object::cast_to<Node>(obj); + node = Object::cast_to<Node>(obj); + } } if (node) { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index aa9682bd80..3fc5fd4a16 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -106,8 +106,8 @@ class CapsuleMesh : public PrimitiveMesh { GDCLASS(CapsuleMesh, PrimitiveMesh); private: - float radius = 1.0; - float height = 3.0; + float radius = 0.5; + float height = 2.0; int radial_segments = 64; int rings = 8; @@ -138,7 +138,7 @@ class BoxMesh : public PrimitiveMesh { GDCLASS(BoxMesh, PrimitiveMesh); private: - Vector3 size = Vector3(2.0, 2.0, 2.0); + Vector3 size = Vector3(1, 1, 1); int subdivide_w = 0; int subdivide_h = 0; int subdivide_d = 0; @@ -171,8 +171,8 @@ class CylinderMesh : public PrimitiveMesh { GDCLASS(CylinderMesh, PrimitiveMesh); private: - float top_radius = 1.0; - float bottom_radius = 1.0; + float top_radius = 0.5; + float bottom_radius = 0.5; float height = 2.0; int radial_segments = 64; int rings = 4; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 1b81455d4c..6bb710b1d9 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -430,7 +430,7 @@ Error ResourceLoaderText::load() { } } - if (path.find("://") == -1 && path.is_relative_path()) { + if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } @@ -774,7 +774,7 @@ void ResourceLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_depen } } - if (!using_uid && path.find("://") == -1 && path.is_relative_path()) { + if (!using_uid && !path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } diff --git a/scene/resources/scene_replication_config.cpp b/scene/resources/scene_replication_config.cpp new file mode 100644 index 0000000000..2acc0f1922 --- /dev/null +++ b/scene/resources/scene_replication_config.cpp @@ -0,0 +1,187 @@ +/*************************************************************************/ +/* scene_replication_config.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 "scene_replication_config.h" + +#include "core/multiplayer/multiplayer_api.h" +#include "scene/main/node.h" + +bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + + if (name.begins_with("properties/")) { + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + + if (properties.size() == idx && what == "path") { + ERR_FAIL_COND_V(p_value.get_type() != Variant::NODE_PATH, false); + NodePath path = p_value; + ERR_FAIL_COND_V(path.is_empty() || path.get_subname_count() == 0, false); + add_property(path); + return true; + } + ERR_FAIL_COND_V(p_value.get_type() != Variant::BOOL, false); + ERR_FAIL_INDEX_V(idx, properties.size(), false); + ReplicationProperty &prop = properties[idx]; + if (what == "sync") { + prop.sync = p_value; + sync_props.push_back(prop.name); + return true; + } else if (what == "spawn") { + prop.spawn = p_value; + spawn_props.push_back(prop.name); + return true; + } + } + return false; +} + +bool SceneReplicationConfig::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + + if (name.begins_with("properties/")) { + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + ERR_FAIL_INDEX_V(idx, properties.size(), false); + const ReplicationProperty &prop = properties[idx]; + if (what == "path") { + r_ret = prop.name; + return true; + } else if (what == "sync") { + r_ret = prop.sync; + return true; + } else if (what == "spawn") { + r_ret = prop.spawn; + return true; + } + } + return false; +} + +void SceneReplicationConfig::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < properties.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/spawn", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::STRING, "properties/" + itos(i) + "/sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + } +} + +TypedArray<NodePath> SceneReplicationConfig::get_properties() const { + TypedArray<NodePath> paths; + for (const ReplicationProperty &prop : properties) { + paths.push_back(prop.name); + } + return paths; +} + +void SceneReplicationConfig::add_property(const NodePath &p_path, int p_index) { + ERR_FAIL_COND(properties.find(p_path)); + + if (p_index < 0 || p_index == properties.size()) { + properties.push_back(ReplicationProperty(p_path)); + return; + } + + ERR_FAIL_INDEX(p_index, properties.size()); + + List<ReplicationProperty>::Element *I = properties.front(); + int c = 0; + while (c < p_index) { + I = I->next(); + c++; + } + properties.insert_before(I, ReplicationProperty(p_path)); +} + +void SceneReplicationConfig::remove_property(const NodePath &p_path) { + properties.erase(p_path); +} + +int SceneReplicationConfig::property_get_index(const NodePath &p_path) const { + for (int i = 0; i < properties.size(); i++) { + if (properties[i].name == p_path) { + return i; + } + } + ERR_FAIL_V(-1); +} + +bool SceneReplicationConfig::property_get_spawn(const NodePath &p_path) { + List<ReplicationProperty>::Element *E = properties.find(p_path); + ERR_FAIL_COND_V(!E, false); + return E->get().spawn; +} + +void SceneReplicationConfig::property_set_spawn(const NodePath &p_path, bool p_enabled) { + List<ReplicationProperty>::Element *E = properties.find(p_path); + ERR_FAIL_COND(!E); + if (E->get().spawn == p_enabled) { + return; + } + E->get().spawn = p_enabled; + spawn_props.clear(); + for (const ReplicationProperty &prop : properties) { + if (prop.spawn) { + spawn_props.push_back(p_path); + } + } +} + +bool SceneReplicationConfig::property_get_sync(const NodePath &p_path) { + List<ReplicationProperty>::Element *E = properties.find(p_path); + ERR_FAIL_COND_V(!E, false); + return E->get().sync; +} + +void SceneReplicationConfig::property_set_sync(const NodePath &p_path, bool p_enabled) { + List<ReplicationProperty>::Element *E = properties.find(p_path); + ERR_FAIL_COND(!E); + if (E->get().sync == p_enabled) { + return; + } + E->get().sync = p_enabled; + sync_props.clear(); + for (const ReplicationProperty &prop : properties) { + if (prop.sync) { + sync_props.push_back(p_path); + } + } +} + +void SceneReplicationConfig::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_properties"), &SceneReplicationConfig::get_properties); + ClassDB::bind_method(D_METHOD("add_property", "path", "index"), &SceneReplicationConfig::add_property, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("remove_property", "path"), &SceneReplicationConfig::remove_property); + ClassDB::bind_method(D_METHOD("property_get_index", "path"), &SceneReplicationConfig::property_get_index); + ClassDB::bind_method(D_METHOD("property_get_spawn", "path"), &SceneReplicationConfig::property_get_spawn); + ClassDB::bind_method(D_METHOD("property_set_spawn", "path", "enabled"), &SceneReplicationConfig::property_set_spawn); + ClassDB::bind_method(D_METHOD("property_get_sync", "path"), &SceneReplicationConfig::property_get_sync); + ClassDB::bind_method(D_METHOD("property_set_sync", "path", "enabled"), &SceneReplicationConfig::property_set_sync); +} diff --git a/scene/resources/scene_replication_config.h b/scene/resources/scene_replication_config.h new file mode 100644 index 0000000000..b791be9414 --- /dev/null +++ b/scene/resources/scene_replication_config.h @@ -0,0 +1,90 @@ +/*************************************************************************/ +/* scene_replication_config.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 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 SCENE_REPLICATION_CONFIG_H +#define SCENE_REPLICATION_CONFIG_H + +#include "core/io/resource.h" + +#include "core/variant/typed_array.h" + +class SceneReplicationConfig : public Resource { + GDCLASS(SceneReplicationConfig, Resource); + OBJ_SAVE_TYPE(SceneReplicationConfig); + RES_BASE_EXTENSION("repl"); + +private: + struct ReplicationProperty { + NodePath name; + bool spawn = true; + bool sync = true; + + bool operator==(const ReplicationProperty &p_to) { + return name == p_to.name; + } + + ReplicationProperty() {} + + ReplicationProperty(const NodePath &p_name) { + name = p_name; + } + }; + + List<ReplicationProperty> properties; + List<NodePath> spawn_props; + List<NodePath> sync_props; + +protected: + static void _bind_methods(); + + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + TypedArray<NodePath> get_properties() const; + + void add_property(const NodePath &p_path, int p_index = -1); + void remove_property(const NodePath &p_path); + + int property_get_index(const NodePath &p_path) const; + bool property_get_spawn(const NodePath &p_path); + void property_set_spawn(const NodePath &p_path, bool p_enabled); + + bool property_get_sync(const NodePath &p_path); + void property_set_sync(const NodePath &p_path, bool p_enabled); + + const List<NodePath> &get_spawn_properties() { return spawn_props; } + const List<NodePath> &get_sync_properties() { return sync_props; } + + SceneReplicationConfig() {} +}; + +#endif // SCENE_REPLICATION_CONFIG_H diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp index b5b3fd5e9f..2c0f6e779e 100644 --- a/scene/resources/skeleton_modification_3d.cpp +++ b/scene/resources/skeleton_modification_3d.cpp @@ -34,8 +34,9 @@ void SkeletonModification3D::_execute(real_t p_delta) { GDVIRTUAL_CALL(_execute, p_delta); - if (!enabled) + if (!enabled) { return; + } } void SkeletonModification3D::_setup_modification(SkeletonModificationStack3D *p_stack) { diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 6ec16f12df..c5d5ba2912 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -292,7 +292,6 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { } ProceduralSkyMaterial::~ProceduralSkyMaterial() { - RS::get_singleton()->material_set_shader(_get_material(), RID()); } ///////////////////////////////////////// @@ -389,7 +388,6 @@ PanoramaSkyMaterial::PanoramaSkyMaterial() { } PanoramaSkyMaterial::~PanoramaSkyMaterial() { - RS::get_singleton()->material_set_shader(_get_material(), RID()); } ////////////////////////////////// diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index cc7322476f..0677d9c1a8 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -30,7 +30,6 @@ #include "surface_tool.h" -#define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr; diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index e0aa21ac37..f1eddd8ffc 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -116,14 +116,6 @@ void SyntaxHighlighter::_bind_methods() { //////////////////////////////////////////////////////////////////////////////// -static bool _is_char(char32_t c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; -} - -static bool _is_hex_symbol(char32_t c) { - return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); -} - Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) { Dictionary color_map; @@ -166,7 +158,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) { color = font_color; bool is_char = !is_symbol(str[j]); bool is_a_symbol = is_symbol(str[j]); - bool is_number = (str[j] >= '0' && str[j] <= '9'); + bool is_number = is_digit(str[j]); /* color regions */ if (is_a_symbol || in_region != -1) { @@ -304,7 +296,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) { } // Allow ABCDEF in hex notation. - if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) { + if (is_hex_notation && (is_hex_digit(str[j]) || is_number)) { is_number = true; } else { is_hex_notation = false; @@ -321,7 +313,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) { } } - if (!in_word && _is_char(str[j]) && !is_number) { + if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !is_number) { in_word = true; } diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index f3752053c0..c3b5bd3564 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -55,7 +55,7 @@ void TextLine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::set_bidi_override); - ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1)); ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER)); @@ -200,9 +200,9 @@ void TextLine::set_bidi_override(const Array &p_override) { dirty = true; } -bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { +bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ERR_FAIL_COND_V(p_fonts.is_null(), false); - bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta); spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP); spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM); dirty = true; diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index e68049ee45..c5762db0f2 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -86,7 +86,7 @@ public: void set_preserve_control(bool p_enabled); bool get_preserve_control() const; - bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()); bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1); bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER); diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index c3bdef7b01..4d75874199 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -63,7 +63,7 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL("")); ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap); - ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language", "meta"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL(""), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1)); ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER)); @@ -344,9 +344,9 @@ void TextParagraph::clear_dropcap() { lines_dirty = true; } -bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { +bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ERR_FAIL_COND_V(p_fonts.is_null(), false); - bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta); spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP); spacing_bottom = p_fonts->get_spacing(TextServer::SPACING_BOTTOM); lines_dirty = true; diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 773cc1a858..8a8a53943b 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -102,7 +102,7 @@ public: bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); void clear_dropcap(); - bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()); bool add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1); bool resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 331674d248..0ee0e4b33e 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -1902,7 +1902,7 @@ void GradientTexture2D::_queue_update() { return; } update_pending = true; - call_deferred("_update"); + call_deferred(SNAME("_update")); } void GradientTexture2D::_update() { @@ -2103,8 +2103,8 @@ void GradientTexture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr"); ADD_GROUP("Fill", "fill_"); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index c3f29ad417..8075497c42 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -595,7 +595,7 @@ public: private: mutable RID _texture; Ref<Curve> _curve; - int _width = 2048; + int _width = 256; int _current_width = 0; TextureMode texture_mode = TEXTURE_MODE_RGB; TextureMode _current_texture_mode = TEXTURE_MODE_RGB; @@ -637,7 +637,7 @@ private: Ref<Curve> _curve_x; Ref<Curve> _curve_y; Ref<Curve> _curve_z; - int _width = 2048; + int _width = 256; int _current_width = 0; void _update(); @@ -685,7 +685,7 @@ private: Ref<Gradient> gradient; bool update_pending = false; RID texture; - int width = 2048; + int width = 256; bool use_hdr = false; void _queue_update(); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 8da287042e..f962e55666 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -46,7 +46,7 @@ int Theme::fallback_font_size = 16; bool Theme::_set(const StringName &p_name, const Variant &p_value) { String sname = p_name; - if (sname.find("/") != -1) { + if (sname.contains("/")) { String type = sname.get_slicec('/', 1); String theme_type = sname.get_slicec('/', 0); String name = sname.get_slicec('/', 2); @@ -78,7 +78,7 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) { bool Theme::_get(const StringName &p_name, Variant &r_ret) const { String sname = p_name; - if (sname.find("/") != -1) { + if (sname.contains("/")) { String type = sname.get_slicec('/', 1); String theme_type = sname.get_slicec('/', 0); String name = sname.get_slicec('/', 2); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index ddb9cc7440..1f77cc0570 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -207,9 +207,6 @@ void TileMapPattern::_get_property_list(List<PropertyInfo> *p_list) const { } void TileMapPattern::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_tile_data", "data"), &TileMapPattern::_set_tile_data); - ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMapPattern::_get_tile_data); - ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell); ClassDB::bind_method(D_METHOD("remove_cell", "coords", "update_size"), &TileMapPattern::remove_cell); @@ -403,7 +400,7 @@ void TileSet::_update_terrains_cache() { int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index); // Executed for each tile_data. - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id)); + TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id); int terrain_set = tile_data->get_terrain_set(); if (terrain_set >= 0) { TileMapCell cell; @@ -1377,7 +1374,7 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti Ref<TileSetSource> source = sources[E->get().source_id]; Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile); sum += tile_data->get_probability(); } else { sum += 1.0; @@ -1398,7 +1395,7 @@ TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, Ti Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile); count += tile_data->get_probability(); } else { count += 1.0; @@ -1663,7 +1660,7 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) { int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index); - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id)); + TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id); int terrain_set = tile_data->get_terrain_set(); if (terrain_set >= 0) { ERR_FAIL_INDEX_V(terrain_set, get_terrain_sets_count(), Vector<Vector<Ref<Texture2D>>>()); @@ -2399,7 +2396,7 @@ void TileSet::_compatibility_conversion() { compatibility_tilemap_mapping[E.key][key_array] = value_array; compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_SINGLE_TILE; - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(coords, alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile); tile_data->set_flip_h(flip_h); tile_data->set_flip_v(flip_v); @@ -2491,7 +2488,7 @@ void TileSet::_compatibility_conversion() { compatibility_tilemap_mapping[E.key][key_array] = value_array; compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_ATLAS_TILE; - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(coords, alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile); tile_data->set_flip_h(flip_h); tile_data->set_flip_v(flip_v); @@ -4123,7 +4120,7 @@ Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_ Vector2 margin = (get_tile_texture_region(p_atlas_coords).size - tile_set->get_tile_size()) / 2; margin = Vector2i(MAX(0, margin.x), MAX(0, margin.y)); - Vector2i effective_texture_offset = Object::cast_to<TileData>(get_tile_data(p_atlas_coords, p_alternative_tile))->get_texture_offset(); + Vector2i effective_texture_offset = get_tile_data(p_atlas_coords, p_alternative_tile)->get_texture_offset(); if (ABS(effective_texture_offset.x) > margin.x || ABS(effective_texture_offset.y) > margin.y) { effective_texture_offset = effective_texture_offset.clamp(-margin, margin); } @@ -4262,7 +4259,7 @@ int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, i return tiles[p_atlas_coords].alternatives_ids[p_index]; } -Object *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const { +TileData *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords))); ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords))); @@ -4413,7 +4410,7 @@ void TileSetAtlasSource::_clear_tiles_outside_texture() { void TileSetAtlasSource::_queue_update_padded_texture() { padded_texture_needs_update = true; - call_deferred("_update_padded_texture"); + call_deferred(SNAME("_update_padded_texture")); } void TileSetAtlasSource::_update_padded_texture() { @@ -5092,7 +5089,7 @@ int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_i } Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const { - ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<ConvexPolygonShape2D>()); ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>()); ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[p_polygon_index].shapes.size(), Ref<ConvexPolygonShape2D>()); return physics[p_layer_id].polygons[p_polygon_index].shapes[shape_index]; diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 2673ca1cb6..95de46c9ab 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -693,7 +693,7 @@ public: virtual int get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const override; // Get data associated to a tile. - Object *get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const; + TileData *get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const; // Helpers. Vector2i get_atlas_grid_size() const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index ece1ba1972..1683756a3e 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -53,8 +53,98 @@ int VisualShaderNode::get_output_port_for_preview() const { return port_preview; } -void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p_value) { - default_input_values[p_port] = p_value; +void VisualShaderNode::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) { + Variant value = p_value; + + if (p_prev_value.get_type() != Variant::NIL) { + switch (p_value.get_type()) { + case Variant::FLOAT: { + switch (p_prev_value.get_type()) { + case Variant::INT: { + value = (float)p_prev_value; + } break; + case Variant::FLOAT: { + value = p_prev_value; + } break; + case Variant::VECTOR2: { + Vector2 pv = p_prev_value; + value = pv.x; + } break; + case Variant::VECTOR3: { + Vector3 pv = p_prev_value; + value = pv.x; + } break; + default: + break; + } + } break; + case Variant::INT: { + switch (p_prev_value.get_type()) { + case Variant::INT: { + value = p_prev_value; + } break; + case Variant::FLOAT: { + value = (int)p_prev_value; + } break; + case Variant::VECTOR2: { + Vector2 pv = p_prev_value; + value = (int)pv.x; + } break; + case Variant::VECTOR3: { + Vector3 pv = p_prev_value; + value = (int)pv.x; + } break; + default: + break; + } + } break; + case Variant::VECTOR2: { + switch (p_prev_value.get_type()) { + case Variant::INT: { + float pv = (float)(int)p_prev_value; + value = Vector2(pv, pv); + } break; + case Variant::FLOAT: { + float pv = p_prev_value; + value = Vector2(pv, pv); + } break; + case Variant::VECTOR2: { + value = p_prev_value; + } break; + case Variant::VECTOR3: { + Vector3 pv = p_prev_value; + value = Vector2(pv.x, pv.y); + } break; + default: + break; + } + } break; + case Variant::VECTOR3: { + switch (p_prev_value.get_type()) { + case Variant::INT: { + float pv = (float)(int)p_prev_value; + value = Vector3(pv, pv, pv); + } break; + case Variant::FLOAT: { + float pv = p_prev_value; + value = Vector3(pv, pv, pv); + } break; + case Variant::VECTOR2: { + Vector2 pv = p_prev_value; + value = Vector3(pv.x, pv.y, 0.0); + } break; + case Variant::VECTOR3: { + value = p_prev_value; + } break; + default: + break; + } + } break; + default: + break; + } + } + default_input_values[p_port] = value; emit_changed(); } @@ -156,8 +246,15 @@ int VisualShaderNode::get_expanded_output_port_count() const { int count2 = count; for (int i = 0; i < count; i++) { if (is_output_port_expandable(i) && _is_output_port_expanded(i)) { - if (get_output_port_type(i) == PORT_TYPE_VECTOR) { - count2 += 3; + switch (get_output_port_type(i)) { + case PORT_TYPE_VECTOR_2D: { + count2 += 2; + } break; + case PORT_TYPE_VECTOR_3D: { + count2 += 3; + } break; + default: + break; } } } @@ -231,8 +328,8 @@ 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 ""; +bool VisualShaderNode::is_input_port_default(int p_port, Shader::Mode p_mode) const { + return false; } void VisualShaderNode::_bind_methods() { @@ -245,7 +342,7 @@ void VisualShaderNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_output_ports_expanded", "values"), &VisualShaderNode::_set_output_ports_expanded); ClassDB::bind_method(D_METHOD("_get_output_ports_expanded"), &VisualShaderNode::_get_output_ports_expanded); - ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value); + ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value", "prev_value"), &VisualShaderNode::set_input_port_default_value, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value); ClassDB::bind_method(D_METHOD("remove_input_port_default_value", "port"), &VisualShaderNode::remove_input_port_default_value); @@ -261,7 +358,8 @@ void VisualShaderNode::_bind_methods() { BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR); BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT); - BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR); + BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR_3D); BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN); BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM); BIND_ENUM_CONSTANT(PORT_TYPE_SAMPLER); @@ -385,9 +483,9 @@ String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, Vis return ""; } -void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value) { +void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) { if (!is_initialized) { - VisualShaderNode::set_input_port_default_value(p_port, p_value); + VisualShaderNode::set_input_port_default_value(p_port, p_value, p_prev_value); } } @@ -484,24 +582,48 @@ void VisualShader::update_engine_version(const Dictionary &p_new_version) { if (expression.is_valid()) { for (int j = 0; j < expression->get_input_port_count(); j++) { int type = expression->get_input_port_type(j); - if (type > 0) { // + PORT_TYPE_SCALAR_INT - type += 1; + if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D + type += 2; } expression->set_input_port_type(j, type); } for (int j = 0; j < expression->get_output_port_count(); j++) { int type = expression->get_output_port_type(j); - if (type > 0) { // + PORT_TYPE_SCALAR_INT - type += 1; + if (type > 0) { // + PORT_TYPE_SCALAR_INT + PORT_TYPE_VECTOR_2D + type += 2; } expression->set_output_port_type(j, type); } } + Ref<VisualShaderNodeStep> step = Object::cast_to<VisualShaderNodeStep>(E.value.node.ptr()); + if (step.is_valid()) { + int op_type = int(step->get_op_type()); + if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR + op_type += 2; + } + step->set_op_type(VisualShaderNodeStep::OpType(op_type)); + } + Ref<VisualShaderNodeSmoothStep> sstep = Object::cast_to<VisualShaderNodeSmoothStep>(E.value.node.ptr()); + if (sstep.is_valid()) { + int op_type = int(sstep->get_op_type()); + if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR + op_type += 2; + } + sstep->set_op_type(VisualShaderNodeSmoothStep::OpType(op_type)); + } + Ref<VisualShaderNodeMix> mix = Object::cast_to<VisualShaderNodeMix>(E.value.node.ptr()); + if (mix.is_valid()) { + int op_type = int(mix->get_op_type()); + if (int(op_type) > 0) { // + OP_TYPE_VECTOR_2D + OP_TYPE_VECTOR_2D_SCALAR + op_type += 2; + } + mix->set_op_type(VisualShaderNodeMix::OpType(op_type)); + } Ref<VisualShaderNodeCompare> compare = Object::cast_to<VisualShaderNodeCompare>(E.value.node.ptr()); if (compare.is_valid()) { int ctype = int(compare->get_comparison_type()); - if (int(ctype) > 0) { // + PORT_TYPE_SCALAR_INT - ctype += 1; + if (int(ctype) > 0) { // + CTYPE_SCALAR_INT + CTYPE_VECTOR_2D + ctype += 2; } compare->set_comparison_type(VisualShaderNodeCompare::ComparisonType(ctype)); } @@ -719,7 +841,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po } bool VisualShader::is_port_types_compatible(int p_a, int p_b) const { - return MAX(0, p_a - 3) == (MAX(0, p_b - 3)); + return MAX(0, p_a - 4) == (MAX(0, p_b - 4)); } void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { @@ -953,15 +1075,27 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port Error err = _write_node(p_type, global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes); ERR_FAIL_COND_V(err != OK, String()); - if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) { - code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " );\n"; - } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR_INT) { - code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n"; - } else if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_BOOLEAN) { - code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n"; - } else { - code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; + switch (node->get_output_port_type(p_port)) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n"; + } break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n"; + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n"; + } break; + default: { + code += " COLOR.rgb = vec3(0.0);\n"; + } break; } + code += "}\n"; //set code secretly @@ -972,10 +1106,6 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port return final_code; } -#define IS_INITIAL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z')) - -#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_') - String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const { String name = p_port_name; @@ -983,7 +1113,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN return String(); } - while (name.length() && !IS_INITIAL_CHAR(name[0])) { + while (name.length() && !is_ascii_char(name[0])) { name = name.substr(1, name.length() - 1); } @@ -991,7 +1121,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN String valid_name; for (int i = 0; i < name.length(); i++) { - if (IS_SYMBOL_CHAR(name[i])) { + if (is_ascii_identifier_char(name[i])) { valid_name += String::chr(name[i]); } else if (name[i] == ' ') { valid_name += "_"; @@ -1028,14 +1158,14 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const { String name = p_name; //validate name first - while (name.length() && !IS_INITIAL_CHAR(name[0])) { + while (name.length() && !is_ascii_char(name[0])) { name = name.substr(1, name.length() - 1); } if (!name.is_empty()) { String valid_name; for (int i = 0; i < name.length(); i++) { - if (IS_SYMBOL_CHAR(name[i])) { + if (is_ascii_identifier_char(name[i])) { valid_name += String::chr(name[i]); } else if (name[i] == ' ') { valid_name += "_"; @@ -1072,7 +1202,7 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua if (exists) { //remove numbers, put new and try again attempt++; - while (name.length() && name[name.length() - 1] >= '0' && name[name.length() - 1] <= '9') { + while (name.length() && is_digit(name[name.length() - 1])) { name = name.substr(0, name.length() - 1); } ERR_FAIL_COND_V(name.is_empty(), String()); @@ -1406,30 +1536,102 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } } 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))"; - } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR_INT && out_type == VisualShaderNode::PORT_TYPE_VECTOR) { - inputs[i] = "dot(float(" + src_var + "), vec3(0.333333, 0.333333, 0.333333))"; - } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { - inputs[i] = "vec3(" + src_var + ")"; - } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { - inputs[i] = "vec3(float(" + src_var + "))"; - } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_VECTOR) { - inputs[i] = "all(bvec3(" + src_var + "))"; - } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { - inputs[i] = src_var + " > 0.0 ? true : false"; - } else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { - inputs[i] = src_var + " > 0 ? true : false"; - } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = "(" + src_var + " ? 1.0 : 0.0)"; - } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR_INT && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = "(" + src_var + " ? 1 : 0)"; - } else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) { - inputs[i] = "vec3(" + src_var + " ? 1.0 : 0.0)"; - } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_SCALAR_INT) { - inputs[i] = "float(" + src_var + ")"; - } else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR_INT && out_type == VisualShaderNode::PORT_TYPE_SCALAR) { - inputs[i] = "int(" + src_var + ")"; + } else { + switch (in_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + switch (out_type) { + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + inputs[i] = "float(" + src_var + ")"; + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + inputs[i] = "(" + src_var + " ? 1.0 : 0.0)"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + inputs[i] = "dot(" + src_var + ", vec2(0.333333, 0.333333))"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + inputs[i] = "dot(" + src_var + ", vec3(0.333333, 0.333333, 0.333333))"; + } break; + default: + break; + } + } break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + switch (out_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + inputs[i] = "int(" + src_var + ")"; + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + inputs[i] = "(" + src_var + " ? 1 : 0)"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + inputs[i] = "dot(float(" + src_var + "), vec2(0.333333, 0.333333))"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + inputs[i] = "dot(float(" + src_var + "), vec3(0.333333, 0.333333, 0.333333))"; + } break; + default: + break; + } + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + switch (out_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + inputs[i] = src_var + " > 0.0 ? true : false"; + } break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + inputs[i] = src_var + " > 0 ? true : false"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + inputs[i] = "all(bvec2(" + src_var + "))"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + inputs[i] = "all(bvec3(" + src_var + "))"; + } break; + default: + break; + } + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + switch (out_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + inputs[i] = "vec2(" + src_var + ")"; + } break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + inputs[i] = "vec2(float(" + src_var + "))"; + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + inputs[i] = "vec2(" + src_var + " ? 1.0 : 0.0)"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + inputs[i] = "vec2(" + src_var + ".xy)"; + } break; + default: + break; + } + } break; + + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + switch (out_type) { + case VisualShaderNode::PORT_TYPE_SCALAR: { + inputs[i] = "vec3(" + src_var + ")"; + } break; + case VisualShaderNode::PORT_TYPE_SCALAR_INT: { + inputs[i] = "vec3(float(" + src_var + "))"; + } break; + case VisualShaderNode::PORT_TYPE_BOOLEAN: { + inputs[i] = "vec3(" + src_var + " ? 1.0 : 0.0)"; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + inputs[i] = "vec3(" + src_var + ", 0.0)"; + } break; + default: + break; + } + } break; + default: + break; + } } } else { if (!vsnode->is_generate_input_var(i)) { @@ -1449,6 +1651,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui bool val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); node_code += " bool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; + } else if (defval.get_type() == Variant::VECTOR2) { + Vector2 val = defval; + inputs[i] = "n_in" + itos(node) + "p" + itos(i); + node_code += " vec2 " + inputs[i] + " = " + vformat("vec2(%.5f, %.5f);\n", val.x, val.y); } else if (defval.get_type() == Variant::VECTOR3) { Vector3 val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); @@ -1485,8 +1691,15 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui if (vsnode->is_output_port_expandable(i) && vsnode->_is_output_port_expanded(i)) { expanded = true; - if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { - output_count += 3; + switch (vsnode->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + output_count += 2; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + output_count += 3; + } break; + default: + break; } } expanded_output_ports.insert(i, expanded); @@ -1506,7 +1719,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui case VisualShaderNode::PORT_TYPE_SCALAR_INT: outputs[i] = "int " + var_name; break; - case VisualShaderNode::PORT_TYPE_VECTOR: + case VisualShaderNode::PORT_TYPE_VECTOR_2D: + outputs[i] = "vec2 " + var_name; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: outputs[i] = "vec3 " + var_name; break; case VisualShaderNode::PORT_TYPE_BOOLEAN: @@ -1515,12 +1731,19 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui case VisualShaderNode::PORT_TYPE_TRANSFORM: outputs[i] = "mat4 " + var_name; break; - default: { - } + default: + break; } if (expanded_output_ports[i]) { - if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { - j += 3; + switch (vsnode->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + j += 2; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + j += 3; + } break; + default: + break; } } } @@ -1535,7 +1758,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui case VisualShaderNode::PORT_TYPE_SCALAR_INT: code += " int " + outputs[i] + ";\n"; break; - case VisualShaderNode::PORT_TYPE_VECTOR: + case VisualShaderNode::PORT_TYPE_VECTOR_2D: + code += " vec2 " + outputs[i] + ";\n"; + break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: code += " vec3 " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_BOOLEAN: @@ -1544,12 +1770,19 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui case VisualShaderNode::PORT_TYPE_TRANSFORM: code += " mat4 " + outputs[i] + ";\n"; break; - default: { - } + default: + break; } if (expanded_output_ports[i]) { - if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { - j += 3; + switch (vsnode->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + j += 2; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + j += 3; + } break; + default: + break; } } } @@ -1565,38 +1798,65 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui for (int i = 0; i < output_count; i++) { bool new_line_inserted = false; if (expanded_output_ports[i]) { - if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { - if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component - if (!new_line_inserted) { - code += "\n"; - new_line_inserted = true; + switch (vsnode->get_output_port_type(i)) { + case VisualShaderNode::PORT_TYPE_VECTOR_2D: { + if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String r = "n_out" + itos(node) + "p" + itos(i + 1); + code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; + outputs[i + 1] = r; } - String r = "n_out" + itos(node) + "p" + itos(i + 1); - code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; - outputs[i + 1] = r; - } - if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component - if (!new_line_inserted) { - code += "\n"; - new_line_inserted = true; + if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String g = "n_out" + itos(node) + "p" + itos(i + 2); + code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; + outputs[i + 2] = g; } - String g = "n_out" + itos(node) + "p" + itos(i + 2); - code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; - outputs[i + 2] = g; - } - if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component - if (!new_line_inserted) { - code += "\n"; - new_line_inserted = true; + i += 2; + } break; + case VisualShaderNode::PORT_TYPE_VECTOR_3D: { + if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String r = "n_out" + itos(node) + "p" + itos(i + 1); + code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; + outputs[i + 1] = r; + } + + if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String g = "n_out" + itos(node) + "p" + itos(i + 2); + code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; + outputs[i + 2] = g; } - String b = "n_out" + itos(node) + "p" + itos(i + 3); - code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; - outputs[i + 3] = b; - } - i += 3; + if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String b = "n_out" + itos(node) + "p" + itos(i + 3); + code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; + outputs[i + 3] = b; + } + + i += 3; + } break; + default: + break; } } } @@ -2062,17 +2322,17 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { // Node3D // Node3D, Vertex - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "instance_custom", "INSTANCE_CUSTOM.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, @@ -2082,29 +2342,29 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, // Node3D, Fragment - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "view", "VIEW" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { 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_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" }, { 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" }, @@ -2112,18 +2372,18 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" }, // Node3D, Light - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV2, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "view", "VIEW" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "view", "VIEW" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "attenuation", "ATTENUATION" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "backlight", "BACKLIGHT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, @@ -2132,75 +2392,75 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection", "PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_projection", "INV_PROJECTION_MATRIX" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, // Canvas Item // Canvas Item, Vertex - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "canvas", "CANVAS_MATRIX" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen", "SCREEN_MATRIX" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "instance_custom", "INSTANCE_CUSTOM.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" }, // Canvas Item, Fragment - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_pixel_size", "vec3(SCREEN_PIXEL_SIZE, 1.0)" }, - { 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_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_pixel_size", "SCREEN_PIXEL_SIZE" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, { 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" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular_shininess", "SPECULAR_SHININESS.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" }, // 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)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_color", "LIGHT_COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_color_alpha", "LIGHT_COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_position", "LIGHT_POSITION" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vertex", "LIGHT_VERTEX" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow", "SHADOW_MODULATE.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_position", "LIGHT_POSITION" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "shadow", "SHADOW_MODULATE.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "shadow_alpha", "SHADOW_MODULATE.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { 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_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "texture_pixel_size", "TEXTURE_PIXEL_SIZE" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "point_coord", "POINT_COORD" }, { 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" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular_shininess", "SPECULAR_SHININESS.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" }, // Particles, Start - { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, @@ -2210,13 +2470,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Start (Custom) - { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, @@ -2226,13 +2486,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Process - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, @@ -2242,13 +2502,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Process (Custom) - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, @@ -2258,15 +2518,15 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Collide - { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "attractor_force", "ATTRACTOR_FORCE" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "collision_depth", "COLLISION_DEPTH" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "collision_normal", "COLLISION_NORMAL" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "collision_normal", "COLLISION_NORMAL" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "velocity", "VELOCITY" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR_3D, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, @@ -2279,40 +2539,39 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "eyedir", "EYEDIR" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "half_res_color", "HALF_RES_COLOR.rgb" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "eyedir", "EYEDIR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "half_res_color", "HALF_RES_COLOR.rgb" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_color", "LIGHT0_COLOR" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_direction", "LIGHT0_DIRECTION" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_color", "LIGHT0_COLOR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light0_direction", "LIGHT0_DIRECTION" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_color", "LIGHT1_COLOR" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_direction", "LIGHT1_DIRECTION" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light1_color", "LIGHT1_COLOR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light1_direction", "LIGHT1_DIRECTION" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_color", "LIGHT2_COLOR" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_direction", "LIGHT2_DIRECTION" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light2_color", "LIGHT2_COLOR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light2_direction", "LIGHT2_DIRECTION" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_color", "LIGHT3_COLOR" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_direction", "LIGHT3_DIRECTION" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light3_color", "LIGHT3_COLOR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light3_direction", "LIGHT3_DIRECTION" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "position", "POSITION" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "quarter_res_color", "QUARTER_RES_COLOR.rgb" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "position", "POSITION" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "quarter_res_color", "QUARTER_RES_COLOR.rgb" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "sky_coords", "SKY_COORDS" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Fog, Fog - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "world_position", "WORLD_POSITION" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "object_position", "OBJECT_POSITION" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "uvw", "UVW" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "extents", "EXTENTS" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "world_position", "WORLD_POSITION" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "object_position", "OBJECT_POSITION" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "uvw", "UVW" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "extents", "EXTENTS" }, { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "sdf", "SDF" }, { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, @@ -2322,64 +2581,64 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { // Spatial, Vertex - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "vec3(0.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Spatial, Fragment - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "vec3(0.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "vec3(1.0, 0.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Spatial, Light - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "vec2(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Canvas Item, Vertex - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Canvas Item, Fragment - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Canvas Item, Light - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles @@ -2392,7 +2651,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { // Sky - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Fog @@ -2456,7 +2715,10 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T case PORT_TYPE_SCALAR_INT: { code = " " + p_output_vars[0] + " = 0;\n"; } break; - case PORT_TYPE_VECTOR: { + case PORT_TYPE_VECTOR_2D: { + code = " " + p_output_vars[0] + " = vec2(0.0);\n"; + } break; + case PORT_TYPE_VECTOR_3D: { code = " " + p_output_vars[0] + " = vec3(0.0);\n"; } break; case PORT_TYPE_BOOLEAN: { @@ -2671,7 +2933,9 @@ int VisualShaderNodeUniformRef::get_output_port_count() const { return 1; case UniformType::UNIFORM_TYPE_BOOLEAN: return 1; - case UniformType::UNIFORM_TYPE_VECTOR: + case UniformType::UNIFORM_TYPE_VECTOR2: + return 1; + case UniformType::UNIFORM_TYPE_VECTOR3: return 1; case UniformType::UNIFORM_TYPE_TRANSFORM: return 1; @@ -2693,13 +2957,15 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port return PortType::PORT_TYPE_SCALAR_INT; case UniformType::UNIFORM_TYPE_BOOLEAN: return PortType::PORT_TYPE_BOOLEAN; - case UniformType::UNIFORM_TYPE_VECTOR: - return PortType::PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_VECTOR2: + return PortType::PORT_TYPE_VECTOR_2D; + case UniformType::UNIFORM_TYPE_VECTOR3: + return PortType::PORT_TYPE_VECTOR_3D; case UniformType::UNIFORM_TYPE_TRANSFORM: return PortType::PORT_TYPE_TRANSFORM; case UniformType::UNIFORM_TYPE_COLOR: if (p_port == 0) { - return PortType::PORT_TYPE_VECTOR; + return PortType::PORT_TYPE_VECTOR_3D; } else if (p_port == 1) { return PORT_TYPE_SCALAR; } @@ -2720,7 +2986,9 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { return ""; case UniformType::UNIFORM_TYPE_BOOLEAN: return ""; - case UniformType::UNIFORM_TYPE_VECTOR: + case UniformType::UNIFORM_TYPE_VECTOR2: + return ""; + case UniformType::UNIFORM_TYPE_VECTOR3: return ""; case UniformType::UNIFORM_TYPE_TRANSFORM: return ""; @@ -2790,12 +3058,14 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_b return PORT_TYPE_SCALAR_INT; case UniformType::UNIFORM_TYPE_SAMPLER: return PORT_TYPE_SAMPLER; - case UniformType::UNIFORM_TYPE_VECTOR: - return PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_VECTOR2: + return PORT_TYPE_VECTOR_2D; + case UniformType::UNIFORM_TYPE_VECTOR3: + return PORT_TYPE_VECTOR_3D; case UniformType::UNIFORM_TYPE_TRANSFORM: return PORT_TYPE_TRANSFORM; case UniformType::UNIFORM_TYPE_COLOR: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; default: break; } @@ -2809,26 +3079,19 @@ String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShad if (uniform_name == "[None]") { return " " + p_output_vars[0] + " = 0.0;\n"; } - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; - case UniformType::UNIFORM_TYPE_INT: - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; - case UniformType::UNIFORM_TYPE_BOOLEAN: - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; - case UniformType::UNIFORM_TYPE_VECTOR: - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; - case UniformType::UNIFORM_TYPE_TRANSFORM: - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + break; case UniformType::UNIFORM_TYPE_COLOR: { String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; return code; } break; case UniformType::UNIFORM_TYPE_SAMPLER: - break; + return String(); default: break; } - return ""; + + return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; } void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) { @@ -2868,29 +3131,29 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { //////////////////////////////////////////////////////////////////////// // Node3D, Vertex. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "TANGENT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "BINORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "UV2:xy" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" }, //////////////////////////////////////////////////////////////////////// // Node3D, Fragment. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "emission", "EMISSION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, @@ -2898,17 +3161,17 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_gloss", "CLEARCOAT_GLOSS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "anisotropy_flow", "ANISOTROPY_FLOW:xy" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "anisotropy_flow", "ANISOTROPY_FLOW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "backlight", "BACKLIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" }, //////////////////////////////////////////////////////////////////////// // Node3D, Light. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, //////////////////////////////////////////////////////////////////////// @@ -2916,41 +3179,41 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { //////////////////////////////////////////////////////////////////////// // Canvas Item, Vertex. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "VERTEX:xy" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "UV:xy" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, //////////////////////////////////////////////////////////////////////// // Canvas Item, Fragment. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light_vertex", "LIGHT_VERTEX" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "shadow_vertex", "SHADOW_VERTEX:xy" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "shadow_vertex", "SHADOW_VERTEX" }, //////////////////////////////////////////////////////////////////////// // Canvas Item, Light. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, //////////////////////////////////////////////////////////////////////// // Sky, Sky. //////////////////////////////////////////////////////////////////////// - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, - { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "fog", "FOG.rgb" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fog", "FOG.rgb" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "fog_alpha", "FOG.a" }, //////////////////////////////////////////////////////////////////////// // Fog, Fog. //////////////////////////////////////////////////////////////////////// { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "density", "DENSITY" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" }, - { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR, "emission", "EMISSION" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" }, + { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" }, //////////////////////////////////////////////////////////////////////// { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr }, @@ -3045,7 +3308,7 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader:: if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) { if (!p_input_vars[count].is_empty()) { String s = ports[idx].string; - if (s.find(":") != -1) { + if (s.contains(":")) { code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n"; } else { code += " " + s + " = " + p_input_vars[count] + ";\n"; @@ -3402,7 +3665,6 @@ bool VisualShaderNodeGroupBase::is_valid_port_name(const String &p_name) const { } void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) { - ERR_FAIL_COND(has_input_port(p_id)); ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX)); ERR_FAIL_COND(!is_valid_port_name(p_name)); @@ -3478,7 +3740,6 @@ bool VisualShaderNodeGroupBase::has_input_port(int p_id) const { } void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const String &p_name) { - ERR_FAIL_COND(has_output_port(p_id)); ERR_FAIL_INDEX(p_type, int(PORT_TYPE_MAX)); ERR_FAIL_COND(!is_valid_port_name(p_name)); @@ -3883,7 +4144,10 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad case PORT_TYPE_SCALAR_INT: tk = "0"; break; - case PORT_TYPE_VECTOR: + case PORT_TYPE_VECTOR_2D: + tk = "vec2(0.0, 0.0)"; + break; + case PORT_TYPE_VECTOR_3D: tk = "vec3(0.0, 0.0, 0.0)"; break; case PORT_TYPE_BOOLEAN: diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 066c18e3bc..e85bf696b0 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -214,7 +214,8 @@ public: enum PortType { PORT_TYPE_SCALAR, PORT_TYPE_SCALAR_INT, - PORT_TYPE_VECTOR, + PORT_TYPE_VECTOR_2D, + PORT_TYPE_VECTOR_3D, PORT_TYPE_BOOLEAN, PORT_TYPE_TRANSFORM, PORT_TYPE_SAMPLER, @@ -229,7 +230,7 @@ public: virtual PortType get_input_port_type(int p_port) const = 0; virtual String get_input_port_name(int p_port) const = 0; - virtual void set_input_port_default_value(int p_port, const Variant &p_value); + virtual void set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value = Variant()); Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied) Array get_default_input_values() const; virtual void set_default_input_values(const Array &p_values); @@ -240,7 +241,7 @@ 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; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const; void set_output_port_for_preview(int p_index); int get_output_port_for_preview() const; @@ -311,7 +312,7 @@ protected: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual void set_input_port_default_value(int p_port, const Variant &p_value) override; + virtual void set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value = Variant()) override; virtual void set_default_input_values(const Array &p_values) override; virtual void remove_input_port_default_value(int p_port) override; virtual void clear_default_input_values() override; @@ -492,7 +493,8 @@ public: UNIFORM_TYPE_FLOAT, UNIFORM_TYPE_INT, UNIFORM_TYPE_BOOLEAN, - UNIFORM_TYPE_VECTOR, + UNIFORM_TYPE_VECTOR2, + UNIFORM_TYPE_VECTOR3, UNIFORM_TYPE_TRANSFORM, UNIFORM_TYPE_COLOR, UNIFORM_TYPE_SAMPLER, diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index b61e3f5d14..1205ba91c4 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -30,6 +30,65 @@ #include "visual_shader_nodes.h" +////////////// Vector Base + +VisualShaderNodeVectorBase::PortType VisualShaderNodeVectorBase::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; + } + return PORT_TYPE_SCALAR; +} + +VisualShaderNodeVectorBase::PortType VisualShaderNodeVectorBase::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; + } + return PORT_TYPE_SCALAR; +} + +void VisualShaderNodeVectorBase::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeVectorBase::OpType VisualShaderNodeVectorBase::get_op_type() const { + return op_type; +} + +void VisualShaderNodeVectorBase::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeVectorBase::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeVectorBase::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Vector2,Vector3"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + +Vector<StringName> VisualShaderNodeVectorBase::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +VisualShaderNodeVectorBase::VisualShaderNodeVectorBase() { +} + ////////////// Constants Base VisualShaderNodeConstant::VisualShaderNodeConstant() { @@ -232,7 +291,7 @@ int VisualShaderNodeColorConstant::get_input_port_count() const { } VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorConstant::get_input_port_name(int p_port) const { @@ -244,7 +303,7 @@ int VisualShaderNodeColorConstant::get_output_port_count() const { } VisualShaderNodeColorConstant::PortType VisualShaderNodeColorConstant::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; } String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const { @@ -294,10 +353,72 @@ void VisualShaderNodeColorConstant::_bind_methods() { VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() { } -////////////// Vector +////////////// Vector2 + +String VisualShaderNodeVec2Constant::get_caption() const { + return "Vector2Constant"; +} + +int VisualShaderNodeVec2Constant::get_input_port_count() const { + return 0; +} + +VisualShaderNodeVec2Constant::PortType VisualShaderNodeVec2Constant::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeVec2Constant::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeVec2Constant::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVec2Constant::PortType VisualShaderNodeVec2Constant::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeVec2Constant::get_output_port_name(int p_port) const { + return ""; //no output port means the editor will be used as port +} + +String VisualShaderNodeVec2Constant::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 " " + p_output_vars[0] + " = " + vformat("vec2(%.6f, %.6f)", constant.x, constant.y) + ";\n"; +} + +void VisualShaderNodeVec2Constant::set_constant(const Vector2 &p_constant) { + if (constant.is_equal_approx(p_constant)) { + return; + } + constant = p_constant; + emit_changed(); +} + +Vector2 VisualShaderNodeVec2Constant::get_constant() const { + return constant; +} + +Vector<StringName> VisualShaderNodeVec2Constant::get_editable_properties() const { + Vector<StringName> props; + props.push_back("constant"); + return props; +} + +void VisualShaderNodeVec2Constant::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_constant", "constant"), &VisualShaderNodeVec2Constant::set_constant); + ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeVec2Constant::get_constant); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant"), "set_constant", "get_constant"); +} + +VisualShaderNodeVec2Constant::VisualShaderNodeVec2Constant() { +} + +////////////// Vector3 String VisualShaderNodeVec3Constant::get_caption() const { - return "VectorConstant"; + return "Vector3Constant"; } int VisualShaderNodeVec3Constant::get_input_port_count() const { @@ -305,7 +426,7 @@ int VisualShaderNodeVec3Constant::get_input_port_count() const { } VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVec3Constant::get_input_port_name(int p_port) const { @@ -317,7 +438,7 @@ int VisualShaderNodeVec3Constant::get_output_port_count() const { } VisualShaderNodeVec3Constant::PortType VisualShaderNodeVec3Constant::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVec3Constant::get_output_port_name(int p_port) const { @@ -367,7 +488,7 @@ int VisualShaderNodeTransformConstant::get_input_port_count() const { } VisualShaderNodeTransformConstant::PortType VisualShaderNodeTransformConstant::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformConstant::get_input_port_name(int p_port) const { @@ -439,7 +560,7 @@ int VisualShaderNodeTexture::get_input_port_count() const { VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_input_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_2D; case 1: return PORT_TYPE_SCALAR; case 2: @@ -470,7 +591,7 @@ VisualShaderNodeTexture::PortType VisualShaderNodeTexture::get_output_port_type( if (p_port == 0 && source == SOURCE_DEPTH) { return PORT_TYPE_SCALAR; } - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; } String VisualShaderNodeTexture::get_output_port_name(int p_port) const { @@ -487,11 +608,13 @@ bool VisualShaderNodeTexture::is_output_port_expandable(int p_port) const { return false; } -String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const { - if (p_port == 0) { - return "default"; +bool VisualShaderNodeTexture::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + if (p_port == 0) { + return true; + } } - return ""; + return false; } Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { @@ -526,8 +649,8 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade String VisualShaderNodeTexture::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 default_uv; - if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { - default_uv = "UV.xy"; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + default_uv = "UV"; } else { default_uv = "vec2(0.0)"; } @@ -545,9 +668,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: } else if (p_input_vars[1].is_empty()) { //no lod - code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 " + id + "_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; } else { - code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += " " + p_output_vars[0] + " = " + id + "_read.rgb;\n"; @@ -573,9 +696,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: } else if (p_input_vars[1].is_empty()) { //no lod - code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 " + id + "_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; } else { - code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 " + id + "_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += " " + p_output_vars[0] + " = " + id + "_tex_read.rgb;\n"; @@ -597,9 +720,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: } else if (p_input_vars[1].is_empty()) { //no lod - code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, 0.0);\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n"; } else { - code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += " " + p_output_vars[0] + " = _tex_read.rgb;\n"; @@ -620,9 +743,9 @@ String VisualShaderNodeTexture::generate_code(Shader::Mode p_mode, VisualShader: } else if (p_input_vars[1].is_empty()) { //no lod - code += " vec4 _tex_read = texture(TEXTURE, " + p_input_vars[0] + ".xy);\n"; + code += " vec4 _tex_read = texture(TEXTURE, " + p_input_vars[0] + ");\n"; } else { - code += " vec4 _tex_read = textureLod(TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 _tex_read = textureLod(TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += " " + p_output_vars[0] + " = _tex_read.rgb;\n"; @@ -941,7 +1064,7 @@ int VisualShaderNodeCurveXYZTexture::get_output_port_count() const { } VisualShaderNodeCurveXYZTexture::PortType VisualShaderNodeCurveXYZTexture::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeCurveXYZTexture::get_output_port_name(int p_port) const { @@ -1012,7 +1135,7 @@ int VisualShaderNodeSample3D::get_input_port_count() const { VisualShaderNodeSample3D::PortType VisualShaderNodeSample3D::get_input_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 1: return PORT_TYPE_SCALAR; case 2: @@ -1038,7 +1161,7 @@ int VisualShaderNodeSample3D::get_output_port_count() const { } VisualShaderNodeSample3D::PortType VisualShaderNodeSample3D::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; } String VisualShaderNodeSample3D::get_output_port_name(int p_port) const { @@ -1052,16 +1175,18 @@ bool VisualShaderNodeSample3D::is_output_port_expandable(int p_port) const { return false; } -String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const { - if (p_port == 0) { - return "default"; +bool VisualShaderNodeSample3D::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + if (p_port == 0) { + return true; + } } - return ""; + return false; } String VisualShaderNodeSample3D::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 default_uv; - if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { default_uv = "vec3(UV, 0.0)"; } else { default_uv = "vec3(0.0)"; @@ -1273,7 +1398,7 @@ int VisualShaderNodeCubemap::get_input_port_count() const { VisualShaderNodeCubemap::PortType VisualShaderNodeCubemap::get_input_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 1: return PORT_TYPE_SCALAR; case 2: @@ -1301,7 +1426,7 @@ int VisualShaderNodeCubemap::get_output_port_count() const { } VisualShaderNodeCubemap::PortType VisualShaderNodeCubemap::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; } String VisualShaderNodeCubemap::get_output_port_name(int p_port) const { @@ -1346,7 +1471,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade 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 default_uv; - if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { default_uv = "vec3(UV, 0.0)"; } else { default_uv = "vec3(0.0)"; @@ -1393,11 +1518,13 @@ String VisualShaderNodeCubemap::generate_code(Shader::Mode p_mode, VisualShader: return code; } -String VisualShaderNodeCubemap::get_input_port_default_hint(int p_port) const { - if (p_port == 0) { - return "default"; +bool VisualShaderNodeCubemap::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + if (p_port == 0) { + return true; + } } - return ""; + return false; } void VisualShaderNodeCubemap::set_source(Source p_source) { @@ -1724,10 +1851,6 @@ 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"; } @@ -1736,12 +1859,8 @@ 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 + return "op"; } String VisualShaderNodeVectorOp::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 { @@ -1772,13 +1891,21 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader code += "min(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; break; case OP_CROSS: - code += "cross(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + if (op_type == OP_TYPE_VECTOR_2D) { // not supported + code += "vec2(0.0);\n"; + } else { + code += "cross(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + } break; case OP_ATAN2: code += "atan(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; break; case OP_REFLECT: - code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + if (op_type == OP_TYPE_VECTOR_2D) { // not supported + code += "vec2(0.0);\n"; + } else { + code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + } break; case OP_STEP: code += "step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; @@ -1790,6 +1917,27 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader return code; } +void VisualShaderNodeVectorOp::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + void VisualShaderNodeVectorOp::set_operator(Operator p_op) { ERR_FAIL_INDEX(int(p_op), int(OP_ENUM_SIZE)); if (op == p_op) { @@ -1804,11 +1952,27 @@ VisualShaderNodeVectorOp::Operator VisualShaderNodeVectorOp::get_operator() cons } Vector<StringName> VisualShaderNodeVectorOp::get_editable_properties() const { - Vector<StringName> props; + Vector<StringName> props = VisualShaderNodeVectorBase::get_editable_properties(); props.push_back("operator"); return props; } +String VisualShaderNodeVectorOp::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + bool invalid_type = false; + + if (op_type == OP_TYPE_VECTOR_2D) { + if (op == OP_CROSS || op == OP_REFLECT) { + invalid_type = true; + } + } + + if (invalid_type) { + return TTR("Invalid operator for that type."); + } + + return String(); +} + void VisualShaderNodeVectorOp::_bind_methods() { ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualShaderNodeVectorOp::set_operator); ClassDB::bind_method(D_METHOD("get_operator"), &VisualShaderNodeVectorOp::get_operator); @@ -1831,8 +1995,18 @@ void VisualShaderNodeVectorOp::_bind_methods() { } VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() { - set_input_port_default_value(0, Vector3()); - set_input_port_default_value(1, Vector3()); + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2()); + set_input_port_default_value(1, Vector2()); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3()); + set_input_port_default_value(1, Vector3()); + } break; + default: + break; + } } ////////////// Color Op @@ -1846,7 +2020,7 @@ int VisualShaderNodeColorOp::get_input_port_count() const { } VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorOp::get_input_port_name(int p_port) const { @@ -1858,7 +2032,7 @@ int VisualShaderNodeColorOp::get_output_port_count() const { } VisualShaderNodeColorOp::PortType VisualShaderNodeColorOp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorOp::get_output_port_name(int p_port) const { @@ -2119,7 +2293,7 @@ int VisualShaderNodeTransformVecMult::get_input_port_count() const { } VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_input_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_TRANSFORM : PORT_TYPE_VECTOR; + return p_port == 0 ? PORT_TYPE_TRANSFORM : PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformVecMult::get_input_port_name(int p_port) const { @@ -2131,7 +2305,7 @@ int VisualShaderNodeTransformVecMult::get_output_port_count() const { } VisualShaderNodeTransformVecMult::PortType VisualShaderNodeTransformVecMult::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformVecMult::get_output_port_name(int p_port) const { @@ -2406,10 +2580,6 @@ 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 ""; } @@ -2418,22 +2588,18 @@ 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 + return "result"; } String VisualShaderNodeVectorFunc::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 { - static const char *vec_func_id[FUNC_MAX] = { + static const char *funcs[FUNC_MAX] = { "normalize($)", - "max(min($, vec3(1.0)), vec3(0.0))", + "", // FUNC_SATURATE "-($)", "1.0 / ($)", - "", - "", + "", // FUNC_RGB2HSV + "", // FUNC_HSV2RGB "abs($)", "acos($)", "acosh($)", @@ -2462,12 +2628,37 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad "tan($)", "tanh($)", "trunc($)", - "vec3(1.0, 1.0, 1.0) - $" + "" // FUNC_ONEMINUS }; + if (func == FUNC_SATURATE) { + String code; + + if (op_type == OP_TYPE_VECTOR_2D) { + code = "max(min($, vec2(1.0)), vec2(0.0))"; + } else { + code = "max(min($, vec3(1.0)), vec3(0.0))"; + } + return " " + p_output_vars[0] + " = " + code.replace("$", p_input_vars[0]) + ";\n"; + } + + if (func == FUNC_ONEMINUS) { + String code; + + if (op_type == OP_TYPE_VECTOR_2D) { + code = "vec2(1.0, 1.0) - $"; + } else { + code = "vec3(1.0, 1.0, 1.0) - $"; + } + return " " + p_output_vars[0] + " = " + code.replace("$", p_input_vars[0]) + ";\n"; + } + String code; if (func == FUNC_RGB2HSV) { + if (op_type == OP_TYPE_VECTOR_2D) { // not supported + return " " + p_output_vars[0] + " = vec2(0.0);\n"; + } code += " {\n"; code += " vec3 c = " + p_input_vars[0] + ";\n"; code += " vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; @@ -2478,6 +2669,9 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad code += " " + p_output_vars[0] + " = vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; code += " }\n"; } else if (func == FUNC_HSV2RGB) { + if (op_type == OP_TYPE_VECTOR_2D) { // not supported + return " " + p_output_vars[0] + " = vec2(0.0);\n"; + } code += " {\n"; code += " vec3 c = " + p_input_vars[0] + ";\n"; code += " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; @@ -2486,12 +2680,31 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad code += " }\n"; } else { - code += " " + p_output_vars[0] + " = " + String(vec_func_id[func]).replace("$", p_input_vars[0]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(funcs[func]).replace("$", p_input_vars[0]) + ";\n"; } return code; } +void VisualShaderNodeVectorFunc::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + void VisualShaderNodeVectorFunc::set_function(Function p_func) { ERR_FAIL_INDEX(int(p_func), int(FUNC_MAX)); if (func == p_func) { @@ -2513,11 +2726,27 @@ VisualShaderNodeVectorFunc::Function VisualShaderNodeVectorFunc::get_function() } Vector<StringName> VisualShaderNodeVectorFunc::get_editable_properties() const { - Vector<StringName> props; + Vector<StringName> props = VisualShaderNodeVectorBase::get_editable_properties(); props.push_back("function"); return props; } +String VisualShaderNodeVectorFunc::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { + bool invalid_type = false; + + if (op_type == OP_TYPE_VECTOR_2D) { + if (func == FUNC_RGB2HSV || func == FUNC_HSV2RGB) { + invalid_type = true; + } + } + + if (invalid_type) { + return TTR("Invalid function for that type."); + } + + return String(); +} + void VisualShaderNodeVectorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); @@ -2563,7 +2792,16 @@ void VisualShaderNodeVectorFunc::_bind_methods() { } VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() { - set_input_port_default_value(0, Vector3()); + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2()); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3()); + } break; + default: + break; + } } ////////////// ColorFunc @@ -2577,7 +2815,7 @@ int VisualShaderNodeColorFunc::get_input_port_count() const { } VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorFunc::get_input_port_name(int p_port) const { @@ -2589,7 +2827,7 @@ int VisualShaderNodeColorFunc::get_output_port_count() const { } VisualShaderNodeColorFunc::PortType VisualShaderNodeColorFunc::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorFunc::get_output_port_name(int p_port) const { @@ -2748,11 +2986,11 @@ int VisualShaderNodeUVFunc::get_input_port_count() const { VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_input_port_type(int p_port) const { switch (p_port) { case 0: - [[fallthrough]]; // uv + return PORT_TYPE_VECTOR_2D; // uv case 1: - return PORT_TYPE_VECTOR; // scale + return PORT_TYPE_VECTOR_2D; // scale case 2: - return PORT_TYPE_VECTOR; // offset & pivot + return PORT_TYPE_VECTOR_2D; // offset & pivot default: break; } @@ -2781,11 +3019,13 @@ String VisualShaderNodeUVFunc::get_input_port_name(int p_port) const { return ""; } -String VisualShaderNodeUVFunc::get_input_port_default_hint(int p_port) const { - if (p_port == 0) { - return "UV"; +bool VisualShaderNodeUVFunc::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + if (p_port == 0) { + return true; + } } - return ""; + return false; } int VisualShaderNodeUVFunc::get_output_port_count() const { @@ -2793,7 +3033,7 @@ int VisualShaderNodeUVFunc::get_output_port_count() const { } VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_2D; } String VisualShaderNodeUVFunc::get_output_port_name(int p_port) const { @@ -2809,7 +3049,11 @@ String VisualShaderNodeUVFunc::generate_code(Shader::Mode p_mode, VisualShader:: String uv; if (p_input_vars[0].is_empty()) { - uv = "vec3(UV.xy, 0.0)"; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + uv = "UV"; + } else { + uv = "vec2(0.0)"; + } } else { uv = vformat("%s", p_input_vars[0]); } @@ -2835,9 +3079,9 @@ void VisualShaderNodeUVFunc::set_function(VisualShaderNodeUVFunc::Function p_fun return; } if (p_func == FUNC_PANNING) { - set_input_port_default_value(2, Vector3()); // offset + set_input_port_default_value(2, Vector2()); // offset } else { // FUNC_SCALING - set_input_port_default_value(2, Vector3(0.5, 0.5, 0.0)); // pivot + set_input_port_default_value(2, Vector2(0.5, 0.5)); // pivot } func = p_func; emit_changed(); @@ -2865,8 +3109,8 @@ void VisualShaderNodeUVFunc::_bind_methods() { } VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() { - set_input_port_default_value(1, Vector3(1.0, 1.0, 0.0)); // scale - set_input_port_default_value(2, Vector3()); // offset + set_input_port_default_value(1, Vector2(1.0, 1.0)); // scale + set_input_port_default_value(2, Vector2()); // offset } ////////////// Dot Product @@ -2880,7 +3124,7 @@ int VisualShaderNodeDotProduct::get_input_port_count() const { } VisualShaderNodeDotProduct::PortType VisualShaderNodeDotProduct::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeDotProduct::get_input_port_name(int p_port) const { @@ -2918,10 +3162,6 @@ 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 ""; } @@ -2938,12 +3178,31 @@ String VisualShaderNodeVectorLen::get_output_port_name(int p_port) const { return "length"; } +void VisualShaderNodeVectorLen::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + String VisualShaderNodeVectorLen::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 " " + p_output_vars[0] + " = length(" + p_input_vars[0] + ");\n"; } VisualShaderNodeVectorLen::VisualShaderNodeVectorLen() { - set_input_port_default_value(0, Vector3()); + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); } ////////////// Determinant @@ -2984,37 +3243,53 @@ VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() { set_input_port_default_value(0, Transform3D()); } -////////////// Scalar Derivative Function +////////////// Derivative Function -String VisualShaderNodeScalarDerivativeFunc::get_caption() const { - return "ScalarDerivativeFunc"; +String VisualShaderNodeDerivativeFunc::get_caption() const { + return "DerivativeFunc"; } -int VisualShaderNodeScalarDerivativeFunc::get_input_port_count() const { +int VisualShaderNodeDerivativeFunc::get_input_port_count() const { return 1; } -VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_input_port_type(int p_port) const { +VisualShaderNodeDerivativeFunc::PortType VisualShaderNodeDerivativeFunc::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarDerivativeFunc::get_input_port_name(int p_port) const { - return ""; +String VisualShaderNodeDerivativeFunc::get_input_port_name(int p_port) const { + return "p"; } -int VisualShaderNodeScalarDerivativeFunc::get_output_port_count() const { +int VisualShaderNodeDerivativeFunc::get_output_port_count() const { return 1; } -VisualShaderNodeScalarDerivativeFunc::PortType VisualShaderNodeScalarDerivativeFunc::get_output_port_type(int p_port) const { +VisualShaderNodeDerivativeFunc::PortType VisualShaderNodeDerivativeFunc::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarDerivativeFunc::get_output_port_name(int p_port) const { - return ""; +String VisualShaderNodeDerivativeFunc::get_output_port_name(int p_port) const { + return "result"; } -String VisualShaderNodeScalarDerivativeFunc::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 VisualShaderNodeDerivativeFunc::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 { static const char *functions[FUNC_MAX] = { "fwidth($)", "dFdx($)", @@ -3026,84 +3301,33 @@ String VisualShaderNodeScalarDerivativeFunc::generate_code(Shader::Mode p_mode, return code; } -void VisualShaderNodeScalarDerivativeFunc::set_function(Function p_func) { - ERR_FAIL_INDEX(int(p_func), int(FUNC_MAX)); - if (func == p_func) { +void VisualShaderNodeDerivativeFunc::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, int(OP_TYPE_MAX)); + if (op_type == p_op_type) { return; } - func = p_func; + switch (p_op_type) { + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + } break; + default: + break; + } + op_type = p_op_type; emit_changed(); } -VisualShaderNodeScalarDerivativeFunc::Function VisualShaderNodeScalarDerivativeFunc::get_function() const { - return func; -} - -Vector<StringName> VisualShaderNodeScalarDerivativeFunc::get_editable_properties() const { - Vector<StringName> props; - props.push_back("function"); - return props; -} - -void VisualShaderNodeScalarDerivativeFunc::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarDerivativeFunc::set_function); - ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarDerivativeFunc::get_function); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); - - BIND_ENUM_CONSTANT(FUNC_SUM); - BIND_ENUM_CONSTANT(FUNC_X); - BIND_ENUM_CONSTANT(FUNC_Y); - BIND_ENUM_CONSTANT(FUNC_MAX); -} - -VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() { - set_input_port_default_value(0, 0.0); -} - -////////////// Vector Derivative Function - -String VisualShaderNodeVectorDerivativeFunc::get_caption() const { - return "VectorDerivativeFunc"; -} - -int VisualShaderNodeVectorDerivativeFunc::get_input_port_count() const { - return 1; -} - -VisualShaderNodeVectorDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorDerivativeFunc::get_input_port_name(int p_port) const { - return ""; -} - -int VisualShaderNodeVectorDerivativeFunc::get_output_port_count() const { - return 1; -} - -VisualShaderNodeVectorDerivativeFunc::PortType VisualShaderNodeVectorDerivativeFunc::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorDerivativeFunc::get_output_port_name(int p_port) const { - return ""; -} - -String VisualShaderNodeVectorDerivativeFunc::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 { - static const char *functions[FUNC_MAX] = { - "fwidth($)", - "dFdx($)", - "dFdy($)" - }; - - String code; - code += " " + p_output_vars[0] + " = " + String(functions[func]).replace("$", p_input_vars[0]) + ";\n"; - return code; +VisualShaderNodeDerivativeFunc::OpType VisualShaderNodeDerivativeFunc::get_op_type() const { + return op_type; } -void VisualShaderNodeVectorDerivativeFunc::set_function(Function p_func) { +void VisualShaderNodeDerivativeFunc::set_function(Function p_func) { ERR_FAIL_INDEX(int(p_func), int(FUNC_MAX)); if (func == p_func) { return; @@ -3112,30 +3336,40 @@ void VisualShaderNodeVectorDerivativeFunc::set_function(Function p_func) { emit_changed(); } -VisualShaderNodeVectorDerivativeFunc::Function VisualShaderNodeVectorDerivativeFunc::get_function() const { +VisualShaderNodeDerivativeFunc::Function VisualShaderNodeDerivativeFunc::get_function() const { return func; } -Vector<StringName> VisualShaderNodeVectorDerivativeFunc::get_editable_properties() const { +Vector<StringName> VisualShaderNodeDerivativeFunc::get_editable_properties() const { Vector<StringName> props; + props.push_back("op_type"); props.push_back("function"); return props; } -void VisualShaderNodeVectorDerivativeFunc::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorDerivativeFunc::set_function); - ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorDerivativeFunc::get_function); +void VisualShaderNodeDerivativeFunc::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeDerivativeFunc::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeDerivativeFunc::get_op_type); + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeDerivativeFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeDerivativeFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3"), "set_op_type", "get_op_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sum,X,Y"), "set_function", "get_function"); + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); + BIND_ENUM_CONSTANT(FUNC_SUM); BIND_ENUM_CONSTANT(FUNC_X); BIND_ENUM_CONSTANT(FUNC_Y); BIND_ENUM_CONSTANT(FUNC_MAX); } -VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { - set_input_port_default_value(0, Vector3()); +VisualShaderNodeDerivativeFunc::VisualShaderNodeDerivativeFunc() { + set_input_port_default_value(0, 0.0); } ////////////// Clamp @@ -3152,8 +3386,10 @@ VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p switch (op_type) { case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3179,8 +3415,10 @@ VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int switch (op_type) { case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3202,19 +3440,24 @@ void VisualShaderNodeClamp::set_op_type(OpType p_op_type) { } switch (p_op_type) { case OP_TYPE_FLOAT: - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); break; case OP_TYPE_INT: - set_input_port_default_value(0, 0); - set_input_port_default_value(1, 0); - set_input_port_default_value(2, 0); + set_input_port_default_value(0, 0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0, get_input_port_default_value(1)); + set_input_port_default_value(2, 0, get_input_port_default_value(2)); + break; + case OP_TYPE_VECTOR_2D: + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); break; - case OP_TYPE_VECTOR: - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + case OP_TYPE_VECTOR_3D: + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); break; default: break; @@ -3237,11 +3480,12 @@ void VisualShaderNodeClamp::_bind_methods() { ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeClamp::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeClamp::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); BIND_ENUM_CONSTANT(OP_TYPE_INT); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); BIND_ENUM_CONSTANT(OP_TYPE_MAX); } @@ -3261,10 +3505,6 @@ int VisualShaderNodeFaceForward::get_input_port_count() const { return 3; } -VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - String VisualShaderNodeFaceForward::get_input_port_name(int p_port) const { switch (p_port) { case 0: @@ -3282,14 +3522,33 @@ int VisualShaderNodeFaceForward::get_output_port_count() const { return 1; } -VisualShaderNodeFaceForward::PortType VisualShaderNodeFaceForward::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - String VisualShaderNodeFaceForward::get_output_port_name(int p_port) const { return ""; } +void VisualShaderNodeFaceForward::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + String VisualShaderNodeFaceForward::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 " " + p_output_vars[0] + " = faceforward(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } @@ -3311,7 +3570,7 @@ int VisualShaderNodeOuterProduct::get_input_port_count() const { } VisualShaderNodeOuterProduct::PortType VisualShaderNodeOuterProduct::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeOuterProduct::get_input_port_name(int p_port) const { @@ -3358,11 +3617,18 @@ int VisualShaderNodeStep::get_input_port_count() const { VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: if (p_port == 1) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_2D; + } + break; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + if (p_port == 1) { + return PORT_TYPE_VECTOR_3D; } break; default: @@ -3372,12 +3638,13 @@ VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_p } String VisualShaderNodeStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge"; - } else if (p_port == 1) { - return "x"; + switch (p_port) { + case 0: + return "edge"; + case 1: + return "x"; } - return ""; + return String(); } int VisualShaderNodeStep::get_output_port_count() const { @@ -3386,10 +3653,14 @@ int VisualShaderNodeStep::get_output_port_count() const { VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3406,30 +3677,26 @@ void VisualShaderNodeStep::set_op_type(OpType p_op_type) { return; } switch (p_op_type) { - case OP_TYPE_SCALAR: - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(0, 0.0); // edge - } - if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { - set_input_port_default_value(1, 0.0); // x - } - break; - case OP_TYPE_VECTOR: - if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge - } - if (op_type == OP_TYPE_SCALAR) { - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x - } - break; - case OP_TYPE_VECTOR_SCALAR: - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(0, 0.0); // edge - } - if (op_type == OP_TYPE_SCALAR) { - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x - } - break; + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + } break; default: break; } @@ -3455,11 +3722,13 @@ void VisualShaderNodeStep::_bind_methods() { ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeStep::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeStep::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR); BIND_ENUM_CONSTANT(OP_TYPE_MAX); } @@ -3480,11 +3749,18 @@ int VisualShaderNodeSmoothStep::get_input_port_count() const { VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: if (p_port == 2) { - return PORT_TYPE_VECTOR; // x + return PORT_TYPE_VECTOR_2D; // x + } + break; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + if (p_port == 2) { + return PORT_TYPE_VECTOR_3D; // x } break; default: @@ -3494,14 +3770,15 @@ VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_ } String VisualShaderNodeSmoothStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge0"; - } else if (p_port == 1) { - return "edge1"; - } else if (p_port == 2) { - return "x"; + switch (p_port) { + case 0: + return "edge0"; + case 1: + return "edge1"; + case 2: + return "x"; } - return ""; + return String(); } int VisualShaderNodeSmoothStep::get_output_port_count() const { @@ -3510,10 +3787,14 @@ int VisualShaderNodeSmoothStep::get_output_port_count() const { VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3531,31 +3812,29 @@ void VisualShaderNodeSmoothStep::set_op_type(OpType p_op_type) { } switch (p_op_type) { case OP_TYPE_SCALAR: - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(0, 0.0); // edge0 - set_input_port_default_value(1, 0.0); // edge1 - } - if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { - set_input_port_default_value(2, 0.0); // x - } - break; - case OP_TYPE_VECTOR: - if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge0 - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // edge1 - } - if (op_type == OP_TYPE_SCALAR) { - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x - } - break; - case OP_TYPE_VECTOR_SCALAR: - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(0, 0.0); // edge0 - set_input_port_default_value(1, 0.0); // edge1 - } - if (op_type == OP_TYPE_SCALAR) { - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x - } + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); // edge0 + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // edge1 + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // x + break; + case OP_TYPE_VECTOR_2D: + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); // edge0 + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); // edge1 + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); // x + break; + case OP_TYPE_VECTOR_2D_SCALAR: + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); // edge0 + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // edge1 + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); // x + break; + case OP_TYPE_VECTOR_3D: + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); // edge0 + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // edge1 + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); // x + break; + case OP_TYPE_VECTOR_3D_SCALAR: + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); // edge0 + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // edge1 + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); // x break; default: break; @@ -3582,18 +3861,20 @@ void VisualShaderNodeSmoothStep::_bind_methods() { ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeSmoothStep::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSmoothStep::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR); BIND_ENUM_CONSTANT(OP_TYPE_MAX); } VisualShaderNodeSmoothStep::VisualShaderNodeSmoothStep() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 1.0); // edge1 + set_input_port_default_value(2, 0.5); // x } ////////////// Distance @@ -3606,17 +3887,14 @@ int VisualShaderNodeVectorDistance::get_input_port_count() const { return 2; } -VisualShaderNodeVectorDistance::PortType VisualShaderNodeVectorDistance::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - String VisualShaderNodeVectorDistance::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "p0"; - } else if (p_port == 1) { - return "p1"; + switch (p_port) { + case 0: + return "a"; + case 1: + return "b"; } - return ""; + return String(); } int VisualShaderNodeVectorDistance::get_output_port_count() const { @@ -3631,13 +3909,34 @@ String VisualShaderNodeVectorDistance::get_output_port_name(int p_port) const { return ""; } +void VisualShaderNodeVectorDistance::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); // b + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // b + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + String VisualShaderNodeVectorDistance::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 " " + p_output_vars[0] + " = distance(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } VisualShaderNodeVectorDistance::VisualShaderNodeVectorDistance() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // b } ////////////// Refract Vector @@ -3655,18 +3954,19 @@ VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_input return PORT_TYPE_SCALAR; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVectorRefract::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "I"; - } else if (p_port == 1) { - return "N"; - } else if (p_port == 2) { - return "eta"; + switch (p_port) { + case 0: + return "I"; + case 1: + return "N"; + case 2: + return "eta"; } - return ""; + return String(); } int VisualShaderNodeVectorRefract::get_output_port_count() const { @@ -3674,7 +3974,7 @@ int VisualShaderNodeVectorRefract::get_output_port_count() const { } VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const { @@ -3703,13 +4003,20 @@ int VisualShaderNodeMix::get_input_port_count() const { VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: if (p_port == 2) { break; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + if (p_port == 2) { + break; + } + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3732,10 +4039,14 @@ int VisualShaderNodeMix::get_output_port_count() const { VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; - case OP_TYPE_VECTOR_SCALAR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + return PORT_TYPE_VECTOR_3D; default: break; } @@ -3752,27 +4063,31 @@ void VisualShaderNodeMix::set_op_type(OpType p_op_type) { return; } switch (p_op_type) { - case OP_TYPE_SCALAR: - set_input_port_default_value(0, 0.0); // a - set_input_port_default_value(1, 1.0); // b - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(2, 0.5); // weight - } - break; - case OP_TYPE_VECTOR: - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b - if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { - set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); // weight - } - break; - case OP_TYPE_VECTOR_SCALAR: - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b - if (op_type == OP_TYPE_VECTOR) { - set_input_port_default_value(2, 0.5); // weight - } - break; + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); // a + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); // b + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // weight + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); // b + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); // weight + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); // b + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // weight + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // b + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); // weight + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); // a + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); // b + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); // weight + } break; default: break; } @@ -3798,11 +4113,13 @@ void VisualShaderNodeMix::_bind_methods() { ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeMix::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMix::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR); BIND_ENUM_CONSTANT(OP_TYPE_MAX); } @@ -3819,7 +4136,15 @@ String VisualShaderNodeVectorCompose::get_caption() const { } int VisualShaderNodeVectorCompose::get_input_port_count() const { - return 3; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return 2; + case OP_TYPE_VECTOR_3D: + return 3; + default: + break; + } + return 0; } VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_input_port_type(int p_port) const { @@ -3827,29 +4152,80 @@ VisualShaderNodeVectorCompose::PortType VisualShaderNodeVectorCompose::get_input } String VisualShaderNodeVectorCompose::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "x"; - } else if (p_port == 1) { - return "y"; - } else { - return "z"; + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + switch (p_port) { + case 0: + return "x"; + case 1: + return "y"; + } + } break; + case OP_TYPE_VECTOR_3D: { + switch (p_port) { + case 0: + return "x"; + case 1: + return "y"; + case 2: + return "z"; + } + } break; + default: + break; } + return String(); } 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"; } +void VisualShaderNodeVectorCompose::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + float p1 = get_input_port_default_value(0); + float p2 = get_input_port_default_value(1); + + set_input_port_default_value(0, p1); + set_input_port_default_value(1, p2); + } break; + case OP_TYPE_VECTOR_3D: { + float p1 = get_input_port_default_value(0); + float p2 = get_input_port_default_value(1); + + set_input_port_default_value(0, p1); + set_input_port_default_value(1, p2); + set_input_port_default_value(2, 0.0); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + String VisualShaderNodeVectorCompose::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 " " + p_output_vars[0] + " = vec3(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + String code; + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + code += " " + p_output_vars[0] + " = vec2(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; + } break; + case OP_TYPE_VECTOR_3D: { + code += " " + p_output_vars[0] + " = vec3(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + } break; + default: + break; + } + return code; } VisualShaderNodeVectorCompose::VisualShaderNodeVectorCompose() { @@ -3869,7 +4245,7 @@ int VisualShaderNodeTransformCompose::get_input_port_count() const { } VisualShaderNodeTransformCompose::PortType VisualShaderNodeTransformCompose::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformCompose::get_input_port_name(int p_port) const { @@ -3916,16 +4292,20 @@ 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"; } int VisualShaderNodeVectorDecompose::get_output_port_count() const { - return 3; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return 2; + case OP_TYPE_VECTOR_3D: + return 3; + default: + break; + } + return 0; } VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_output_port_type(int p_port) const { @@ -3933,25 +4313,70 @@ VisualShaderNodeVectorDecompose::PortType VisualShaderNodeVectorDecompose::get_o } String VisualShaderNodeVectorDecompose::get_output_port_name(int p_port) const { - if (p_port == 0) { - return "x"; - } else if (p_port == 1) { - return "y"; - } else { - return "z"; + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + switch (p_port) { + case 0: + return "x"; + case 1: + return "y"; + } + } break; + case OP_TYPE_VECTOR_3D: { + switch (p_port) { + case 0: + return "x"; + case 1: + return "y"; + case 2: + return "z"; + } + } break; + default: + break; } + return String(); +} + +void VisualShaderNodeVectorDecompose::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } String VisualShaderNodeVectorDecompose::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 code; - code += " " + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; - code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; - code += " " + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n"; + switch (op_type) { + case OP_TYPE_VECTOR_2D: { + code += " " + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; + code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; + } break; + case OP_TYPE_VECTOR_3D: { + code += " " + p_output_vars[0] + " = " + p_input_vars[0] + ".x;\n"; + code += " " + p_output_vars[1] + " = " + p_input_vars[0] + ".y;\n"; + code += " " + p_output_vars[2] + " = " + p_input_vars[0] + ".z;\n"; + } break; + default: + break; + } return code; } VisualShaderNodeVectorDecompose::VisualShaderNodeVectorDecompose() { - set_input_port_default_value(0, Vector3()); + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); } ////////////// Transform Decompose @@ -3977,7 +4402,7 @@ int VisualShaderNodeTransformDecompose::get_output_port_count() const { } VisualShaderNodeTransformDecompose::PortType VisualShaderNodeTransformDecompose::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformDecompose::get_output_port_name(int p_port) const { @@ -4508,7 +4933,7 @@ int VisualShaderNodeColorUniform::get_input_port_count() const { } VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const { @@ -4520,7 +4945,7 @@ int VisualShaderNodeColorUniform::get_output_port_count() const { } VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_3D : PORT_TYPE_SCALAR; } String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { @@ -4601,10 +5026,110 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { } -////////////// Vector Uniform +////////////// Vector2 Uniform + +String VisualShaderNodeVec2Uniform::get_caption() const { + return "Vector2Uniform"; +} + +int VisualShaderNodeVec2Uniform::get_input_port_count() const { + return 0; +} + +VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeVec2Uniform::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeVec2Uniform::get_output_port_count() const { + return 1; +} + +VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeVec2Uniform::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeVec2Uniform::set_default_value_enabled(bool p_enabled) { + default_value_enabled = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeVec2Uniform::is_default_value_enabled() const { + return default_value_enabled; +} + +void VisualShaderNodeVec2Uniform::set_default_value(const Vector2 &p_value) { + default_value = p_value; + emit_changed(); +} + +Vector2 VisualShaderNodeVec2Uniform::get_default_value() const { + return default_value; +} + +String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform vec2 " + get_uniform_name(); + if (default_value_enabled) { + code += vformat(" = vec2(%.6f, %.6f)", default_value.x, default_value.y); + } + code += ";\n"; + return code; +} + +String VisualShaderNodeVec2Uniform::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 " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +} + +void VisualShaderNodeVec2Uniform::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Uniform::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Uniform::is_default_value_enabled); + + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Uniform::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Uniform::get_default_value); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "default_value"), "set_default_value", "get_default_value"); +} + +bool VisualShaderNodeVec2Uniform::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeVec2Uniform::is_use_prop_slots() const { + return true; +} + +bool VisualShaderNodeVec2Uniform::is_qualifier_supported(Qualifier p_qual) const { + return true; // all qualifiers are supported +} + +bool VisualShaderNodeVec2Uniform::is_convertible_to_constant() const { + return true; // conversion is allowed +} + +Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); + props.push_back("default_value_enabled"); + if (default_value_enabled) { + props.push_back("default_value"); + } + return props; +} + +VisualShaderNodeVec2Uniform::VisualShaderNodeVec2Uniform() { +} + +////////////// Vector3 Uniform String VisualShaderNodeVec3Uniform::get_caption() const { - return "VectorUniform"; + return "Vector3Uniform"; } int VisualShaderNodeVec3Uniform::get_input_port_count() const { @@ -4612,7 +5137,7 @@ int VisualShaderNodeVec3Uniform::get_input_port_count() const { } VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const { @@ -4624,7 +5149,7 @@ int VisualShaderNodeVec3Uniform::get_output_port_count() const { } VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const { @@ -4712,7 +5237,7 @@ int VisualShaderNodeTransformUniform::get_input_port_count() const { } VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const { @@ -4819,7 +5344,7 @@ int VisualShaderNodeTextureUniform::get_input_port_count() const { } VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const { - return p_port == 0 ? PORT_TYPE_VECTOR : PORT_TYPE_SCALAR; + return p_port == 0 ? PORT_TYPE_VECTOR_2D : PORT_TYPE_SCALAR; } String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { @@ -4833,7 +5358,7 @@ int VisualShaderNodeTextureUniform::get_output_port_count() const { VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 1: return PORT_TYPE_SCALAR; case 2: @@ -4966,8 +5491,8 @@ bool VisualShaderNodeTextureUniform::is_code_generated() const { String VisualShaderNodeTextureUniform::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 default_uv; - if (p_mode != Shader::MODE_PARTICLES && p_mode != Shader::MODE_SKY) { - default_uv = "UV.xy"; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + default_uv = "UV"; } else { default_uv = "vec2(0.0)"; } @@ -4982,9 +5507,9 @@ String VisualShaderNodeTextureUniform::generate_code(Shader::Mode p_mode, Visual } } else if (p_input_vars[1].is_empty()) { //no lod - code += " vec4 n_tex_read = texture(" + id + ", " + p_input_vars[0] + ".xy);\n"; + code += " vec4 n_tex_read = texture(" + id + ", " + p_input_vars[0] + ");\n"; } else { - code += " vec4 n_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n"; + code += " vec4 n_tex_read = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } code += " " + p_output_vars[0] + " = n_tex_read.rgb;\n"; @@ -5112,11 +5637,13 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(REPEAT_MAX); } -String VisualShaderNodeTextureUniform::get_input_port_default_hint(int p_port) const { - if (p_port == 0) { - return "default"; +bool VisualShaderNodeTextureUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + if (p_port == 0) { + return true; + } } - return ""; + return false; } bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) const { @@ -5153,7 +5680,7 @@ int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const { VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const { if (p_port == 0 || p_port == 1) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -5224,13 +5751,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod return code; } -String VisualShaderNodeTextureUniformTriplanar::get_input_port_default_hint(int p_port) const { +bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const { if (p_port == 0) { - return "default"; + return true; } else if (p_port == 1) { - return "default"; + return true; } - return ""; + return false; } VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() { @@ -5266,8 +5793,8 @@ String VisualShaderNodeTexture2DArrayUniform::get_input_port_name(int p_port) co return ""; } -String VisualShaderNodeTexture2DArrayUniform::get_input_port_default_hint(int p_port) const { - return ""; +bool VisualShaderNodeTexture2DArrayUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const { + return false; } String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { @@ -5339,8 +5866,8 @@ String VisualShaderNodeTexture3DUniform::get_input_port_name(int p_port) const { return ""; } -String VisualShaderNodeTexture3DUniform::get_input_port_default_hint(int p_port) const { - return ""; +bool VisualShaderNodeTexture3DUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const { + return false; } String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { @@ -5412,8 +5939,8 @@ String VisualShaderNodeCubemapUniform::get_input_port_name(int p_port) const { return ""; } -String VisualShaderNodeCubemapUniform::get_input_port_default_hint(int p_port) const { - return ""; +bool VisualShaderNodeCubemapUniform::is_input_port_default(int p_port, Shader::Mode p_mode) const { + return false; } String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { @@ -5469,7 +5996,7 @@ VisualShaderNodeIf::PortType VisualShaderNodeIf::get_input_port_type(int p_port) if (p_port == 0 || p_port == 1 || p_port == 2) { return PORT_TYPE_SCALAR; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeIf::get_input_port_name(int p_port) const { @@ -5496,7 +6023,7 @@ int VisualShaderNodeIf::get_output_port_count() const { } VisualShaderNodeIf::PortType VisualShaderNodeIf::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeIf::get_output_port_name(int p_port) const { @@ -5548,8 +6075,10 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int switch (op_type) { case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; case OP_TYPE_BOOLEAN: return PORT_TYPE_BOOLEAN; case OP_TYPE_TRANSFORM: @@ -5582,8 +6111,10 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(in switch (op_type) { case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; - case OP_TYPE_VECTOR: - return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; case OP_TYPE_BOOLEAN: return PORT_TYPE_BOOLEAN; case OP_TYPE_TRANSFORM: @@ -5605,16 +6136,20 @@ void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) { } switch (p_op_type) { case OP_TYPE_FLOAT: - set_input_port_default_value(1, 1.0); - set_input_port_default_value(2, 0.0); + set_input_port_default_value(1, 1.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); break; case OP_TYPE_INT: - set_input_port_default_value(1, 1); - set_input_port_default_value(2, 0); + set_input_port_default_value(1, 1, get_input_port_default_value(1)); + set_input_port_default_value(2, 0, get_input_port_default_value(2)); break; - case OP_TYPE_VECTOR: - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + case OP_TYPE_VECTOR_2D: + set_input_port_default_value(1, Vector2(1.0, 1.0), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(0.0, 0.0), get_input_port_default_value(2)); + break; + case OP_TYPE_VECTOR_3D: + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0), get_input_port_default_value(2)); break; case OP_TYPE_BOOLEAN: set_input_port_default_value(1, true); @@ -5645,11 +6180,12 @@ void VisualShaderNodeSwitch::_bind_methods() { // static ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSwitch::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSwitch::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector,Boolean,Transform"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Boolean,Transform"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); BIND_ENUM_CONSTANT(OP_TYPE_INT); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); BIND_ENUM_CONSTANT(OP_TYPE_BOOLEAN); BIND_ENUM_CONSTANT(OP_TYPE_TRANSFORM); BIND_ENUM_CONSTANT(OP_TYPE_MAX); @@ -5688,15 +6224,15 @@ int VisualShaderNodeFresnel::get_input_port_count() const { VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_input_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 1: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 2: return PORT_TYPE_BOOLEAN; case 3: return PORT_TYPE_SCALAR; default: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } } @@ -5738,12 +6274,20 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader: String normal; String view; if (p_input_vars[0].is_empty()) { - normal = "NORMAL"; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + normal = "NORMAL"; + } else { + normal = "vec3(0.0)"; + } } else { normal = p_input_vars[0]; } if (p_input_vars[1].is_empty()) { - view = "VIEW"; + if (p_mode == Shader::MODE_SPATIAL) { + view = "VIEW"; + } else { + view = "vec3(0.0)"; + } } else { view = p_input_vars[1]; } @@ -5759,13 +6303,17 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader: } } -String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const { +bool VisualShaderNodeFresnel::is_input_port_default(int p_port, Shader::Mode p_mode) const { if (p_port == 0) { - return "default"; + if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) { + return true; + } } else if (p_port == 1) { - return "default"; + if (p_mode == Shader::MODE_SPATIAL) { + return true; + } } - return ""; + return false; } VisualShaderNodeFresnel::VisualShaderNodeFresnel() { @@ -5867,8 +6415,10 @@ VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(i return PORT_TYPE_SCALAR; case CTYPE_SCALAR_INT: return PORT_TYPE_SCALAR_INT; - case CTYPE_VECTOR: - return PORT_TYPE_VECTOR; + case CTYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case CTYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; case CTYPE_BOOLEAN: return PORT_TYPE_BOOLEAN; case CTYPE_TRANSFORM: @@ -5939,7 +6489,7 @@ String VisualShaderNodeCompare::generate_code(Shader::Mode p_mode, VisualShader: String code; switch (comparison_type) { - case CTYPE_SCALAR: + case CTYPE_SCALAR: { if (func == FUNC_EQUAL) { code += " " + p_output_vars[0] + " = (abs(" + p_input_vars[0] + " - " + p_input_vars[1] + ") < " + p_input_vars[2] + ");"; } else if (func == FUNC_NOT_EQUAL) { @@ -5947,33 +6497,34 @@ String VisualShaderNodeCompare::generate_code(Shader::Mode p_mode, VisualShader: } else { code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", operators[func]) + ";\n"; } - break; - - case CTYPE_SCALAR_INT: + } break; + case CTYPE_SCALAR_INT: { code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", operators[func]) + ";\n"; - break; - - case CTYPE_VECTOR: + } break; + case CTYPE_VECTOR_2D: { + code += " {\n"; + code += " bvec2 _bv = " + String(functions[func]).replace("$", p_input_vars[0] + ", " + p_input_vars[1]) + ";\n"; + code += " " + p_output_vars[0] + " = " + String(conditions[condition]).replace("$", "_bv") + ";\n"; + code += " }\n"; + } break; + case CTYPE_VECTOR_3D: { code += " {\n"; code += " bvec3 _bv = " + String(functions[func]).replace("$", p_input_vars[0] + ", " + p_input_vars[1]) + ";\n"; code += " " + p_output_vars[0] + " = " + String(conditions[condition]).replace("$", "_bv") + ";\n"; code += " }\n"; - break; - - case CTYPE_BOOLEAN: + } break; + case CTYPE_BOOLEAN: { if (func > FUNC_NOT_EQUAL) { return " " + p_output_vars[0] + " = false;\n"; } code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", operators[func]) + ";\n"; - break; - - case CTYPE_TRANSFORM: + } break; + case CTYPE_TRANSFORM: { if (func > FUNC_NOT_EQUAL) { return " " + p_output_vars[0] + " = false;\n"; } code += " " + p_output_vars[0] + " = " + (p_input_vars[0] + " $ " + p_input_vars[1]).replace("$", operators[func]) + ";\n"; - break; - + } break; default: break; } @@ -5987,18 +6538,23 @@ void VisualShaderNodeCompare::set_comparison_type(ComparisonType p_comparison_ty } switch (p_comparison_type) { case CTYPE_SCALAR: - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); simple_decl = true; break; case CTYPE_SCALAR_INT: - set_input_port_default_value(0, 0); - set_input_port_default_value(1, 0); + set_input_port_default_value(0, 0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0, get_input_port_default_value(1)); simple_decl = true; break; - case CTYPE_VECTOR: - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + case CTYPE_VECTOR_2D: + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + simple_decl = false; + break; + case CTYPE_VECTOR_3D: + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); simple_decl = false; break; case CTYPE_BOOLEAN: @@ -6052,7 +6608,7 @@ Vector<StringName> VisualShaderNodeCompare::get_editable_properties() const { Vector<StringName> props; props.push_back("type"); props.push_back("function"); - if (comparison_type == CTYPE_VECTOR) { + if (comparison_type == CTYPE_VECTOR_2D || comparison_type == CTYPE_VECTOR_3D) { props.push_back("condition"); } return props; @@ -6068,13 +6624,14 @@ void VisualShaderNodeCompare::_bind_methods() { ClassDB::bind_method(D_METHOD("set_condition", "condition"), &VisualShaderNodeCompare::set_condition); ClassDB::bind_method(D_METHOD("get_condition"), &VisualShaderNodeCompare::get_condition); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Float,Int,Vector,Boolean,Transform"), "set_comparison_type", "get_comparison_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Boolean,Transform"), "set_comparison_type", "get_comparison_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "a == b,a != b,a > b,a >= b,a < b,a <= b"), "set_function", "get_function"); ADD_PROPERTY(PropertyInfo(Variant::INT, "condition", PROPERTY_HINT_ENUM, "All,Any"), "set_condition", "get_condition"); BIND_ENUM_CONSTANT(CTYPE_SCALAR); BIND_ENUM_CONSTANT(CTYPE_SCALAR_INT); - BIND_ENUM_CONSTANT(CTYPE_VECTOR); + BIND_ENUM_CONSTANT(CTYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(CTYPE_VECTOR_3D); BIND_ENUM_CONSTANT(CTYPE_BOOLEAN); BIND_ENUM_CONSTANT(CTYPE_TRANSFORM); BIND_ENUM_CONSTANT(CTYPE_MAX); @@ -6109,8 +6666,13 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const { } VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const { - if (op_type == OP_TYPE_VECTOR) { - return PORT_TYPE_VECTOR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; } return PORT_TYPE_SCALAR; } @@ -6131,11 +6693,15 @@ int VisualShaderNodeMultiplyAdd::get_output_port_count() const { } VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_output_port_type(int p_port) const { - if (op_type == OP_TYPE_SCALAR) { - return PORT_TYPE_SCALAR; - } else { - return PORT_TYPE_VECTOR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + default: + break; } + return PORT_TYPE_SCALAR; } String VisualShaderNodeMultiplyAdd::get_output_port_name(int p_port) const { @@ -6152,16 +6718,21 @@ void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) { return; } switch (p_op_type) { - case OP_TYPE_SCALAR: - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); - break; - case OP_TYPE_VECTOR: - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); - break; + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 0.0, get_input_port_default_value(2)); + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(), get_input_port_default_value(2)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(), get_input_port_default_value(2)); + } break; default: break; } @@ -6183,10 +6754,11 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() { ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMultiplyAdd::set_op_type); ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMultiplyAdd::get_op_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector3"), "set_op_type", "get_op_type"); BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); - BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); BIND_ENUM_CONSTANT(OP_TYPE_MAX); } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index f1dda634f1..5c7a674d34 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -34,6 +34,49 @@ #include "scene/resources/visual_shader.h" /////////////////////////////////////// +/// Vector Base Node +/////////////////////////////////////// + +class VisualShaderNodeVectorBase : public VisualShaderNode { + GDCLASS(VisualShaderNodeVectorBase, VisualShaderNode); + +public: + enum OpType { + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_3D, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_VECTOR_3D; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override = 0; + + virtual int get_input_port_count() const override = 0; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override = 0; + + virtual int get_output_port_count() const override = 0; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override = 0; + + 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 override = 0; + + virtual void set_op_type(OpType p_op_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeVectorBase(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeVectorBase::OpType) + +/////////////////////////////////////// /// CONSTANTS /////////////////////////////////////// @@ -177,6 +220,36 @@ public: /////////////////////////////////////// +class VisualShaderNodeVec2Constant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeVec2Constant, VisualShaderNodeConstant); + Vector2 constant; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + 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 override; + + void set_constant(const Vector2 &p_constant); + Vector2 get_constant() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeVec2Constant(); +}; + +/////////////////////////////////////// + class VisualShaderNodeVec3Constant : public VisualShaderNodeConstant { GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNodeConstant); Vector3 constant; @@ -280,7 +353,7 @@ public: virtual String get_output_port_name(int p_port) const override; virtual bool is_output_port_expandable(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; @@ -392,7 +465,7 @@ public: virtual int get_input_port_count() const override; virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; @@ -488,7 +561,7 @@ public: virtual int get_input_port_count() const override; virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; @@ -615,8 +688,8 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeIntOp::Operator) -class VisualShaderNodeVectorOp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorOp, VisualShaderNode); +class VisualShaderNodeVectorOp : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorOp, VisualShaderNodeVectorBase); public: enum Operator { @@ -644,19 +717,20 @@ public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; 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 override; + virtual void set_op_type(OpType p_op_type) override; + void set_operator(Operator p_op); Operator get_operator() const; virtual Vector<StringName> get_editable_properties() const override; + String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeVectorOp(); }; @@ -923,8 +997,10 @@ VARIANT_ENUM_CAST(VisualShaderNodeIntFunc::Function) /// VECTOR FUNC /////////////////////////////////////// -class VisualShaderNodeVectorFunc : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNode); +class VisualShaderNodeVectorFunc : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorFunc, VisualShaderNodeVectorBase); + + void _update_default_input_values(); public: enum Function { @@ -975,19 +1051,20 @@ public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; 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 override; + virtual void set_op_type(OpType p_op_type) override; + void set_function(Function p_func); Function get_function() const; virtual Vector<StringName> get_editable_properties() const override; + String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; VisualShaderNodeVectorFunc(); }; @@ -1103,7 +1180,7 @@ public: virtual int get_input_port_count() const override; virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; @@ -1150,20 +1227,20 @@ public: /// LENGTH /////////////////////////////////////// -class VisualShaderNodeVectorLen : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorLen, VisualShaderNode); +class VisualShaderNodeVectorLen : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorLen, VisualShaderNodeVectorBase); public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual void set_op_type(OpType p_op_type) override; 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 override; VisualShaderNodeVectorLen(); @@ -1203,7 +1280,8 @@ public: enum OpType { OP_TYPE_FLOAT, OP_TYPE_INT, - OP_TYPE_VECTOR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_3D, OP_TYPE_MAX, }; @@ -1235,54 +1313,20 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeClamp::OpType) /////////////////////////////////////// -/// DERIVATIVE FUNCTIONS +/// DERIVATIVE FUNCTION /////////////////////////////////////// -class VisualShaderNodeScalarDerivativeFunc : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarDerivativeFunc, VisualShaderNode); +class VisualShaderNodeDerivativeFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeDerivativeFunc, VisualShaderNode); public: - enum Function { - FUNC_SUM, - FUNC_X, - FUNC_Y, - FUNC_MAX, + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_3D, + OP_TYPE_MAX, }; -protected: - Function func = FUNC_SUM; - - static void _bind_methods(); - -public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - 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 override; - - void set_function(Function p_func); - Function get_function() const; - - virtual Vector<StringName> get_editable_properties() const override; - - VisualShaderNodeScalarDerivativeFunc(); -}; - -VARIANT_ENUM_CAST(VisualShaderNodeScalarDerivativeFunc::Function) - -/////////////////////////////////////// - -class VisualShaderNodeVectorDerivativeFunc : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorDerivativeFunc, VisualShaderNode); - -public: enum Function { FUNC_SUM, FUNC_X, @@ -1291,8 +1335,10 @@ public: }; protected: + OpType op_type = OP_TYPE_SCALAR; Function func = FUNC_SUM; +protected: static void _bind_methods(); public: @@ -1308,34 +1354,37 @@ public: 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 override; + void set_op_type(OpType p_op_type); + OpType get_op_type() const; + void set_function(Function p_func); Function get_function() const; virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeVectorDerivativeFunc(); + VisualShaderNodeDerivativeFunc(); }; -VARIANT_ENUM_CAST(VisualShaderNodeVectorDerivativeFunc::Function) +VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::OpType) +VARIANT_ENUM_CAST(VisualShaderNodeDerivativeFunc::Function) /////////////////////////////////////// /// FACEFORWARD /////////////////////////////////////// -class VisualShaderNodeFaceForward : public VisualShaderNode { - GDCLASS(VisualShaderNodeFaceForward, VisualShaderNode); +class VisualShaderNodeFaceForward : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeFaceForward, VisualShaderNodeVectorBase); public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual void set_op_type(OpType p_op_type) override; 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 override; VisualShaderNodeFaceForward(); @@ -1374,8 +1423,10 @@ class VisualShaderNodeStep : public VisualShaderNode { public: enum OpType { OP_TYPE_SCALAR, - OP_TYPE_VECTOR, - OP_TYPE_VECTOR_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_2D_SCALAR, + OP_TYPE_VECTOR_3D, + OP_TYPE_VECTOR_3D_SCALAR, OP_TYPE_MAX, }; @@ -1416,8 +1467,10 @@ class VisualShaderNodeSmoothStep : public VisualShaderNode { public: enum OpType { OP_TYPE_SCALAR, - OP_TYPE_VECTOR, - OP_TYPE_VECTOR_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_2D_SCALAR, + OP_TYPE_VECTOR_3D, + OP_TYPE_VECTOR_3D_SCALAR, OP_TYPE_MAX, }; @@ -1452,20 +1505,20 @@ VARIANT_ENUM_CAST(VisualShaderNodeSmoothStep::OpType) /// DISTANCE /////////////////////////////////////// -class VisualShaderNodeVectorDistance : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorDistance, VisualShaderNode); +class VisualShaderNodeVectorDistance : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorDistance, VisualShaderNodeVectorBase); public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual void set_op_type(OpType p_op_type) override; 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 override; VisualShaderNodeVectorDistance(); @@ -1504,8 +1557,10 @@ class VisualShaderNodeMix : public VisualShaderNode { public: enum OpType { OP_TYPE_SCALAR, - OP_TYPE_VECTOR, - OP_TYPE_VECTOR_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_2D_SCALAR, + OP_TYPE_VECTOR_3D, + OP_TYPE_VECTOR_3D_SCALAR, OP_TYPE_MAX, }; @@ -1540,8 +1595,8 @@ VARIANT_ENUM_CAST(VisualShaderNodeMix::OpType) /// COMPOSE /////////////////////////////////////// -class VisualShaderNodeVectorCompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNode); +class VisualShaderNodeVectorCompose : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorCompose, VisualShaderNodeVectorBase); public: virtual String get_caption() const override; @@ -1551,9 +1606,9 @@ public: virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual void set_op_type(OpType p_op_type) override; 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 override; VisualShaderNodeVectorCompose(); @@ -1584,20 +1639,20 @@ public: /// DECOMPOSE /////////////////////////////////////// -class VisualShaderNodeVectorDecompose : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNode); +class VisualShaderNodeVectorDecompose : public VisualShaderNodeVectorBase { + GDCLASS(VisualShaderNodeVectorDecompose, VisualShaderNodeVectorBase); public: virtual String get_caption() const override; virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual void set_op_type(OpType p_op_type) override; 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 override; VisualShaderNodeVectorDecompose(); @@ -1849,6 +1904,49 @@ public: /////////////////////////////////////// +class VisualShaderNodeVec2Uniform : public VisualShaderNodeUniform { + GDCLASS(VisualShaderNodeVec2Uniform, VisualShaderNodeUniform); + +private: + bool default_value_enabled = false; + Vector2 default_value; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + 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 override; + + virtual bool is_show_prop_names() const override; + virtual bool is_use_prop_slots() const override; + + void set_default_value_enabled(bool p_enabled); + bool is_default_value_enabled() const; + + void set_default_value(const Vector2 &p_value); + Vector2 get_default_value() const; + + bool is_qualifier_supported(Qualifier p_qual) const override; + bool is_convertible_to_constant() const override; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeVec2Uniform(); +}; + +/////////////////////////////////////// + class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); @@ -1986,7 +2084,7 @@ public: virtual int get_input_port_count() const override; virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; @@ -2036,7 +2134,7 @@ public: virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; @@ -2061,7 +2159,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; 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 override; @@ -2084,7 +2182,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; 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 override; @@ -2107,7 +2205,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; 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 override; @@ -2148,7 +2246,8 @@ public: enum OpType { OP_TYPE_FLOAT, OP_TYPE_INT, - OP_TYPE_VECTOR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_3D, OP_TYPE_BOOLEAN, OP_TYPE_TRANSFORM, OP_TYPE_MAX, @@ -2200,7 +2299,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; virtual bool is_generate_input_var(int p_port) const override; 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 override; @@ -2261,7 +2360,8 @@ public: enum ComparisonType { CTYPE_SCALAR, CTYPE_SCALAR_INT, - CTYPE_VECTOR, + CTYPE_VECTOR_2D, + CTYPE_VECTOR_3D, CTYPE_BOOLEAN, CTYPE_TRANSFORM, CTYPE_MAX, @@ -2329,7 +2429,8 @@ class VisualShaderNodeMultiplyAdd : public VisualShaderNode { public: enum OpType { OP_TYPE_SCALAR, - OP_TYPE_VECTOR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_3D, OP_TYPE_MAX, }; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index c970b9c08b..3376d6aa0b 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -39,7 +39,7 @@ int VisualShaderNodeParticleEmitter::get_output_port_count() const { } VisualShaderNodeParticleEmitter::PortType VisualShaderNodeParticleEmitter::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const { @@ -154,7 +154,7 @@ int VisualShaderNodeParticleBoxEmitter::get_input_port_count() const { VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleBoxEmitter::get_input_port_type(int p_port) const { if (p_port == 0) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -270,17 +270,17 @@ int VisualShaderNodeParticleMeshEmitter::get_output_port_count() const { VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter::get_output_port_type(int p_port) const { switch (p_port) { case 0: - return PORT_TYPE_VECTOR; // position + return PORT_TYPE_VECTOR_3D; // position case 1: - return PORT_TYPE_VECTOR; // normal + return PORT_TYPE_VECTOR_3D; // normal case 2: - return PORT_TYPE_VECTOR; // color + return PORT_TYPE_VECTOR_3D; // color case 3: return PORT_TYPE_SCALAR; // alpha case 4: - return PORT_TYPE_VECTOR; // uv + return PORT_TYPE_VECTOR_3D; // uv case 5: - return PORT_TYPE_VECTOR; // uv2 + return PORT_TYPE_VECTOR_3D; // uv2 } return PORT_TYPE_SCALAR; } @@ -731,7 +731,7 @@ int VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_count() const { VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_type(int p_port) const { if (p_port == 0 || p_port == 1) { // position, rotation_axis - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; // angle (degrees/radians) } @@ -762,7 +762,7 @@ int VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_count() const { } VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_name(int p_port) const { @@ -815,7 +815,7 @@ int VisualShaderNodeParticleConeVelocity::get_input_port_count() const { VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_input_port_type(int p_port) const { if (p_port == 0) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } else if (p_port == 1) { return PORT_TYPE_SCALAR; } @@ -836,7 +836,7 @@ int VisualShaderNodeParticleConeVelocity::get_output_port_count() const { } VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) const { @@ -899,7 +899,7 @@ int VisualShaderNodeParticleRandomness::get_output_port_count() const { VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_output_port_type(int p_port) const { if (op_type == OP_TYPE_VECTOR) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -914,7 +914,7 @@ int VisualShaderNodeParticleRandomness::get_input_port_count() const { VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_input_port_type(int p_port) const { if (op_type == OP_TYPE_VECTOR) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -996,7 +996,7 @@ int VisualShaderNodeParticleAccelerator::get_output_port_count() const { } VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeParticleAccelerator::get_output_port_name(int p_port) const { @@ -1009,11 +1009,11 @@ int VisualShaderNodeParticleAccelerator::get_input_port_count() const { VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_input_port_type(int p_port) const { if (p_port == 0) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } else if (p_port == 1) { return PORT_TYPE_SCALAR; } else if (p_port == 2) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -1106,19 +1106,19 @@ VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_inp switch (p_port) { case 0: if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { - return PORT_TYPE_VECTOR; // custom.rgb + return PORT_TYPE_VECTOR_3D; // custom.rgb } return PORT_TYPE_BOOLEAN; // active case 1: if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { break; // custom.a (scalar) } - return PORT_TYPE_VECTOR; // velocity + return PORT_TYPE_VECTOR_3D; // velocity case 2: - return PORT_TYPE_VECTOR; // color & velocity + return PORT_TYPE_VECTOR_3D; // color & velocity case 3: if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { - return PORT_TYPE_VECTOR; // color + return PORT_TYPE_VECTOR_3D; // color } break; // alpha (scalar) case 4: @@ -1131,18 +1131,18 @@ VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_inp if (shader_type == VisualShader::TYPE_COLLIDE) { return PORT_TYPE_TRANSFORM; // transform } - return PORT_TYPE_VECTOR; // position + return PORT_TYPE_VECTOR_3D; // position case 5: if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { return PORT_TYPE_TRANSFORM; // transform } if (shader_type == VisualShader::TYPE_PROCESS) { - return PORT_TYPE_VECTOR; // rotation_axis + return PORT_TYPE_VECTOR_3D; // rotation_axis } break; // scale (scalar) case 6: if (shader_type == VisualShader::TYPE_START) { - return PORT_TYPE_VECTOR; // rotation_axis + return PORT_TYPE_VECTOR_3D; // rotation_axis } break; case 7: @@ -1372,13 +1372,13 @@ VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_input_p case 1: return PORT_TYPE_TRANSFORM; case 2: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 3: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 4: return PORT_TYPE_SCALAR; case 5: - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; case 6: return PORT_TYPE_SCALAR; } @@ -1448,22 +1448,22 @@ bool VisualShaderNodeParticleEmit::is_generate_input_var(int p_port) const { return true; } -String VisualShaderNodeParticleEmit::get_input_port_default_hint(int p_port) const { +bool VisualShaderNodeParticleEmit::is_input_port_default(int p_port, Shader::Mode p_mode) const { switch (p_port) { case 1: - return "default"; + return true; case 2: - return "default"; + return true; case 3: - return "default"; + return true; case 4: - return "default"; + return true; case 5: - return "default"; + return true; case 6: - return "default"; + return true; } - return String(); + return false; } String VisualShaderNodeParticleEmit::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_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index add6928841..ce0d896c01 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -342,7 +342,7 @@ public: virtual bool is_show_prop_names() const override; virtual bool is_generate_input_var(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; 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 override; VisualShaderNodeParticleEmit(); diff --git a/scene/resources/visual_shader_sdf_nodes.cpp b/scene/resources/visual_shader_sdf_nodes.cpp index 1b43fda4c5..559831c3c2 100644 --- a/scene/resources/visual_shader_sdf_nodes.cpp +++ b/scene/resources/visual_shader_sdf_nodes.cpp @@ -41,7 +41,7 @@ int VisualShaderNodeSDFToScreenUV::get_input_port_count() const { } VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeSDFToScreenUV::get_input_port_name(int p_port) const { @@ -53,7 +53,7 @@ int VisualShaderNodeSDFToScreenUV::get_output_port_count() const { } VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeSDFToScreenUV::get_output_port_name(int p_port) const { @@ -78,7 +78,7 @@ int VisualShaderNodeScreenUVToSDF::get_input_port_count() const { } VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeScreenUVToSDF::get_input_port_name(int p_port) const { @@ -90,18 +90,18 @@ int VisualShaderNodeScreenUVToSDF::get_output_port_count() const { } VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeScreenUVToSDF::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeScreenUVToSDF::get_input_port_default_hint(int p_port) const { +bool VisualShaderNodeScreenUVToSDF::is_input_port_default(int p_port, Shader::Mode p_mode) const { if (p_port == 0) { - return "default"; + return true; } - return ""; + return false; } String VisualShaderNodeScreenUVToSDF::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 { @@ -122,7 +122,7 @@ int VisualShaderNodeTextureSDF::get_input_port_count() const { } VisualShaderNodeTextureSDF::PortType VisualShaderNodeTextureSDF::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTextureSDF::get_input_port_name(int p_port) const { @@ -159,7 +159,7 @@ int VisualShaderNodeTextureSDFNormal::get_input_port_count() const { } VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTextureSDFNormal::get_input_port_name(int p_port) const { @@ -171,7 +171,7 @@ int VisualShaderNodeTextureSDFNormal::get_output_port_count() const { } VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } String VisualShaderNodeTextureSDFNormal::get_output_port_name(int p_port) const { @@ -197,7 +197,7 @@ int VisualShaderNodeSDFRaymarch::get_input_port_count() const { VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_input_port_type(int p_port) const { if (p_port == 0 || p_port == 1) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } @@ -221,7 +221,7 @@ VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_output_po } else if (p_port == 1) { return PORT_TYPE_BOOLEAN; } else if (p_port == 2) { - return PORT_TYPE_VECTOR; + return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } diff --git a/scene/resources/visual_shader_sdf_nodes.h b/scene/resources/visual_shader_sdf_nodes.h index d2d1dde4ea..7c1f695423 100644 --- a/scene/resources/visual_shader_sdf_nodes.h +++ b/scene/resources/visual_shader_sdf_nodes.h @@ -66,7 +66,7 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String get_input_port_default_hint(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; 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 override; VisualShaderNodeScreenUVToSDF(); diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index c937d988d2..9d8e0f7547 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -83,8 +83,8 @@ World2D::World2D() { // Create and configure the navigation_map to be more friendly with pixels than meters. navigation_map = NavigationServer2D::get_singleton()->map_create(); NavigationServer2D::get_singleton()->map_set_active(navigation_map, true); - NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10)); - NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5)); + NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1)); + NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1)); } World2D::~World2D() { |