refactor: Deduplicate Roundraff battery drawing (#1847)

## Summary

Deduplicated battery drawing code for Roundraff theme with other themes.

Now `BaseTheme` provides non-virtual `drawBatteryLeft` and
`drawBatteryRight` methods, which use a shared static
`drawBatteryOutline` implementation, and defer to a virtual
`fillBatteryIcon` implementation. In Classic and Roundraff
`fillBatteryIcon` uses a solid fill, while Lyra and Lyra Extended use a
segmented fill.

The charging indicator inside the battery was missing for Roundraff, but
is now consistent with other themes because of the shared drawing
implementation.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**PARTIALLY**_
This commit is contained in:
Zach Nelson
2026-05-07 16:57:33 -05:00
committed by GitHub
parent 83f0cee565
commit e841c84194
5 changed files with 72 additions and 155 deletions
+16 -51
View File
@@ -41,30 +41,6 @@ constexpr int listIconSize = 24;
constexpr int mainMenuColumns = 2;
int coverWidth = 0;
void drawLyraBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight,
uint16_t percentage) {
BaseTheme::drawBatteryOutline(renderer, x, y, battWidth, rectHeight);
const bool charging = gpio.isUsbConnected();
if (charging) {
// Draw solid fill when charging so lightning bolt is visible
renderer.fillRect(x + 2, y + 2, battWidth - 5, rectHeight - 4);
BaseTheme::drawBatteryLightningBolt(renderer, x + 4, y + 2);
} else {
// Draw bars when not charging
if (percentage > 10) {
renderer.fillRect(x + 2, y + 2, 3, rectHeight - 4);
}
if (percentage > 40) {
renderer.fillRect(x + 6, y + 2, 3, rectHeight - 4);
}
if (percentage > 70) {
renderer.fillRect(x + 10, y + 2, 3, rectHeight - 4);
}
}
}
const uint8_t* iconForName(UIIcon icon, int size) {
if (size == 24) {
switch (icon) {
@@ -107,35 +83,24 @@ const uint8_t* iconForName(UIIcon icon, int size) {
}
} // namespace
void LyraTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const {
// Left aligned: icon on left, percentage on right (reader mode)
const uint16_t percentage = powerManager.getBatteryPercentage();
void LyraTheme::fillBatteryIcon(const GfxRenderer& renderer, Rect rect, uint16_t percentage) const {
const bool charging = gpio.isUsbConnected();
if (showPercentage) {
const auto percentageText = std::to_string(percentage) + "%";
renderer.drawText(SMALL_FONT_ID, rect.x + BaseTheme::batteryPercentSpacing + LyraMetrics::values.batteryWidth,
rect.y, percentageText.c_str());
if (charging) {
// Solid fill when charging so lightning bolt is visible
renderer.fillRect(rect.x + 2, rect.y + 2, rect.width - 5, rect.height - 4);
drawBatteryLightningBolt(renderer, rect.x + 4, rect.y + 2);
} else {
if (percentage > 10) {
renderer.fillRect(rect.x + 2, rect.y + 2, 3, rect.height - 4);
}
if (percentage > 40) {
renderer.fillRect(rect.x + 6, rect.y + 2, 3, rect.height - 4);
}
if (percentage > 70) {
renderer.fillRect(rect.x + 10, rect.y + 2, 3, rect.height - 4);
}
}
drawLyraBatteryIcon(renderer, rect.x, rect.y + 6, LyraMetrics::values.batteryWidth, rect.height, percentage);
}
void LyraTheme::drawBatteryRight(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const {
// Right aligned: percentage on left, icon on right (UI headers)
const uint16_t percentage = powerManager.getBatteryPercentage();
if (showPercentage) {
const auto percentageText = std::to_string(percentage) + "%";
const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str());
// Clear the area where we're going to draw the text to prevent ghosting
const auto textHeight = renderer.getTextHeight(SMALL_FONT_ID);
renderer.fillRect(rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y, textWidth, textHeight, false);
// Draw text to the left of the icon
renderer.drawText(SMALL_FONT_ID, rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y,
percentageText.c_str());
}
drawLyraBatteryIcon(renderer, rect.x, rect.y + 6, LyraMetrics::values.batteryWidth, rect.height, percentage);
}
void LyraTheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* title, const char* subtitle) const {