refactor: redesign on-screen keyboard with 10-col layout, symbol mode, long-press, visual improvements

This commit is contained in:
pablohc
2026-04-12 23:08:50 +02:00
committed by jpirnay
parent 4449b807a4
commit 53d621a91f
7 changed files with 380 additions and 249 deletions
+58 -9
View File
@@ -862,17 +862,66 @@ void BaseTheme::drawHelpText(const GfxRenderer& renderer, Rect rect, const char*
}
void BaseTheme::drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth) const {
renderer.drawText(UI_12_FONT_ID, rect.x + 10, rect.y, "[");
renderer.drawText(UI_12_FONT_ID, rect.x + rect.width - 15, rect.y + rect.height, "]");
const int lineHeight = renderer.getLineHeight(UI_12_FONT_ID);
const int bracketHeight = lineHeight;
const int fieldLeft = rect.x + 10;
const int fieldRight = rect.x + rect.width - 15;
const int topY = rect.y;
const int bottomY = rect.y + rect.height + lineHeight;
const int tickLen = bracketHeight / 2;
renderer.drawLine(fieldLeft, topY, fieldLeft, bottomY);
renderer.drawLine(fieldLeft, topY, fieldLeft + tickLen, topY);
renderer.drawLine(fieldLeft, bottomY, fieldLeft + tickLen, bottomY);
renderer.drawLine(fieldRight, topY, fieldRight, bottomY);
renderer.drawLine(fieldRight, topY, fieldRight - tickLen, topY);
renderer.drawLine(fieldRight, bottomY, fieldRight - tickLen, bottomY);
}
void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label,
const bool isSelected) const {
const int itemWidth = renderer.getTextWidth(UI_10_FONT_ID, label);
const int textX = rect.x + (rect.width - itemWidth) / 2;
void BaseTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected,
const char* secondaryLabel, const KeyboardKeyType keyType) const {
if (isSelected) {
renderer.drawText(UI_10_FONT_ID, textX - 6, rect.y, "[");
renderer.drawText(UI_10_FONT_ID, textX + itemWidth, rect.y, "]");
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) {
renderer.drawRect(rect.x, rect.y, rect.width, rect.height);
}
if (keyType == KeyboardKeyType::Space) {
const int lineHalfWidth = rect.width * 3 / 10;
const int centerX = rect.x + rect.width / 2;
const int lineY = rect.y + rect.height / 2 + 3;
renderer.drawLine(centerX - lineHalfWidth, lineY, centerX + lineHalfWidth, lineY, 3, !isSelected);
return;
}
if (keyType == KeyboardKeyType::Del) {
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;
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX + arrowLen / 2, centerY, 3, !isSelected);
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX - arrowLen / 2 + arrowHead, centerY - arrowHead, 3,
!isSelected);
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX - arrowLen / 2 + arrowHead, centerY + arrowHead, 3,
!isSelected);
return;
}
const bool hasSecondary = secondaryLabel != nullptr && secondaryLabel[0] != '\0';
const int primaryOffset = hasSecondary ? 0 : 0;
const int itemWidth = renderer.getTextWidth(UI_12_FONT_ID, label);
const int textX = rect.x + (rect.width - itemWidth) / 2;
const int textY = rect.y + (rect.height - renderer.getLineHeight(UI_12_FONT_ID)) / 2 + primaryOffset;
if (isSelected) {
renderer.fillRect(rect.x, rect.y, rect.width, rect.height, true);
}
renderer.drawText(UI_12_FONT_ID, textX, textY, label, !isSelected);
if (hasSecondary) {
const int secWidth = renderer.getTextWidth(SMALL_FONT_ID, secondaryLabel);
renderer.drawText(SMALL_FONT_ID, rect.x + rect.width - secWidth - 1, rect.y - 3, secondaryLabel, !isSelected);
}
renderer.drawText(UI_10_FONT_ID, textX, rect.y, label);
}
+9 -3
View File
@@ -62,10 +62,13 @@ struct ThemeMetrics {
int keyboardKeySpacing;
bool keyboardBottomAligned;
bool keyboardCenteredText;
int keyboardVerticalOffset;
};
enum UIIcon { Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot, Weather };
enum class KeyboardKeyType { Normal, Shift, Mode, Space, Del, Ok };
// Default theme implementation (Classic Theme)
// Additional themes can inherit from this and override methods as needed
@@ -98,8 +101,9 @@ constexpr ThemeMetrics values = {.batteryWidth = 15,
.keyboardKeyWidth = 22,
.keyboardKeyHeight = 30,
.keyboardKeySpacing = 10,
.keyboardBottomAligned = false,
.keyboardCenteredText = false};
.keyboardBottomAligned = true,
.keyboardCenteredText = false,
.keyboardVerticalOffset = -10};
}
class BaseTheme {
@@ -142,7 +146,9 @@ class BaseTheme {
const int textYOffset = 0) const;
virtual void drawHelpText(const GfxRenderer& renderer, Rect rect, const char* label) const;
virtual void drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth) const;
virtual void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected) const;
virtual void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected,
const char* secondaryLabel = nullptr,
KeyboardKeyType keyType = KeyboardKeyType::Normal) const;
virtual bool showsFileIcons() const { return false; }
// Shared constants and helpers for battery drawing (used by all themes)
@@ -37,7 +37,8 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
.keyboardKeyHeight = 50,
.keyboardKeySpacing = 0,
.keyboardBottomAligned = true,
.keyboardCenteredText = true};
.keyboardCenteredText = true,
.keyboardVerticalOffset = 0};
}
class Lyra3CoversTheme : public LyraTheme {
+37 -4
View File
@@ -796,14 +796,47 @@ void LyraTheme::drawTextField(const GfxRenderer& renderer, Rect rect, const int
renderer.drawLine(rect.x + (rect.width - lineW) / 2, lineY, rect.x + (rect.width + lineW) / 2, lineY, 3);
}
void LyraTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label,
const bool isSelected) const {
void LyraTheme::drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected,
const char* secondaryLabel, const KeyboardKeyType keyType) const {
if (isSelected) {
renderer.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, cornerRadius, Color::Black);
} else if (keyType == KeyboardKeyType::Shift || keyType == KeyboardKeyType::Mode || keyType == KeyboardKeyType::Del ||
keyType == KeyboardKeyType::Space || keyType == KeyboardKeyType::Ok) {
renderer.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 1, cornerRadius, true);
}
const bool invert = isSelected;
if (keyType == KeyboardKeyType::Space) {
const int lineHalfWidth = rect.width * 3 / 10;
const int centerX = rect.x + rect.width / 2;
const int lineY = rect.y + rect.height / 2 + 3;
renderer.drawLine(centerX - lineHalfWidth, lineY, centerX + lineHalfWidth, lineY, 3, !invert);
return;
}
if (keyType == KeyboardKeyType::Del) {
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;
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);
renderer.drawLine(centerX - arrowLen / 2, centerY, centerX - arrowLen / 2 + arrowHead, centerY + arrowHead, 3,
!invert);
return;
}
const bool hasSecondary = secondaryLabel != nullptr && secondaryLabel[0] != '\0';
const int primaryOffset = hasSecondary ? 0 : 0;
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, label);
const int textX = rect.x + (rect.width - textWidth) / 2;
const int textY = rect.y + (rect.height - renderer.getLineHeight(UI_12_FONT_ID)) / 2;
renderer.drawText(UI_12_FONT_ID, textX, textY, label, !isSelected);
const int textY = rect.y + (rect.height - renderer.getLineHeight(UI_12_FONT_ID)) / 2 + primaryOffset;
renderer.drawText(UI_12_FONT_ID, textX, textY, label, !invert);
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);
}
}
+6 -3
View File
@@ -32,10 +32,11 @@ constexpr ThemeMetrics values = {.batteryWidth = 16,
.statusBarHorizontalMargin = 5,
.statusBarVerticalMargin = 19,
.keyboardKeyWidth = 31,
.keyboardKeyHeight = 50,
.keyboardKeyHeight = 40,
.keyboardKeySpacing = 0,
.keyboardBottomAligned = true,
.keyboardCenteredText = true};
.keyboardCenteredText = true,
.keyboardVerticalOffset = -10};
}
class LyraTheme : public BaseTheme {
@@ -67,7 +68,9 @@ class LyraTheme : public BaseTheme {
Rect drawPopup(const GfxRenderer& renderer, const char* message) const override;
void fillPopupProgress(const GfxRenderer& renderer, const Rect& layout, const int progress) const override;
void drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth) const override;
void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected) const override;
void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected,
const char* secondaryLabel = nullptr,
KeyboardKeyType keyType = KeyboardKeyType::Normal) const override;
bool showsFileIcons() const override { return true; }
protected: