Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve nine patch behavior of TextureProgressBar #45815

Merged
merged 1 commit into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 116 additions & 24 deletions scene/gui/texture_progress_bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,43 +221,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);

// 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 (mode) {
switch (p_mode) {
case FILL_LEFT_TO_RIGHT: {
src_rect.size.x = width_texture;
dst_rect.size.x = width_filled;
Expand Down Expand Up @@ -287,16 +331,32 @@ 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;
}
}

Expand All @@ -310,19 +370,34 @@ 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();
Expand Down Expand Up @@ -353,7 +428,7 @@ 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);
draw_texture_rect(progress, region, false, tint_progress);
} else if (val != 0) {
Array pts;
float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
Expand Down Expand Up @@ -416,20 +491,37 @@ void TextureProgressBar::_notification(int p_what) {
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);
} 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);
}
}
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;
}
}

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();
}
Expand Down Expand Up @@ -512,7 +604,7 @@ 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::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");
Expand Down
3 changes: 2 additions & 1 deletion scene/gui/texture_progress_bar.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class TextureProgressBar : public Range {
FILL_COUNTER_CLOCKWISE,
FILL_BILINEAR_LEFT_AND_RIGHT,
FILL_BILINEAR_TOP_AND_BOTTOM,
FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE
FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE,
FILL_MODE_MAX,
};

void set_fill_mode(int p_fill);
Expand Down