Add icon generation script and list scroll helper
Introduce gen_icons.sh to regenerate UI icons from a manifest file using the FreeInk SDK's Lucide icon set. Add icons.manifest mapping UI icons to Lucide names. Refactor vertical swipe list scrolling into a reusable wasListScroll() helper method used by both reader chapter selection and settings activities. Add static assertion to ensure ThemeMetrics scaling stays in sync with struct changes.
This commit is contained in:
@@ -25,6 +25,13 @@ int sp(int v, float s) { return static_cast<int>(std::lround(v * s)); }
|
||||
} // namespace
|
||||
|
||||
ThemeMetrics scaleThemeMetrics(const ThemeMetrics& b, float s) {
|
||||
// Every pixel field is scaled explicitly below. Counts, percents, ratios, bools,
|
||||
// and the intentionally-unscaled chrome (homeCover*, statusBar*, progressBar*) are
|
||||
// NOT touched. This guard fails when a ThemeMetrics field is added or removed —
|
||||
// classify the new field (scale it, or leave it and note it here) and bump the
|
||||
// expected size, so scaling can never silently miss a field.
|
||||
static_assert(sizeof(ThemeMetrics) == THEME_METRICS_SIZEOF,
|
||||
"ThemeMetrics changed: review scaleThemeMetrics() and update THEME_METRICS_SIZEOF");
|
||||
ThemeMetrics m = b;
|
||||
if (s == 1.0f) return m;
|
||||
m.batteryWidth = sp(b.batteryWidth, s);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# CrossPoint UI icon set: each UIIcon -> a Lucide icon name.
|
||||
# Edit this, then run scripts/gen_icons.sh to regenerate generated_icons.h.
|
||||
# Browse names in freeink-sdk/libs/assets/Icons/lucide/icons/*.svg.
|
||||
folder = folder
|
||||
text = file-text
|
||||
image = image
|
||||
book = book-open
|
||||
file = file
|
||||
recent = clock
|
||||
settings = settings
|
||||
transfer = arrow-down-up
|
||||
library = library-big
|
||||
wifi = wifi
|
||||
hotspot = router
|
||||
bookmark = bookmark
|
||||
@@ -104,6 +104,11 @@ struct ThemeMetrics {
|
||||
int textFieldLineEndOffset;
|
||||
};
|
||||
|
||||
// Expected sizeof(ThemeMetrics), in bytes. scaleThemeMetrics() static_asserts
|
||||
// against this so a new/removed metric field can't slip through unclassified;
|
||||
// update it after adding a field (and decide there whether the field scales).
|
||||
inline constexpr unsigned THEME_METRICS_SIZEOF = 216;
|
||||
|
||||
enum UIIcon { None = 0, Folder, Text, Image, Book, File, Recent, Settings, Transfer, Library, Wifi, Hotspot, Bookmark };
|
||||
|
||||
enum class KeyboardKeyType { Normal, Shift, Mode, Space, Del, Ok, Disabled };
|
||||
|
||||
@@ -34,9 +34,29 @@ constexpr int listIconSize = 24;
|
||||
constexpr int mainMenuColumns = 2;
|
||||
int coverWidth = 0;
|
||||
|
||||
// Pick the generated Lucide icon variant nearest to targetPx for a UIIcon. The
|
||||
// generator emits 24/32/40/48px with each icon's optical center baked in, so a
|
||||
// scaled UI gets a crisp larger asset (not an upscaled one) and exact alignment.
|
||||
// The generated icon sizes (px). The generator (gen_icons.py) emits these.
|
||||
constexpr int kIconSizes[] = {24, 32, 40, 48};
|
||||
|
||||
// Scale a base icon size by the board uiScale.
|
||||
int scaledIcon(int base) { return static_cast<int>(base * UITheme::uiScale() + 0.5f); }
|
||||
|
||||
// Index of the generated size nearest targetPx, and that size in px.
|
||||
int iconVariantIndex(int targetPx) {
|
||||
int best = 0, bestDist = 1 << 30;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
const int d = kIconSizes[i] > targetPx ? kIconSizes[i] - targetPx : targetPx - kIconSizes[i];
|
||||
if (d < bestDist) {
|
||||
bestDist = d;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
int nearestIconSize(int targetPx) { return kIconSizes[iconVariantIndex(targetPx)]; }
|
||||
|
||||
// Generated Lucide icon variant nearest targetPx for a UIIcon. Each icon ships at
|
||||
// every size with its optical center baked in, so a scaled UI gets a crisp larger
|
||||
// asset (not an upscale) with exact alignment.
|
||||
const freeink::Icon* pickIcon(UIIcon icon, int targetPx) {
|
||||
const freeink::Icon* const* v = nullptr;
|
||||
#define VARIANTS(n) \
|
||||
@@ -61,33 +81,7 @@ const freeink::Icon* pickIcon(UIIcon icon, int targetPx) {
|
||||
default: return nullptr;
|
||||
}
|
||||
#undef VARIANTS
|
||||
static constexpr int kSizes[] = {24, 32, 40, 48};
|
||||
int best = 0, bestDist = 1 << 30;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
const int d = kSizes[i] > targetPx ? kSizes[i] - targetPx : targetPx - kSizes[i];
|
||||
if (d < bestDist) {
|
||||
bestDist = d;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
return v[best];
|
||||
}
|
||||
|
||||
// Scale a base icon size by the board uiScale.
|
||||
int scaledIcon(int base) { return static_cast<int>(base * UITheme::uiScale() + 0.5f); }
|
||||
|
||||
// Nearest generated icon size (24/32/40/48) to targetPx.
|
||||
int nearestIconSize(int targetPx) {
|
||||
static constexpr int kSizes[] = {24, 32, 40, 48};
|
||||
int best = kSizes[0], bestDist = 1 << 30;
|
||||
for (int s : kSizes) {
|
||||
const int d = s > targetPx ? s - targetPx : targetPx - s;
|
||||
if (d < bestDist) {
|
||||
bestDist = d;
|
||||
best = s;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
return v[iconVariantIndex(targetPx)];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user