Public Access
Progress bars can show the percentage on top
The percentage (rounded down, in the element's font) is centred inside the bar and its dots invert the bar, so it reads on the filled and the empty part. It uses the bar's unused format and font fields, so the page format stays the same. The Bad page shows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9959c1aa74
commit
948087077d
9 files changed
+187
-9
No files matched your search
@@ -2443,6 +2443,109 @@ void test_bar_render()
|
||||
TEST_ASSERT_TRUE(bitmapPixel(b, 61, 17));
|
||||
}
|
||||
|
||||
void test_bar_percent_text()
|
||||
{
|
||||
PageElement e = barPage().elements[0];
|
||||
char t[8];
|
||||
barPercent(e, nullptr, t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("--", t);
|
||||
barPercent(e, "unavailable", t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("--", t);
|
||||
barPercent(e, "-5", t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("0%", t);
|
||||
barPercent(e, "42.9", t, sizeof(t)); // rounded down
|
||||
TEST_ASSERT_EQUAL_STRING("42%", t);
|
||||
barPercent(e, "29", t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("29%", t);
|
||||
barPercent(e, "99.99", t, sizeof(t)); // 100% only when full
|
||||
TEST_ASSERT_EQUAL_STRING("99%", t);
|
||||
barPercent(e, "250", t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("100%", t);
|
||||
e.bar_max = 7200;
|
||||
barPercent(e, "1800", t, sizeof(t));
|
||||
TEST_ASSERT_EQUAL_STRING("25%", t);
|
||||
}
|
||||
|
||||
// The dots that differ between two bitmaps
|
||||
static int countDiff(const uint8_t *a, const uint8_t *b, int &left, int &top, int &right, int &bottom)
|
||||
{
|
||||
int n = 0;
|
||||
left = top = 99;
|
||||
right = bottom = -1;
|
||||
for (int y = 0; y < BITMAP_HEIGHT; y++)
|
||||
for (int x = 0; x < BITMAP_WIDTH; x++)
|
||||
if (bitmapPixel(a, x, y) != bitmapPixel(b, x, y))
|
||||
{
|
||||
n++;
|
||||
left = x < left ? x : left;
|
||||
right = x > right ? x : right;
|
||||
top = y < top ? y : top;
|
||||
bottom = y > bottom ? y : bottom;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void test_bar_percent_render()
|
||||
{
|
||||
FakeResources res;
|
||||
DynamicPage page = barPage();
|
||||
PageElement &e = page.elements[0];
|
||||
e.x = 10;
|
||||
e.y = 5;
|
||||
e.bar_width = 30; // 28 x 7 inside the frame
|
||||
e.bar_height = 9;
|
||||
strcpy(e.font, "Small");
|
||||
TEST_ASSERT_NULL(validatePage(page));
|
||||
uint8_t plain[BITMAP_BYTES], with[BITMAP_BYTES], text[BITMAP_BYTES];
|
||||
res.value = "50";
|
||||
renderPage(page, at(12, 0), 0, res, plain);
|
||||
e.format = BAR_PERCENT;
|
||||
TEST_ASSERT_NULL(validatePage(page));
|
||||
ElementBox box;
|
||||
renderPage(page, at(12, 0), 0, res, with, &box);
|
||||
TEST_ASSERT_EQUAL(30, box.width); // the box stays the bar
|
||||
|
||||
// Every dot of the text flips the bar: as many changes as the text has dots, all inside
|
||||
memset(text, 0, BITMAP_BYTES);
|
||||
drawText(text, builtinFont(*findBuiltinFont("Small")), 0, 0, "50%", DrawMode::Set);
|
||||
int left, top, right, bottom;
|
||||
TEST_ASSERT_EQUAL(countOn(text), countDiff(plain, with, left, top, right, bottom));
|
||||
TEST_ASSERT_TRUE(left >= 11 && right <= 38 && top >= 6 && bottom <= 12);
|
||||
// Centred: 5 dots high in 7 rows, one row free above and below
|
||||
TEST_ASSERT_EQUAL(7, top);
|
||||
TEST_ASSERT_EQUAL(11, bottom);
|
||||
int free_left = left - 11, free_right = 38 - right;
|
||||
TEST_ASSERT_TRUE(free_left - free_right <= 1 && free_right - free_left <= 1);
|
||||
// Columns 11-24 are filled: the text is dark there and lit over the empty part
|
||||
int dark = 0, lit = 0;
|
||||
for (int y = top; y <= bottom; y++)
|
||||
for (int x = left; x <= right; x++)
|
||||
if (bitmapPixel(plain, x, y) != bitmapPixel(with, x, y))
|
||||
{
|
||||
TEST_ASSERT_EQUAL(x > 24, bitmapPixel(with, x, y));
|
||||
(x > 24 ? lit : dark)++;
|
||||
}
|
||||
TEST_ASSERT_TRUE(dark > 0 && lit > 0);
|
||||
|
||||
// Unknown: "--" on the empty bar
|
||||
res.value = nullptr;
|
||||
renderPage(page, at(12, 0), 0, res, with);
|
||||
TEST_ASSERT_TRUE(countOn(with) > 2 * 30 + 2 * 7);
|
||||
|
||||
// Doesn't fit (Small digits are 5 dots high, 4 rows inside): only the bar
|
||||
res.value = "50";
|
||||
e.bar_height = 6;
|
||||
e.format = BAR_PLAIN;
|
||||
renderPage(page, at(12, 0), 0, res, plain);
|
||||
e.format = BAR_PERCENT;
|
||||
renderPage(page, at(12, 0), 0, res, with);
|
||||
TEST_ASSERT_EQUAL(0, countDiff(plain, with, left, top, right, bottom));
|
||||
|
||||
// Format 2 doesn't exist
|
||||
e.format = BAR_FORMAT_COUNT;
|
||||
TEST_ASSERT_NOT_NULL(validatePage(page));
|
||||
}
|
||||
|
||||
void test_date_days_ahead()
|
||||
{
|
||||
LocalTime t; // Thursday 31 December 2026
|
||||
@@ -2703,6 +2806,8 @@ int main()
|
||||
RUN_TEST(test_frame_check_periodic_resync);
|
||||
RUN_TEST(test_bar_fill);
|
||||
RUN_TEST(test_bar_render);
|
||||
RUN_TEST(test_bar_percent_text);
|
||||
RUN_TEST(test_bar_percent_render);
|
||||
RUN_TEST(test_bar_validation);
|
||||
RUN_TEST(test_date_days_ahead);
|
||||
RUN_TEST(test_attribute_paths_and_16_elements);
|
||||
|
||||
Reference in new issue
Block a user