diff options
Diffstat (limited to 'scene/gui/texture_progress_bar.cpp')
-rw-r--r-- | scene/gui/texture_progress_bar.cpp | 195 |
1 files changed, 155 insertions, 40 deletions
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 46ce9d5ca9..286f01ee33 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -100,6 +100,15 @@ Ref<Texture2D> TextureProgressBar::get_progress_texture() const { return progress; } +void TextureProgressBar::set_progress_offset(Point2 p_offset) { + progress_offset = p_offset; + update(); +} + +Point2 TextureProgressBar::get_progress_offset() const { + return progress_offset; +} + void TextureProgressBar::set_tint_under(const Color &p_tint) { tint_under = p_tint; update(); @@ -221,43 +230,87 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu double width_texture = 0.0; double first_section_size = 0.0; double last_section_size = 0.0; - switch (mode) { - case FILL_LEFT_TO_RIGHT: - case FILL_RIGHT_TO_LEFT: { + switch (p_mode) { + case FILL_LEFT_TO_RIGHT: { width_total = dst_rect.size.x; width_texture = texture_size.x; first_section_size = topleft.x; last_section_size = bottomright.x; } break; - case FILL_TOP_TO_BOTTOM: - case FILL_BOTTOM_TO_TOP: { + case FILL_RIGHT_TO_LEFT: { + width_total = dst_rect.size.x; + width_texture = texture_size.x; + // In contrast to `FILL_LEFT_TO_RIGHT`, `first_section_size` and `last_section_size` should switch value. + first_section_size = bottomright.x; + last_section_size = topleft.x; + } break; + case FILL_TOP_TO_BOTTOM: { width_total = dst_rect.size.y; width_texture = texture_size.y; first_section_size = topleft.y; last_section_size = bottomright.y; } break; + case FILL_BOTTOM_TO_TOP: { + width_total = dst_rect.size.y; + width_texture = texture_size.y; + // Similar to `FILL_RIGHT_TO_LEFT`. + first_section_size = bottomright.y; + last_section_size = topleft.y; + } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - // TODO: Implement + width_total = dst_rect.size.x; + width_texture = texture_size.x; + first_section_size = topleft.x; + last_section_size = bottomright.x; } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - // TODO: Implement + width_total = dst_rect.size.y; + width_texture = texture_size.y; + first_section_size = topleft.y; + last_section_size = bottomright.y; } break; case FILL_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: { - // Those modes are circular, not relevant for nine patch + // Those modes are circular, not relevant for nine patch. } break; + case FILL_MODE_MAX: + break; } double width_filled = width_total * p_ratio; double middle_section_size = MAX(0.0, width_texture - first_section_size - last_section_size); - middle_section_size *= MIN(1.0, (MAX(0.0, width_filled - first_section_size) / MAX(1.0, width_total - first_section_size - last_section_size))); - last_section_size = MAX(0.0, last_section_size - (width_total - width_filled)); - first_section_size = MIN(first_section_size, width_filled); - width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + // Maximum middle texture size. + double max_middle_texture_size = middle_section_size; + + // Maximum real middle texture size. + double max_middle_real_size = MAX(0.0, width_total - (first_section_size + last_section_size)); + + switch (p_mode) { + case FILL_BILINEAR_LEFT_AND_RIGHT: + case FILL_BILINEAR_TOP_AND_BOTTOM: { + last_section_size = MAX(0.0, last_section_size - (width_total - width_filled) * 0.5); + first_section_size = MAX(0.0, first_section_size - (width_total - width_filled) * 0.5); - switch (mode) { + // When `width_filled` increases, `middle_section_size` only increases when either of `first_section_size` and `last_section_size` is zero. + // Also, it should always be smaller than or equal to `(width_total - (first_section_size + last_section_size))`. + double real_middle_size = width_filled - first_section_size - last_section_size; + middle_section_size *= MIN(max_middle_real_size, real_middle_size) / max_middle_real_size; + + width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + } break; + case FILL_MODE_MAX: + break; + default: { + middle_section_size *= MIN(1.0, (MAX(0.0, width_filled - first_section_size) / MAX(1.0, width_total - first_section_size - last_section_size))); + last_section_size = MAX(0.0, last_section_size - (width_total - width_filled)); + first_section_size = MIN(first_section_size, width_filled); + width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + } + } + + switch (p_mode) { case FILL_LEFT_TO_RIGHT: { src_rect.size.x = width_texture; dst_rect.size.x = width_filled; @@ -287,19 +340,38 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu bottomright.y = first_section_size; } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - // TODO: Implement + double center_mapped_from_real_width = (width_total * 0.5 - topleft.x) / max_middle_real_size * max_middle_texture_size + topleft.x; + double drift_from_unscaled_center = (src_rect.size.x * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.x - topleft.x); + src_rect.position.x += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; + src_rect.size.x = width_texture; + dst_rect.position.x += (width_total - width_filled) * 0.5; + dst_rect.size.x = width_filled; + topleft.x = first_section_size; + bottomright.x = last_section_size; } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - // TODO: Implement + double center_mapped_from_real_width = (width_total * 0.5 - topleft.y) / max_middle_real_size * max_middle_texture_size + topleft.y; + double drift_from_unscaled_center = (src_rect.size.y * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.y - topleft.y); + src_rect.position.y += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; + src_rect.size.y = width_texture; + dst_rect.position.y += (width_total - width_filled) * 0.5; + dst_rect.size.y = width_filled; + topleft.y = first_section_size; + bottomright.y = last_section_size; } break; case FILL_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: { - // Those modes are circular, not relevant for nine patch + // Those modes are circular, not relevant for nine patch. } break; + case FILL_MODE_MAX: + break; } } + if (p_texture == progress) { + dst_rect.position += progress_offset; + } p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect); RID ci = get_canvas_item(); @@ -310,38 +382,57 @@ void TextureProgressBar::_notification(int p_what) { const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 }; switch (p_what) { case NOTIFICATION_DRAW: { - if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP)) { + if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP || mode == FILL_BILINEAR_LEFT_AND_RIGHT || mode == FILL_BILINEAR_TOP_AND_BOTTOM)) { if (under.is_valid()) { - draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0, tint_under); + draw_nine_patch_stretched(under, mode, 1.0, tint_under); } if (progress.is_valid()) { draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress); } if (over.is_valid()) { - draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0, tint_over); + draw_nine_patch_stretched(over, mode, 1.0, tint_over); } } else { if (under.is_valid()) { - draw_texture(under, Point2(), tint_under); + switch (mode) { + case FILL_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { + if (nine_patch_stretch) { + Rect2 region = Rect2(Point2(), get_size()); + draw_texture_rect(under, region, false, tint_under); + } else { + draw_texture(under, Point2(), tint_under); + } + } break; + case FILL_MODE_MAX: + break; + default: + draw_texture(under, Point2(), tint_under); + } } if (progress.is_valid()) { Size2 s = progress->get_size(); switch (mode) { case FILL_LEFT_TO_RIGHT: { - Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_RIGHT_TO_LEFT: { - Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_TOP_TO_BOTTOM: { - Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_BOTTOM_TO_TOP: { - Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: @@ -352,8 +443,9 @@ void TextureProgressBar::_notification(int p_what) { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { - Rect2 region = Rect2(Point2(), s); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset, s); + Rect2 source = Rect2(Point2(), s); + draw_texture_rect_region(progress, region, source, tint_progress); } else if (val != 0) { Array pts; float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; @@ -379,14 +471,14 @@ void TextureProgressBar::_notification(int p_what) { Vector<Point2> uvs; Vector<Point2> points; uvs.push_back(get_relative_center()); - points.push_back(Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); + points.push_back(progress_offset + Point2(s.x * get_relative_center().x, s.y * get_relative_center().y)); for (int i = 0; i < pts.size(); i++) { Point2 uv = unit_val_to_uv(pts[i]); if (uvs.find(uv) >= 0) { continue; } uvs.push_back(uv); - points.push_back(Point2(uv.x * s.x, uv.y * s.y)); + points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y)); } Vector<Color> colors; colors.push_back(tint_progress); @@ -409,19 +501,38 @@ void TextureProgressBar::_notification(int p_what) { } } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); + Rect2 source = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, source, tint_progress); } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); - draw_texture_rect_region(progress, region, region, tint_progress); + Rect2 region = Rect2(progress_offset + Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); + Rect2 source = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, source, tint_progress); } break; + case FILL_MODE_MAX: + break; default: - draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); + draw_texture_rect_region(progress, Rect2(progress_offset, Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } } if (over.is_valid()) { - draw_texture(over, Point2(), tint_over); + switch (mode) { + case FILL_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { + if (nine_patch_stretch) { + Rect2 region = Rect2(Point2(), get_size()); + draw_texture_rect(over, region, false, tint_over); + } else { + draw_texture(over, Point2(), tint_over); + } + } break; + case FILL_MODE_MAX: + break; + default: + draw_texture(over, Point2(), tint_over); + } } } } break; @@ -429,7 +540,7 @@ void TextureProgressBar::_notification(int p_what) { } void TextureProgressBar::set_fill_mode(int p_fill) { - ERR_FAIL_INDEX(p_fill, 9); + ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX); mode = (FillMode)p_fill; update(); } @@ -493,6 +604,9 @@ void TextureProgressBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgressBar::set_tint_over); ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgressBar::get_tint_over); + ClassDB::bind_method(D_METHOD("set_texture_progress_offset", "offset"), &TextureProgressBar::set_progress_offset); + ClassDB::bind_method(D_METHOD("get_texture_progress_offset"), &TextureProgressBar::get_progress_offset); + ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgressBar::set_radial_initial_angle); ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgressBar::get_radial_initial_angle); @@ -512,7 +626,8 @@ void TextureProgressBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_over_texture", "get_over_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_progress_texture", "get_progress_texture"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_progress_offset"), "set_texture_progress_offset", "get_texture_progress_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); ADD_GROUP("Tint", "tint_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over"), "set_tint_over", "get_tint_over"); |