Improve nine patch behavior of TextureProgressBar
This commit is contained in:
parent
d696bd17ed
commit
b08dc1ea35
2 changed files with 118 additions and 25 deletions
|
@ -221,43 +221,87 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu
|
||||||
double width_texture = 0.0;
|
double width_texture = 0.0;
|
||||||
double first_section_size = 0.0;
|
double first_section_size = 0.0;
|
||||||
double last_section_size = 0.0;
|
double last_section_size = 0.0;
|
||||||
switch (mode) {
|
switch (p_mode) {
|
||||||
case FILL_LEFT_TO_RIGHT:
|
case FILL_LEFT_TO_RIGHT: {
|
||||||
case FILL_RIGHT_TO_LEFT: {
|
|
||||||
width_total = dst_rect.size.x;
|
width_total = dst_rect.size.x;
|
||||||
width_texture = texture_size.x;
|
width_texture = texture_size.x;
|
||||||
first_section_size = topleft.x;
|
first_section_size = topleft.x;
|
||||||
last_section_size = bottomright.x;
|
last_section_size = bottomright.x;
|
||||||
} break;
|
} break;
|
||||||
case FILL_TOP_TO_BOTTOM:
|
case FILL_RIGHT_TO_LEFT: {
|
||||||
case FILL_BOTTOM_TO_TOP: {
|
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_total = dst_rect.size.y;
|
||||||
width_texture = texture_size.y;
|
width_texture = texture_size.y;
|
||||||
first_section_size = topleft.y;
|
first_section_size = topleft.y;
|
||||||
last_section_size = bottomright.y;
|
last_section_size = bottomright.y;
|
||||||
} break;
|
} 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: {
|
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;
|
} break;
|
||||||
case FILL_BILINEAR_TOP_AND_BOTTOM: {
|
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;
|
} break;
|
||||||
case FILL_CLOCKWISE:
|
case FILL_CLOCKWISE:
|
||||||
case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE:
|
case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE:
|
||||||
case FILL_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;
|
} break;
|
||||||
|
case FILL_MODE_MAX:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
double width_filled = width_total * p_ratio;
|
double width_filled = width_total * p_ratio;
|
||||||
double middle_section_size = MAX(0.0, width_texture - first_section_size - last_section_size);
|
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)));
|
// Maximum middle texture size.
|
||||||
last_section_size = MAX(0.0, last_section_size - (width_total - width_filled));
|
double max_middle_texture_size = middle_section_size;
|
||||||
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) {
|
// 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 (p_mode) {
|
||||||
case FILL_LEFT_TO_RIGHT: {
|
case FILL_LEFT_TO_RIGHT: {
|
||||||
src_rect.size.x = width_texture;
|
src_rect.size.x = width_texture;
|
||||||
dst_rect.size.x = width_filled;
|
dst_rect.size.x = width_filled;
|
||||||
|
@ -287,16 +331,32 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu
|
||||||
bottomright.y = first_section_size;
|
bottomright.y = first_section_size;
|
||||||
} break;
|
} break;
|
||||||
case FILL_BILINEAR_LEFT_AND_RIGHT: {
|
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;
|
} break;
|
||||||
case FILL_BILINEAR_TOP_AND_BOTTOM: {
|
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;
|
} break;
|
||||||
case FILL_CLOCKWISE:
|
case FILL_CLOCKWISE:
|
||||||
case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE:
|
case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE:
|
||||||
case FILL_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;
|
} break;
|
||||||
|
case FILL_MODE_MAX:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 };
|
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) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_DRAW: {
|
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()) {
|
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()) {
|
if (progress.is_valid()) {
|
||||||
draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress);
|
draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress);
|
||||||
}
|
}
|
||||||
if (over.is_valid()) {
|
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 {
|
} else {
|
||||||
if (under.is_valid()) {
|
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()) {
|
if (progress.is_valid()) {
|
||||||
Size2 s = progress->get_size();
|
Size2 s = progress->get_size();
|
||||||
|
@ -353,7 +428,7 @@ void TextureProgressBar::_notification(int p_what) {
|
||||||
float val = get_as_ratio() * rad_max_degrees / 360;
|
float val = get_as_ratio() * rad_max_degrees / 360;
|
||||||
if (val == 1) {
|
if (val == 1) {
|
||||||
Rect2 region = Rect2(Point2(), s);
|
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) {
|
} else if (val != 0) {
|
||||||
Array pts;
|
Array pts;
|
||||||
float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
|
float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
|
||||||
|
@ -416,12 +491,29 @@ 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()));
|
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);
|
draw_texture_rect_region(progress, region, region, tint_progress);
|
||||||
} break;
|
} break;
|
||||||
|
case FILL_MODE_MAX:
|
||||||
|
break;
|
||||||
default:
|
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(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()) {
|
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;
|
} break;
|
||||||
|
@ -429,7 +521,7 @@ void TextureProgressBar::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureProgressBar::set_fill_mode(int p_fill) {
|
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;
|
mode = (FillMode)p_fill;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -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_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_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::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_GROUP("Tint", "tint_");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under");
|
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");
|
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over"), "set_tint_over", "get_tint_over");
|
||||||
|
|
|
@ -54,7 +54,8 @@ public:
|
||||||
FILL_COUNTER_CLOCKWISE,
|
FILL_COUNTER_CLOCKWISE,
|
||||||
FILL_BILINEAR_LEFT_AND_RIGHT,
|
FILL_BILINEAR_LEFT_AND_RIGHT,
|
||||||
FILL_BILINEAR_TOP_AND_BOTTOM,
|
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);
|
void set_fill_mode(int p_fill);
|
||||||
|
|
Loading…
Add table
Reference in a new issue