Add UI scaling support for touch vs button devices
Introduces uiScale() method to apply per-board UI scaling based on device type (1.0 for button devices, >1 for touch devices to make UI elements finger-sized). Adds scaledMetrics member to store scaled theme metrics that are returned by getMetrics().
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
#include "UITheme.h"
|
||||
|
||||
#include <BoardConfig.h>
|
||||
#include <FsHelpers.h>
|
||||
#include <GfxRenderer.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
@@ -15,6 +17,66 @@
|
||||
|
||||
UITheme UITheme::instance;
|
||||
|
||||
float UITheme::uiScale() { return BoardConfig::ACTIVE.uiScale; }
|
||||
|
||||
namespace {
|
||||
// Round a pixel dimension by the UI scale.
|
||||
int sp(int v, float s) { return static_cast<int>(std::lround(v * s)); }
|
||||
} // namespace
|
||||
|
||||
ThemeMetrics scaleThemeMetrics(const ThemeMetrics& b, float s) {
|
||||
ThemeMetrics m = b;
|
||||
if (s == 1.0f) return m;
|
||||
m.batteryWidth = sp(b.batteryWidth, s);
|
||||
m.batteryHeight = sp(b.batteryHeight, s);
|
||||
m.topPadding = sp(b.topPadding, s);
|
||||
m.batteryBarHeight = sp(b.batteryBarHeight, s);
|
||||
m.headerHeight = sp(b.headerHeight, s);
|
||||
m.verticalSpacing = sp(b.verticalSpacing, s);
|
||||
m.contentSidePadding = sp(b.contentSidePadding, s);
|
||||
m.listRowHeight = sp(b.listRowHeight, s);
|
||||
m.listWithSubtitleRowHeight = sp(b.listWithSubtitleRowHeight, s);
|
||||
m.menuRowHeight = sp(b.menuRowHeight, s);
|
||||
m.menuSpacing = sp(b.menuSpacing, s);
|
||||
m.tabSpacing = sp(b.tabSpacing, s);
|
||||
m.tabBarHeight = sp(b.tabBarHeight, s);
|
||||
m.scrollBarWidth = sp(b.scrollBarWidth, s);
|
||||
m.scrollBarRightOffset = sp(b.scrollBarRightOffset, s);
|
||||
m.homeTopPadding = sp(b.homeTopPadding, s);
|
||||
// homeCoverHeight / homeCoverTileHeight are intentionally NOT scaled: the home
|
||||
// screen fills the fixed panel height exactly, so scaling the decorative cover
|
||||
// would push the menu off the bottom. The cover stays native; the menu (a touch
|
||||
// target) scales and is fit into the remaining space by drawButtonMenu.
|
||||
m.homeMenuTopOffset = sp(b.homeMenuTopOffset, s);
|
||||
m.buttonHintsHeight = sp(b.buttonHintsHeight, s);
|
||||
m.sideButtonHintsWidth = sp(b.sideButtonHintsWidth, s);
|
||||
m.progressBarHeight = sp(b.progressBarHeight, s);
|
||||
m.progressBarMarginTop = sp(b.progressBarMarginTop, s);
|
||||
m.statusBarHorizontalMargin = sp(b.statusBarHorizontalMargin, s);
|
||||
m.statusBarVerticalMargin = sp(b.statusBarVerticalMargin, s);
|
||||
m.keyboardKeyWidth = sp(b.keyboardKeyWidth, s);
|
||||
m.keyboardKeyHeight = sp(b.keyboardKeyHeight, s);
|
||||
m.keyboardKeySpacing = sp(b.keyboardKeySpacing, s);
|
||||
m.keyboardBottomKeyHeight = sp(b.keyboardBottomKeyHeight, s);
|
||||
m.keyboardBottomKeySpacing = sp(b.keyboardBottomKeySpacing, s);
|
||||
m.keyboardVerticalOffset = sp(b.keyboardVerticalOffset, s);
|
||||
m.keyboardKeyCornerRadius = sp(b.keyboardKeyCornerRadius, s);
|
||||
m.keyboardSecondaryLabelRightPadding = sp(b.keyboardSecondaryLabelRightPadding, s);
|
||||
m.keyboardSecondaryLabelTopPadding = sp(b.keyboardSecondaryLabelTopPadding, s);
|
||||
m.keyboardMinArrowHeadSize = sp(b.keyboardMinArrowHeadSize, s);
|
||||
m.popupMarginX = sp(b.popupMarginX, s);
|
||||
m.popupMarginY = sp(b.popupMarginY, s);
|
||||
m.popupFrameThickness = sp(b.popupFrameThickness, s);
|
||||
m.popupCornerRadius = sp(b.popupCornerRadius, s);
|
||||
m.popupTextBaselineOffsetY = sp(b.popupTextBaselineOffsetY, s);
|
||||
m.popupProgressBarHeight = sp(b.popupProgressBarHeight, s);
|
||||
m.textFieldHorizontalPadding = sp(b.textFieldHorizontalPadding, s);
|
||||
m.textFieldNormalThickness = sp(b.textFieldNormalThickness, s);
|
||||
m.textFieldCursorThickness = sp(b.textFieldCursorThickness, s);
|
||||
m.textFieldLineEndOffset = sp(b.textFieldLineEndOffset, s);
|
||||
return m;
|
||||
}
|
||||
|
||||
UITheme::UITheme() {
|
||||
auto themeType = static_cast<CrossPointSettings::UI_THEME>(SETTINGS.uiTheme);
|
||||
setTheme(themeType);
|
||||
@@ -26,28 +88,31 @@ void UITheme::reload() {
|
||||
}
|
||||
|
||||
void UITheme::setTheme(CrossPointSettings::UI_THEME type) {
|
||||
const ThemeMetrics* base = &BaseMetrics::values;
|
||||
switch (type) {
|
||||
case CrossPointSettings::UI_THEME::CLASSIC:
|
||||
LOG_DBG("UI", "Using Classic theme");
|
||||
currentTheme = std::make_unique<BaseTheme>();
|
||||
currentMetrics = &BaseMetrics::values;
|
||||
base = &BaseMetrics::values;
|
||||
break;
|
||||
case CrossPointSettings::UI_THEME::LYRA:
|
||||
LOG_DBG("UI", "Using Lyra theme");
|
||||
currentTheme = std::make_unique<LyraTheme>();
|
||||
currentMetrics = &LyraMetrics::values;
|
||||
base = &LyraMetrics::values;
|
||||
break;
|
||||
case CrossPointSettings::UI_THEME::ROUNDEDRAFF:
|
||||
LOG_DBG("UI", "Using RoundedRaff theme");
|
||||
currentTheme = std::make_unique<RoundedRaffTheme>();
|
||||
currentMetrics = &RoundedRaffMetrics::values;
|
||||
base = &RoundedRaffMetrics::values;
|
||||
break;
|
||||
case CrossPointSettings::UI_THEME::LYRA_3_COVERS:
|
||||
LOG_DBG("UI", "Using Lyra 3 Covers theme");
|
||||
currentTheme = std::make_unique<Lyra3CoversTheme>();
|
||||
currentMetrics = &Lyra3CoversMetrics::values;
|
||||
base = &Lyra3CoversMetrics::values;
|
||||
break;
|
||||
}
|
||||
scaledMetrics = scaleThemeMetrics(*base, uiScale());
|
||||
currentMetrics = &scaledMetrics;
|
||||
}
|
||||
|
||||
int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader, bool hasTabBar, bool hasButtonHints,
|
||||
|
||||
Reference in New Issue
Block a user