refactor: Consolidate theme rendering into ThemeMetrics (#1868)

This commit is contained in:
Uri Tauber
2026-05-19 22:50:26 +03:00
committed by GitHub
parent 86a9510957
commit b69111bea5
5 changed files with 176 additions and 75 deletions
+79 -30
View File
@@ -668,34 +668,57 @@ void BaseTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount
}
Rect BaseTheme::drawPopup(const GfxRenderer& renderer, const char* message) const {
constexpr int margin = 15;
// Scale y position proportionally to screen height (7.5% from top)
const int y = static_cast<int>(renderer.getScreenHeight() * 0.075f);
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, message, EpdFontFamily::BOLD);
const auto& metrics = UITheme::getInstance().getMetrics();
const int marginX = metrics.popupMarginX;
const int marginY = metrics.popupMarginY;
const int frameThickness = metrics.popupFrameThickness;
const EpdFontFamily::Style popupFontFamily = metrics.popupTextBold ? EpdFontFamily::BOLD : EpdFontFamily::REGULAR;
// Scale y position proportionally to screen height
const int y = static_cast<int>(renderer.getScreenHeight() * metrics.popupTopOffsetRatio);
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, message, popupFontFamily);
const int textHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int w = textWidth + margin * 2;
const int h = textHeight + margin * 2;
const int w = textWidth + marginX * 2;
const int h = textHeight + marginY * 2;
const int x = (renderer.getScreenWidth() - w) / 2;
renderer.fillRect(x - 2, y - 2, w + 4, h + 4, true); // frame thickness 2
renderer.fillRect(x, y, w, h, false);
const bool useRoundedPopup = metrics.popupCornerRadius > 0;
if (useRoundedPopup) {
renderer.fillRoundedRect(x - frameThickness, y - frameThickness, w + frameThickness * 2, h + frameThickness * 2,
metrics.popupCornerRadius + frameThickness, Color::White);
renderer.fillRoundedRect(x, y, w, h, metrics.popupCornerRadius, Color::Black);
} else {
renderer.fillRect(x - frameThickness, y - frameThickness, w + frameThickness * 2, h + frameThickness * 2, true);
renderer.fillRect(x, y, w, h, false);
}
const int textX = x + (w - textWidth) / 2;
const int textY = y + margin - 2;
renderer.drawText(UI_12_FONT_ID, textX, textY, message, true, EpdFontFamily::BOLD);
const int textY = y + marginY + metrics.popupTextBaselineOffsetY;
renderer.drawText(UI_12_FONT_ID, textX, textY, message, metrics.popupTextInverted, popupFontFamily);
renderer.displayBuffer();
return Rect{x, y, w, h};
}
void BaseTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const {
constexpr int barHeight = 4;
const int barWidth = layout.width - 30; // twice the margin in drawPopup to match text width
const auto& metrics = UITheme::getInstance().getMetrics();
const int barHeight = metrics.popupProgressBarHeight;
const int barWidth =
std::max(0, layout.width - metrics.popupMarginX * 2); // twice the margin in drawPopup to match text width
const int barX = layout.x + (layout.width - barWidth) / 2;
const int barY = layout.y + layout.height - 10;
const int barY = layout.y + layout.height - metrics.popupMarginY / 2 - barHeight / 2 - 1;
if (barWidth <= 0 || barHeight <= 0) {
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
return;
}
int fillWidth = barWidth * progress / 100;
const int scaledProgress = metrics.popupProgressClampPercent ? std::clamp(progress, 0, 100) : progress;
const int fillWidth = barWidth * scaledProgress / 100;
renderer.fillRect(barX, barY, fillWidth, barHeight, true);
if (metrics.popupProgressDrawOutline) {
renderer.drawRect(barX, barY, barWidth, barHeight, 1, metrics.popupProgressOutlineInverted);
}
if (fillWidth > 0) {
renderer.fillRect(barX, barY, fillWidth, barHeight, metrics.popupProgressFillInverted);
}
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
}
@@ -821,14 +844,14 @@ void BaseTheme::drawTextField(const GfxRenderer& renderer, Rect rect, const int
const auto& metrics = UITheme::getInstance().getMetrics();
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int lineY = rect.y + rect.height + lineHeight + metrics.verticalSpacing;
const int thickness = cursorMode ? 3 : 1;
const int thickness = cursorMode ? metrics.textFieldCursorThickness : metrics.textFieldNormalThickness;
if (contentWidth > 0) {
renderer.drawLine(rect.x + contentStartX, lineY, rect.x + contentStartX + contentWidth, lineY, thickness, true);
renderer.drawLine(rect.x + contentStartX, lineY,
rect.x + contentStartX + contentWidth + metrics.textFieldLineEndOffset, lineY, thickness, true);
} else {
const int hPadding = 6;
const int lineW = textWidth + hPadding * 2;
renderer.drawLine(rect.x + (rect.width - lineW) / 2, lineY, rect.x + (rect.width + lineW) / 2, lineY, thickness,
true);
const int lineW = textWidth + metrics.textFieldHorizontalPadding * 2;
const int lineStart = rect.x + (rect.width - lineW) / 2;
renderer.drawLine(lineStart, lineY, lineStart + lineW + metrics.textFieldLineEndOffset, lineY, thickness, true);
}
}
@@ -837,6 +860,9 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
const bool inactiveSelection) const {
const auto& metrics = UITheme::getInstance().getMetrics();
const int cr = metrics.keyboardKeyCornerRadius;
const bool isSpecialKey = keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode ||
keyType == KeyboardKeyType::Del || keyType == KeyboardKeyType::Space ||
keyType == KeyboardKeyType::Ok || keyType == KeyboardKeyType::Disabled;
if (isSelected) {
if (inactiveSelection) {
@@ -858,13 +884,31 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
renderer.fillRect(rect.x, rect.y, rect.width, rect.height, true);
}
}
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok ||
keyType == KeyboardKeyType::Disabled) {
if (cr > 0) {
renderer.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 1, cr, true);
} else {
renderer.drawRect(rect.x, rect.y, rect.width, rect.height);
} else {
if (metrics.keyboardFillUnselected) {
if (keyType == KeyboardKeyType::Disabled) {
if (cr > 0) {
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cr, Color::LightGray);
} else {
renderer.fillRectDither(rect.x, rect.y, rect.width, rect.height, Color::LightGray);
}
} else {
if (cr > 0) {
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cr, Color::White);
} else {
renderer.fillRect(rect.x, rect.y, rect.width, rect.height, false);
}
}
}
const bool shouldDrawOutline =
(metrics.keyboardDrawSpecialOutlineWhenUnselected && isSpecialKey) || metrics.keyboardOutlineAllUnselected;
if (shouldDrawOutline) {
if (cr > 0) {
renderer.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 1, cr, true);
} else {
renderer.drawRect(rect.x, rect.y, rect.width, rect.height);
}
}
}
@@ -882,7 +926,7 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
const int centerX = rect.x + rect.width / 2;
const int centerY = rect.y + rect.height / 2;
const int arrowLen = rect.width / 4;
const int arrowHead = arrowLen / 2;
const int arrowHead = std::max(metrics.keyboardMinArrowHeadSize, arrowLen / 2);
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX + arrowLen / 2, centerY, 3, !invert);
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX - arrowLen / 2 + arrowHead, centerY - arrowHead, 3,
!invert);
@@ -891,6 +935,10 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
return;
}
if (label == nullptr || label[0] == '\0') {
return;
}
const bool hasSecondary = secondaryLabel != nullptr && secondaryLabel[0] != '\0';
const int itemWidth = renderer.getTextWidth(UI_12_FONT_ID, label);
const int textX = rect.x + (rect.width - itemWidth) / 2;
@@ -900,6 +948,7 @@ void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const ch
if (hasSecondary) {
const int secWidth = renderer.getTextWidth(SMALL_FONT_ID, secondaryLabel);
renderer.drawText(SMALL_FONT_ID, rect.x + rect.width - secWidth - 1, rect.y, secondaryLabel, !invert);
renderer.drawText(SMALL_FONT_ID, rect.x + rect.width - secWidth - metrics.keyboardSecondaryLabelRightPadding,
rect.y + metrics.keyboardSecondaryLabelTopPadding, secondaryLabel, !invert);
}
}
+49 -1
View File
@@ -70,6 +70,31 @@ struct ThemeMetrics {
int keyboardTextFieldWidthPercent;
int keyboardWidthPercent;
int keyboardKeyCornerRadius;
bool keyboardFillUnselected;
bool keyboardOutlineAllUnselected;
bool keyboardDrawSpecialOutlineWhenUnselected;
int keyboardSecondaryLabelRightPadding;
int keyboardSecondaryLabelTopPadding;
int keyboardMinArrowHeadSize;
float popupTopOffsetRatio;
int popupMarginX;
int popupMarginY;
int popupFrameThickness;
int popupCornerRadius;
bool popupTextBold;
bool popupTextInverted;
int popupTextBaselineOffsetY;
int popupProgressBarHeight;
bool popupProgressDrawOutline;
bool popupProgressClampPercent;
bool popupProgressFillInverted;
bool popupProgressOutlineInverted;
int textFieldHorizontalPadding;
int textFieldNormalThickness;
int textFieldCursorThickness;
int textFieldLineEndOffset;
};
enum UIIcon { Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot };
@@ -117,7 +142,30 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
.keyboardVerticalOffset = -13,
.keyboardTextFieldWidthPercent = 85,
.keyboardWidthPercent = 90,
.keyboardKeyCornerRadius = 0};
.keyboardKeyCornerRadius = 0,
.keyboardFillUnselected = false,
.keyboardOutlineAllUnselected = false,
.keyboardDrawSpecialOutlineWhenUnselected = true,
.keyboardSecondaryLabelRightPadding = 1,
.keyboardSecondaryLabelTopPadding = 0,
.keyboardMinArrowHeadSize = 0,
.popupTopOffsetRatio = 0.075f,
.popupMarginX = 15,
.popupMarginY = 15,
.popupFrameThickness = 2,
.popupCornerRadius = 0,
.popupTextBold = true,
.popupTextInverted = true,
.popupTextBaselineOffsetY = -2,
.popupProgressBarHeight = 4,
.popupProgressDrawOutline = false,
.popupProgressClampPercent = false,
.popupProgressFillInverted = true,
.popupProgressOutlineInverted = true,
.textFieldHorizontalPadding = 6,
.textFieldNormalThickness = 1,
.textFieldCursorThickness = 3,
.textFieldLineEndOffset = 0};
}
class BaseTheme {
-40
View File
@@ -33,8 +33,6 @@ namespace {
constexpr int hPaddingInSelection = 8;
constexpr int cornerRadius = 6;
constexpr int topHintButtonY = 345;
constexpr int popupMarginX = 16;
constexpr int popupMarginY = 12;
constexpr int maxListValueWidth = 200;
constexpr int mainMenuIconSize = 32;
constexpr int listIconSize = 24;
@@ -536,41 +534,3 @@ void LyraTheme::drawButtonMenu(GfxRenderer& renderer, Rect rect, int buttonCount
renderer.drawText(UI_12_FONT_ID, textX, textY, label, true);
}
}
Rect LyraTheme::drawPopup(const GfxRenderer& renderer, const char* message) const {
// Scale y position proportionally to screen height (16.5% from top)
const int y = static_cast<int>(renderer.getScreenHeight() * 0.165f);
constexpr int outline = 2;
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, message, EpdFontFamily::REGULAR);
const int textHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int w = textWidth + popupMarginX * 2;
const int h = textHeight + popupMarginY * 2;
const int x = (renderer.getScreenWidth() - w) / 2;
renderer.fillRoundedRect(x - outline, y - outline, w + outline * 2, h + outline * 2, cornerRadius + outline,
Color::White);
renderer.fillRoundedRect(x, y, w, h, cornerRadius, Color::Black);
const int textX = x + (w - textWidth) / 2;
const int textY = y + popupMarginY - 2;
renderer.drawText(UI_12_FONT_ID, textX, textY, message, false, EpdFontFamily::REGULAR);
renderer.displayBuffer();
return Rect{x, y, w, h};
}
void LyraTheme::fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const {
constexpr int barHeight = 4;
// Twice the margin in drawPopup to match text width
const int barWidth = layout.width - popupMarginX * 2;
const int barX = layout.x + (layout.width - barWidth) / 2;
// Center inside the margin of drawPopup. The - 1 is added to account for the - 2 in drawPopup.
const int barY = layout.y + layout.height - popupMarginY / 2 - barHeight / 2 - 1;
int fillWidth = barWidth * progress / 100;
renderer.fillRect(barX, barY, fillWidth, barHeight, false);
renderer.displayBuffer(HalDisplay::FAST_REFRESH);
}
+24 -3
View File
@@ -43,7 +43,30 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
.keyboardVerticalOffset = -7,
.keyboardTextFieldWidthPercent = 85,
.keyboardWidthPercent = 90,
.keyboardKeyCornerRadius = 6};
.keyboardKeyCornerRadius = 6,
.keyboardFillUnselected = false,
.keyboardOutlineAllUnselected = false,
.keyboardDrawSpecialOutlineWhenUnselected = true,
.keyboardSecondaryLabelRightPadding = 1,
.keyboardSecondaryLabelTopPadding = 0,
.keyboardMinArrowHeadSize = 0,
.popupTopOffsetRatio = 0.165f,
.popupMarginX = 16,
.popupMarginY = 12,
.popupFrameThickness = 2,
.popupCornerRadius = 6,
.popupTextBold = false,
.popupTextInverted = false,
.popupTextBaselineOffsetY = -2,
.popupProgressBarHeight = 4,
.popupProgressDrawOutline = false,
.popupProgressClampPercent = false,
.popupProgressFillInverted = false,
.popupProgressOutlineInverted = false,
.textFieldHorizontalPadding = 6,
.textFieldNormalThickness = 1,
.textFieldCursorThickness = 3,
.textFieldLineEndOffset = 0};
}
class LyraTheme : public BaseTheme {
@@ -70,7 +93,5 @@ class LyraTheme : public BaseTheme {
const int selectorIndex, bool& coverRendered, bool& coverBufferStored, bool& bufferRestored,
std::function<bool()> storeCoverBuffer) const override;
void drawEmptyRecents(const GfxRenderer& renderer, const Rect rect) const;
Rect drawPopup(const GfxRenderer& renderer, const char* message) const override;
void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const override;
bool showsFileIcons() const override { return true; }
};
@@ -43,7 +43,30 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
.keyboardVerticalOffset = 0,
.keyboardTextFieldWidthPercent = 85,
.keyboardWidthPercent = 90,
.keyboardKeyCornerRadius = 0};
.keyboardKeyCornerRadius = 10,
.keyboardFillUnselected = true,
.keyboardOutlineAllUnselected = true,
.keyboardDrawSpecialOutlineWhenUnselected = true,
.keyboardSecondaryLabelRightPadding = 3,
.keyboardSecondaryLabelTopPadding = 1,
.keyboardMinArrowHeadSize = 1,
.popupTopOffsetRatio = 0.12f,
.popupMarginX = 20,
.popupMarginY = 14,
.popupFrameThickness = 2,
.popupCornerRadius = 18,
.popupTextBold = true,
.popupTextInverted = false,
.popupTextBaselineOffsetY = -2,
.popupProgressBarHeight = 4,
.popupProgressDrawOutline = true,
.popupProgressClampPercent = true,
.popupProgressFillInverted = false,
.popupProgressOutlineInverted = false,
.textFieldHorizontalPadding = 8,
.textFieldNormalThickness = 2,
.textFieldCursorThickness = 3,
.textFieldLineEndOffset = -1};
}
class RoundedRaffTheme : public BaseTheme {